Fix most warnings from GCJ
[jpcrr.git] / org / jpc / Misc.java
blobece2b58272a72edc0f5cfd4a23e6663484d7521d
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
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;
32 import java.io.*;
33 import java.nio.*;
34 import java.nio.charset.*;
35 import java.util.*;
36 import javax.swing.*;
38 import org.jpc.diskimages.ImageLibrary;
39 import org.jpc.jrsr.UTFInputLineStream;
41 import static org.jpc.Exceptions.classes;
42 import static org.jpc.emulator.memory.codeblock.optimised.MicrocodeSet.*;
44 public class Misc
46 public static String randomHexes(int bytes)
48 java.security.SecureRandom prng = new java.security.SecureRandom();
49 byte[] rnd = new byte[bytes];
50 prng.nextBytes(rnd);
51 StringBuffer buf = new StringBuffer(2 * rnd.length);
52 for(int i = 0; i < rnd.length; i++) {
53 int b = (int)rnd[i] & 0xFF;
54 buf.append(Character.forDigit(b / 16, 16));
55 buf.append(Character.forDigit(b % 16, 16));
57 return buf.toString();
60 public static String tempname(String prefix)
62 //As we don't create files atomically, we need to be unpredictable.
63 return prefix + "." + randomHexes(12);
66 public static String arrayToString(byte[] array) throws IOException
68 if(array == null)
69 return null;
70 return (new ImageLibrary.ByteArray(array)).toString();
73 public static byte[] stringToArray(String name) throws IOException
75 if(name == null)
76 return null;
78 if((name.length() % 2) != 0)
79 throw new IOException("Trying to transform odd-length string into byte array");
80 int l = name.length() / 2;
81 byte[] parsed = new byte[l];
82 for(int i = 0; i < l; i++)
83 parsed[i] = (byte)(Character.digit(name.charAt(2 * i), 16) * 16 +
84 Character.digit(name.charAt(2 * i + 1), 16));
86 return parsed;
89 public static boolean isspace(char ch)
91 if(ch == 12)
92 return true;
93 if(ch == 32)
94 return true;
95 if(ch == 9)
96 return true;
97 if(ch == 0x1680)
98 return true;
99 if(ch == 0x180E)
100 return true;
101 if(ch >= 0x2000 && ch <= 0x200A)
102 return true;
103 if(ch == 0x2028)
104 return true;
105 if(ch == 0x205F)
106 return true;
107 if(ch == 0x3000)
108 return true;
109 return false;
112 public static String componentEscape(String in)
114 boolean needEscape = false;
115 boolean needParens = false;
116 Stack<Integer> parens = new Stack<Integer>();
117 Stack<Integer> parens2 = new Stack<Integer>();
119 int strlen = in.length();
120 for(int i = 0; i < strlen; i++) {
121 char ch = in.charAt(i);
122 if(isspace(ch))
123 needParens = true;
124 if(ch == '\\') {
125 needEscape = true;
126 } if(ch == '(') {
127 needParens = true;
128 parens.push(new Integer(i));
129 } else if(ch == ')') {
130 if(!parens.empty())
131 parens.pop();
132 else
133 needEscape = true;
137 if(!parens.empty())
138 needEscape = true;
140 //Copy the paren stack to another to reverse it.
141 while(!parens.empty())
142 parens2.push(parens.pop());
144 if(!needEscape && !needParens)
145 return in;
147 StringBuilder out = new StringBuilder();
148 if(needParens)
149 out.append('(');
151 if(needEscape) {
152 int parenDepth = 0;
153 for(int i = 0; i < strlen; i++) {
154 char ch = in.charAt(i);
155 if(ch == '\\') {
156 out.append("\\\\");
157 } else if(!parens2.empty() && parens2.peek().intValue() == i) {
158 out.append("\\(");
159 parens2.pop();
160 } else if(ch == '(') {
161 out.append("(");
162 parenDepth++;
163 } else if(ch == ')') {
164 if(parenDepth > 0) {
165 out.append(")");
166 parenDepth--;
167 } else
168 out.append("\\)");
169 } else
170 out.append(ch);
172 } else
173 out.append(in);
175 if(needParens)
176 out.append(')');
178 return out.toString();
181 public static String componentUnescape(String in) throws IOException
183 if(in.indexOf('\\') < 0)
184 return in; //No escapes.
185 StringBuilder out = new StringBuilder();
186 boolean escapeActive = false;
187 int strlen = in.length();
188 for(int i = 0; i < strlen; i++) {
189 char ch = in.charAt(i);
190 if(escapeActive) {
191 out.append(ch);
192 escapeActive = false;
193 } else if(ch == '\\') {
194 escapeActive = true;
195 } else
196 out.append(ch);
198 if(escapeActive)
199 throw new IOException("Invalid escaped string: unexpected end of string after \\");
200 return out.toString();
203 public static String[] nextParseLine(UTFInputLineStream in) throws IOException
205 String[] ret = null;
207 String parseLine = "";
208 while(parseLine != null && "".equals(parseLine))
209 parseLine = in.readLine();
210 if(parseLine == null)
211 return null;
213 ret = parseString(parseLine);
215 if(ret == null)
216 return nextParseLine(in);
218 return ret;
221 public static String[] parseString(String parseLine) throws IOException
223 String[] ret = null;
224 boolean escapeActive = false;
226 if(parseLine == null)
227 return null;
229 //System.err.println("Line: \"" + parseLine + "\".");
230 int parenDepth = 0;
231 int lastSplitStart = 0;
232 int strlen = parseLine.length();
234 for(int i = 0; i < strlen; i++) {
235 String component = null;
236 char ch = parseLine.charAt(i);
237 if(escapeActive) {
238 escapeActive = false;
239 } else if(ch == '\\') {
240 escapeActive = true;
241 } else if(ch == '(') {
242 if(parenDepth > 0)
243 parenDepth++;
244 else if(parenDepth == 0) {
245 //Split here.
246 component = parseLine.substring(lastSplitStart, i);
247 lastSplitStart = i + 1;
248 parenDepth++;
250 } else if(ch == ')') {
251 if(parenDepth == 0)
252 throw new IOException("Unbalanced ) in initialization segment line \"" + parseLine + "\".");
253 else if(parenDepth == 1) {
254 //Split here.
255 component = parseLine.substring(lastSplitStart, i);
256 lastSplitStart = i + 1;
257 parenDepth--;
258 } else
259 parenDepth--;
260 } else if(parenDepth == 0 && isspace(ch)) {
261 //Split here.
262 //System.err.println("Splitting at point " + i + ".");
263 component = componentUnescape(parseLine.substring(lastSplitStart, i));
264 lastSplitStart = i + 1;
267 if(component != null && !component.equals(""))
268 if(ret != null) {
269 String[] ret2 = new String[ret.length + 1];
270 System.arraycopy(ret, 0, ret2, 0, ret.length);
271 ret2[ret.length] = component;
272 ret = ret2;
273 } else
274 ret = new String[]{component};
276 if(parenDepth > 0)
277 throw new IOException("Unbalanced ( in initialization segment line \"" + parseLine + "\".");
278 String component = componentUnescape(parseLine.substring(lastSplitStart));
279 if(component != null && !component.equals(""))
280 if(ret != null) {
281 String[] ret2 = new String[ret.length + 1];
282 System.arraycopy(ret, 0, ret2, 0, ret.length);
283 ret2[ret.length] = component;
284 ret = ret2;
285 } else
286 ret = new String[]{component};
288 return ret;
291 public static boolean hasParensInserted(String in)
293 return (in.charAt(0) == '(');
296 public static String encodeLine(String[] components)
298 String s = "";
299 boolean lastParen = true; //Hack to supress initial space.
300 for(int i = 0; i < components.length; i++) {
301 String escaped = componentEscape(components[i]);
302 boolean thisParen = hasParensInserted(escaped);
303 if(!lastParen && !thisParen)
304 s = s + " ";
305 s = s + escaped;
306 lastParen = thisParen;
308 return s;
311 public static int callShowOptionDialog(java.awt.Component parent, Object msg, String title, int oType,
312 int mType, Icon icon, Object[] buttons, Object deflt)
314 try {
315 return JOptionPane.showOptionDialog(parent, msg, title, oType, mType, icon, buttons, deflt);
316 } catch(Throwable e) { //Catch errors too!
317 //No GUI available.
318 System.err.println("MESSAGE: *** " + title + " ***: " + msg.toString());
319 for(int i = 0; i < buttons.length; i++)
320 if(buttons[i] == deflt)
321 return i;
322 return 0;
327 public static String messageForException(Throwable e)
329 boolean supressClass = false;
330 String message = e.getMessage();
331 Class<?> eClass = e.getClass();
332 while(eClass != null) {
333 if(classes.containsKey(eClass.getName())) {
334 if(message != null && !message.equals("") && !message.equals("null"))
335 message = classes.get(eClass.getName()) + " (" + message + ")";
336 else
337 message = classes.get(eClass.getName());
338 if(eClass == e.getClass())
339 supressClass = true;
340 break;
342 eClass = eClass.getSuperclass();
345 if(!supressClass)
346 if(message != null && !message.equals("") && !message.equals("null"))
347 message = message + " [" + e.getClass().getName() + "]";
348 else
349 message = message + "<no description available> [" + e.getClass().getName() + "]";
350 return message;
353 public static void errorDialog(Throwable e, String title, java.awt.Component component, String text)
355 String message = messageForException(e);
356 int i = callShowOptionDialog(null, message, title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[]{text, "Save stack trace"}, "Save stack Trace");
357 if(i > 0) {
358 saveStackTrace(e, null, text);
362 public static void saveStackTrace(Throwable e, java.awt.Component component, String text)
364 StackTraceElement[] traceback = e.getStackTrace();
365 StringBuffer sb = new StringBuffer();
366 sb.append(messageForException(e) + "\n");
367 for(int i = 0; i < traceback.length; i++) {
368 StackTraceElement el = traceback[i];
369 if(el.getClassName().startsWith("sun.reflect."))
370 continue; //Clean up the trace a bit.
371 if(el.isNativeMethod())
372 sb.append(el.getMethodName() + " of " + el.getClassName() + " <native>\n");
373 else
374 sb.append(el.getMethodName() + " of " + el.getClassName() + " <" + el.getFileName() + ":" +
375 el.getLineNumber() + ">\n");
377 String exceptionMessage = sb.toString();
379 try {
380 ByteBuffer buf;
381 buf = Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap(exceptionMessage));
382 byte[] buf2 = new byte[buf.remaining()];
383 buf.get(buf2);
385 String traceFileName = "StackTrace-" + System.currentTimeMillis() + ".text";
386 OutputStream stream = new FileOutputStream(traceFileName);
387 stream.write(buf2);
388 stream.close();
389 callShowOptionDialog(component, "Stack trace saved to " + traceFileName + ".", "Stack trace saved", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[]{text}, text);
390 } catch(Exception e2) {
391 callShowOptionDialog(component, e.getMessage(), "Saving stack trace failed", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[]{text}, text);
395 public static Map<String, String> parseStringToComponents(String string) throws IOException
397 Map<String,String> ret = new HashMap<String, String>();
398 while(!string.equals("")) {
399 int i = string.indexOf(',');
400 String element;
401 if(i < 0) {
402 element = string;
403 string = "";
404 } else {
405 element = string.substring(0, i);
406 string = string.substring(i + 1);
408 int j = element.indexOf('=');
409 if(j < 0)
410 throw new IOException("Bad string element: \"" + element + "\"");
411 String key = element.substring(0, j);
412 String value = element.substring(j + 1);
413 ret.put(key, value);
415 return ret;
418 public static void moveWindow(JFrame window, int x, int y, int w, int h)
420 final int x2 = x;
421 final int y2 = y;
422 final int w2 = w;
423 final int h2 = h;
424 final JFrame window2 = window;
426 if(!SwingUtilities.isEventDispatchThread())
427 try {
428 SwingUtilities.invokeAndWait(new Thread() { public void run() {
429 window2.setBounds(x2, y2, w2, h2); }});
430 } catch(Exception e) {
432 else
433 window2.setBounds(x2, y2, w2, h2);
436 public static boolean isFPUOp(int op)
438 switch(op) {
439 case FWAIT:
440 case FLOAD0_ST0:
441 case FLOAD0_STN:
442 case FLOAD0_MEM_SINGLE:
443 case FLOAD0_MEM_DOUBLE:
444 case FLOAD0_MEM_EXTENDED:
445 case FLOAD0_REG0:
446 case FLOAD0_REG0L:
447 case FLOAD0_1:
448 case FLOAD0_L2TEN:
449 case FLOAD0_L2E:
450 case FLOAD0_PI:
451 case FLOAD0_LOG2:
452 case FLOAD0_LN2:
453 case FLOAD0_POS0:
454 case FLOAD1_ST0:
455 case FLOAD1_STN:
456 case FLOAD1_MEM_SINGLE:
457 case FLOAD1_MEM_DOUBLE:
458 case FLOAD1_MEM_EXTENDED:
459 case FLOAD1_REG0:
460 case FLOAD1_REG0L:
461 case FLOAD1_POS0:
462 case FSTORE0_ST0:
463 case FSTORE0_STN:
464 case FSTORE0_MEM_SINGLE:
465 case FSTORE0_MEM_DOUBLE:
466 case FSTORE0_MEM_EXTENDED:
467 case FSTORE0_REG0:
468 case FSTORE1_ST0:
469 case FSTORE1_STN:
470 case FSTORE1_MEM_SINGLE:
471 case FSTORE1_MEM_DOUBLE:
472 case FSTORE1_MEM_EXTENDED:
473 case FSTORE1_REG0:
474 case LOAD0_FPUCW:
475 case STORE0_FPUCW:
476 case LOAD0_FPUSW:
477 case STORE0_FPUSW:
478 case FPOP:
479 case FPUSH:
480 case FADD:
481 case FMUL:
482 case FCOM:
483 case FUCOM:
484 case FCOMI:
485 case FUCOMI:
486 case FSUB:
487 case FDIV:
488 case FCHS:
489 case FABS:
490 case FXAM:
491 case F2XM1:
492 case FYL2X:
493 case FPTAN:
494 case FPATAN:
495 case FXTRACT:
496 case FPREM1:
497 case FDECSTP:
498 case FINCSTP:
499 case FPREM:
500 case FYL2XP1:
501 case FSQRT:
502 case FSINCOS:
503 case FRNDINT:
504 case FSCALE:
505 case FSIN:
506 case FCOS:
507 case FRSTOR_94:
508 case FRSTOR_108:
509 case FSAVE_94:
510 case FSAVE_108:
511 case FFREE:
512 case FBCD2F:
513 case FF2BCD:
514 case FLDENV_14:
515 case FLDENV_28:
516 case FSTENV_14:
517 case FSTENV_28:
518 case FCMOVB:
519 case FCMOVE:
520 case FCMOVBE:
521 case FCMOVU:
522 case FCMOVNB:
523 case FCMOVNE:
524 case FCMOVNBE:
525 case FCMOVNU:
526 case FCHOP:
527 case FCLEX:
528 case FINIT:
529 case FCHECK0:
530 case FCHECK1:
531 case FXSAVE:
532 return true;
533 default:
534 return false;