/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.gui.hex;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Arrays;
import java.util.StringTokenizer;
import com.cburch.hex.HexModel;
public class HexFile {
private static class HexReader {
private BufferedReader in;
private int[] data;
private StringTokenizer curLine;
private long leftCount;
private long leftValue;
public HexReader(BufferedReader in) throws IOException {
this.in = in;
data = new int[4096];
curLine = findNonemptyLine();
}
private StringTokenizer findNonemptyLine() throws IOException {
String line = in.readLine();
while (line != null) {
int index = line.indexOf(COMMENT_MARKER);
if (index >= 0) {
line = line.substring(0, index);
}
StringTokenizer ret = new StringTokenizer(line);
if (ret.hasMoreTokens())
return ret;
line = this.in.readLine();
}
return null;
}
public boolean hasNext() throws IOException {
if (leftCount > 0) {
return true;
} else if (curLine != null && curLine.hasMoreTokens()) {
return true;
} else {
curLine = findNonemptyLine();
return curLine != null;
}
}
public int[] next() throws IOException {
int pos = 0;
if (leftCount > 0) {
int n = (int) Math.min(data.length - pos, leftCount);
if (n == 1) {
data[pos] = (int) leftValue;
pos++;
leftCount--;
} else {
Arrays.fill(data, pos, pos + n, (int) leftValue);
pos += n;
leftCount -= n;
}
}
if (pos >= data.length)
return data;
for (String tok = nextToken(); tok != null; tok = nextToken()) {
try {
int star = tok.indexOf("*");
if (star < 0) {
leftCount = 1;
leftValue = Long.parseLong(tok, 16);
} else {
leftCount = Long.parseLong(tok.substring(0, star));
leftValue = Long.parseLong(tok.substring(star + 1), 16);
}
} catch (NumberFormatException e) {
throw new IOException(Strings.get("hexNumberFormatError"));
}
int n = (int) Math.min(data.length - pos, leftCount);
if (n == 1) {
data[pos] = (int) leftValue;
pos++;
leftCount--;
} else {
Arrays.fill(data, pos, pos + n, (int) leftValue);
pos += n;
leftCount -= n;
}
if (pos >= data.length)
return data;
}
if (pos >= data.length) {
return data;
} else {
int[] ret = new int[pos];
System.arraycopy(data, 0, ret, 0, pos);
return ret;
}
}
private String nextToken() throws IOException {
if (curLine != null && curLine.hasMoreTokens()) {
return curLine.nextToken();
} else {
curLine = findNonemptyLine();
return curLine == null ? null : curLine.nextToken();
}
}
}
public static void open(HexModel dst, File src) throws IOException {
BufferedReader in;
try {
in = new BufferedReader(new FileReader(src));
} catch (IOException e) {
throw new IOException(Strings.get("hexFileOpenError"));
}
try {
String header = in.readLine();
if (!header.equals(RAW_IMAGE_HEADER)) {
throw new IOException(Strings.get("hexHeaderFormatError"));
}
open(dst, in);
try {
BufferedReader oldIn = in;
in = null;
oldIn.close();
} catch (IOException e) {
throw new IOException(Strings.get("hexFileReadError"));
}
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
}
}
}
public static void open(HexModel dst, Reader in) throws IOException {
HexReader reader = new HexReader(new BufferedReader(in));
long offs = dst.getFirstOffset();
while (reader.hasNext()) {
int[] values = reader.next();
if (offs + values.length - 1 > dst.getLastOffset()) {
throw new IOException(Strings.get("hexFileSizeError"));
}
dst.set(offs, values);
offs += values.length;
}
dst.fill(offs, dst.getLastOffset() - offs + 1, 0);
}
public static int[] parse(Reader in) throws IOException {
HexReader reader = new HexReader(new BufferedReader(in));
int cur = 0;
int[] data = new int[4096];
while (reader.hasNext()) {
int[] values = reader.next();
if (cur + values.length > data.length) {
int[] oldData = data;
data = new int[Math.max(cur + values.length,
3 * data.length / 2)];
System.arraycopy(oldData, 0, data, 0, cur);
}
System.arraycopy(values, 0, data, cur, values.length);
cur += values.length;
}
if (cur != data.length) {
int[] oldData = data;
data = new int[cur];
System.arraycopy(oldData, 0, data, 0, cur);
}
return data;
}
public static void save(File dst, HexModel src) throws IOException {
FileWriter out;
try {
out = new FileWriter(dst);
} catch (IOException e) {
throw new IOException(Strings.get("hexFileOpenError"));
}
try {
try {
out.write(RAW_IMAGE_HEADER + "\n");
} catch (IOException e) {
throw new IOException(Strings.get("hexFileWriteError"));
}
save(out, src);
} finally {
try {
out.close();
} catch (IOException e) {
throw new IOException(Strings.get("hexFileWriteError"));
}
}
}
public static void save(Writer out, HexModel src) throws IOException {
long first = src.getFirstOffset();
long last = src.getLastOffset();
while (last > first && src.get(last) == 0)
last--;
int tokens = 0;
long cur = 0;
while (cur <= last) {
int val = src.get(cur);
long start = cur;
cur++;
while (cur <= last && src.get(cur) == val)
cur++;
long len = cur - start;
if (len < 4) {
cur = start + 1;
len = 1;
}
try {
if (tokens > 0)
out.write(tokens % 8 == 0 ? '\n' : ' ');
if (cur != start + 1)
out.write((cur - start) + "*");
out.write(Integer.toHexString(val));
} catch (IOException e) {
throw new IOException(Strings.get("hexFileWriteError"));
}
tokens++;
}
if (tokens > 0)
out.write('\n');
}
private static final String RAW_IMAGE_HEADER = "v2.0 raw";
private static final String COMMENT_MARKER = "#";
private HexFile() {
}
}