2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 import java.util.LinkedList;
22 import java.util.Arrays;
24 class HexFileInputStream extends PushbackInputStream {
27 public HexFileInputStream(FileInputStream o) {
28 super(new BufferedInputStream(o));
32 public int read() throws IOException {
39 public void unread(int c) throws IOException {
47 class HexRecord implements Comparable<Object> {
53 static final int NORMAL = 0;
54 static final int EOF = 1;
55 static final int EXTENDED_ADDRESS = 2;
69 boolean ishex(int c) {
70 if ('0' <= c && c <= '9')
72 if ('a' <= c && c <= 'f')
74 if ('A' <= c && c <= 'F')
79 boolean isspace(int c) {
89 if ('0' <= c && c <= '9')
91 if ('a' <= c && c <= 'f')
93 if ('A' <= c && c <= 'F')
98 public byte checksum() {
102 got += (address >> 8) & 0xff;
103 got += (address ) & 0xff;
105 for (int i = 0; i < data.length; i++)
107 return (byte) (-got);
110 public int compareTo(Object other) {
111 HexRecord o = (HexRecord) other;
112 return address - o.address;
115 public String toString() {
116 return String.format("%04x: %02x (%d)", address, type, data.length);
119 public HexRecord(HexFileInputStream input) throws IOException {
120 read_state state = read_state.marker;
126 while (state != read_state.done) {
127 int c = input.read();
128 if (c < 0 && state != read_state.white)
129 throw new IOException(String.format("%d: Unexpected EOF", input.line));
135 throw new IOException("Missing ':'");
136 state = read_state.length;
146 throw new IOException(String.format("Non-hex char '%c'", c));
147 hex = hex << 4 | fromhex(c);
154 data = new byte[hex];
155 state = read_state.address;
160 state = read_state.type;
166 state = read_state.data;
168 state = read_state.checksum;
173 data[ndata] = (byte) hex;
176 if (ndata == data.length)
177 state = read_state.checksum;
180 checksum = (byte) hex;
181 state = read_state.newline;
189 if (c != '\n' && c != '\r')
190 throw new IOException("Missing newline");
191 state = read_state.white;
196 state = read_state.done;
203 got_checksum = checksum();
204 if (got_checksum != checksum)
205 throw new IOException(String.format("Invalid checksum (read 0x%02x computed 0x%02x)\n",
206 checksum, got_checksum));
210 public class AltosHexfile {
214 public byte get_byte(int a) {
215 return data[a - address];
218 public AltosHexfile(FileInputStream file) throws IOException {
219 HexFileInputStream input = new HexFileInputStream(file);
220 LinkedList<HexRecord> record_list = new LinkedList<HexRecord>();
221 boolean done = false;
224 HexRecord record = new HexRecord(input);
226 if (record.type == HexRecord.EOF)
229 record_list.add(record);
231 HexRecord[] records = record_list.toArray(new HexRecord[0]);
232 Arrays.sort(records);
233 if (records.length > 0) {
234 int base = records[0].address;
235 int bound = records[records.length-1].address +
236 records[records.length-1].data.length;
238 data = new byte[bound - base];
240 Arrays.fill(data, (byte) 0xff);
242 /* Paint the records into the new array */
243 for (int i = 0; i < records.length; i++) {
244 for (int j = 0; j < records[i].data.length; j++)
245 data[records[i].address - base + j] = records[i].data[j];