Logos.java
/*
* Copyright © 2012-2025 The CTAN Team and individual authors
*
* This file is distributed under the 3-clause BSD license.
* See file LICENSE for details.
*/
package org.ctan.markup;
/**
* This utility class contains translations for logos to HTML.
*
* @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
*/
public interface Logos {
/**
* The field <code>TEX</code> contains the <span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logo in HTML.
*/
String TEX =
"<span class=\"t-logo\">T<span class=\"e\">e</span>X</span>";
/**
* The field <code>P_TEX</code> contains the unprotected <span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logo in HTML.
*/
String P_TEX = "T<span class=\"e\">e</span>X";
/**
* The field <code>TETEX</code> contains the te<span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logo in HTML.
*/
String TETEX =
"<span class=\"t-logo\">teT<span class=\"e\">e</span>X</span>";
/**
* The field <code>BIBTEX</code> contains the BibTeX logo in HTML.
*/
String BIBTEX =
"<span class=\"t-logo\"><span class=\"sc\">Bib</span>"
+ "<span class=\"t\">T</span>"
+ "<span class=\"e\">e</span>X</span>";
/**
* The field <code>ETEX</code> contains the eTeX logo in HTML.
*/
String ETEX =
"<span class=\"t-logo\"><span class=\"t-logo\">ε-" + P_TEX
+ "</span>";
/**
* The field <code>EMTEX</code> contains the emTeX logo in HTML.
*/
String EMTEX =
"<span class=\"t-logo\">em" + P_TEX + "</span></span>";
/**
* The field <code>CONTEXT</code> contains the Con<span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>t
* logo in HTML.
*/
String CONTEXT =
"<span class=\"t-logo\">Con" + P_TEX + "t</span>";
/**
* The field <code>LATEX</code> contains the
* L<span style="font-size: 75%; margin-left: -.36em; margin-right: -.125em;
* text-transform: uppercase; vertical-align: .45ex;">a</span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X logo in
* HTML.
*/
String LATEX =
"<span class=\"t-logo\">L<span class=\"a\">a</span>" + P_TEX
+ "</span>";
/**
* The field <code>P_LATEX</code> contains the unprotected
* L<span style="font-size: 75%; margin-left: -.36em; margin-right: -.125em;
* text-transform: uppercase; vertical-align: .45ex;">a</span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X logo in
* HTML.
*/
String P_LATEX = "L<span class=\"a\">a</span>" + P_TEX;
/**
* The field <code>_LA_TEX</code> contains the (La)<span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logo in HTML.
*/
String _LA_TEX =
"<span class=\"t-logo\">(L<span class=\"a\">a</span>)"
+ "<span class=\"T\">T</span><span class=\"e\">e</span>"
+ "X</span>";
/**
* The field <code>LATEX_2E_</code> contains the
* L<span style="font-size: 75%; margin-left: -.36em; margin-right: -.125em;
* text-transform: uppercase; vertical-align: .45ex;">a</span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X(2e)
* logo in HTML.
*/
String LATEX_2E_ =
"<span class=\"t-logo\">" + P_LATEX + "(2ε)</span>";
/**
* The field <code>LATEX2E</code> contains the
* L<span style="font-size: 75%; margin-left: -.36em; margin-right: -.125em;
* text-transform: uppercase; vertical-align: .45ex;">a</span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X2e logo
* in HTML.
*/
String LATEX2E =
"<span class=\"t-logo\">" + P_LATEX + "2ε</span>";
/**
* The field <code>METAFONT</code> contains the METAFONT logo in HTML.
*/
String METAFONT =
"<span class=\"mflogo\">METAFONT</span>";
/**
* The field <code>METAPOST</code> contains the METAPOST logo in HTML.
*/
String METAPOST =
"<span class=\"mflogo\">METAPOST</span>";
/**
* The field <code>MIKTEX</code> contains the MiK<span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logo in HTML.
*/
String MIKTEX =
"<span class=\"t-logo\">MiK" + P_TEX + "</span>";
/**
* The field <code>PICTEX</code> contains the Pic<span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logo in HTML.
*/
String PICTEX =
"<span>P<span class=\"e\">i</span>C<span class=\"t\">T</span>"
+ "<span class=\"e\">e</span>X</span>";
/**
* The field <code>XELATEX</code> contains the XeLaTeX logo in HTML.
*/
String XELATEX =
"<span class=\"t-logo\">X<span class=\"E\">e</span>" + P_LATEX
+ "</span>";
/**
* The field <code>XE_LA_TEX</code> contains the Xe(La)TeX logo in HTML.
*/
String XE_LA_TEX =
"<span class=\"t-logo\">X<span class=\"E\">e</span>"
+ "(L<span class=\"a\">a</span>)T<span class=\"e\">e</span>"
+ "X</span>";
/**
* The field <code>XETEX</code> contains the XeTeX logo in HTML.
*/
String XETEX =
"<span class=\"t-logo\">X<span class=\"E\">e</span>"
+ "<span class=\"t\">T</span><span class=\"e\">e</span>X"
+ "</span>";
/**
* The field <code>AMS</code> contains the AMS logo in HTML.
*/
String AMS = "AMS";
// "<span class=\"cal-logo\">A<span class=\"M\">M</span>S</span>";
/**
* The field <code>AMS</code> contains the AmS-<span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logo in HTML.
*/
String AMS_TEX =
"<span class=\"t-logo\">" + AMS + "-" + P_TEX + "</span>";
/**
* The field <code>AMS</code> contains the AmS-LaTeX logo in HTML.
*/
String AMS_LATEX =
"<span class=\"t-logo\">" + AMS + "-" + P_LATEX + "</span>";
/**
* The field <code>LyX</code> contains the LyX logo in HTML.
*/
String LYX = "<span class=\"t-logo\">"
+ "L<span class=\"y\">y</span>X" + "</span>";
/**
* The method <code>lookingAt</code> provides means to translate a single
* logo.
*
* @param s the string to analyse
* @param si the index
* @param expected the expected string
* @param i the start index
* @param b the target buffer
* @param logo the logo to replace
* @return the result
*/
private static boolean lookingAt(String s, int si, String expected, int i,
StringBuilder b, String logo) {
if (i >= expected.length()) {
b.append('\\');
b.append(logo == null ? expected : logo);
b.append("{}");
return true;
}
if (si >= s.length() || s.charAt(si) != expected.charAt(i)) {
return false;
}
return lookingAt(s, si + 1, expected, i + 1, b, logo);
}
/**
* Translate <span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logos to HTML.
*
* @param s the string to translate
* @return the translated string
*/
static String tex2html(String s) {
if (s == null || s.isEmpty()) {
return "";
}
return s.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll("\\\"", """)
.replaceAll("\\\\-", "­")
.replaceAll("\\\\ +", " ")
.replaceAll("\r", "")
.replaceAll("\n *\n+", "</p><p>")
.replaceAll("\\\\par", "</p><p>")
.replaceAll("\\\\\\\\", "<br />")
.replaceAll("\\\\BibTeX(\\{\\})?", BIBTEX)
.replaceAll("\\\\ConTeXt(\\{\\})?", CONTEXT)
.replaceAll("\\\\Pi[cC]TeX(\\{\\})?", PICTEX)
.replaceAll("\\\\XeTeX(\\{\\})?", XETEX)
.replaceAll("\\\\XeLaTeX(\\{\\})?", XELATEX)
.replaceAll("\\\\TeXLaTeX(\\{\\})?", _LA_TEX)
.replaceAll("\\\\LaTeX2?e(\\{\\})?", LATEX2E)
.replaceAll("\\\\LaTeX(2e)", LATEX_2E_)
.replaceAll("\\\\LaTeX(\\{\\})?", LATEX)
.replaceAll("\\\\LyX(\\{\\})?", LYX)
.replaceAll("\\\\MiKTeX(\\{\\})?", MIKTEX)
.replaceAll("\\\\TeXLaTeX(\\{\\})?", _LA_TEX)
.replaceAll("\\\\teTeX(\\{\\})?", TETEX)
.replaceAll("\\\\eTeX(\\{\\})?", ETEX)
.replaceAll("\\\\emTeX(\\{\\})?", EMTEX)
.replaceAll("\\\\A[mM]STeX(\\{\\})?", AMS_TEX)
.replaceAll("\\\\A[mM]SLaTeX(\\{\\})?", AMS_LATEX)
.replaceAll("\\\\TeX(\\{\\})?", TEX)
.replaceAll("\\\\Meta[Ff]ont(\\{\\})?", METAFONT)
.replaceAll("\\\\Meta[Pp]ost(\\{\\})?", METAPOST);
}
/**
* Translate <span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logos from text to HTML.
*
* @param s the string to translate
* @return the translated string
*/
static String text2html(String s) {
return text2html(s, true);
}
/**
* Translate <span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logos from text to HTML.
*
* @param s the string to translate
* @param translateEntities also translate HTML entities
*
* @return the translated string
*/
static String text2html(String s, boolean translateEntities) {
if (s == null || s.isEmpty()) {
return "";
}
s = s.replaceAll("==>", "⇒").replaceAll("-->", "→");
if (translateEntities) {
s = s.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll("\"", """);
}
return s.replaceAll("([0-9])(th)([ .,;!?:])", "$1<sup>$2</sup>$3")
.replaceAll("(1)(st)([ .,;!?:])", "$1<sup>$2</sup>$3")
.replaceAll("(2)(nd)([ .,;!?:])", "$1<sup>$2</sup>$3")
.replaceAll("(3)(rd)([ .,;!?:])", "$1<sup>$2</sup>$3")
.replaceAll("\r", "")
.replaceAll(" -- ", " – ")
.replaceAll("---", "—")
.replaceAll("\n *\n+", "<br />")
.replaceAll("A[mM]S-?TeX", AMS_TEX)
.replaceAll("A[mM]S-?LaTeX", AMS_LATEX)
.replaceAll("AMS", AMS)
.replaceAll("BibTeX", BIBTEX)
.replaceAll("ConTeXt", CONTEXT)
.replaceAll("emTeX", EMTEX)
.replaceAll("Pi[cC]TeX", PICTEX)
.replaceAll("XeTeX", XETEX)
.replaceAll("XeLaTeX", XELATEX)
.replaceAll("Xe\\(La\\)TeX", XE_LA_TEX)
.replaceAll("eTeX", ETEX)
.replaceAll("LaTeX2e", LATEX2E)
.replaceAll("LaTeX(2e)", LATEX_2E_)
.replaceAll("LaTeXe", LATEX2E)
.replaceAll("LaTeX", LATEX)
.replaceAll("LyX", LYX)
.replaceAll("\\(La\\)TeX", _LA_TEX)
.replaceAll("Meta[Ff]ont", METAFONT)
.replaceAll("Meta[Pp]ost", METAPOST)
.replaceAll("Mi[kK]TeX", MIKTEX)
.replaceAll("teTeX", TETEX)
.replaceAll("TeXLaTeX", _LA_TEX)
.replaceAll("TeX", TEX);
}
/**
* Translate <span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X</span>
* logos from text to
* L<span style="font-size: 75%; margin-left: -.36em; margin-right: -.125em;
* text-transform: uppercase; vertical-align: .45ex;">a</span>T<span style=
* "text-transform:uppercase;font-size:90%;vertical-align:-0.4ex;
* margin-left:-0.2em;margin-right:-0.1em;line-height:0;" >e</span>X.
*
* @param s the string to translate
* @return the translated string
*/
static String text2latex(String s) {
if (s == null || s.isEmpty()) {
return "";
}
var out = new StringBuilder();
char c;
for (var i = 0; i < s.length(); i++) {
switch (c = s.charAt(i)) {
case '\\':
out.append(c);
if (++i >= s.length()) {
return out.toString();
}
c = s.charAt(i);
if (Character.isLetter(c)) {
while (++i < s.length() && Character.isLetter(c)) {
out.append(c);
c = s.charAt(i);
}
i--;
}
break;
case 'e':
if (lookingAt(s, i, "eTeX", 0, out, null)) {
i += 3;
continue;
} else if (lookingAt(s, i, "e-TeX", 0, out, "eTeX")) {
i += 4;
continue;
} else if (lookingAt(s, i, "emTeX", 0, out, null)) {
i += 4;
continue;
}
break;
case '(':
if (lookingAt(s, i, "(La)TeX", 0, out, "TeXLaTeX")) {
i += 6;
continue;
}
break;
case 'A':
if (lookingAt(s, i, "AmSTeX", 0, out, null)
|| lookingAt(s, i, "AmsTeX", 0, out, "AmSTeX")) {
i += 5;
continue;
} else if (lookingAt(s, i, "AmSLaTeX", 0, out, null)
|| lookingAt(s, i, "AmsLaTeX", 0, out,
"AmSLaTeX")) {
i += 7;
continue;
}
break;
case 'B':
if (lookingAt(s, i, "BibTeX", 0, out, null)) {
i += 5;
continue;
}
break;
case 'C':
if (lookingAt(s, i, "ConTeXt", 0, out, null)) {
i += 6;
continue;
}
break;
case 'T':
if (lookingAt(s, i, "TeX", 0, out, null)) {
i += 2;
continue;
}
break;
case 'L':
if (lookingAt(s, i, "LaTeXe", 0, out, "LaTeXe")) {
i += 5;
continue;
} else if (lookingAt(s, i, "LaTeX2e", 0, out, "LaTeXe")) {
i += 6;
continue;
} else if (lookingAt(s, i, "LaTeX(2e)", 0, out,
"LaTeX(2e)")) {
i += 9;
continue;
} else if (lookingAt(s, i, "LaTeX", 0, out, null)) {
i += 4;
continue;
} else if (lookingAt(s, i, "LyX", 0, out, null)) {
i += 2;
continue;
}
break;
case 'M':
if (lookingAt(s, i, "Metafont", 0, out, "METAFONT")
|| lookingAt(s, i, "MetaFont", 0, out, "METAFONT")
|| lookingAt(s, i, "Metapost", 0, out, "METAPOST")
|| lookingAt(s, i, "MetaPost", 0, out,
"METAPOST")) {
i += 7;
continue;
} else if (lookingAt(s, i, "MiKTeX", 0, out, null)) {
i += 5;
continue;
}
break;
case 'N':
if (lookingAt(s, i, "NTS", 0, out, null)) {
i += 2;
continue;
}
break;
case 'P':
if (lookingAt(s, i, "PiCTeX", 0, out, null)
|| lookingAt(s, i, "PicTeX", 0, out, "PiCTeX")) {
i += 5;
continue;
}
break;
case 'X':
if (lookingAt(s, i, "XeTeX", 0, out, null)) {
i += 4;
continue;
} else if (lookingAt(s, i, "XeLaTeX", 0, out, null)) {
i += 6;
continue;
}
break;
default:
// nothing to do
}
out.append(c);
}
return out.toString();
}
}