2 JPC-RR: A x86 PC Hardware Emulator
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
34 import java
.util
.List
;
35 import java
.lang
.reflect
.*;
38 import org
.jpc
.diskimages
.ImageLibrary
;
39 import org
.jpc
.diskimages
.ImageMaker
;
40 import org
.jpc
.diskimages
.DiskImage
;
41 import org
.jpc
.pluginsbase
.*;
43 import static org
.jpc
.Revision
.getRevision
;
44 import static org
.jpc
.Misc
.errorDialog
;
45 import static org
.jpc
.Misc
.callShowOptionDialog
;
46 import static org
.jpc
.Misc
.parseString
;
48 public class JPCApplication
50 public static Plugin
instantiatePlugin(Plugins pluginManager
, Class
<?
> plugin
, String arguments
) throws IOException
54 if(arguments
!= null) {
56 cc
= plugin
.getConstructor(Plugins
.class, String
.class);
57 } catch(Exception e
) {
58 throw new IOException("Plugin \"" + plugin
.getName() + "\" does not take arguments.");
62 cc
= plugin
.getConstructor(Plugins
.class);
63 } catch(Exception e
) {
64 throw new IOException("Plugin \"" + plugin
.getName() + "\" requires arguments.");
70 return (Plugin
)cc
.newInstance(pluginManager
, arguments
);
72 return (Plugin
)cc
.newInstance(pluginManager
);
73 } catch(InvocationTargetException e
) {
74 Throwable e2
= e
.getCause();
75 //If the exception is something unchecked, just pass it through.
76 if(e2
instanceof RuntimeException
)
77 throw (RuntimeException
)e2
;
78 if(e2
instanceof Error
) {
79 IOException ne
= new IOException("Error while invoking loader: " + e2
);
80 ne
.setStackTrace(e2
.getStackTrace()); //Copy stack trace.
83 //Also pass IOException through.
84 if(e2
instanceof IOException
)
85 throw (IOException
)e2
;
86 //What the heck is that?
87 IOException ne
= new IOException("Unknown exception while invoking loader: " + e2
);
88 ne
.setStackTrace(e2
.getStackTrace()); //Copy stack trace.
90 } catch(Exception e
) {
91 throw new IOException("Failed to invoke plugin \"" + plugin
.getName() + "\" constructor.");
95 private static void loadPlugin(Plugins pluginManager
, String arg
) throws IOException
97 String moduleString
= arg
;
101 int paramsStart
= -1;
103 int stringLen
= moduleString
.length();
104 boolean requireNextSep
= false;
106 for(int i
= 0; true; i
++) {
109 cp
= moduleString
.codePointAt(i
);
110 else if(parenDepth
== 0) {
113 currentModule
= moduleString
.substring(0, i
);
115 moduleString
= moduleString
.substring(i
+ 1);
116 if(moduleString
.equals(""))
117 throw new IOException("Error in module string: Blank module name not allowed.");
122 throw new IOException("Error in module string: unclosed '('.");
124 i
++; //Skip the next surrogate.
125 if((cp
>= 0xD800 && cp
< 0xE000) || ((cp
& 0xFFFE) == 0xFFFE) || (cp
>>> 16) > 16 || cp
< 0)
126 throw new IOException("Error In module string: invalid Unicode character.");
127 if(requireNextSep
&& cp
!= ',')
128 throw new IOException("Error in module string: Expected ',' after ')' closing parameter list.");
129 else if(cp
== ',' && i
== 0)
130 throw new IOException("Error in module string: Blank module name not allowed.");
132 if(parenDepth
== 0) {
137 } else if(cp
== ')') {
139 throw new IOException("Error in module string: Unpaired ')'.");
140 else if(parenDepth
== 1) {
142 requireNextSep
= true;
148 String name
= currentModule
.substring(0, nameEnd
+ 1);
149 String params
= null;
151 params
= currentModule
.substring(paramsStart
, paramsEnd
+ 1);
156 plugin
= Class
.forName(name
);
157 } catch(Exception e
) {
158 throw new IOException("Unable to find plugin \"" + name
+ "\".");
161 if(!Plugin
.class.isAssignableFrom(plugin
)) {
162 throw new IOException("Plugin \"" + name
+ "\" is not valid plugin.");
164 Plugin c
= instantiatePlugin(pluginManager
, plugin
, params
);
165 pluginManager
.registerPlugin(c
);
168 private static void doListImages(ImageLibrary lib
, String restOfCommand
) throws IOException
170 PrintStream out
= System
.out
;
171 boolean doClose
= false;
172 if(restOfCommand
!= null) {
173 OutputStream outb
= new BufferedOutputStream(new FileOutputStream(restOfCommand
));
174 out
= new PrintStream(outb
, false, "UTF-8");
178 //Get present images of any tyype.
179 String
[] images
= lib
.imagesByType(~
0x1L
);
180 for(String i
: images
)
181 printImageInfo(out
, lib
, i
, true);
188 public static void printImageInfo(PrintStream out
, ImageLibrary lib
, String origName
, boolean brief
) throws IOException
190 String fileName
= lib
.searchFileName(origName
);
191 if(fileName
== null) {
192 System
.err
.println("No image named '" + origName
+ "' exists.");
196 ImageMaker
.ParsedImage pimg
= new ImageMaker
.ParsedImage(fileName
);
198 switch(pimg
.typeCode
) {
200 typeString
= "floppy ";
206 typeString
= "CD-ROM ";
209 typeString
= "BIOS ";
212 typeString
= "<Unknown> ";
216 out
.println("" + (new ImageLibrary
.ByteArray(pimg
.diskID
)) + " " + typeString
+ " " + origName
);
220 out
.println("Name : " + origName
);
221 out
.println("File name : " + fileName
);
222 out
.println("Type : " + typeString
);
223 if(pimg
.typeCode
== 0 || pimg
.typeCode
== 1) {
224 out
.println("Tracks : " + pimg
.tracks
);
225 out
.println("Sides : " + pimg
.sides
);
226 out
.println("Sectors : " + pimg
.sectors
);
227 out
.println("Total sectors : " + pimg
.totalSectors
);
228 out
.println("Primary extent size: " + pimg
.sectorsPresent
);
229 out
.println("Storage Method : " + pimg
.method
);
230 int actualSectors
= 0;
232 for(int i
= 0; i
< pimg
.totalSectors
; i
++) {
233 if(i
< pimg
.sectorOffsetMap
.length
&& pimg
.sectorOffsetMap
[i
] > 0)
236 out
.println("Sectors present : " + actualSectors
);
237 } else if(pimg
.typeCode
== 2) {
238 out
.println("Total sectors : " + pimg
.totalSectors
);
239 } else if(pimg
.typeCode
== 3) {
240 out
.println("Image Size : " + pimg
.rawImage
.length
);
243 out
.println("Claimed Disk ID : " + (new ImageLibrary
.ByteArray(pimg
.diskID
)));
244 List
<String
> comments
= pimg
.comments
;
245 if(comments
!= null) {
247 out
.println("Comments section:");
249 for(String x
: comments
)
252 } catch(IOException e
) {
253 errorDialog(e
, "Failed to read image", null, "Quit");
258 private static void doImageInfo(ImageLibrary lib
, String restOfCommand
) throws IOException
260 PrintStream out
= System
.out
;
261 boolean doClose
= false;
262 int sIndex
= restOfCommand
.indexOf(" ");
264 String outName
= restOfCommand
.substring(0, sIndex
);
265 restOfCommand
= restOfCommand
.substring(sIndex
+ 1);
266 OutputStream outb
= new BufferedOutputStream(new FileOutputStream(outName
));
267 out
= new PrintStream(outb
, false, "UTF-8");
271 printImageInfo(out
, lib
, restOfCommand
, false);
278 public static void doCommand(Plugins pluginManager
, String cmd
) throws IOException
280 if(cmd
.toLowerCase().startsWith("load ")) {
282 loadPlugin(pluginManager
, cmd
.substring(5));
283 } catch(Exception e
) {
284 errorDialog(e
, "Plugin Loading failed", null, "Dismiss");
286 } else if(cmd
.toLowerCase().equals("exit")) {
287 pluginManager
.shutdownEmulator();
288 } else if(cmd
.toLowerCase().equals("")) {
289 } else if(cmd
.toLowerCase().startsWith("command ")) {
291 String
[] arr
= parseString(cmd
.substring(8));
293 throw new Exception("No command to send given");
294 String rcmd
= arr
[0];
295 String
[] rargs
= null;
297 rargs
= new String
[arr
.length
- 1];
298 System
.arraycopy(arr
, 1, rargs
, 0, arr
.length
- 1);
300 pluginManager
.invokeExternalCommandSynchronous(rcmd
, rargs
);
301 } catch(Exception e
) {
302 errorDialog(e
, "Command sending failed", null, "Dismiss");
304 } else if(cmd
.toLowerCase().startsWith("call ")) {
306 String
[] arr
= parseString(cmd
.substring(5));
308 throw new Exception("No command to send given");
309 String rcmd
= arr
[0];
310 String
[] rargs
= null;
312 rargs
= new String
[arr
.length
- 1];
313 System
.arraycopy(arr
, 1, rargs
, 0, arr
.length
- 1);
315 Object
[] ret
= pluginManager
.invokeExternalCommandReturn(rcmd
, rargs
);
317 for(int i
= 0; i
< ret
.length
; i
++)
318 System
.out
.println(ret
[i
].toString());
320 System
.out
.println("Nothing returned.");
321 } catch(Exception e
) {
322 errorDialog(e
, "Command sending failed", null, "Dismiss");
324 } else if(cmd
.toLowerCase().startsWith("library ")) {
325 String library
= cmd
.substring(8);
326 File libraryFile
= new File(library
);
327 if(!libraryFile
.isDirectory()) {
328 if(!libraryFile
.mkdirs()) {
329 callShowOptionDialog(null, "Library (" + library
+ ") does not exist and can't be created",
330 "Disk library error", JOptionPane
.OK_OPTION
, JOptionPane
.WARNING_MESSAGE
, null,
331 new String
[]{"Dismiss"}, "Dismiss");
335 DiskImage
.setLibrary(new ImageLibrary(library
));
336 } else if(cmd
.toLowerCase().equals("lsdisks") || cmd
.toLowerCase().startsWith("lsdisks ")) {
339 rest
= cmd
.substring(8);
340 ImageLibrary lib
= DiskImage
.getLibrary();
342 System
.err
.println("No library loaded");
346 doListImages(lib
, rest
);
347 } catch(Exception e
) {
348 errorDialog(e
, "Failed to lisk known images", null, "Dismiss");
350 } else if(cmd
.toLowerCase().startsWith("diskinfo ")) {
351 String rest
= cmd
.substring(9);
352 ImageLibrary lib
= DiskImage
.getLibrary();
354 System
.err
.println("No library loaded");
358 doImageInfo(lib
, rest
);
359 } catch(Exception e
) {
360 errorDialog(e
, "Failed to get information for image", null, "Dismiss");
363 System
.err
.println("Invalid command");
367 public static void main(String
[] args
) throws Exception
371 UIManager
.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
372 } catch (Throwable e
) { //Yes, we need to catch errors too.
373 System
.err
.println("Warning: System Look-and-Feel not loaded" + e
.getMessage());
376 System
.out
.println("JPC-RR: Rerecording PC emulator based on JPC PC emulator. Release 10.9");
377 System
.out
.println("Revision: " + getRevision());
378 System
.out
.println("Based on JPC PC emulator.");
379 System
.out
.println("Copyright (C) 2007-2009 Isis Innovation Limited");
380 System
.out
.println("Copyright (C) 2009-2010 H. Ilari Liusvaara");
381 System
.out
.println("JPC-RR is released under GPL Version 2 and comes with absoutely no warranty.");
383 //Probe if rename-over is supported.
384 Misc
.probeRenameOver(ArgProcessor
.findFlag(args
, "-norenames"));
386 Plugins pluginManager
= new Plugins();
387 BufferedReader kbd
= new BufferedReader(new InputStreamReader(System
.in
, "UTF-8"));
389 boolean noautoexec
= ArgProcessor
.findFlag(args
, "-noautoexec");
390 String autoexec
= ArgProcessor
.findVariable(args
, "autoexec", null);
391 if(autoexec
!= null && !noautoexec
) {
393 BufferedReader kbd2
= new BufferedReader(new InputStreamReader(
394 new FileInputStream(autoexec
), "UTF-8"));
396 String cmd
= kbd2
.readLine();
399 doCommand(pluginManager
, cmd
);
401 } catch (Exception e
) {
402 System
.err
.println("Failed to load autoexec script: " + e
.getMessage());
407 System
.out
.print("JPC-RR> ");
409 String cmd
= kbd
.readLine();
411 doCommand(pluginManager
, cmd
);
412 } catch (Exception e
) {
413 errorDialog(e
, "Command execution failed", null, "Dismiss");