2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009 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
;
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
)
53 public byte[] toByteArray()
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) {
76 public boolean equals(Object o
) {
79 if(this.getClass() != o
.getClass())
81 ByteArray o2
= (ByteArray
)o
;
82 if(content
== null && o2
.content
== null)
84 if(content
== null && o2
.content
!= null)
86 if(content
!= null && o2
.content
== null)
88 if(content
.length
!= o2
.content
.length
)
90 for(int i
= 0; i
< content
.length
; i
++)
91 if(content
[i
] != o2
.content
[i
])
96 public String
toString()
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();
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
);
149 throw new IOException("Libary directory \"" + libraryDirName
+ "\" does not exist.");
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
))
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(); }
172 return idToFile
.get(res
);
175 private boolean validHexChar(char 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':
190 public String
searchFileName(String resource
)
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));
205 out
= lookupFileName(bytes
);
210 return lookupFileName(resource
);
213 public byte[] canonicalNameFor(String resource
)
217 if(fileToID
.containsKey(resource
)) {
218 //Its by object name.
219 return fileToID
.get(resource
).toByteArray();
221 if((resource
.length() & 1) != 0)
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
))
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
);
239 idToFile
.put(resource
, fileName
);
240 fileToID
.put(imageName
, resource
);
241 byte tByte
= getTypeForImage(r
, fileName
);
242 idToType
.put(id
, new Byte(tByte
));
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];
251 if(image
.read(rawhdr
) < 21 || rawhdr
[0] != 73 || rawhdr
[1] != 77 || rawhdr
[2] != 65 || rawhdr
[3] != 71 ||
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];
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];
270 if(image
.read(typehdr
) < 1) {
271 throw new IOException(fileName
+ " is not image file.");
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];
282 if((type
& 1) != 0) {
283 if(entries
== ret
.length
)
284 ret
= Arrays
.copyOf(ret
, 2 * ret
.length
);
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();
301 ret
= Arrays
.copyOf(ret
, entries
);
302 Arrays
.sort(ret
, null);