JlatexmathJsGenerator.java
package net.sourceforge.plantuml.math;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
// ::remove file when JAVA8 or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
/**
* Generates <code>src/main/teavm/generated/jlatexmath.js</code>, the companion
* script that gives the resources of JLaTeXMath (the XML files and the glyph
* outlines, the same files as the C build embeds) to the browser build, which
* has no class loader. It fills <code>PLANTUML_JLATEXMATH</code>, a map from the
* path under <code>org/scilab/forge/jlatexmath/</code> to the Base64 of the file.
* <p>
* Loaded on demand, only by a diagram that has a formula, like
* <code>emoji.js</code>. It is GPL (as the library): it is not in the packages
* of the MIT, EPL, BSD, ASL and LGPL variants.
* <p>
* Run it after changing the resources of the library:
*
* <pre>
* java net.sourceforge.plantuml.math.JlatexmathJsGenerator
* </pre>
*/
public final class JlatexmathJsGenerator {
static final String RESOURCES_DIR = "src/main/resources/org/scilab/forge/jlatexmath";
static final String OUTPUT = "src/main/teavm/generated/jlatexmath.js";
private JlatexmathJsGenerator() {
}
public static void main(String[] args) throws IOException {
final File output = new File(OUTPUT);
if (output.getParentFile().isDirectory() == false)
throw new IOException("Target directory does not exist: " + output.getParentFile());
final String content = generate(new File(RESOURCES_DIR));
Files.write(output.toPath(), content.getBytes(StandardCharsets.UTF_8));
System.out.println("Generated " + output.getAbsolutePath());
}
/** The content of jlatexmath.js (explicit \n, identical on every platform). */
static String generate(File dir) throws IOException {
if (dir.isDirectory() == false)
throw new IOException("Resources directory does not exist: " + dir.getAbsolutePath());
final List<String> names = new ArrayList<String>();
collect(dir, "", names);
Collections.sort(names);
final StringBuilder out = new StringBuilder();
out.append("// jlatexmath.js - Generated by JlatexmathJsGenerator.main()\n");
out.append("// Do not edit manually\n");
out.append("(function () {\n");
out.append("var g = (typeof globalThis !== 'undefined') ? globalThis"
+ " : ((typeof self !== 'undefined') ? self : this);\n");
out.append("g.PLANTUML_JLATEXMATH = g.PLANTUML_JLATEXMATH || {};\n");
out.append("\n");
for (String name : names) {
byte[] data = Files.readAllBytes(new File(dir, name).toPath());
if (name.endsWith(".xml"))
data = removeCarriageReturns(data);
out.append("g.PLANTUML_JLATEXMATH[\"").append(name).append("\"]=\"")
.append(Base64.getEncoder().encodeToString(data)).append("\";\n");
}
out.append("})();\n");
return out.toString();
}
/**
* jlatexmath.js must be the same on every platform: with a CRLF checkout (git
* autocrlf on Windows) the XML files have CRLF, and the generated file would
* not be the committed one. A CR is only a whitespace in these XML files and
* is never part of a UTF-8 multi-byte character, so removing it is harmless.
* Not applied to the binary glyphs.
*/
static byte[] removeCarriageReturns(byte[] data) {
int count = 0;
for (byte b : data)
if (b == '\r')
count++;
if (count == 0)
return data;
final byte[] result = new byte[data.length - count];
int i = 0;
for (byte b : data)
if (b != '\r')
result[i++] = b;
return result;
}
private static void collect(File dir, String prefix, List<String> names) throws IOException {
final File[] files = dir.listFiles();
if (files == null)
throw new IOException("Cannot list " + dir.getAbsolutePath());
for (File file : files) {
final String name = prefix + file.getName();
if (file.isDirectory())
collect(file, name + "/", names);
// Same files as the C build embeds (copyNativeSources)
else if (name.endsWith(".xml") || name.endsWith("/glyphs.bin"))
names.add(name);
}
}
}