package net.sourceforge.plantuml.preproc;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.brotli.BrotliInputStream;

public class Stdlib6 {

	static private final Map all = new ConcurrentHashMap();
	private static final String SEPARATOR = "\uF8FF";

	private final Map> raw = new HashMap>();
	// private final Map> cache = new ConcurrentHashMap>();
	private final String name;
	private final Map info = new HashMap();

	public static InputStream getResourceAsStream(String fullname) {
		fullname = fullname.toLowerCase().replace(".puml", "");
		final int last = fullname.indexOf('/');
		if (last == -1) {
			return null;
		}
		try {
			final Stdlib6 folder = retrieve(fullname.substring(0, last));
			if (folder == null || folder.raw.size() == 0) {
				return null;
			}
			final byte[] data = folder.getData(fullname.substring(last + 1));
			if (data == null) {
				return null;
			}
			return new ByteArrayInputStream(data);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	private static InputStream getInternalInputStream(String fullname, String extension) {
		final String res = "/stdlib/" + fullname + extension;
		return Stdlib6.class.getResourceAsStream(res);
	}

	private static Stdlib6 retrieve(final String name) throws IOException {
		Stdlib6 result = all.get(name);
		if (result == null) {
			result = new Stdlib6(name);
			all.put(name, result);
		}
		return result;
	}

	private final Pattern sizePattern = Pattern.compile("\\[(\\d+)x(\\d+)/16\\]");

	private Stdlib6(String name) throws IOException {
		this.name = name;
		Log.info("Opening archive " + name);
		final DataInputStream dataStream = getDataStream();
		if (dataStream == null) {
			return;
		}
		fillMap(dataStream.readUTF());
		// final InputStream spriteStream = getSpriteStream();
		int pos = 0;
		while (true) {
			final String filename = dataStream.readUTF();
			// System.err.println("filename=" + filename);
			if (filename.equals(SEPARATOR)) {
				break;
			}
			final List text = new ArrayList();
			while (true) {
				final String s = dataStream.readUTF();
				if (s.equals(SEPARATOR)) {
					break;
				}
				text.add(s);
				if (isSpriteLine(s)) {
					final Matcher m = sizePattern.matcher(s);
					final boolean ok = m.find();
					if (ok == false) {
						throw new IOException(s);
					}
					final int width = Integer.parseInt(m.group(1));
					final int height = Integer.parseInt(m.group(2));
					text.add("" + pos);
					pos += spriteSize(width, height);
					// System.err.println("Sprite! " + width + " " + height + " " + s);
					text.add("}");
				}
			}
			raw.put(filename.toLowerCase(), text);
			// System.err.println("data=" + text.size());
			// final int len = is.readInt();
			// this.data.put(filename.toLowerCase(), new Portion(pos, len));
			// pos += len;
		}
		dataStream.close();
	}

	private int spriteSize(int width, int height) {
		final int nbLines = (height + 1) / 2;
		return width * nbLines;
	}

	private String readSprite(int width, int height, InputStream inputStream) throws IOException {
		final StringBuilder result = new StringBuilder();
		final int nbLines = (height + 1) / 2;
		int line = 0;
		for (int j = 0; j < nbLines; j++) {
			final StringBuilder sb1 = new StringBuilder();
			final StringBuilder sb2 = new StringBuilder();
			for (int i = 0; i < width; i++) {
				final int b = inputStream.read();
				final int b1 = (b & 0xF0) >> 4;
				final int b2 = (b & 0x0F);
				sb1.append(toHexString(b1));
				sb2.append(toHexString(b2));
			}
			result.append(sb1.toString());
			result.append("\n");
			line++;
			if (line < height) {
				result.append(sb2.toString());
				result.append("\n");
				line++;
			}
		}
		return result.toString();
	}

	private String toHexString(final int b) {
		return Integer.toHexString(b).toUpperCase();
	}

	private boolean isSpriteLine(String s) {
		return s.trim().startsWith("sprite") && s.trim().endsWith("{");
	}

	private void fillMap(String infoString) {
		for (String s : infoString.split("\n")) {
			if (s.contains("=")) {
				final String data[] = s.split("=");
				this.info.put(data[0], data[1]);
			}
		}
	}

	private DataInputStream getDataStream() throws IOException {
		final InputStream raw = getInternalInputStream(name, "-dat2.repx");
		if (raw == null) {
			return null;
		}
		return new DataInputStream(new BrotliInputStream(raw));
	}

	private InputStream getSpriteStream() throws IOException {
		final InputStream raw = getInternalInputStream(name, "-spr.repx");
		if (raw == null) {
			return null;
		}
		return new BrotliInputStream(raw);
	}

	private byte[] getData(String filename) throws IOException {
		final List result = raw.get(filename);
		if (result == null) {
			return null;
		}
		final StringBuilder sb = new StringBuilder();
		for (Iterator it = result.iterator(); it.hasNext();) {
			final String s = it.next();
			sb.append(s);
			sb.append("\n");
			if (isSpriteLine(s)) {
				final Matcher m = sizePattern.matcher(s);
				final boolean ok = m.find();
				if (ok == false) {
					throw new IOException(s);
				}
				final int width = Integer.parseInt(m.group(1));
				final int height = Integer.parseInt(m.group(2));
				final InputStream spriteStream = getSpriteStream();
				final int pos = Integer.parseInt(it.next());
				// System.err.println("pos=" + pos);
				spriteStream.skip(pos);
				sb.append(readSprite(width, height, spriteStream));
				sb.append("\n");
				spriteStream.close();
			}
		}
		return sb.toString().getBytes("UTF-8");
	}

	public static void extractStdLib() throws IOException {
		// for (String name : getAll()) {
		// final Stdlib6 folder = new Stdlib6(name);
		// folder.extractMeFull(new File("stdlib", name));
		// }
	}

	private static List getAll() throws IOException {
		final List result = new ArrayList();
		final InputStream home = getInternalInputStream("home", ".repx");
		final BufferedReader br = new BufferedReader(new InputStreamReader(home));
		String name;
		while ((name = br.readLine()) != null) {
			result.add(name);
		}
		return Collections.unmodifiableList(result);
	}

	// private void extractMeFull(File dir) throws IOException {
	// final DataInputStream idx = getDataIndex();
	// final DataInputStream txt = getFullTexts();
	// final String infoString = idx.readUTF();
	// while (true) {
	// final String filename = idx.readUTF();
	// if (filename.length() == 0) {
	// idx.close();
	// txt.close();
	// return;
	// }
	// final int len = idx.readInt();
	// final File f = new File("stdlib/" + name + "/" + filename + ".puml");
	// f.getParentFile().mkdirs();
	// final FileOutputStream fos = new FileOutputStream(f);
	// final byte data[] = new byte[len];
	// txt.readFully(data);
	// fos.write(data);
	// fos.close();
	// }
	// }

	public static void addInfoVersion(List strings) {
		try {
			for (String name : getAll()) {
				final Stdlib6 folder = new Stdlib6(name);
				strings.add("* " + name + " (Version " + folder.getVersion() + ")");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private String getVersion() {
		return info.get("VERSION");
	}
}

 

Ads help maintain this website.