NHMLFixup v10
[jpcrr.git] / org / jpc / diskimages / ImageLibrary.java
blobc057ac508e6d587ca4c97353dcc9ecf6567e74be
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009-2010 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
30 package org.jpc.diskimages;
32 import java.io.*;
33 import java.util.*;
35 public class ImageLibrary
37 private String directoryPrefix;
39 public String getPathPrefix()
41 return directoryPrefix;
44 public static class ByteArray
46 private byte[] content;
48 public ByteArray(byte[] array)
50 content = array;
53 public byte[] toByteArray()
55 return content;
58 public int hashCode()
60 if(content == null)
61 return 1;
62 //Assume contents are well-distributed.
63 if(content.length > 3) {
64 return 256 * (256 * (256 * content[0] + content[1]) + content[2]) + content[3];
65 } else if(content.length == 3) {
66 return 256 * (256 * content[0] + content[1]) + content[2];
67 } else if(content.length == 2) {
68 return 256 * content[0] + content[1];
69 } else if(content.length == 1) {
70 return content[0];
71 } else {
72 return 0;
76 public boolean equals(Object o) {
77 if(o == null)
78 return false;
79 if(this.getClass() != o.getClass())
80 return false;
81 ByteArray o2 = (ByteArray)o;
82 if(content == null && o2.content == null)
83 return true;
84 if(content == null && o2.content != null)
85 return false;
86 if(content != null && o2.content == null)
87 return false;
88 if(content.length != o2.content.length)
89 return false;
90 for(int i = 0; i < content.length; i++)
91 if(content[i] != o2.content[i])
92 return false;
93 return true;
96 public String toString()
98 if(content == null)
99 return "(null)";
100 StringBuffer buf = new StringBuffer(2 * content.length);
101 for(int i = 0; i < content.length; i++) {
102 int b = (int)content[i] & 0xFF;
103 buf.append(Character.forDigit(b / 16, 16));
104 buf.append(Character.forDigit(b % 16, 16));
106 return buf.toString();
110 HashMap<ByteArray, String> idToFile;
111 HashMap<String, ByteArray> fileToID;
112 HashMap<ByteArray, Byte> idToType;
114 public ImageLibrary()
116 idToFile = new HashMap<ByteArray, String>();
117 fileToID = new HashMap<String, ByteArray>();
118 idToType = new HashMap<ByteArray, Byte>();
121 private void recursiveHandleDirectory(String prefix, String pathPrefix, File directory)
123 File[] fileList = directory.listFiles();
124 for(int i = 0; i < fileList.length; i++) {
125 File imageFile = fileList[i];
126 String fileName = directoryPrefix + pathPrefix + imageFile.getName();
127 String imageName = prefix + imageFile.getName();
128 try {
129 if(imageFile.isDirectory())
130 recursiveHandleDirectory(prefix + imageFile.getName() + "/",
131 pathPrefix + imageFile.getName() + File.separator, imageFile);
132 else if(imageFile.isFile()) {
133 insertFileName(null, fileName, imageName);
135 } catch(IOException e) {
136 System.err.println("Can't load \"" + imageFile.getName() + "\": " + e.getMessage());
141 public ImageLibrary(String libraryDirName) throws IOException
143 idToFile = new HashMap<ByteArray, String>();
144 fileToID = new HashMap<String, ByteArray>();
145 idToType = new HashMap<ByteArray, Byte>();
147 File f = new File(libraryDirName);
148 if(!f.exists())
149 throw new IOException("Libary directory \"" + libraryDirName + "\" does not exist.");
150 if(!f.isDirectory())
151 throw new IOException("Libary directory \"" + libraryDirName + "\" is not directory.");
153 directoryPrefix = f.getAbsolutePath() + File.separator;
154 recursiveHandleDirectory("", "", f);
157 public String lookupFileName(String res)
159 if(!fileToID.containsKey(res))
160 return null;
161 return directoryPrefix + res;
164 public String lookupFileName(byte[] resource)
166 ByteArray res = new ByteArray(resource);
167 if(!idToFile.containsKey(res)) {
168 //System.err.println("Error: Unsuccessful lookup on " + res.toString() + ".");
169 //try { throw new Exception(""); } catch(Exception e) { e.printStackTrace(); }
170 return null;
172 return idToFile.get(res);
175 private boolean validHexChar(char x)
177 switch(x) {
178 case '0': case '1': case '2': case '3':
179 case '4': case '5': case '6': case '7':
180 case '8': case '9': case 'A': case 'B':
181 case 'C': case 'D': case 'E': case 'F':
182 case 'a': case 'b': case 'c': case 'd':
183 case 'e': case 'f':
184 return true;
185 default:
186 return false;
190 public String searchFileName(String resource)
192 String out = null;
193 boolean nameOK = true;
194 if((resource.length() & 1) == 0) {
195 byte[] bytes = new byte[resource.length() / 2];
196 for(int i = 0; i < resource.length() / 2; i++) {
197 char ch1 = resource.charAt(2 * i);
198 char ch2 = resource.charAt(2 * i);
199 if(!validHexChar(ch1)) nameOK = false;
200 if(!validHexChar(ch2)) nameOK = false;
201 bytes[i] = (byte)(Character.digit(resource.charAt(2 * i), 16) * 16 +
202 Character.digit(resource.charAt(2 * i + 1), 16));
204 if(nameOK)
205 out = lookupFileName(bytes);
206 if(out != null)
207 return out;
210 return lookupFileName(resource);
213 public byte[] canonicalNameFor(String resource)
215 if(resource == null)
216 return null;
217 if(fileToID.containsKey(resource)) {
218 //Its by object name.
219 return fileToID.get(resource).toByteArray();
221 if((resource.length() & 1) != 0)
222 return null;
223 byte[] bytes = new byte[resource.length() / 2];
224 for(int i = 0; i < resource.length() / 2; i++)
225 bytes[i] = (byte)(Character.digit(resource.charAt(2 * i), 16) * 16 +
226 Character.digit(resource.charAt(2 * i + 1), 16));
227 ByteArray _bytes = new ByteArray(bytes);
228 if(!idToFile.containsKey(_bytes))
229 return null;
230 return bytes; //The name is canonical.
233 public void insertFileName(ByteArray resource, String fileName, String imageName) throws IOException
235 RandomAccessFile r = new RandomAccessFile(fileName, "r");
236 ByteArray id = getIdentifierForImageAsArray(r, fileName);
237 if(resource == null)
238 resource = id;
239 idToFile.put(resource, fileName);
240 fileToID.put(imageName, resource);
241 byte tByte = getTypeForImage(r, fileName);
242 idToType.put(id, new Byte(tByte));
243 r.close();
244 System.err.println("Notice: " + imageName + " -> " + resource.toString() + " -> " + fileName + ".");
247 public static byte[] getIdentifierForImage(RandomAccessFile image, String fileName) throws IOException
249 byte[] rawhdr = new byte[21];
250 image.seek(0);
251 if(image.read(rawhdr) < 21 || rawhdr[0] != 73 || rawhdr[1] != 77 || rawhdr[2] != 65 || rawhdr[3] != 71 ||
252 rawhdr[4] != 69) {
253 throw new IOException(fileName + " is not image file.");
255 byte[] id = new byte[16];
256 for(int i = 0; i < 16; i++)
257 id[i] = rawhdr[i + 5];
258 return id;
261 public static ByteArray getIdentifierForImageAsArray(RandomAccessFile image, String fileName) throws IOException
263 return new ByteArray(getIdentifierForImage(image, fileName));
266 public static byte getTypeForImage(RandomAccessFile image, String fileName) throws IOException
268 byte[] typehdr = new byte[1];
269 image.seek(21);
270 if(image.read(typehdr) < 1) {
271 throw new IOException(fileName + " is not image file.");
273 return typehdr[0];
276 //type is bitmask. Bit 0 is blank, bit 1 is floppes, bit 2 is HDDs, bit3 is CDROMs, Bit 4 is BIOS
277 public String[] imagesByType(long type)
279 String[] ret = new String[10];
280 int entries = 0;
282 if((type & 1) != 0) {
283 if(entries == ret.length)
284 ret = Arrays.copyOf(ret, 2 * ret.length);
285 ret[entries++] = "";
288 for(Map.Entry<String, ByteArray> x : fileToID.entrySet()) {
289 byte iType = idToType.get(x.getValue()).byteValue();
291 if((type & (2 << iType)) != 0) {
292 if(entries == ret.length)
293 ret = Arrays.copyOf(ret, 2 * ret.length);
294 ret[entries++] = x.getKey();
298 if(entries == 0)
299 return null;
301 ret = Arrays.copyOf(ret, entries);
302 Arrays.sort(ret, null);
303 return ret;