<commit_before>package org.warp.picalculator.gui.graphicengine.cpu;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;

import org.warp.picalculator.Utils;
import org.warp.picalculator.gui.graphicengine.BinaryFont;
import org.warp.picalculator.gui.graphicengine.GraphicEngine;

import com.sun.xml.internal.bind.v2.model.util.ArrayInfoUtil;

public class CPUFont implements BinaryFont {

	public boolean[][] rawchars;
	public int[] chars32;
	public int minBound = 10;
	public int maxBound = 0;
	public int charW;
	public int charH;
	public int charS;
	public int charIntCount;
	public LinkedList<Integer[]> intervals;
	public int intervalsTotalSize = 0;
	public static final int intBits = 31;
	private final boolean isResource;

	public CPUFont(String fontName) throws IOException {
		this(fontName, false);
	}

	CPUFont(String fontName, boolean onlyRaw) throws IOException {
		isResource = true;
		load("/font_" + fontName + ".rft", onlyRaw);
	}
	
	public CPUFont(String path, String fontName) throws IOException {
		this(path, fontName, false);
	}
	
	CPUFont(String path, String fontName, boolean onlyRaw) throws IOException {
		isResource = false;
		load(path + "/font_" + fontName + ".rft", onlyRaw);
	}

	public static CPUFont loadTemporaryFont(String name) throws IOException {
		return new CPUFont(name, true);
	}

	public static CPUFont loadTemporaryFont(String path, String name) throws IOException {
		return new CPUFont(path, name, true);
	}

	@Override
	public void load(String path) throws IOException {
		load(path, false);
	}
	
	private void load(String path, boolean onlyRaw) throws IOException {
		Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_MIN, "Loading font " + path);
		loadFont(path);
		if (!onlyRaw) {
			chars32 = new int[(intervalsTotalSize) * charIntCount];
			for (int charCompressedIndex = 0; charCompressedIndex < intervalsTotalSize; charCompressedIndex++) {
				final boolean[] currentChar = rawchars[charCompressedIndex];
				if (currentChar == null) {
					int currentInt = 0;
					int currentBit = 0;
					for (int i = 0; i < charS; i++) {
						if (currentInt * intBits + currentBit >= (currentInt + 1) * intBits) {
							currentInt += 1;
							currentBit = 0;
						}
						chars32[charCompressedIndex * charIntCount + currentInt] = (chars32[charCompressedIndex * charIntCount + currentInt] << 1) + 1;
						currentBit += 1;
					}
				} else {
					int currentInt = 0;
					int currentBit = 0;
					for (int i = 0; i < charS; i++) {
						if (currentBit >= intBits) {
							currentInt += 1;
							currentBit = 0;
						}
						chars32[charCompressedIndex * charIntCount + currentInt] = (chars32[charCompressedIndex * charIntCount + currentInt]) | ((currentChar[i] ? 1 : 0) << currentBit);
						currentBit++;
					}
				}
			}
		}

		Utils.gc();
	}

	private void loadFont(String string) throws IOException {
		final URL res = isResource ? this.getClass().getResource(string) : new File(string).toURI().toURL();
		final int[] file = Utils.realBytes(Utils.convertStreamToByteArray(res.openStream(), res.getFile().length()));
		final int filelength = file.length;
		if (filelength >= 16) {
			if (file[0x0] == 114 && file[0x1] == 97 && file[0x2] == 119 && file[0x3] == 0xFF && file[0x8] == 0xFF && file[0xD] == 0xFF) {
				charW = file[0x4] << 8 | file[0x5];
				charH = file[0x6] << 8 | file[0x7];
				charS = charW * charH;
				charIntCount = (int) Math.ceil(((double) charS) / ((double) intBits));
				minBound = file[0x9] << 24 | file[0xA] << 16 | file[0xB] << 8 | file[0xC];
				maxBound = file[0xE] << 24 | file[0xF] << 16 | file[0x10] << 8 | file[0x11];
				if (maxBound <= minBound) {
					maxBound = 9900; //TODO remove it: temp fix
				}
				rawchars = new boolean[maxBound - minBound][];
				int index = 0x12;
				while (index < filelength) {
					try {
						final int charIndex = file[index] << 8 | file[index + 1];
						final boolean[] rawchar = new boolean[charS];
						int charbytescount = 0;
						while (charbytescount * 8 < charS) {
							charbytescount += 1;
						}
						int currentBit = 0;
						for (int i = 0; i <= charbytescount; i++) {
							for (int bit = 0; bit < 8; bit++) {
								if (currentBit >= charS) {
									break;
								}
								rawchar[currentBit] = (((file[index + 2 + i] >> (8 - 1 - bit)) & 0x1) == 1) ? true : false;
								currentBit++;
							}
						}
						rawchars[charIndex - minBound] = rawchar;
						index += 2 + charbytescount;
					} catch (final Exception ex) {
						ex.printStackTrace();
						System.out.println(string);
						System.exit(-1);
					}
				}
			} else {
				throw new IOException();
			}
		} else {
			throw new IOException();
		}
		findIntervals();
		/*int[] screen = new int[rawchars.length * charW * charH];
		for (int i = 0; i < rawchars.length; i++) {
			if (rawchars[i] != null)
				for (int charX = 0; charX < charW; charX++) {
					for (int charY = 0; charY < charH; charY++) {
						int x = i * charW + charX;
						int y = charY;
						screen[x + y * rawchars.length * charW] = rawchars[i][charX + charY * charW] ? 0xFF000000 : 0xFFFFFFFF;
					}
				}
		}
		System.out.println();
		System.out.println((('1' & 0xFFFF) - minBound) + "=>"+ (getCharIndexes("1")[0]));
		this.saveArray(screen, rawchars.length * charW, charH, "N:\\TimedTemp"+string+".png");
		System.out.println();
		System.out.println();
		*/
	}

	private void findIntervals() {
		intervals = new LinkedList<Integer[]>();
		int beginIndex = -1;
		int endIndex = 0;
		int intervalSize = 0;
		int holeSize = 0;
		for (int i = 0; i < rawchars.length; i++) {
			if (rawchars[i] != null) {
				beginIndex = i;
				int firstNull = 0;
				while(i+firstNull < rawchars.length && rawchars[i+firstNull] != null) {
					firstNull++;
				}
				endIndex = beginIndex + firstNull - 1;
				i = endIndex;
				if (endIndex >= 0) {
					intervalSize = endIndex - beginIndex + 1;
					intervals.add(new Integer[] {beginIndex, endIndex, intervalSize});
					intervalsTotalSize += intervalSize;
				}
				beginIndex = -1;
			}
		}
		int lastIndex = 0;
		boolean[][] newrawchars = new boolean[intervalsTotalSize][];
		for (Integer[] interval: intervals) {
			if (rawchars.length - (interval[0]) - interval[2] < 0) {
				System.err.println(interval[0] + "-" + interval[1] + "(" + interval[2] + ")");
				System.err.println(rawchars.length - (interval[0]) - interval[2]);
				throw new ArrayIndexOutOfBoundsException();
			}
			if (newrawchars.length - (lastIndex-1) - interval[2] < 0) {
				System.err.println(newrawchars.length - (lastIndex-1) - interval[2]);
				throw new ArrayIndexOutOfBoundsException();
			}
			System.arraycopy(rawchars, interval[0], newrawchars, lastIndex, interval[2]);
			lastIndex += interval[2];
		}
		rawchars = newrawchars;
	}

	@SuppressWarnings("unused")
	private void saveArray(int[] screen, int w, int h, String coutputpng) {
		final BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		final int[] a = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
		System.arraycopy(screen, 0, a, 0, screen.length);
		try {
			ImageIO.write(bi, "PNG", new File(coutputpng));
		} catch (final IOException ex) {
			Logger.getLogger(BinaryFont.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public int[] getCharIndexes(String txt) {
		final int l = txt.length();
		final int[] indexes = new int[l];
		final char[] chars = txt.toCharArray();
		for (int i = 0; i < l; i++) {
			int originalIndex = (chars[i] & 0xFFFF) - minBound;
			indexes[i] = compressIndex(originalIndex);
		}
		return indexes;
	}
	
	public int getCharIndex(char c) {
		int originalIndex = c & 0xFFFF;
		return compressIndex(originalIndex);
	}
	
	private int compressIndex(int originalIndex) {
		int compressedIndex = 0;
		for (Integer[] interval : intervals) {
			if (interval[0] > originalIndex) {
				break;
			} else if (originalIndex <= interval[1]) {
				compressedIndex+=(originalIndex-interval[0]);
				break;
			} else {
				compressedIndex+=interval[2];
			}
		}
		return compressedIndex;
	}
	
	private int decompressIndex(int compressedIndex) {
		int originalIndex = 0;
		int i = 0;
		for (Integer[] interval : intervals) {
			i+=interval[2];
			if (i == compressedIndex) {
				return interval[1];
			} else if (i > compressedIndex) {
				return interval[1] - (i - compressedIndex);
			}
		}
		return originalIndex;
	}

	@Override
	public void initialize(GraphicEngine d) {}

	@Override
	public void use(GraphicEngine d) {
		if (d.getRenderer() instanceof CPURenderer) {
			((CPURenderer) d.getRenderer()).currentFont = this;
		}
	}

	@Override
	public int getStringWidth(String text) {
		final int w = charW * text.length();
		if (text.length() > 0 && w > 0) {
			return w;
		} else {
			return 0;
		}
	}

	@Override
	public int getCharacterWidth() {
		return charW;
	}

	@Override
	public int getCharacterHeight() {
		return charH;
	}

	@Override
	public boolean isInitialized() {
		return true;
	}

}
<commit_msg>Removed old imports<commit_after>package org.warp.picalculator.gui.graphicengine.cpu;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;

import org.warp.picalculator.Utils;
import org.warp.picalculator.gui.graphicengine.BinaryFont;
import org.warp.picalculator.gui.graphicengine.GraphicEngine;

public class CPUFont implements BinaryFont {

	public boolean[][] rawchars;
	public int[] chars32;
	public int minBound = 10;
	public int maxBound = 0;
	public int charW;
	public int charH;
	public int charS;
	public int charIntCount;
	public LinkedList<Integer[]> intervals;
	public int intervalsTotalSize = 0;
	public static final int intBits = 31;
	private final boolean isResource;

	public CPUFont(String fontName) throws IOException {
		this(fontName, false);
	}

	CPUFont(String fontName, boolean onlyRaw) throws IOException {
		isResource = true;
		load("/font_" + fontName + ".rft", onlyRaw);
	}
	
	public CPUFont(String path, String fontName) throws IOException {
		this(path, fontName, false);
	}
	
	CPUFont(String path, String fontName, boolean onlyRaw) throws IOException {
		isResource = false;
		load(path + "/font_" + fontName + ".rft", onlyRaw);
	}

	public static CPUFont loadTemporaryFont(String name) throws IOException {
		return new CPUFont(name, true);
	}

	public static CPUFont loadTemporaryFont(String path, String name) throws IOException {
		return new CPUFont(path, name, true);
	}

	@Override
	public void load(String path) throws IOException {
		load(path, false);
	}
	
	private void load(String path, boolean onlyRaw) throws IOException {
		Utils.out.println(Utils.OUTPUTLEVEL_DEBUG_MIN, "Loading font " + path);
		loadFont(path);
		if (!onlyRaw) {
			chars32 = new int[(intervalsTotalSize) * charIntCount];
			for (int charCompressedIndex = 0; charCompressedIndex < intervalsTotalSize; charCompressedIndex++) {
				final boolean[] currentChar = rawchars[charCompressedIndex];
				if (currentChar == null) {
					int currentInt = 0;
					int currentBit = 0;
					for (int i = 0; i < charS; i++) {
						if (currentInt * intBits + currentBit >= (currentInt + 1) * intBits) {
							currentInt += 1;
							currentBit = 0;
						}
						chars32[charCompressedIndex * charIntCount + currentInt] = (chars32[charCompressedIndex * charIntCount + currentInt] << 1) + 1;
						currentBit += 1;
					}
				} else {
					int currentInt = 0;
					int currentBit = 0;
					for (int i = 0; i < charS; i++) {
						if (currentBit >= intBits) {
							currentInt += 1;
							currentBit = 0;
						}
						chars32[charCompressedIndex * charIntCount + currentInt] = (chars32[charCompressedIndex * charIntCount + currentInt]) | ((currentChar[i] ? 1 : 0) << currentBit);
						currentBit++;
					}
				}
			}
		}

		Utils.gc();
	}

	private void loadFont(String string) throws IOException {
		final URL res = isResource ? this.getClass().getResource(string) : new File(string).toURI().toURL();
		final int[] file = Utils.realBytes(Utils.convertStreamToByteArray(res.openStream(), res.getFile().length()));
		final int filelength = file.length;
		if (filelength >= 16) {
			if (file[0x0] == 114 && file[0x1] == 97 && file[0x2] == 119 && file[0x3] == 0xFF && file[0x8] == 0xFF && file[0xD] == 0xFF) {
				charW = file[0x4] << 8 | file[0x5];
				charH = file[0x6] << 8 | file[0x7];
				charS = charW * charH;
				charIntCount = (int) Math.ceil(((double) charS) / ((double) intBits));
				minBound = file[0x9] << 24 | file[0xA] << 16 | file[0xB] << 8 | file[0xC];
				maxBound = file[0xE] << 24 | file[0xF] << 16 | file[0x10] << 8 | file[0x11];
				if (maxBound <= minBound) {
					maxBound = 9900; //TODO remove it: temp fix
				}
				rawchars = new boolean[maxBound - minBound][];
				int index = 0x12;
				while (index < filelength) {
					try {
						final int charIndex = file[index] << 8 | file[index + 1];
						final boolean[] rawchar = new boolean[charS];
						int charbytescount = 0;
						while (charbytescount * 8 < charS) {
							charbytescount += 1;
						}
						int currentBit = 0;
						for (int i = 0; i <= charbytescount; i++) {
							for (int bit = 0; bit < 8; bit++) {
								if (currentBit >= charS) {
									break;
								}
								rawchar[currentBit] = (((file[index + 2 + i] >> (8 - 1 - bit)) & 0x1) == 1) ? true : false;
								currentBit++;
							}
						}
						rawchars[charIndex - minBound] = rawchar;
						index += 2 + charbytescount;
					} catch (final Exception ex) {
						ex.printStackTrace();
						System.out.println(string);
						System.exit(-1);
					}
				}
			} else {
				throw new IOException();
			}
		} else {
			throw new IOException();
		}
		findIntervals();
		/*int[] screen = new int[rawchars.length * charW * charH];
		for (int i = 0; i < rawchars.length; i++) {
			if (rawchars[i] != null)
				for (int charX = 0; charX < charW; charX++) {
					for (int charY = 0; charY < charH; charY++) {
						int x = i * charW + charX;
						int y = charY;
						screen[x + y * rawchars.length * charW] = rawchars[i][charX + charY * charW] ? 0xFF000000 : 0xFFFFFFFF;
					}
				}
		}
		System.out.println();
		System.out.println((('1' & 0xFFFF) - minBound) + "=>"+ (getCharIndexes("1")[0]));
		this.saveArray(screen, rawchars.length * charW, charH, "N:\\TimedTemp"+string+".png");
		System.out.println();
		System.out.println();
		*/
	}

	private void findIntervals() {
		intervals = new LinkedList<Integer[]>();
		int beginIndex = -1;
		int endIndex = 0;
		int intervalSize = 0;
		int holeSize = 0;
		for (int i = 0; i < rawchars.length; i++) {
			if (rawchars[i] != null) {
				beginIndex = i;
				int firstNull = 0;
				while(i+firstNull < rawchars.length && rawchars[i+firstNull] != null) {
					firstNull++;
				}
				endIndex = beginIndex + firstNull - 1;
				i = endIndex;
				if (endIndex >= 0) {
					intervalSize = endIndex - beginIndex + 1;
					intervals.add(new Integer[] {beginIndex, endIndex, intervalSize});
					intervalsTotalSize += intervalSize;
				}
				beginIndex = -1;
			}
		}
		int lastIndex = 0;
		boolean[][] newrawchars = new boolean[intervalsTotalSize][];
		for (Integer[] interval: intervals) {
			if (rawchars.length - (interval[0]) - interval[2] < 0) {
				System.err.println(interval[0] + "-" + interval[1] + "(" + interval[2] + ")");
				System.err.println(rawchars.length - (interval[0]) - interval[2]);
				throw new ArrayIndexOutOfBoundsException();
			}
			if (newrawchars.length - (lastIndex-1) - interval[2] < 0) {
				System.err.println(newrawchars.length - (lastIndex-1) - interval[2]);
				throw new ArrayIndexOutOfBoundsException();
			}
			System.arraycopy(rawchars, interval[0], newrawchars, lastIndex, interval[2]);
			lastIndex += interval[2];
		}
		rawchars = newrawchars;
	}

	@SuppressWarnings("unused")
	private void saveArray(int[] screen, int w, int h, String coutputpng) {
		final BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		final int[] a = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
		System.arraycopy(screen, 0, a, 0, screen.length);
		try {
			ImageIO.write(bi, "PNG", new File(coutputpng));
		} catch (final IOException ex) {
			Logger.getLogger(BinaryFont.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public int[] getCharIndexes(String txt) {
		final int l = txt.length();
		final int[] indexes = new int[l];
		final char[] chars = txt.toCharArray();
		for (int i = 0; i < l; i++) {
			int originalIndex = (chars[i] & 0xFFFF) - minBound;
			indexes[i] = compressIndex(originalIndex);
		}
		return indexes;
	}
	
	public int getCharIndex(char c) {
		int originalIndex = c & 0xFFFF;
		return compressIndex(originalIndex);
	}
	
	private int compressIndex(int originalIndex) {
		int compressedIndex = 0;
		for (Integer[] interval : intervals) {
			if (interval[0] > originalIndex) {
				break;
			} else if (originalIndex <= interval[1]) {
				compressedIndex+=(originalIndex-interval[0]);
				break;
			} else {
				compressedIndex+=interval[2];
			}
		}
		return compressedIndex;
	}
	
	private int decompressIndex(int compressedIndex) {
		int originalIndex = 0;
		int i = 0;
		for (Integer[] interval : intervals) {
			i+=interval[2];
			if (i == compressedIndex) {
				return interval[1];
			} else if (i > compressedIndex) {
				return interval[1] - (i - compressedIndex);
			}
		}
		return originalIndex;
	}

	@Override
	public void initialize(GraphicEngine d) {}

	@Override
	public void use(GraphicEngine d) {
		if (d.getRenderer() instanceof CPURenderer) {
			((CPURenderer) d.getRenderer()).currentFont = this;
		}
	}

	@Override
	public int getStringWidth(String text) {
		final int w = charW * text.length();
		if (text.length() > 0 && w > 0) {
			return w;
		} else {
			return 0;
		}
	}

	@Override
	public int getCharacterWidth() {
		return charW;
	}

	@Override
	public int getCharacterHeight() {
		return charH;
	}

	@Override
	public boolean isInitialized() {
		return true;
	}

}

{'fraction_non_alphanumeric': 0.1370515398454863, 'fraction_numerical': 0.01867922531484813, 'mean_word_length': 2.9168911917098446, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6745021', 'n_tokens_mistral': 7547, 'n_tokens_neox': 6166, 'n_words': 1562}