--- /dev/null
+package gnu.gcj;
+public class RawData {
+}
static final Font DEFAULT_FONT;
static {
- try { DEFAULT_FONT = Font.getFont(Main.builtin.get(JS.S("fonts/vera/Vera.ttf")), 10); }
+ try { DEFAULT_FONT = Font.getFont((JS)Main.builtin.get(JS.S("fonts/vera/Vera.ttf")), 10); }
catch(JSExn e) { throw new Error("Error loading default font: " + e); }
}
public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
switch (nargs) {
case 1: {
- //#jswitch(method)
+ //#switch(JS.toString(method))
case "indexof":
Box b = (Box)a0;
if (b.parent != this)
if (JS.isInt(name))
return redirect == null ? null : redirect == this ? getChild(JS.toInt(name)) : redirect.get(name);
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "surface": return parent == null ? null : parent.getAndTriggerTraps(name);
case "indexof": return METHOD;
case "distanceto": return METHOD;
private class Mouse extends JS implements JS.Cloneable {
public JS get(JS key) throws JSExn {
- //#jswitch(key)
+ //#switch(JS.toString(key))
case "x": return N(globalToLocalX(getSurface()._mousex));
case "y": return N(globalToLocalY(getSurface()._mousey));
public void put(JS name, JS value) throws JSExn {
if (JS.isInt(name)) { put(JS.toInt(name), value); return; }
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "thisbox": if (value == null) removeSelf();
case "text": { String s = value == null ? "" : JS.toString(value); CHECKSET_STRING(text); RECONSTRAIN(); dirty(); }
case "strokecolor": value = N(Color.stringToColor(JS.toString(value))); CHECKSET_INT(strokecolor); dirty();
private void setAlign(JS value) throws JSExn {
clear(ALIGNS);
- //#jswitch(value)
+ //#switch(JS.toString(value))
case "topleft": set(ALIGN_TOP | ALIGN_LEFT);
case "bottomleft": set(ALIGN_BOTTOM | ALIGN_LEFT);
case "topright": set(ALIGN_TOP | ALIGN_RIGHT);
// FIXME: SHouldn't need this (just trap [""])
if (JS.isString(name) && JS.toString(name).length() == 0) return rr;
// FEATURE: Preprocessor hack to generate specialized JS instances (avoid all this string concatenation)
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "math": return ibexMath;
case "string": return ibexString;
case "date": return METHOD;
}
public void put(JS name, JS value) throws JSExn {
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "thread": Scheduler.add((Task)value); return;
case "ui.clipboard": Platform.setClipBoard(JS.toString(value)); return;
case "ui.frame": Platform.createSurface((Box)value, true, true); return;
public JS callMethod(JS name, JS a, JS b, JS c, JS[] rest, int nargs) throws JSExn {
try {
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "date": return new JSDate(a, b, c, rest, nargs);
case "net.rpc.soap": return new SOAP(JS.toString(a), "", JS.toString(b), JS.toString(c));
// FIXME support object dumping
switch (nargs) {
case 0:
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "thread.yield": sleep(0); return null;
//#end
break;
case 1:
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "clone":
if(a == null) throw new JSExn("can't clone the null value");
return ((JS)a).jsclone();
case "bless": return bless((JS)a);
case "ui.browser": Platform.newBrowserWindow(JS.toString(a)); return null;
- case "stream.unzip": return a == null ? null : new Stream.Zip(a);
- case "stream.uncab": return a == null ? null : new Stream.Cab(a);
+ case "stream.unzip": return a == null ? null : new Stream.Zip((Stream)a);
+ //case "stream.uncab": return a == null ? null : new Stream.Cab(a);
case "stream.cache":
- try { return a == null ? null : new Stream.CachedStream(a, "resources", true); }
+ try { return a == null ? null : new Stream.CachedStream((Stream)a, "resources", true); }
catch (Stream.NotCacheableException e) { throw new JSExn("this resource cannot be cached"); }
case "stream.url": {
String url = JS.toString(a);
//#end
break;
case 2:
- //#jswitch(name)
- case "stream.watch": return new Stream.ProgressWatcher(a, b);
+ //#switch(JS.toString(name))
+ case "stream.watch": return new Stream.ProgressWatcher((Stream)a, b);
case "regexp": return new JSRegexp(a, b);
//#end
case 3:
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "ui.font.height": return N(Font.getFont(a, JS.toInt(b)).textheight(JS.toString(c)));
case "ui.font.wait": throw new Error("FIXME: ibex.ui.font.wait not implemented");
case "ui.font.width": return N(Font.getFont(a, JS.toInt(b)).textwidth(JS.toString(c)));
// FEATURE: find a cleaner way to do this
private JS gs = /*new JSScope.Global();*/ null; // FIXME: Global scope
public JS get(JS key) throws JSExn {
- //#jswitch(key)
+ //#switch(JS.toString(key))
case "isNaN": return METHOD;
case "isFinite": return METHOD;
case "NaN": return METHOD;
return MATH.get(key);
}
public JS callMethod(JS name, JS a, JS b, JS c, JS[] rest, int nargs) throws JSExn {
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "isNaN": return gs.callMethod(name,a,b,c,rest,nargs);
case "isFinite": return gs.callMethod(name,a,b,c,rest,nargs);
case "NaN": return gs.callMethod(name,a,b,c,rest,nargs);
public static final JS ibexString = new JS() {
private JS gs = /*new JSScope.Global();*/ null; // FIXME: Global scope
public JS get(JS key) throws JSExn {
- //#jswitch(key)
+ //#switch(JS.toString(key))
case "parseInt": return METHOD;
case "parseFloat": return METHOD;
case "decodeURI": return METHOD;
return super.get(key);
}
public JS callMethod(JS name, JS a, JS b, JS c, JS[] rest, int nargs) throws JSExn {
- //#jswitch(name)
+ //#switch(JS.toString(name))
case "parseInt": return gs.callMethod(name,a,b,c,rest,nargs);
case "parseFloat": return gs.callMethod(name,a,b,c,rest,nargs);
case "decodeURI": return gs.callMethod(name,a,b,c,rest,nargs);
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.util;
+package org.ibex.core;
import java.io.IOException;
// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
+package org.ibex.core;
import java.io.*;
import java.util.zip.*;
+import org.ibex.js.*;
import org.ibex.util.*;
-//import org.ibex.plat.*;
+import org.ibex.plat.*;
import org.ibex.net.*;
/**
* be totally independent of the others (ie separate stream position
* and state) although they draw from the same data source.
*/
-public abstract class Stream extends JS.Cloneable {
+public abstract class Stream extends JS.O implements JS.Cloneable {
// Public Interface //////////////////////////////////////////////////////////////////////////////
/** HTTP or HTTPS resource */
public static class HTTP extends Stream {
private String url;
- public String toString() { return "Stream.HTTP:" + url; }
+ //public String toString() { return "Stream.HTTP:" + url; }
public HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; }
public Object _get(Object key) { return new HTTP(url + "/" + (String)key); }
public String getCacheKey(Vec path) throws NotCacheableException { return url; }
- public InputStream getInputStream() throws IOException { return new org.ibex.net.HTTP(url).GET(); }
+ public InputStream getInputStream() throws IOException { return new org.ibex.net.HTTP(url).GET(null, null); }
}
/** byte arrays */
public static class File extends Stream {
private String path;
public File(String path) { this.path = path; }
- public String toString() { return "file:" + path; }
+ //public String toString() { return "file:" + path; }
public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); /* already on disk */ }
public InputStream getInputStream() throws IOException { return new FileInputStream(path); }
public Object _get(Object key) { return new File(path + java.io.File.separatorChar + (String)key); }
}
/** "unwrap" a Cab archive */
+ /*
public static class Cab extends Stream {
private Stream parent;
private String path;
public Object _get(Object key) { return new Cab(parent, path==null?(String)key:path+'/'+(String)key); }
public InputStream getInputStream() throws IOException { return new MSPack(parent.getInputStream()).getInputStream(path); }
}
+ */
/** the Builtin resource */
public static class Builtin extends Stream {
import java.io.*;
import java.util.Hashtable;
import org.ibex.js.*;
+import org.ibex.core.*;
import org.ibex.nestedvm.*;
import org.ibex.plat.*;
import org.ibex.nestedvm.Runtime;
-package org.ibex.util;
+package org.ibex.graphics;
import org.ibex.core.Main;
import org.ibex.util.*;
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-/**
- * Constants for the various JavaScript ByteCode operations.
- *
- * Each instruction is an opcode and an optional literal literal;
- * some Tokens are also valid; see Tokens.java
- */
-interface ByteCodes {
-
- /** push the literal onto the stack */
- public static final byte LITERAL = -2;
-
- /** push a new array onto the stack with length equal to the literal */
- public static final byte ARRAY = -3;
-
- /** push an empty object onto the stack */
- public static final byte OBJECT = -4;
-
- /** create a new instance; literal is a reference to the corresponding ForthBlock */
- public static final byte NEWFUNCTION = -5;
-
- /** if given a non-null argument declare its argument in the current scope and push
- it to the stack, else, declares the element on the top of the stack and leaves it
- there */
- //public static final byte DECLARE = -6;
-
- /** push a reference to the current scope onto the stack */
- // FIXME: Document this
- public static final byte GLOBALSCOPE = -7;
-
- /** if given a null literal pop two elements off the stack; push stack[-1].get(stack[top])
- else pop one element off the stack, push stack[top].get(literal) */
- public static final byte GET = -8;
-
- /** push stack[-1].get(stack[top]) */
- public static final byte GET_PRESERVE = -9;
-
- /** pop two elements off the stack; stack[-2].put(stack[-1], stack[top]); push stack[top] */
- public static final byte PUT = -10;
-
- /** literal is a relative address; pop stacktop and jump if the value is true */
- public static final byte JT = -11;
-
- /** literal is a relative address; pop stacktop and jump if the value is false */
- public static final byte JF = -12;
-
- /** literal is a relative address; jump to it */
- public static final byte JMP = -13;
-
- /** discard the top stack element */
- static public final byte POP = -14;
-
- /** pop element; call stack[top](stack[-n], stack[-n+1]...) where n is the number of args to the function */
- public static final byte CALL = -15;
-
- /** pop an element; push a JS.JSArray containing the keys of the popped element */
- public static final byte PUSHKEYS = -16;
-
- /** push the top element down so that (arg) elements are on top of it; all other elements retain ordering */
- public static final byte SWAP = -17;
-
- /** execute the bytecode block pointed to by the literal in a fresh scope with parentScope==THIS */
- public static final byte NEWSCOPE = -18;
-
- /** execute the bytecode block pointed to by the literal in a fresh scope with parentScope==THIS */
- public static final byte OLDSCOPE = -19;
-
- /** push a copy of the top stack element */
- public static final byte DUP = -20;
-
- /** a NOP; confers a label upon the following instruction */
- public static final byte LABEL = -21;
-
- /** execute the ForthBlock pointed to by the literal until BREAK encountered; push TRUE onto the stack for the first iteration
- * and FALSE for all subsequent iterations */
- public static final byte LOOP = -22;
-
- /** similar effect a a GET followed by a CALL */
- public static final byte CALLMETHOD = -23;
-
- /** finish a finally block and carry out whatever instruction initiated the finally block */
- public static final byte FINALLY_DONE = -24;
-
- /** finish a finally block and carry out whatever instruction initiated the finally block */
- public static final byte MAKE_GRAMMAR = -25;
-
- // FIXME: Document these and NEWSCOPE/OLDSCOPE/TOPSCOPE changes
- public static final byte SCOPEGET = -26;
- public static final byte SCOPEPUT = -27;
-
- public static final String[] bytecodeToString = new String[] {
- "", "", "LITERAL", "ARRAY", "OBJECT", "NEWFUNCTION", "DECLARE", "GLOBALSCOPE",
- "GET", "GET_PRESERVE", "PUT", "JT", "JF", "JMP", "POP", "CALL", "PUSHKEYS",
- "SWAP", "NEWSCOPE", "OLDSCOPE", "DUP", "LABEL", "LOOP", "CALLMETHOD",
- "FINALLY_DONE", "MAKE_GRAMMAR", "SCOPEGET", "SCOPEPUT"
- };
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.util.*;
-import java.io.*;
-
-// FEATURE: support for move
-// FEATURE: support for bytestreams
-// FEATURE: cache directories so we can do equality checking on them?
-// FEATURE: autoconvert "true" to true and "0.3" to 0.3 on readback
-
-/**
- * A crude mechanism for using a filesystem as object storage.
- *
- * This object represents a directory; writing a string, number, or
- * boolean to any of its properties will create a file with the
- * (encoded) property name as its filename and the "stringified"
- * value as its contents.
- *
- * Writing 'null' to one of this object's properties will
- * [recursively if necessary] delete the corresponding directory
- * entry.
- *
- * Writing any other object to one of this object's properties will
- * create a new Directory object and copy the other object's keys()
- * into the new Directory. This means that assigning one directory
- * to a property of another directory will <i>copy</i> the directory,
- * not move it. There is currently no way to move directories.
- *
- * If an object is written to a property that already has an entry,
- * the old one is deleted (equivalent to writing 'null') first.
- *
- * WARNING: when instantiating a Directory object with a file
- * argument that points to a non-directory File, this class will
- * delete that file and create a directory!
- */
-public class Directory extends JS {
-
- File f;
-
- /**
- * Create the directory object. Existing directories will be
- * preserved; if a file is present it will be obliterated.
- */
-
- public Directory(File f) throws IOException {
- this.f = f;
- if (!f.exists()) new Directory(new File(f.getParent()));
- if (!f.isDirectory()) destroy(f);
- f.mkdirs();
- }
-
- private static void destroy(File f) throws IOException {
- if (!f.exists()) return;
- if (f.isDirectory()) {
- String[] entries = f.list();
- for(int i=0; i<entries.length; i++) destroy(new File(f.getAbsolutePath() + File.separatorChar + entries[i]));
- }
- f.delete();
- }
-
- public void put(JS key0, JS val) throws JSExn {
- try {
- if (key0 == null) return;
- String key = toString(key0);
- File f2 = new File(f.getAbsolutePath() + File.separatorChar + FileNameEncoder.encode(key));
- destroy(f2);
- if (val == null) return;
- if (val instanceof JSPrimitive) {
- OutputStream out = new FileOutputStream(f2);
- Writer w = new OutputStreamWriter(out);
- w.write(toString(val));
- w.flush();
- out.close();
- } else {
- Directory d2 = new Directory(f2);
- JS.Enumeration e = val.keys();
- while(e.hasMoreElements()) {
- JS k = e.nextElement();
- JS v = val.get(k);
- d2.put(k, v);
- }
- }
- } catch (IOException ioe) {
- throw new JSExn.IO(ioe);
- }
- }
-
- public JS get(JS key0) throws JSExn {
- try {
- if (key0 == null) return null;
- String key = toString(key0);
- File f2 = new File(f.getAbsolutePath() + File.separatorChar + FileNameEncoder.encode(key));
- if (!f2.exists()) return null;
- if (f2.isDirectory()) return new Directory(f2);
- char[] chars = new char[((int)f2.length()) * 2];
- int numchars = 0;
- Reader r = new InputStreamReader(new FileInputStream(f2));
- while(true) {
- int numread = r.read(chars, numchars, chars.length - numchars);
- if (numread == -1) return JS.S(new String(chars, 0, numchars));
- numchars += numread;
- }
- } catch (IOException ioe) {
- throw new JSExn.IO(ioe);
- }
- }
-
- public Enumeration keys() {
- final String[] elements = f.list();
- return new Enumeration(null) {
- int i = 0;
- public boolean _hasMoreElements() { return i < elements.length; }
- public JS _nextElement() { return JS.S(FileNameEncoder.decode(elements[i++])); }
- };
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.util.*;
-
-/** Encapsulates a single JS interpreter (ie call stack) */
-class Interpreter implements ByteCodes, Tokens {
- // Thread-Interpreter Mapping /////////////////////////////////////////////////////////////////////////
-
- static Interpreter current() { return (Interpreter)threadToInterpreter.get(Thread.currentThread()); }
- private static Hashtable threadToInterpreter = new Hashtable();
-
-
- // Instance members and methods //////////////////////////////////////////////////////////////////////
-
- int pausecount; ///< the number of times pause() has been invoked; -1 indicates unpauseable
- JSFunction f = null; ///< the currently-executing JSFunction
- JSScope scope; ///< the current top-level scope (LIFO stack via NEWSCOPE/OLDSCOPE)
- final Stack stack = new Stack(); ///< the object stack
- int pc = 0; ///< the program counter
-
- Interpreter(JSFunction f, boolean pauseable, JSArgs args) {
- this.f = f;
- this.pausecount = pauseable ? 0 : -1;
- this.scope = f.parentScope;
- try {
- stack.push(new CallMarker(null)); // the "root function returned" marker -- f==null
- stack.push(args);
- } catch(JSExn e) {
- throw new Error("should never happen");
- }
- }
-
- Interpreter(Trap t, JS val, boolean pauseOnPut) {
- this.pausecount = -1;
- try {
- setupTrap(t,val,new TrapMarker(null,t,val,pauseOnPut));
- } catch(JSExn e) {
- throw new Error("should never happen");
- }
- }
-
- /** this is the only synchronization point we need in order to be threadsafe */
- synchronized JS resume() throws JSExn {
- if(f == null) throw new RuntimeException("function already finished");
- if(scope == null) throw new RuntimeException("scope is null");
- Thread t = Thread.currentThread();
- Interpreter old = (Interpreter)threadToInterpreter.get(t);
- threadToInterpreter.put(t, this);
- try {
- return run();
- } finally {
- if (old == null) threadToInterpreter.remove(t);
- else threadToInterpreter.put(t, old);
- }
- }
-
- static int getLine() {
- Interpreter c = Interpreter.current();
- return c == null || c.f == null || c.pc < 0 || c.pc >= c.f.size ? -1 : c.f.line[c.pc];
- }
-
- static String getSourceName() {
- Interpreter c = Interpreter.current();
- return c == null || c.f == null ? null : c.f.sourceName;
- }
-
- private static JSExn je(String s) { return new JSExn(getSourceName() + ":" + getLine() + " " + s); }
-
- private JS run() throws JSExn {
-
- // if pausecount changes after a get/put/call, we know we've been paused
- final int initialPauseCount = pausecount;
-
- OUTER: for(;; pc++) {
- try {
- int op = f.op[pc];
- Object arg = f.arg[pc];
- if(op == FINALLY_DONE) {
- FinallyData fd = (FinallyData) stack.pop();
- if(fd == null) continue OUTER; // NOP
- if(fd.exn != null) throw fd.exn;
- op = fd.op;
- arg = fd.arg;
- }
- switch(op) {
- case LITERAL: stack.push((JS)arg); break;
- case OBJECT: stack.push(new JS.O()); break;
- case ARRAY: stack.push(new JSArray(JS.toInt((JS)arg))); break;
- //case DECLARE: scope.declare((JS)(arg==null ? stack.peek() : arg)); if(arg != null) stack.push((JS)arg); break;
- case JT: if (JS.toBoolean(stack.pop())) pc += JS.toInt((JS)arg) - 1; break;
- case JF: if (!JS.toBoolean(stack.pop())) pc += JS.toInt((JS)arg) - 1; break;
- case JMP: pc += JS.toInt((JS)arg) - 1; break;
- case POP: stack.pop(); break;
- case SWAP: stack.swap(); break;
- case DUP: stack.push(stack.peek()); break;
- case NEWSCOPE: {
- int n = JS.toInt((JS)arg);
- scope = new JSScope(scope,(n>>>16)&0xffff,(n>>>0)&0xffff);
- break;
- }
- case OLDSCOPE: scope = scope.parent; break;
- case GLOBALSCOPE: stack.push(scope.getGlobal()); break;
- case SCOPEGET: stack.push(scope.get((JS)arg)); break;
- case SCOPEPUT: scope.put((JS)arg,stack.peek()); break;
- case ASSERT: if (!JS.toBoolean(stack.pop())) throw je("ibex.assertion.failed"); break;
- case BITNOT: stack.push(JS.N(~JS.toLong(stack.pop()))); break;
- case BANG: stack.push(JS.B(!JS.toBoolean(stack.pop()))); break;
- case NEWFUNCTION: stack.push(((JSFunction)arg)._cloneWithNewParentScope(scope)); break;
- case LABEL: break;
-
- case TYPEOF: {
- Object o = stack.pop();
- if (o == null) stack.push(null);
- else if (o instanceof JSString) stack.push(JS.S("string"));
- else if (o instanceof JSNumber.B) stack.push(JS.S("boolean"));
- else if (o instanceof JSNumber) stack.push(JS.S("number"));
- else stack.push(JS.S("object"));
- break;
- }
-
- case PUSHKEYS: {
- JS o = stack.peek();
- stack.push(o == null ? null : o.keys());
- break;
- }
-
- case LOOP:
- stack.push(new LoopMarker(pc, pc > 0 && f.op[pc - 1] == LABEL ? (String)f.arg[pc - 1] : (String)null, scope));
- stack.push(JS.T);
- break;
-
- case BREAK:
- case CONTINUE:
- while(!stack.empty()) {
- JS o = stack.pop();
- if (o instanceof CallMarker) je("break or continue not within a loop");
- if (o instanceof TryMarker) {
- if(((TryMarker)o).finallyLoc < 0) continue; // no finally block, keep going
- stack.push(new FinallyData(op, arg));
- scope = ((TryMarker)o).scope;
- pc = ((TryMarker)o).finallyLoc - 1;
- continue OUTER;
- }
- if (o instanceof LoopMarker) {
- if (arg == null || arg.equals(((LoopMarker)o).label)) {
- int loopInstructionLocation = ((LoopMarker)o).location;
- int endOfLoop = JS.toInt((JS)f.arg[loopInstructionLocation]) + loopInstructionLocation;
- scope = ((LoopMarker)o).scope;
- if (op == CONTINUE) { stack.push(o); stack.push(JS.F); }
- pc = op == BREAK ? endOfLoop - 1 : loopInstructionLocation;
- continue OUTER;
- }
- }
- }
- throw new Error("CONTINUE/BREAK invoked but couldn't find LoopMarker at " +
- getSourceName() + ":" + getLine());
-
- case TRY: {
- int[] jmps = (int[]) arg;
- // jmps[0] is how far away the catch block is, jmps[1] is how far away the finally block is
- // each can be < 0 if the specified block does not exist
- stack.push(new TryMarker(jmps[0] < 0 ? -1 : pc + jmps[0], jmps[1] < 0 ? -1 : pc + jmps[1], this));
- break;
- }
-
- case RETURN: {
- JS retval = stack.pop();
- while(!stack.empty()) {
- Object o = stack.pop();
- if (o instanceof TryMarker) {
- if(((TryMarker)o).finallyLoc < 0) continue;
- stack.push(retval);
- stack.push(new FinallyData(RETURN));
- scope = ((TryMarker)o).scope;
- pc = ((TryMarker)o).finallyLoc - 1;
- continue OUTER;
- } else if (o instanceof CallMarker) {
- boolean didTrapPut = false;
- if (o instanceof TrapMarker) { // handles return component of a write trap
- TrapMarker tm = (TrapMarker) o;
- boolean cascade = tm.t.isWriteTrap() && !tm.cascadeHappened && !JS.toBoolean(retval);
- if(cascade) {
- Trap t = tm.t.nextWriteTrap();
- if(t == null && tm.t.target instanceof JS.Clone) {
- t = ((JS.Clone)tm.t.target).clonee.getTrap(tm.t.key);
- if(t != null) t = t.writeTrap();
- }
- if(t != null) {
- tm.t = t; // we reuse the old trap marker
- setupTrap(t,tm.val,tm);
- pc--; // we increment it on the next iter
- continue OUTER;
- } else {
- didTrapPut = true;
- if(!tm.pauseOnPut) tm.t.target.put(tm.t.key,tm.val);
- }
- }
- }
- CallMarker cm = (CallMarker) o;
- scope = cm.scope;
- pc = cm.pc - 1;
- f = cm.f;
- if (didTrapPut) {
- if (((TrapMarker)cm).pauseOnPut) { pc++; return ((TrapMarker)cm).val; }
- if (pausecount > initialPauseCount) { pc++; return null; } // we were paused
- } else {
- stack.push(retval);
- }
- if (f == null) return retval;
- continue OUTER;
- }
- }
- throw new Error("error: RETURN invoked but couldn't find a CallMarker!");
- }
-
- case CASCADE: {
- boolean write = JS.toBoolean((JS)arg);
- JS val = write ? stack.pop() : null;
- CallMarker o = stack.findCall();
- if(!(o instanceof TrapMarker)) throw new JSExn("tried to CASCADE while not in a trap");
- TrapMarker tm = (TrapMarker) o;
- JS key = tm.t.key;
- JS target = tm.t.target;
- if(tm.t.isWriteTrap() != write) throw new JSExn("tried to do a " + (write?"write":"read") + " cascade in a " + (write?"read":"write") + " trap");
- Trap t = write ? tm.t.nextWriteTrap() : tm.t.nextReadTrap();
- // FIXME: Doesn't handle multiple levels of clone's (probably can just make this a while loop)
- if(t == null && target instanceof JS.Clone) {
- target = ((JS.Clone)target).clonee;
- t = target.getTrap(key);
- if(t != null) t = write ? t.writeTrap() : t.readTrap();
- }
- if(write) {
- tm.cascadeHappened = true;
- stack.push(val);
- }
- if(t != null) {
- setupTrap(t,val,new TrapMarker(this,t,val,tm.pauseOnPut));
- pc--; // we increment later
- } else {
- if(write) {
- if (tm.pauseOnPut) { pc++; return val; }
- target.put(key,val);
- } else {
- JS ret = target.get(key);
- if (ret == JS.METHOD) ret = new Stub(target, key);
- stack.push(ret);
- }
- if (pausecount > initialPauseCount) { pc++; return null; } // we were paused
- }
- break;
- }
-
- case PUT: {
- JS val = stack.pop();
- JS key = stack.pop();
- JS target = stack.peek();
- if (target == null) throw je("tried to put " + JS.debugToString(val) + " to the " + JS.debugToString(key) + " property on the null value");
- if (key == null) throw je("tried to assign \"" + JS.debugToString(val) + "\" to the null key");
-
- Trap t = target.getTrap(key);
- if(t != null) t = t.writeTrap();
-
- if(t == null && target instanceof JS.Clone) {
- target = ((JS.Clone)target).clonee;
- t = target.getTrap(key);
- if(t != null) t = t.writeTrap();
- }
-
- stack.push(val);
-
- if(t != null) {
- setupTrap(t,val,new TrapMarker(this,t,val));
- pc--; // we increment later
- } else {
- target.put(key,val);
- if (pausecount > initialPauseCount) { pc++; return null; } // we were paused
- }
- break;
- }
-
- case GET:
- case GET_PRESERVE: {
- JS target, key;
- if (op == GET) {
- key = arg == null ? stack.pop() : (JS)arg;
- target = stack.pop();
- } else {
- key = stack.pop();
- target = stack.peek();
- stack.push(key);
- }
- JS ret = null;
- if (key == null) throw je("tried to get the null key from " + JS.debugToString(target));
- if (target == null) throw je("tried to get property \"" + JS.debugToString(key) + "\" from the null object");
-
- Trap t = target.getTrap(key);
- if(t != null) t = t.readTrap();
-
- if(t == null && target instanceof JS.Clone) {
- target = ((JS.Clone)target).clonee;
- t = target.getTrap(key);
- if(t != null) t = t.readTrap();
- }
-
- if(t != null) {
- setupTrap(t,null,new TrapMarker(this,t,null));
- pc--; // we increment later
- } else {
- ret = target.get(key);
- if (pausecount > initialPauseCount) { pc++; return null; } // we were paused
- if (ret == JS.METHOD) ret = new Stub(target, key);
- stack.push(ret);
- }
- break;
- }
-
- case CALL: case CALLMETHOD: {
- int numArgs = JS.toInt((JS)arg);
-
- JS[] rest = numArgs > 3 ? new JS[numArgs - 3] : null;
- for(int i=numArgs - 1; i>2; i--) rest[i-3] = stack.pop();
- JS a2 = numArgs <= 2 ? null : stack.pop();
- JS a1 = numArgs <= 1 ? null : stack.pop();
- JS a0 = numArgs <= 0 ? null : stack.pop();
-
- JS method = null;
- JS ret = null;
- JS object = stack.pop();
-
- if (op == CALLMETHOD) {
- if (object == JS.METHOD) {
- method = stack.pop();
- object = stack.pop();
- } else if (object == null) {
- method = stack.pop();
- object = stack.pop();
- throw new JSExn("function '"+JS.debugToString(method)+"' not found in " + object.getClass().getName());
- } else {
- stack.pop();
- stack.pop();
- }
- }
-
- if (object instanceof JSFunction) {
- stack.push(new CallMarker(this));
- stack.push(new JSArgs(a0,a1,a2,rest,numArgs,object));
- f = (JSFunction)object;
- scope = f.parentScope;
- pc = -1;
- break;
- } else {
- JS c = (JS)object;
- ret = method == null ? c.call(a0, a1, a2, rest, numArgs) : c.callMethod(method, a0, a1, a2, rest, numArgs);
- }
-
- if (pausecount > initialPauseCount) { pc++; return null; }
- stack.push(ret);
- break;
- }
-
- case THROW:
- throw new JSExn(stack.pop(), this);
-
- /* FIXME GRAMMAR
- case MAKE_GRAMMAR: {
- final Grammar r = (Grammar)arg;
- final JSScope final_scope = scope;
- Grammar r2 = new Grammar() {
- public int match(String s, int start, Hash v, JSScope scope) throws JSExn {
- return r.match(s, start, v, final_scope);
- }
- public int matchAndWrite(String s, int start, Hash v, JSScope scope, String key) throws JSExn {
- return r.matchAndWrite(s, start, v, final_scope, key);
- }
- public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- Hash v = new Hash();
- r.matchAndWrite((String)a0, 0, v, final_scope, "foo");
- return v.get("foo");
- }
- };
- Object obj = stack.pop();
- if (obj != null && obj instanceof Grammar) r2 = new Grammar.Alternative((Grammar)obj, r2);
- stack.push(r2);
- break;
- }
- */
- case ADD_TRAP: case DEL_TRAP: {
- JS val = stack.pop();
- JS key = stack.pop();
- JS js = stack.peek();
- // A trap addition/removal
- if(!(val instanceof JSFunction)) throw new JSExn("tried to add/remove a non-function trap");
- if(op == ADD_TRAP) js.addTrap(key, (JSFunction)val);
- else js.delTrap(key, (JSFunction)val);
- break;
- }
-
- case ADD: {
- int count = ((JSNumber)arg).toInt();
- if(count < 2) throw new Error("this should never happen");
- if(count == 2) {
- // common case
- JS right = stack.pop();
- JS left = stack.pop();
- JS ret;
- if(left instanceof JSString || right instanceof JSString)
- ret = JS.S(JS.toString(left).concat(JS.toString(right)));
- else if(left instanceof JSNumber.D || right instanceof JSNumber.D)
- ret = JS.N(JS.toDouble(left) + JS.toDouble(right));
- else {
- long l = JS.toLong(left) + JS.toLong(right);
- if(l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) ret = JS.N(l);
- ret = JS.N((int)l);
- }
- stack.push(ret);
- } else {
- JS[] args = new JS[count];
- while(--count >= 0) args[count] = stack.pop();
- if(args[0] instanceof JSString) {
- StringBuffer sb = new StringBuffer(64);
- for(int i=0;i<args.length;i++) sb.append(JS.toString(args[i]));
- stack.push(JS.S(sb.toString()));
- } else {
- int numStrings = 0;
- for(int i=0;i<args.length;i++) if(args[i] instanceof JSString) numStrings++;
- if(numStrings == 0) {
- double d = 0.0;
- for(int i=0;i<args.length;i++) d += JS.toDouble(args[i]);
- stack.push(JS.N(d));
- } else {
- int i=0;
- StringBuffer sb = new StringBuffer(64);
- if(!(args[0] instanceof JSString || args[1] instanceof JSString)) {
- double d=0.0;
- do {
- d += JS.toDouble(args[i++]);
- } while(!(args[i] instanceof JSString));
- sb.append(JS.toString(JS.N(d)));
- }
- while(i < args.length) sb.append(JS.toString(args[i++]));
- stack.push(JS.S(sb.toString()));
- }
- }
- }
- break;
- }
-
- default: {
- JS right = stack.pop();
- JS left = stack.pop();
- switch(op) {
-
- case BITOR: stack.push(JS.N(JS.toLong(left) | JS.toLong(right))); break;
- case BITXOR: stack.push(JS.N(JS.toLong(left) ^ JS.toLong(right))); break;
- case BITAND: stack.push(JS.N(JS.toLong(left) & JS.toLong(right))); break;
-
- case SUB: stack.push(JS.N(JS.toDouble(left) - JS.toDouble(right))); break;
- case MUL: stack.push(JS.N(JS.toDouble(left) * JS.toDouble(right))); break;
- case DIV: stack.push(JS.N(JS.toDouble(left) / JS.toDouble(right))); break;
- case MOD: stack.push(JS.N(JS.toDouble(left) % JS.toDouble(right))); break;
-
- case LSH: stack.push(JS.N(JS.toLong(left) << JS.toLong(right))); break;
- case RSH: stack.push(JS.N(JS.toLong(left) >> JS.toLong(right))); break;
- case URSH: stack.push(JS.N(JS.toLong(left) >>> JS.toLong(right))); break;
-
- //#repeat </<=/>/>= LT/LE/GT/GE
- case LT: {
- if(left instanceof JSString && right instanceof JSString)
- stack.push(JS.B(JS.toString(left).compareTo(JS.toString(right)) < 0));
- else
- stack.push(JS.B(JS.toDouble(left) < JS.toDouble(right)));
- }
- //#end
-
- case EQ:
- case NE: {
- boolean ret;
- if(left == null && right == null) ret = true;
- else if(left == null || right == null) ret = false;
- else ret = left.jsequals(right);
- stack.push(JS.B(op == EQ ? ret : !ret)); break;
- }
-
- default: throw new Error("unknown opcode " + op);
- } }
- }
-
- } catch(JSExn e) {
- catchException(e);
- pc--; // it'll get incremented on the next iteration
- } // end try/catch
- } // end for
- }
-
- /** tries to find a handler withing the call chain for this exception
- if a handler is found the interpreter is setup to call the exception handler
- if a handler is not found the exception is thrown
- */
- void catchException(JSExn e) throws JSExn {
- while(!stack.empty()) {
- JS o = stack.pop();
- if (o instanceof CatchMarker || o instanceof TryMarker) {
- boolean inCatch = o instanceof CatchMarker;
- if(inCatch) {
- o = stack.pop();
- if(((TryMarker)o).finallyLoc < 0) continue; // no finally block, keep going
- }
- if(!inCatch && ((TryMarker)o).catchLoc >= 0) {
- // run the catch block, this will implicitly run the finally block, if it exists
- stack.push(o);
- stack.push(catchMarker);
- stack.push(e.getObject());
- f = ((TryMarker)o).f;
- scope = ((TryMarker)o).scope;
- pc = ((TryMarker)o).catchLoc;
- return;
- } else {
- stack.push(new FinallyData(e));
- f = ((TryMarker)o).f;
- scope = ((TryMarker)o).scope;
- pc = ((TryMarker)o).finallyLoc;
- return;
- }
- }
- }
- throw e;
- }
-
- void setupTrap(Trap t, JS val, CallMarker cm) throws JSExn {
- stack.push(cm);
- stack.push(new TrapArgs(t,val));
- f = t.f;
- scope = f.parentScope;
- pc = 0;
- }
-
-
- // Markers //////////////////////////////////////////////////////////////////////
-
- static class Marker extends JS {
- public JS get(JS key) throws JSExn { throw new Error("this should not be accessible from a script"); }
- public void put(JS key, JS val) throws JSExn { throw new Error("this should not be accessible from a script"); }
- public String coerceToString() { throw new Error("this should not be accessible from a script"); }
- public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn { throw new Error("this should not be accessible from a script"); }
- }
-
- static class CallMarker extends Marker {
- final int pc;
- final JSScope scope;
- final JSFunction f;
- public CallMarker(Interpreter cx) {
- pc = cx == null ? -1 : cx.pc + 1;
- scope = cx == null ? null : cx.scope;
- f = cx == null ? null : cx.f;
- }
- }
-
- static class TrapMarker extends CallMarker {
- Trap t;
- JS val;
- boolean cascadeHappened;
- final boolean pauseOnPut;
- public TrapMarker(Interpreter cx, Trap t, JS val) { this(cx,t,val,false); }
- public TrapMarker(Interpreter cx, Trap t, JS val, boolean pauseOnPut) {
- super(cx);
- this.t = t;
- this.val = val;
- this.pauseOnPut = pauseOnPut;
- }
- }
-
- static class CatchMarker extends Marker { }
- private static CatchMarker catchMarker = new CatchMarker();
-
- static class LoopMarker extends Marker {
- final public int location;
- final public String label;
- final public JSScope scope;
- public LoopMarker(int location, String label, JSScope scope) {
- this.location = location;
- this.label = label;
- this.scope = scope;
- }
- }
- static class TryMarker extends Marker {
- final public int catchLoc;
- final public int finallyLoc;
- final public JSScope scope;
- final public JSFunction f;
- public TryMarker(int catchLoc, int finallyLoc, Interpreter cx) {
- this.catchLoc = catchLoc;
- this.finallyLoc = finallyLoc;
- this.scope = cx.scope;
- this.f = cx.f;
- }
- }
- static class FinallyData extends Marker {
- final public int op;
- final public Object arg;
- final public JSExn exn;
- public FinallyData(int op) { this(op,null); }
- public FinallyData(int op, Object arg) { this.op = op; this.arg = arg; this.exn = null; }
- public FinallyData(JSExn exn) { this.exn = exn; this.op = -1; this.arg = null; } // Just throw this exn
- }
-
- static class TrapArgs extends JS {
- private Trap t;
- private JS val;
- public TrapArgs(Trap t, JS val) { this.t = t; this.val = val; }
- public JS get(JS key) throws JSExn {
- if(JS.isInt(key) && JS.toInt(key) == 0) return val;
- //#jswitch(key)
- case "trapee": return t.target;
- case "callee": return t.f;
- case "trapname": return t.key;
- case "length": return t.isWriteTrap() ? ONE : ZERO;
- //#end
- return super.get(key);
- }
- }
-
- static class JSArgs extends JS {
- private final JS a0;
- private final JS a1;
- private final JS a2;
- private final JS[] rest;
- private final int nargs;
- private final JS callee;
-
- public JSArgs(JS callee) { this(null,null,null,null,0,callee); }
- public JSArgs(JS a0, JS callee) { this(a0,null,null,null,1,callee); }
- public JSArgs(JS a0, JS a1, JS a2, JS[] rest, int nargs, JS callee) {
- this.a0 = a0; this.a1 = a1; this.a2 = a2;
- this.rest = rest; this.nargs = nargs;
- this.callee = callee;
- }
-
- public JS get(JS key) throws JSExn {
- if(JS.isInt(key)) {
- int n = JS.toInt(key);
- switch(n) {
- case 0: return a0;
- case 1: return a1;
- case 2: return a2;
- default: return n>= 0 && n < nargs ? rest[n-3] : null;
- }
- }
- //#jswitch(key)
- case "callee": return callee;
- case "length": return JS.N(nargs);
- //#end
- return super.get(key);
- }
- }
-
- static class Stub extends JS {
- private JS method;
- JS obj;
- public Stub(JS obj, JS method) { this.obj = obj; this.method = method; }
- public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- return ((JS)obj).callMethod(method, a0, a1, a2, rest, nargs);
- }
- }
-
- static class Stack {
- private static final int MAX_STACK_SIZE = 512;
- private JS[] stack = new JS[64];
- private int sp = 0;
-
- boolean empty() { return sp == 0; }
- void push(JS o) throws JSExn { if(sp == stack.length) grow(); stack[sp++] = o; }
- JS peek() { if(sp == 0) throw new RuntimeException("Stack underflow"); return stack[sp-1]; }
- final JS pop() { if(sp == 0) throw new RuntimeException("Stack underflow"); return stack[--sp]; }
- void swap() throws JSExn {
- if(sp < 2) throw new JSExn("stack overflow");
- JS tmp = stack[sp-2];
- stack[sp-2] = stack[sp-1];
- stack[sp-1] = tmp;
- }
- CallMarker findCall() {
- for(int i=sp-1;i>=0;i--) if(stack[i] instanceof CallMarker) return (CallMarker) stack[i];
- return null;
- }
- void grow() throws JSExn {
- if(stack.length >= MAX_STACK_SIZE) throw new JSExn("Stack overflow");
- JS[] stack2 = new JS[stack.length * 2];
- System.arraycopy(stack,0,stack2,0,stack.length);
- }
-
- void backtrace(JSExn e) {
- for(int i=sp-1;i>=0;i--) {
- if (stack[i] instanceof CallMarker) {
- CallMarker cm = (CallMarker)stack[i];
- if(cm.f == null) break;
- String s = cm.f.sourceName + ":" + cm.f.line[cm.pc-1];
- if(cm instanceof Interpreter.TrapMarker)
- s += " (trap on " + JS.debugToString(((Interpreter.TrapMarker)cm).t.key) + ")";
- e.addBacktrace(s);
- }
- }
- }
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.io.*;
-import java.util.*;
-
-/** The minimum set of functionality required for objects which are manipulated by JavaScript */
-public abstract class JS {
- public static final JS METHOD = new JS() { };
-
- public JS.Enumeration keys() throws JSExn { throw new JSExn("you can't enumerate the keys of this object (class=" + getClass().getName() +")"); }
- public JS get(JS key) throws JSExn { return null; }
- public void put(JS key, JS val) throws JSExn { throw new JSExn("" + key + " is read only (class=" + getClass().getName() +")"); }
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- throw new JSExn("method not found (" + JS.debugToString(method) + ")");
- }
- public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")");
- }
- public InputStream getInputStream() throws IOException {
- throw new IOException("this object doesn't have a stream associated with it " + getClass().getName() + ")");
- }
-
- public final JS unclone() { return _unclone(); }
- public final JS jsclone() throws JSExn { return new Clone(this); }
- public final boolean hasTrap(JS key) { return getTrap(key) != null; }
- public final boolean equals(Object o) { return this == o || ((o instanceof JS) && jsequals((JS)o)); }
- // Discourage people from using toString()
- public final String toString() { return "JS Object [class=" + getClass().getName() + "]"; }
-
- // Package private methods
- Trap getTrap(JS key) { return null; }
- void putTrap(JS key, Trap value) throws JSExn { throw new JSExn("traps cannot be placed on this object (class=" + this.getClass().getName() +")"); }
- String coerceToString() throws JSExn { throw new JSExn("can't coerce to a string (class=" + getClass().getName() +")"); }
- boolean jsequals(JS o) { return this == o; }
- JS _unclone() { return this; }
-
- public static class O extends JS implements Cloneable {
- private Hash entries;
-
- public Enumeration keys() throws JSExn { return entries == null ? (Enumeration)EMPTY_ENUMERATION : (Enumeration)new JavaEnumeration(null,entries.keys()); }
- public JS get(JS key) throws JSExn { return entries == null ? null : (JS)entries.get(key, null); }
- public void put(JS key, JS val) throws JSExn { (entries==null?entries=new Hash():entries).put(key,null,val); }
-
- /** retrieve a trap from the entries hash */
- final Trap getTrap(JS key) {
- return entries == null ? null : (Trap)entries.get(key, Trap.class);
- }
-
- /** retrieve a trap from the entries hash */
- final void putTrap(JS key, Trap value) {
- if (entries == null) entries = new Hash();
- entries.put(key, Trap.class, value);
- }
- }
-
- public interface Cloneable { }
-
- public static class Clone extends O {
- protected final JS clonee;
- public Clone(JS clonee) throws JSExn {
- if(!(clonee instanceof Cloneable)) throw new JSExn("" + clonee.getClass().getName() + " isn't cloneable");
- this.clonee = clonee;
- }
- JS _unclone() { return clonee.unclone(); }
- boolean jsequals(JS o) { return clonee.jsequals(o); }
-
- public Enumeration keys() throws JSExn { return clonee.keys(); }
- public final JS get(JS key) throws JSExn { return clonee.get(key); }
- public final void put(JS key, JS val) throws JSExn { clonee.put(key,val); }
- public final JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- return clonee.callMethod(method,a0,a1,a2,rest,nargs);
- }
- public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- return clonee.call(a0, a1, a2, rest, nargs);
- }
- public InputStream getInputStream() throws IOException { return clonee.getInputStream(); }
- // FIXME: This shouldn't be necessary (its for Ibex.Blessing)
- public JS getClonee() { return clonee; }
- }
-
- public static abstract class Enumeration extends JS {
- final Enumeration parent;
- boolean done;
- public Enumeration(Enumeration parent) { this.parent = parent; }
- protected abstract boolean _hasMoreElements();
- protected abstract JS _nextElement() throws JSExn;
-
- public final boolean hasMoreElements() {
- if(!done && !_hasMoreElements()) done = true;
- return !done ? true : parent != null ? parent.hasMoreElements() : false;
- }
- public final JS nextElement() throws JSExn { return !done ? _nextElement() : parent != null ? parent.nextElement() : null; }
-
- public JS get(JS key) throws JSExn {
- //#jswitch(key)
- case "hasMoreElements": return B(hasMoreElements());
- case "nextElement": return nextElement();
- //#end
- return super.get(key);
- }
- }
-
- public static class EmptyEnumeration extends Enumeration {
- public EmptyEnumeration(Enumeration parent) { super(parent); }
- protected boolean _hasMoreElements() { return false; }
- protected JS _nextElement() { return null; }
- }
- public static class JavaEnumeration extends Enumeration {
- private final java.util.Enumeration e;
- public JavaEnumeration(Enumeration parent, java.util.Enumeration e) { super(parent); this.e = e; }
- protected boolean _hasMoreElements() { return e.hasMoreElements(); }
- protected JS _nextElement() { return (JS) e.nextElement(); }
- }
-
- // Static Interpreter Control Methods ///////////////////////////////////////////////////////////////
-
- /** log a message with the current JavaScript sourceName/line */
- public static void log(Object message) { info(message); }
- public static void debug(Object message) { Log.debug(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
- public static void info(Object message) { Log.info(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
- public static void warn(Object message) { Log.warn(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
- public static void error(Object message) { Log.error(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
-
- public static class NotPauseableException extends Exception { NotPauseableException() { } }
-
- /** returns a callback which will restart the context; expects a value to be pushed onto the stack when unpaused */
- public static UnpauseCallback pause() throws NotPauseableException {
- Interpreter i = Interpreter.current();
- if (i.pausecount == -1) throw new NotPauseableException();
- boolean get;
- switch(i.f.op[i.pc]) {
- case Tokens.RETURN: case ByteCodes.PUT: get = false; break;
- case ByteCodes.GET: case ByteCodes.CALL: get = true; break;
- default: throw new Error("should never happen");
- }
- i.pausecount++;
- return new JS.UnpauseCallback(i,get);
- }
-
- public static class UnpauseCallback implements Task {
- private Interpreter i;
- private boolean get;
- UnpauseCallback(Interpreter i, boolean get) { this.i = i; this.get = get; }
- public void perform() throws JSExn { unpause(); }
- public JS unpause() throws JSExn { return unpause((JS)null); }
- public JS unpause(JS o) throws JSExn {
- if (o == JS.METHOD) throw new JSExn("can't return a method to a paused context");
- if(get) i.stack.push(o);
- return i.resume();
- }
- public JS unpause(JSExn e) throws JSExn {
- i.catchException(e);
- return i.resume();
- }
- }
-
-
-
- // Static Helper Methods ///////////////////////////////////////////////////////////////////////////////////
-
- /** coerce an object to a Boolean */
- public static boolean toBoolean(JS o) {
- if(o == null) return false;
- if(o instanceof JSNumber) return ((JSNumber)o).toBoolean();
- if(o instanceof JSString) return ((JSString)o).s.length() != 0;
- return true;
- }
- //#repeat long/int/double/float toLong/toInt/toDouble/toFloat Long/Integer/Double/Float parseLong/parseInt/parseDouble/parseFloat
- /** coerce an object to a Number */
- public static long toLong(JS o) throws JSExn {
- if(o == null) return 0;
- if(o instanceof JSNumber) return ((JSNumber)o).toLong();
- if(o instanceof JSString) return Long.parseLong(o.coerceToString());
- throw new JSExn("can't coerce a " + o.getClass().getName() + " to a number");
- }
- //#end
-
- public static String toString(JS o) throws JSExn {
- if(o == null) return "null";
- return o.coerceToString();
- }
-
- public static String debugToString(JS o) {
- try { return toString(o); }
- catch(JSExn e) { return o.toString(); }
- }
-
- public static boolean isInt(JS o) {
- if(o == null) return true;
- if(o instanceof JSNumber.I) return true;
- if(o instanceof JSNumber.B) return false;
- if(o instanceof JSNumber) {
- JSNumber n = (JSNumber) o;
- return n.toInt() == n.toDouble();
- }
- if(o instanceof JSString) {
- String s = ((JSString)o).s;
- for(int i=0;i<s.length();i++)
- if(s.charAt(i) < '0' || s.charAt(i) > '9') return false;
- return true;
- }
- return false;
- }
-
- public static boolean isString(JS o) {
- if(o instanceof JSString) return true;
- return false;
- }
-
- // Instance Methods ////////////////////////////////////////////////////////////////////
-
- public final static JS NaN = new JSNumber.D(Double.NaN);
- public final static JS ZERO = new JSNumber.I(0);
- public final static JS ONE = new JSNumber.I(1);
- public final static JS MATH = new JSMath();
-
- public static final JS T = new JSNumber.B(true);
- public static final JS F = new JSNumber.B(false);
-
- public static final JS B(boolean b) { return b ? T : F; }
- public static final JS B(int i) { return i==0 ? F : T; }
-
- private static final int CACHE_SIZE = 65536 / 4; // must be a power of two
- private static final JSString[] stringCache = new JSString[CACHE_SIZE];
- public static final JS S(String s) {
- if(s == null) return null;
- int slot = s.hashCode()&(CACHE_SIZE-1);
- JSString ret = stringCache[slot];
- if(ret == null || !ret.s.equals(s)) stringCache[slot] = ret = new JSString(s);
- return ret;
- }
- public static final JS S(String s, boolean intern) { return intern ? JSString.intern(s) : S(s); }
-
- public static final JS N(double d) { return new JSNumber.D(d); }
- public static final JS N(long l) { return new JSNumber.L(l); }
-
- public static final JS N(Number n) {
- if(n instanceof Integer) return N(n.intValue());
- if(n instanceof Long) return N(n.longValue());
- return N(n.doubleValue());
- }
-
- private static final JSNumber.I[] smallIntCache = new JSNumber.I[CACHE_SIZE];
- private static final JSNumber.I[] largeIntCache = new JSNumber.I[CACHE_SIZE];
- public static final JS N(int i) {
- JSNumber.I ret = null;
- int idx = i + smallIntCache.length / 2;
- if (idx < CACHE_SIZE && idx > 0) {
- ret = smallIntCache[idx];
- if (ret != null) return ret;
- }
- else ret = largeIntCache[Math.abs(idx % CACHE_SIZE)];
- if (ret == null || ret.i != i) {
- ret = new JSNumber.I(i);
- if (idx < smallIntCache.length && idx > 0) smallIntCache[idx] = ret;
- else largeIntCache[Math.abs(idx % CACHE_SIZE)] = ret;
- }
- return ret;
- }
-
- private static Enumeration EMPTY_ENUMERATION = new EmptyEnumeration(null);
-
- public static JS fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
- return Parser.fromReader(sourceName, firstLine, sourceCode);
- }
-
- public static JS cloneWithNewGlobalScope(JS js, JS s) {
- if(js instanceof JSFunction)
- return ((JSFunction)js)._cloneWithNewParentScope(new JSScope.Top(s));
- else
- return js;
- }
-
-
- // Trap support //////////////////////////////////////////////////////////////////////////////
-
- /** performs a put, triggering traps if present; traps are run in an unpauseable interpreter */
- public final void putAndTriggerTraps(JS key, JS value) throws JSExn {
- Trap t = getTrap(key);
- if(t == null || (t = t.writeTrap()) == null) put(key,value);
- else new Interpreter(t,value,false).resume();
- }
-
- /** performs a get, triggering traps if present; traps are run in an unpauseable interpreter */
- public final JS getAndTriggerTraps(JS key) throws JSExn {
- Trap t = getTrap(key);
- if (t == null || (t = t.readTrap()) == null) return get(key);
- else return new Interpreter(t,null,false).resume();
- }
-
- public final JS justTriggerTraps(JS key, JS value) throws JSExn {
- Trap t = getTrap(key);
- if(t == null || (t = t.writeTrap()) == null) return value;
- else return new Interpreter(t,value,true).resume();
- }
-
- /** adds a trap, avoiding duplicates */
- // FIXME: This shouldn't be public, it is needed for a hack in Template.java
- public void addTrap(JS key, JSFunction f) throws JSExn {
- if (f.numFormalArgs > 1) throw new JSExn("traps must take either one argument (write) or no arguments (read)");
- boolean isRead = f.numFormalArgs == 0;
- for(Trap t = getTrap(key); t != null; t = t.next) if (t.f == f) return;
- putTrap(key, new Trap(this, key, f, (Trap)getTrap(key)));
- }
-
- /** deletes a trap, if present */
- // FIXME: This shouldn't be public, it is needed for a hack in Template.java
- public void delTrap(JS key, JSFunction f) throws JSExn {
- Trap t = (Trap)getTrap(key);
- if (t == null) return;
- if (t.f == f) { putTrap(t.target, t.next); return; }
- for(; t.next != null; t = t.next) if (t.next.f == f) { t.next = t.next.next; return; }
- }
-
-
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.util.*;
-
-/** A JavaScript JSArray */
-public class JSArray extends JS.O {
- private static final Object NULL = new Object();
- private final BalancedTree bt = new BalancedTree();
-
- public JSArray() { }
- public JSArray(int size) { setSize(size); }
-
- /*private static int intVal(Object o) {
- if (o instanceof Number) {
- int intVal = ((Number)o).intValue();
- if (intVal == ((Number)o).doubleValue()) return intVal;
- return Integer.MIN_VALUE;
- }
- if (!(o instanceof String)) return Integer.MIN_VALUE;
- String s = (String)o;
- for(int i=0; i<s.length(); i++) if (s.charAt(i) < '0' || s.charAt(i) > '9') return Integer.MIN_VALUE;
- return Integer.parseInt(s);
- }*/
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- //#jswitch(method)
- case "pop": {
- int oldSize = size();
- if(oldSize == 0) return null;
- return removeElementAt(oldSize-1);
- }
- case "reverse": return reverse();
- case "toString": return join(",");
- case "shift":
- if(length() == 0) return null;
- return removeElementAt(0);
- case "join":
- return join(nargs == 0 ? "," : JS.toString(a0));
- case "sort":
- return sort(nargs < 1 ? null : a0);
- case "slice":
- int start = toInt(nargs < 1 ? null : a0);
- int end = nargs < 2 ? length() : toInt(a1);
- return slice(start, end);
- case "push": {
- int oldSize = size();
- for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],oldSize+i);
- return N(oldSize + nargs);
- }
- case "unshift":
- for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],i);
- return N(size());
- case "splice":
- JSArray array = new JSArray();
- for(int i=0; i<nargs; i++) array.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
- return splice(array);
- //#end
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
-
- public JS get(JS key) throws JSExn {
- if (isInt(key)) {
- int i = toInt(key);
- if (i < 0 || i >= size()) return null;
- return elementAt(i);
- }
- //#jswitch(key)
- case "pop": return METHOD;
- case "reverse": return METHOD;
- case "toString": return METHOD;
- case "shift": return METHOD;
- case "join": return METHOD;
- case "sort": return METHOD;
- case "slice": return METHOD;
- case "push": return METHOD;
- case "unshift": return METHOD;
- case "splice": return METHOD;
- case "length": return N(size());
- //#end
- return super.get(key);
- }
-
- public void put(JS key, JS val) throws JSExn {
- if (isInt(key)) {
- int i = toInt(key);
- int oldSize = size();
- if(i < oldSize) {
- setElementAt(val,i);
- } else {
- if(i > oldSize) setSize(i);
- insertElementAt(val,i);
- }
- return;
- }
- if(isString(key)) {
- if (JS.toString(key).equals("length")) {
- setSize(JS.toInt(val));
- return;
- }
- }
- super.put(key,val);
- }
-
- public Enumeration keys() throws JSExn {
- return new Enumeration(super.keys()) {
- private int n = 0;
- public boolean _hasMoreElements() { return n < size(); }
- public JS _nextElement() {
- return n >= size() ? null : JS.N(n++);
- }
- };
- }
-
- public final void setSize(int newSize) {
- // FEATURE: This could be done a lot more efficiently in BalancedTree
- int oldSize = size();
- for(int i=oldSize;i<newSize;i++) insertElementAt(null,i);
- for(int i=oldSize-1;i>=newSize;i--) removeElementAt(i);
- }
-
- public final int length() { return size(); }
- public final JS elementAt(int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- Object o = bt.getNode(i);
- return o == NULL ? (JS)null : (JS)o;
- }
- public final void addElement(JS o) {
- bt.insertNode(size(),o==null ? NULL : o);
- }
- public final void setElementAt(JS o, int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- bt.replaceNode(i,o==null ? NULL : o);
- }
- public final void insertElementAt(JS o, int i) {
- if(i < 0 || i > size()) throw new ArrayIndexOutOfBoundsException(i);
- bt.insertNode(i,o==null ? NULL : o);
- }
- public final JS removeElementAt(int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- Object o = bt.deleteNode(i);
- return o == NULL ? (JS)null : (JS)o;
- }
-
- public final int size() { return bt.treeSize(); }
-
- private JS join(String sep) throws JSExn {
- int length = size();
- if(length == 0) return JS.S("");
- StringBuffer sb = new StringBuffer(64);
- int i=0;
- while(true) {
- JS o = elementAt(i);
- if(o != null) sb.append(JS.toString(o));
- if(++i == length) break;
- sb.append(sep);
- }
- return JS.S(sb.toString());
- }
-
- // FEATURE: Implement this more efficiently
- private JS reverse() {
- int size = size();
- if(size < 2) return this;
- Vec vec = toVec();
- bt.clear();
- for(int i=size-1,j=0;i>=0;i--,j++) insertElementAt((JS)vec.elementAt(i),j);
- return this;
- }
-
- private JS slice(int start, int end) {
- int length = length();
- if(start < 0) start = length+start;
- if(end < 0) end = length+end;
- if(start < 0) start = 0;
- if(end < 0) end = 0;
- if(start > length) start = length;
- if(end > length) end = length;
- JSArray a = new JSArray(end-start);
- for(int i=0;i<end-start;i++)
- a.setElementAt(elementAt(start+i),i);
- return a;
- }
-
- private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
- public int compare(Object a, Object b) {
- try {
- return JS.toString((JS)a).compareTo(JS.toString((JS)b));
- } catch(JSExn e) { throw new JSExn.Wrapper(e); }
- }
- };
- private JS sort(JS tmp) throws JSExn {
- Vec vec = toVec();
- try {
- if(tmp instanceof JS) {
- final JS jsFunc = (JS) tmp;
- vec.sort(new Vec.CompareFunc() {
- public int compare(Object a, Object b) {
- try {
- return JS.toInt(jsFunc.call((JS)a, (JS)b, null, null, 2));
- } catch(JSExn e) { throw new JSExn.Wrapper(e); }
- }
- });
- } else {
- vec.sort(defaultSort);
- }
- } catch(JSExn.Wrapper e) {
- throw e.refill();
- }
- setFromVec(vec);
- return this;
- }
-
- private JS splice(JSArray args) throws JSExn {
- int oldLength = length();
- int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
- int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
- int newCount = args.length() - 2;
- if(newCount < 0) newCount = 0;
- if(start < 0) start = oldLength+start;
- if(start < 0) start = 0;
- if(start > oldLength) start = oldLength;
- if(deleteCount < 0) deleteCount = 0;
- if(deleteCount > oldLength-start) deleteCount = oldLength-start;
- int newLength = oldLength - deleteCount + newCount;
- int lengthChange = newLength - oldLength;
- JSArray ret = new JSArray(deleteCount);
- for(int i=0;i<deleteCount;i++)
- ret.setElementAt(elementAt(start+i),i);
- if(lengthChange > 0) {
- setSize(newLength);
- for(int i=newLength-1;i>=start+newCount;i--)
- setElementAt(elementAt(i-lengthChange),i);
- } else if(lengthChange < 0) {
- for(int i=start+newCount;i<newLength;i++)
- setElementAt(elementAt(i-lengthChange),i);
- setSize(newLength);
- }
- for(int i=0;i<newCount;i++)
- setElementAt(args.elementAt(i+2),start+i);
- return ret;
- }
-
- protected Vec toVec() {
- int count = size();
- Vec vec = new Vec();
- vec.setSize(count);
- for(int i=0;i<count;i++) {
- Object o = bt.getNode(i);
- vec.setElementAt(o == NULL ? null : o,i);
- }
- return vec;
- }
-
- protected void setFromVec(Vec vec) {
- int count = vec.size();
- bt.clear();
- for(int i=0;i<count;i++) {
- Object o = vec.elementAt(i);
- bt.insertNode(i,o==null ? NULL : o);
- }
- }
-
- String coerceToString() throws JSExn { return JS.toString(join(",")); }
-}
+++ /dev/null
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * The contents of this file are subject to the Netscape Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/NPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1997-1999 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- * Norris Boyd
- * Mike McCabe
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License (the "GPL"), in which case the
- * provisions of the GPL are applicable instead of those above.
- * If you wish to allow use of your version of this file only
- * under the terms of the GPL and not to allow others to use your
- * version of this file under the NPL, indicate your decision by
- * deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL. If you do not delete
- * the provisions above, a recipient may use your version of this
- * file under either the NPL or the GPL.
- */
-
-package org.ibex.js;
-
-import java.text.DateFormat;
-
-/**
- * This class implements the Date native object.
- * See ECMA 15.9.
- * @author Mike McCabe
- * @author Adam Megacz (many modifications
- */
-public class JSDate extends JS {
-
- public JSDate() {
- if (thisTimeZone == null) {
- // j.u.TimeZone is synchronized, so setting class statics from it
- // should be OK.
- thisTimeZone = java.util.TimeZone.getDefault();
- LocalTZA = thisTimeZone.getRawOffset();
- }
- }
-
- String coerceToString() { return date_format(date, FORMATSPEC_FULL); }
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- switch(nargs) {
- case 0: {
- //#jswitch(method)
- case "toString": return JS.S(date_format(date, FORMATSPEC_FULL));
- case "toTimeString": return JS.S(date_format(date, FORMATSPEC_TIME));
- case "toDateString": return JS.S(date_format(date, FORMATSPEC_DATE));
- case "toLocaleString": return JS.S(toLocaleString(date));
- case "toLocaleTimeString": return JS.S(toLocaleTimeString(date));
- case "toLocaleDateString": return JS.S(toLocaleDateString(date));
- case "toUTCString": return JS.S(toUTCString(date));
- case "valueOf": return N(this.date);
- case "getTime": return N(this.date);
- case "getYear": return N(getYear(date));
- case "getFullYear": return N(YearFromTime(LocalTime(date)));
- case "getUTCFullYear": return N(YearFromTime(date));
- case "getMonth": return N(MonthFromTime(LocalTime(date)));
- case "getUTCMonth": return N(MonthFromTime(date));
- case "getDate": return N(DateFromTime(LocalTime(date)));
- case "getUTCDate": return N(DateFromTime(date));
- case "getDay": return N(WeekDay(LocalTime(date)));
- case "getUTCDay": return N(WeekDay(date));
- case "getHours": return N(HourFromTime(LocalTime(date)));
- case "getUTCHours": return N(HourFromTime(date));
- case "getMinutes": return N(MinFromTime(LocalTime(date)));
- case "getUTCMinutes": return N(MinFromTime(date));
- case "getSeconds": return N(SecFromTime(LocalTime(date)));
- case "getUTCSeconds": return N(SecFromTime(date));
- case "getMilliseconds": return N(msFromTime(LocalTime(date)));
- case "getUTCMilliseconds": return N(msFromTime(date));
- case "getTimezoneOffset": return N(getTimezoneOffset(date));
- //#end
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
- case 1: {
- //#jswitch(method)
- case "setTime": return N(this.setTime(toDouble(a0)));
- case "setYear": return N(this.setYear(toDouble(a0)));
- //#end
- // fall through
- }
- default: {
- JS[] args = new JS[nargs];
- for(int i=0; i<nargs; i++) args[i] = i==0 ? a0 : i==1 ? a1 : i==2 ? a2 : rest[i-3];
- //#jswitch(method)
- case "setMilliseconds": return N(this.makeTime(args, 1, true));
- case "setUTCMilliseconds": return N(this.makeTime(args, 1, false));
- case "setSeconds": return N(this.makeTime(args, 2, true));
- case "setUTCSeconds": return N(this.makeTime(args, 2, false));
- case "setMinutes": return N(this.makeTime(args, 3, true));
- case "setUTCMinutes": return N(this.makeTime(args, 3, false));
- case "setHours": return N(this.makeTime(args, 4, true));
- case "setUTCHours": return N(this.makeTime(args, 4, false));
- case "setDate": return N(this.makeDate(args, 1, true));
- case "setUTCDate": return N(this.makeDate(args, 1, false));
- case "setMonth": return N(this.makeDate(args, 2, true));
- case "setUTCMonth": return N(this.makeDate(args, 2, false));
- case "setFullYear": return N(this.makeDate(args, 3, true));
- case "setUTCFullYear": return N(this.makeDate(args, 3, false));
- //#end
- }
- }
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
-
- public JS get(JS key) throws JSExn {
- //#jswitch(key)
- case "toString": return METHOD;
- case "toTimeString": return METHOD;
- case "toDateString": return METHOD;
- case "toLocaleString": return METHOD;
- case "toLocaleTimeString": return METHOD;
- case "toLocaleDateString": return METHOD;
- case "toUTCString": return METHOD;
- case "valueOf": return METHOD;
- case "getTime": return METHOD;
- case "getYear": return METHOD;
- case "getFullYear": return METHOD;
- case "getUTCFullYear": return METHOD;
- case "getMonth": return METHOD;
- case "getUTCMonth": return METHOD;
- case "getDate": return METHOD;
- case "getUTCDate": return METHOD;
- case "getDay": return METHOD;
- case "getUTCDay": return METHOD;
- case "getHours": return METHOD;
- case "getUTCHours": return METHOD;
- case "getMinutes": return METHOD;
- case "getUTCMinutes": return METHOD;
- case "getSeconds": return METHOD;
- case "getUTCSeconds": return METHOD;
- case "getMilliseconds": return METHOD;
- case "getUTCMilliseconds": return METHOD;
- case "getTimezoneOffset": return METHOD;
- case "setTime": return METHOD;
- case "setYear": return METHOD;
- case "setMilliseconds": return METHOD;
- case "setUTCMilliseconds": return METHOD;
- case "setSeconds": return METHOD;
- case "setUTCSeconds": return METHOD;
- case "setMinutes": return METHOD;
- case "setUTCMinutes": return METHOD;
- case "setHours": return METHOD;
- case "setUTCHours": return METHOD;
- case "setDate": return METHOD;
- case "setUTCDate": return METHOD;
- case "setMonth": return METHOD;
- case "setUTCMonth": return METHOD;
- case "setFullYear": return METHOD;
- case "setUTCFullYear": return METHOD;
- //#end
- return super.get(key);
- }
-
- /* ECMA helper functions */
-
- private static final double HalfTimeDomain = 8.64e15;
- private static final double HoursPerDay = 24.0;
- private static final double MinutesPerHour = 60.0;
- private static final double SecondsPerMinute = 60.0;
- private static final double msPerSecond = 1000.0;
- private static final double MinutesPerDay = (HoursPerDay * MinutesPerHour);
- private static final double SecondsPerDay = (MinutesPerDay * SecondsPerMinute);
- private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute);
- private static final double msPerDay = (SecondsPerDay * msPerSecond);
- private static final double msPerHour = (SecondsPerHour * msPerSecond);
- private static final double msPerMinute = (SecondsPerMinute * msPerSecond);
-
- private static double Day(double t) {
- return java.lang.Math.floor(t / msPerDay);
- }
-
- private static double TimeWithinDay(double t) {
- double result;
- result = t % msPerDay;
- if (result < 0)
- result += msPerDay;
- return result;
- }
-
- private static int DaysInYear(int y) {
- if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
- return 366;
- else
- return 365;
- }
-
-
- /* math here has to be f.p, because we need
- * floor((1968 - 1969) / 4) == -1
- */
- private static double DayFromYear(double y) {
- return ((365 * ((y)-1970) + java.lang.Math.floor(((y)-1969)/4.0)
- - java.lang.Math.floor(((y)-1901)/100.0) + java.lang.Math.floor(((y)-1601)/400.0)));
- }
-
- private static double TimeFromYear(double y) {
- return DayFromYear(y) * msPerDay;
- }
-
- private static int YearFromTime(double t) {
- int lo = (int) java.lang.Math.floor((t / msPerDay) / 366) + 1970;
- int hi = (int) java.lang.Math.floor((t / msPerDay) / 365) + 1970;
- int mid;
-
- /* above doesn't work for negative dates... */
- if (hi < lo) {
- int temp = lo;
- lo = hi;
- hi = temp;
- }
-
- /* Use a simple binary search algorithm to find the right
- year. This seems like brute force... but the computation
- of hi and lo years above lands within one year of the
- correct answer for years within a thousand years of
- 1970; the loop below only requires six iterations
- for year 270000. */
- while (hi > lo) {
- mid = (hi + lo) / 2;
- if (TimeFromYear(mid) > t) {
- hi = mid - 1;
- } else {
- if (TimeFromYear(mid) <= t) {
- int temp = mid + 1;
- if (TimeFromYear(temp) > t) {
- return mid;
- }
- lo = mid + 1;
- }
- }
- }
- return lo;
- }
-
- private static boolean InLeapYear(double t) {
- return DaysInYear(YearFromTime(t)) == 366;
- }
-
- private static int DayWithinYear(double t) {
- int year = YearFromTime(t);
- return (int) (Day(t) - DayFromYear(year));
- }
- /*
- * The following array contains the day of year for the first day of
- * each month, where index 0 is January, and day 0 is January 1.
- */
-
- private static double DayFromMonth(int m, boolean leap) {
- int day = m * 30;
-
- if (m >= 7) { day += m / 2 - 1; }
- else if (m >= 2) { day += (m - 1) / 2 - 1; }
- else { day += m; }
-
- if (leap && m >= 2) { ++day; }
-
- return day;
- }
-
- private static int MonthFromTime(double t) {
- int d, step;
-
- d = DayWithinYear(t);
-
- if (d < (step = 31))
- return 0;
-
- // Originally coded as step += (InLeapYear(t) ? 29 : 28);
- // but some jits always returned 28!
- if (InLeapYear(t))
- step += 29;
- else
- step += 28;
-
- if (d < step)
- return 1;
- if (d < (step += 31))
- return 2;
- if (d < (step += 30))
- return 3;
- if (d < (step += 31))
- return 4;
- if (d < (step += 30))
- return 5;
- if (d < (step += 31))
- return 6;
- if (d < (step += 31))
- return 7;
- if (d < (step += 30))
- return 8;
- if (d < (step += 31))
- return 9;
- if (d < (step += 30))
- return 10;
- return 11;
- }
-
- private static int DateFromTime(double t) {
- int d, step, next;
-
- d = DayWithinYear(t);
- if (d <= (next = 30))
- return d + 1;
- step = next;
-
- // Originally coded as next += (InLeapYear(t) ? 29 : 28);
- // but some jits always returned 28!
- if (InLeapYear(t))
- next += 29;
- else
- next += 28;
-
- if (d <= next)
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
-
- return d - step;
- }
-
- private static int WeekDay(double t) {
- double result;
- result = Day(t) + 4;
- result = result % 7;
- if (result < 0)
- result += 7;
- return (int) result;
- }
-
- private static double Now() {
- return (double) System.currentTimeMillis();
- }
-
- /* Should be possible to determine the need for this dynamically
- * if we go with the workaround... I'm not using it now, because I
- * can't think of any clean way to make toLocaleString() and the
- * time zone (comment) in toString match the generated string
- * values. Currently it's wrong-but-consistent in all but the
- * most recent betas of the JRE - seems to work in 1.1.7.
- */
- private final static boolean TZO_WORKAROUND = false;
- private static double DaylightSavingTA(double t) {
- if (!TZO_WORKAROUND) {
- java.util.Date date = new java.util.Date((long) t);
- if (thisTimeZone.inDaylightTime(date))
- return msPerHour;
- else
- return 0;
- } else {
- /* Use getOffset if inDaylightTime() is broken, because it
- * seems to work acceptably. We don't switch over to it
- * entirely, because it requires (expensive) exploded date arguments,
- * and the api makes it impossible to handle dst
- * changeovers cleanly.
- */
-
- // Hardcode the assumption that the changeover always
- // happens at 2:00 AM:
- t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
-
- int year = YearFromTime(t);
- double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,
- year,
- MonthFromTime(t),
- DateFromTime(t),
- WeekDay(t),
- (int)TimeWithinDay(t));
-
- if ((offset - LocalTZA) != 0)
- return msPerHour;
- else
- return 0;
- // return offset - LocalTZA;
- }
- }
-
- private static double LocalTime(double t) {
- return t + LocalTZA + DaylightSavingTA(t);
- }
-
- public static double internalUTC(double t) {
- return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
- }
-
- private static int HourFromTime(double t) {
- double result;
- result = java.lang.Math.floor(t / msPerHour) % HoursPerDay;
- if (result < 0)
- result += HoursPerDay;
- return (int) result;
- }
-
- private static int MinFromTime(double t) {
- double result;
- result = java.lang.Math.floor(t / msPerMinute) % MinutesPerHour;
- if (result < 0)
- result += MinutesPerHour;
- return (int) result;
- }
-
- private static int SecFromTime(double t) {
- double result;
- result = java.lang.Math.floor(t / msPerSecond) % SecondsPerMinute;
- if (result < 0)
- result += SecondsPerMinute;
- return (int) result;
- }
-
- private static int msFromTime(double t) {
- double result;
- result = t % msPerSecond;
- if (result < 0)
- result += msPerSecond;
- return (int) result;
- }
-
- private static double MakeTime(double hour, double min,
- double sec, double ms)
- {
- return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
- * msPerSecond + ms;
- }
-
- private static double MakeDay(double year, double month, double date) {
- double result;
- boolean leap;
- double yearday;
- double monthday;
-
- year += java.lang.Math.floor(month / 12);
-
- month = month % 12;
- if (month < 0)
- month += 12;
-
- leap = (DaysInYear((int) year) == 366);
-
- yearday = java.lang.Math.floor(TimeFromYear(year) / msPerDay);
- monthday = DayFromMonth((int) month, leap);
-
- result = yearday
- + monthday
- + date - 1;
- return result;
- }
-
- private static double MakeDate(double day, double time) {
- return day * msPerDay + time;
- }
-
- private static double TimeClip(double d) {
- if (d != d ||
- d == Double.POSITIVE_INFINITY ||
- d == Double.NEGATIVE_INFINITY ||
- java.lang.Math.abs(d) > HalfTimeDomain)
- {
- return Double.NaN;
- }
- if (d > 0.0)
- return java.lang.Math.floor(d + 0.);
- else
- return java.lang.Math.ceil(d + 0.);
- }
-
- /* end of ECMA helper functions */
-
- /* find UTC time from given date... no 1900 correction! */
- public static double date_msecFromDate(double year, double mon,
- double mday, double hour,
- double min, double sec,
- double msec)
- {
- double day;
- double time;
- double result;
-
- day = MakeDay(year, mon, mday);
- time = MakeTime(hour, min, sec, msec);
- result = MakeDate(day, time);
- return result;
- }
-
-
- private static final int MAXARGS = 7;
- private static double jsStaticJSFunction_UTC(JS[] args) throws JSExn {
- double array[] = new double[MAXARGS];
- int loop;
- double d;
-
- for (loop = 0; loop < MAXARGS; loop++) {
- if (loop < args.length) {
- d = _toNumber(args[loop]);
- if (d != d || Double.isInfinite(d)) {
- return Double.NaN;
- }
- array[loop] = toDouble(args[loop]);
- } else {
- array[loop] = 0;
- }
- }
-
- /* adjust 2-digit years into the 20th century */
- if (array[0] >= 0 && array[0] <= 99)
- array[0] += 1900;
-
- /* if we got a 0 for 'date' (which is out of range)
- * pretend it's a 1. (So Date.UTC(1972, 5) works) */
- if (array[2] < 1)
- array[2] = 1;
-
- d = date_msecFromDate(array[0], array[1], array[2],
- array[3], array[4], array[5], array[6]);
- d = TimeClip(d);
- return d;
- // return N(d);
- }
-
- /*
- * Use ported code from jsdate.c rather than the locale-specific
- * date-parsing code from Java, to keep js and rhino consistent.
- * Is this the right strategy?
- */
-
- /* for use by date_parse */
-
- /* replace this with byte arrays? Cheaper? */
- private static String wtb[] = {
- "am", "pm",
- "monday", "tuesday", "wednesday", "thursday", "friday",
- "saturday", "sunday",
- "january", "february", "march", "april", "may", "june",
- "july", "august", "september", "october", "november", "december",
- "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
- "mst", "mdt", "pst", "pdt"
- /* time zone table needs to be expanded */
- };
-
- private static int ttb[] = {
- -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
- 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 10000 + 0, 10000 + 0, 10000 + 0, /* UT/UTC */
- 10000 + 5 * 60, 10000 + 4 * 60, /* EDT */
- 10000 + 6 * 60, 10000 + 5 * 60,
- 10000 + 7 * 60, 10000 + 6 * 60,
- 10000 + 8 * 60, 10000 + 7 * 60
- };
-
- /* helper for date_parse */
- private static boolean date_regionMatches(String s1, int s1off,
- String s2, int s2off,
- int count)
- {
- boolean result = false;
- /* return true if matches, otherwise, false */
- int s1len = s1.length();
- int s2len = s2.length();
-
- while (count > 0 && s1off < s1len && s2off < s2len) {
- if (Character.toLowerCase(s1.charAt(s1off)) !=
- Character.toLowerCase(s2.charAt(s2off)))
- break;
- s1off++;
- s2off++;
- count--;
- }
-
- if (count == 0) {
- result = true;
- }
- return result;
- }
-
- private static double date_parseString(String s) {
- double msec;
-
- int year = -1;
- int mon = -1;
- int mday = -1;
- int hour = -1;
- int min = -1;
- int sec = -1;
- char c = 0;
- char si = 0;
- int i = 0;
- int n = -1;
- double tzoffset = -1;
- char prevc = 0;
- int limit = 0;
- boolean seenplusminus = false;
-
- if (s == null) // ??? Will s be null?
- return Double.NaN;
- limit = s.length();
- while (i < limit) {
- c = s.charAt(i);
- i++;
- if (c <= ' ' || c == ',' || c == '-') {
- if (i < limit) {
- si = s.charAt(i);
- if (c == '-' && '0' <= si && si <= '9') {
- prevc = c;
- }
- }
- continue;
- }
- if (c == '(') { /* comments) */
- int depth = 1;
- while (i < limit) {
- c = s.charAt(i);
- i++;
- if (c == '(')
- depth++;
- else if (c == ')')
- if (--depth <= 0)
- break;
- }
- continue;
- }
- if ('0' <= c && c <= '9') {
- n = c - '0';
- while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
- n = n * 10 + c - '0';
- i++;
- }
-
- /* allow TZA before the year, so
- * 'Wed Nov 05 21:49:11 GMT-0800 1997'
- * works */
-
- /* uses of seenplusminus allow : in TZA, so Java
- * no-timezone style of GMT+4:30 works
- */
- if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
- /* make ':' case below change tzoffset */
- seenplusminus = true;
-
- /* offset */
- if (n < 24)
- n = n * 60; /* EG. "GMT-3" */
- else
- n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
- if (prevc == '+') /* plus means east of GMT */
- n = -n;
- if (tzoffset != 0 && tzoffset != -1)
- return Double.NaN;
- tzoffset = n;
- } else if (n >= 70 ||
- (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
- if (year >= 0)
- return Double.NaN;
- else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
- year = n < 100 ? n + 1900 : n;
- else
- return Double.NaN;
- } else if (c == ':') {
- if (hour < 0)
- hour = /*byte*/ n;
- else if (min < 0)
- min = /*byte*/ n;
- else
- return Double.NaN;
- } else if (c == '/') {
- if (mon < 0)
- mon = /*byte*/ n-1;
- else if (mday < 0)
- mday = /*byte*/ n;
- else
- return Double.NaN;
- } else if (i < limit && c != ',' && c > ' ' && c != '-') {
- return Double.NaN;
- } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
- if (tzoffset < 0)
- tzoffset -= n;
- else
- tzoffset += n;
- } else if (hour >= 0 && min < 0) {
- min = /*byte*/ n;
- } else if (min >= 0 && sec < 0) {
- sec = /*byte*/ n;
- } else if (mday < 0) {
- mday = /*byte*/ n;
- } else {
- return Double.NaN;
- }
- prevc = 0;
- } else if (c == '/' || c == ':' || c == '+' || c == '-') {
- prevc = c;
- } else {
- int st = i - 1;
- int k;
- while (i < limit) {
- c = s.charAt(i);
- if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
- break;
- i++;
- }
- if (i <= st + 1)
- return Double.NaN;
- for (k = wtb.length; --k >= 0;)
- if (date_regionMatches(wtb[k], 0, s, st, i-st)) {
- int action = ttb[k];
- if (action != 0) {
- if (action < 0) {
- /*
- * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
- * 12:30, instead of blindly adding 12 if PM.
- */
- if (hour > 12 || hour < 0) {
- return Double.NaN;
- } else {
- if (action == -1 && hour == 12) { // am
- hour = 0;
- } else if (action == -2 && hour != 12) {// pm
- hour += 12;
- }
- }
- } else if (action <= 13) { /* month! */
- if (mon < 0) {
- mon = /*byte*/ (action - 2);
- } else {
- return Double.NaN;
- }
- } else {
- tzoffset = action - 10000;
- }
- }
- break;
- }
- if (k < 0)
- return Double.NaN;
- prevc = 0;
- }
- }
- if (year < 0 || mon < 0 || mday < 0)
- return Double.NaN;
- if (sec < 0)
- sec = 0;
- if (min < 0)
- min = 0;
- if (hour < 0)
- hour = 0;
- if (tzoffset == -1) { /* no time zone specified, have to use local */
- double time;
- time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
- return internalUTC(time);
- }
-
- msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
- msec += tzoffset * msPerMinute;
- return msec;
- }
-
- private static double jsStaticJSFunction_parse(String s) {
- return date_parseString(s);
- }
-
- private static final int FORMATSPEC_FULL = 0;
- private static final int FORMATSPEC_DATE = 1;
- private static final int FORMATSPEC_TIME = 2;
-
- private static String date_format(double t, int format) {
- if (t != t)
- return NaN_date_str;
-
- StringBuffer result = new StringBuffer(60);
- double local = LocalTime(t);
-
- /* offset from GMT in minutes. The offset includes daylight savings,
- if it applies. */
- int minutes = (int) java.lang.Math.floor((LocalTZA + DaylightSavingTA(t))
- / msPerMinute);
- /* map 510 minutes to 0830 hours */
- int offset = (minutes / 60) * 100 + minutes % 60;
-
- String dateStr = Integer.toString(DateFromTime(local));
- String hourStr = Integer.toString(HourFromTime(local));
- String minStr = Integer.toString(MinFromTime(local));
- String secStr = Integer.toString(SecFromTime(local));
- String offsetStr = Integer.toString(offset > 0 ? offset : -offset);
- int year = YearFromTime(local);
- String yearStr = Integer.toString(year > 0 ? year : -year);
-
- /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
- /* Tue Oct 31 2000 */
- /* 09:41:40 GMT-0800 (PST) */
-
- if (format != FORMATSPEC_TIME) {
- result.append(days[WeekDay(local)]);
- result.append(' ');
- result.append(months[MonthFromTime(local)]);
- if (dateStr.length() == 1)
- result.append(" 0");
- else
- result.append(' ');
- result.append(dateStr);
- result.append(' ');
- }
-
- if (format != FORMATSPEC_DATE) {
- if (hourStr.length() == 1)
- result.append('0');
- result.append(hourStr);
- if (minStr.length() == 1)
- result.append(":0");
- else
- result.append(':');
- result.append(minStr);
- if (secStr.length() == 1)
- result.append(":0");
- else
- result.append(':');
- result.append(secStr);
- if (offset > 0)
- result.append(" GMT+");
- else
- result.append(" GMT-");
- for (int i = offsetStr.length(); i < 4; i++)
- result.append('0');
- result.append(offsetStr);
-
- if (timeZoneFormatter == null)
- timeZoneFormatter = new java.text.SimpleDateFormat("zzz");
-
- if (timeZoneFormatter != null) {
- result.append(" (");
- java.util.Date date = new java.util.Date((long) t);
- result.append(timeZoneFormatter.format(date));
- result.append(')');
- }
- if (format != FORMATSPEC_TIME)
- result.append(' ');
- }
-
- if (format != FORMATSPEC_TIME) {
- if (year < 0)
- result.append('-');
- for (int i = yearStr.length(); i < 4; i++)
- result.append('0');
- result.append(yearStr);
- }
-
- return result.toString();
- }
-
- private static double _toNumber(JS o) throws JSExn { return JS.toDouble(o); }
- private static double _toNumber(JS[] o, int index) throws JSExn { return JS.toDouble(o[index]); }
- private static double toDouble(double d) { return d; }
-
- public JSDate(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
-
- JSDate obj = this;
- switch (nargs) {
- case 0: {
- obj.date = Now();
- return;
- }
- case 1: {
- double date;
- if(isString(a0))
- date = date_parseString(JS.toString(a0));
- else
- date = _toNumber(a0);
- obj.date = TimeClip(date);
- return;
- }
- default: {
- // multiple arguments; year, month, day etc.
- double array[] = new double[MAXARGS];
- array[0] = toDouble(a0);
- array[1] = toDouble(a1);
- if (nargs >= 2) array[2] = toDouble(a2);
- for(int i=0; i<nargs; i++) {
- double d = _toNumber(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
- if (d != d || Double.isInfinite(d)) {
- obj.date = Double.NaN;
- return;
- }
- array[i] = d;
- }
-
- /* adjust 2-digit years into the 20th century */
- if (array[0] >= 0 && array[0] <= 99)
- array[0] += 1900;
-
- /* if we got a 0 for 'date' (which is out of range)
- * pretend it's a 1 */
- if (array[2] < 1)
- array[2] = 1;
-
- double day = MakeDay(array[0], array[1], array[2]);
- double time = MakeTime(array[3], array[4], array[5], array[6]);
- time = MakeDate(day, time);
- time = internalUTC(time);
- obj.date = TimeClip(time);
-
- return;
- }
- }
- }
-
- /* constants for toString, toUTCString */
- private static String NaN_date_str = "Invalid Date";
-
- private static String[] days = {
- "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
- };
-
- private static String[] months = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- private static String toLocale_helper(double t,
- java.text.DateFormat formatter)
- {
- if (t != t)
- return NaN_date_str;
-
- java.util.Date tempdate = new java.util.Date((long) t);
- return formatter.format(tempdate);
- }
-
- private static String toLocaleString(double date) {
- if (localeDateTimeFormatter == null)
- localeDateTimeFormatter =
- DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
-
- return toLocale_helper(date, localeDateTimeFormatter);
- }
-
- private static String toLocaleTimeString(double date) {
- if (localeTimeFormatter == null)
- localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG);
-
- return toLocale_helper(date, localeTimeFormatter);
- }
-
- private static String toLocaleDateString(double date) {
- if (localeDateFormatter == null)
- localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG);
-
- return toLocale_helper(date, localeDateFormatter);
- }
-
- private static String toUTCString(double date) {
- StringBuffer result = new StringBuffer(60);
-
- String dateStr = Integer.toString(DateFromTime(date));
- String hourStr = Integer.toString(HourFromTime(date));
- String minStr = Integer.toString(MinFromTime(date));
- String secStr = Integer.toString(SecFromTime(date));
- int year = YearFromTime(date);
- String yearStr = Integer.toString(year > 0 ? year : -year);
-
- result.append(days[WeekDay(date)]);
- result.append(", ");
- if (dateStr.length() == 1)
- result.append('0');
- result.append(dateStr);
- result.append(' ');
- result.append(months[MonthFromTime(date)]);
- if (year < 0)
- result.append(" -");
- else
- result.append(' ');
- int i;
- for (i = yearStr.length(); i < 4; i++)
- result.append('0');
- result.append(yearStr);
-
- if (hourStr.length() == 1)
- result.append(" 0");
- else
- result.append(' ');
- result.append(hourStr);
- if (minStr.length() == 1)
- result.append(":0");
- else
- result.append(':');
- result.append(minStr);
- if (secStr.length() == 1)
- result.append(":0");
- else
- result.append(':');
- result.append(secStr);
-
- result.append(" GMT");
- return result.toString();
- }
-
- private static double getYear(double date) {
- int result = YearFromTime(LocalTime(date));
- result -= 1900;
- return result;
- }
-
- private static double getTimezoneOffset(double date) {
- return (date - LocalTime(date)) / msPerMinute;
- }
-
- public double setTime(double time) {
- this.date = TimeClip(time);
- return this.date;
- }
-
- private double makeTime(JS[] args, int maxargs, boolean local) throws JSExn {
- int i;
- double conv[] = new double[4];
- double hour, min, sec, msec;
- double lorutime; /* Local or UTC version of date */
-
- double time;
- double result;
-
- double date = this.date;
-
- /* just return NaN if the date is already NaN */
- if (date != date)
- return date;
-
- /* Satisfy the ECMA rule that if a function is called with
- * fewer arguments than the specified formal arguments, the
- * remaining arguments are set to undefined. Seems like all
- * the Date.setWhatever functions in ECMA are only varargs
- * beyond the first argument; this should be set to undefined
- * if it's not given. This means that "d = new Date();
- * d.setMilliseconds()" returns NaN. Blech.
- */
- if (args.length == 0)
- args = new JS[] { null };
-
- for (i = 0; i < args.length && i < maxargs; i++) {
- conv[i] = _toNumber(args[i]);
-
- // limit checks that happen in MakeTime in ECMA.
- if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
- this.date = Double.NaN;
- return this.date;
- }
- conv[i] = toDouble(conv[i]);
- }
-
- if (local)
- lorutime = LocalTime(date);
- else
- lorutime = date;
-
- i = 0;
- int stop = args.length;
-
- if (maxargs >= 4 && i < stop)
- hour = conv[i++];
- else
- hour = HourFromTime(lorutime);
-
- if (maxargs >= 3 && i < stop)
- min = conv[i++];
- else
- min = MinFromTime(lorutime);
-
- if (maxargs >= 2 && i < stop)
- sec = conv[i++];
- else
- sec = SecFromTime(lorutime);
-
- if (maxargs >= 1 && i < stop)
- msec = conv[i++];
- else
- msec = msFromTime(lorutime);
-
- time = MakeTime(hour, min, sec, msec);
- result = MakeDate(Day(lorutime), time);
-
- if (local)
- result = internalUTC(result);
- date = TimeClip(result);
-
- this.date = date;
- return date;
- }
-
- private double setHours(JS[] args) throws JSExn {
- return makeTime(args, 4, true);
- }
-
- private double setUTCHours(JS[] args) throws JSExn {
- return makeTime(args, 4, false);
- }
-
- private double makeDate(JS[] args, int maxargs, boolean local) throws JSExn {
- int i;
- double conv[] = new double[3];
- double year, month, day;
- double lorutime; /* local or UTC version of date */
- double result;
-
- double date = this.date;
-
- /* See arg padding comment in makeTime.*/
- if (args.length == 0)
- args = new JS[] { null };
-
- for (i = 0; i < args.length && i < maxargs; i++) {
- conv[i] = _toNumber(args[i]);
-
- // limit checks that happen in MakeDate in ECMA.
- if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
- this.date = Double.NaN;
- return this.date;
- }
- conv[i] = toDouble(conv[i]);
- }
-
- /* return NaN if date is NaN and we're not setting the year,
- * If we are, use 0 as the time. */
- if (date != date) {
- if (args.length < 3) {
- return Double.NaN;
- } else {
- lorutime = 0;
- }
- } else {
- if (local)
- lorutime = LocalTime(date);
- else
- lorutime = date;
- }
-
- i = 0;
- int stop = args.length;
-
- if (maxargs >= 3 && i < stop)
- year = conv[i++];
- else
- year = YearFromTime(lorutime);
-
- if (maxargs >= 2 && i < stop)
- month = conv[i++];
- else
- month = MonthFromTime(lorutime);
-
- if (maxargs >= 1 && i < stop)
- day = conv[i++];
- else
- day = DateFromTime(lorutime);
-
- day = MakeDay(year, month, day); /* day within year */
- result = MakeDate(day, TimeWithinDay(lorutime));
-
- if (local)
- result = internalUTC(result);
-
- date = TimeClip(result);
-
- this.date = date;
- return date;
- }
-
- private double setYear(double year) {
- double day, result;
- if (year != year || Double.isInfinite(year)) {
- this.date = Double.NaN;
- return this.date;
- }
-
- if (this.date != this.date) {
- this.date = 0;
- } else {
- this.date = LocalTime(this.date);
- }
-
- if (year >= 0 && year <= 99)
- year += 1900;
-
- day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date));
- result = MakeDate(day, TimeWithinDay(this.date));
- result = internalUTC(result);
-
- this.date = TimeClip(result);
- return this.date;
- }
-
-
- // private static final int
- // Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6
-// #/string_id_map#
-
- /* cached values */
- private static java.util.TimeZone thisTimeZone;
- private static double LocalTZA;
- private static java.text.DateFormat timeZoneFormatter;
- private static java.text.DateFormat localeDateTimeFormatter;
- private static java.text.DateFormat localeDateFormatter;
- private static java.text.DateFormat localeTimeFormatter;
-
- private double date;
-
- public long getRawTime() { return (long)this.date; }
-}
-
-
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.io.*;
-
-/** An exception which can be thrown and caught by JavaScript code */
-public class JSExn extends Exception {
- private Vec backtrace = new Vec();
- private JS js;
- public JSExn(String s) { this(JS.S(s)); }
- public JSExn(JS js) { this(js,null); }
- public JSExn(JS js, Interpreter cx) { this.js = js; fill(cx); }
-
- private void fill(Interpreter cx) {
- if(cx == null) cx = Interpreter.current();
- if(cx == null) return;
- addBacktrace(cx.f.sourceName + ":" + cx.f.line[cx.pc]);
- cx.stack.backtrace(this);
- }
- public void printStackTrace() { printStackTrace(System.err); }
- public void printStackTrace(PrintWriter pw) {
- for(int i=0; i<backtrace.size(); i++) pw.println(" at " + (String) backtrace.elementAt(i));
- super.printStackTrace(pw);
- }
- public void printStackTrace(PrintStream ps) {
- for(int i=0; i<backtrace.size(); i++) ps.println(" at " + (String) backtrace.elementAt(i));
- super.printStackTrace(ps);
- }
- public String toString() { return "JSExn: " + JS.debugToString(js); }
- public String getMessage() { return toString(); }
- public JS getObject() { return js; }
-
- void addBacktrace(String line) { backtrace.addElement(line); }
-
- public static class Wrapper extends RuntimeException {
- public final JSExn e;
- public Wrapper(JSExn e) { this.e = e; }
- public JSExn refill() {
- e.addBacktrace("[foreign code]");
- e.fill(null);
- return e;
- }
- }
-
- public static class IO extends JSExn {
- public IO(java.io.IOException ioe) {
- super("ibex.io: " + ioe.toString());
- JS.warn(ioe);
- }
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import java.io.*;
-import org.ibex.util.*;
-
-/** A JavaScript function, compiled into bytecode */
-// FIXME: This shouldn't be public, needed for public add/delTrap (which is needed for the Template.java hack)
-public class JSFunction extends JS implements ByteCodes, Tokens, Task {
-
-
- // Fields and Accessors ///////////////////////////////////////////////
-
- int numFormalArgs = 0; ///< the number of formal arguments
-
- String sourceName; ///< the source code file that this block was drawn from
- private int firstLine = -1; ///< the first line of this script
-
- int[] line = new int[10]; ///< the line numbers
- int[] op = new int[10]; ///< the instructions
- Object[] arg = new Object[10]; ///< the arguments to the instructions
- int size = 0; ///< the number of instruction/argument pairs
-
- JSScope parentScope; ///< the default scope to use as a parent scope when executing this
-
-
- // Public //////////////////////////////////////////////////////////////////////////////
-
- // FEATURE: make sure that this can only be called from the Scheduler...
- /** if you enqueue a function, it gets invoked in its own pauseable context */
- public void perform() throws JSExn {
- Interpreter i = new Interpreter(this, true, new Interpreter.JSArgs(this));
- i.resume();
- }
-
- public JSFunction _cloneWithNewParentScope(JSScope s) {
- JSFunction ret = new JSFunction(sourceName, firstLine, s);
- // Reuse the same op, arg, line, and size variables for the new "instance" of the function
- // NOTE: Neither *this* function nor the new function should be modified after this call
- ret.op = this.op;
- ret.arg = this.arg;
- ret.line = this.line;
- ret.size = this.size;
- ret.numFormalArgs = this.numFormalArgs;
- return ret;
- }
-
- /** Note: code gets run in an <i>unpauseable</i> context. */
- public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- Interpreter cx = new Interpreter(this, false, new Interpreter.JSArgs(a0,a1,a2,rest,nargs,this));
- return cx.resume();
- }
-
- public JSScope getParentScope() { return parentScope; }
-
- // Adding and Altering Bytecodes ///////////////////////////////////////////////////
-
- JSFunction(String sourceName, int firstLine, JSScope parentScope) {
- this.sourceName = sourceName;
- this.firstLine = firstLine;
- this.parentScope = parentScope;
- }
-
- int get(int pos) { return op[pos]; }
- Object getArg(int pos) { return arg[pos]; }
- void set(int pos, int op_, Object arg_) { op[pos] = op_; arg[pos] = arg_; }
- void set(int pos, Object arg_) { arg[pos] = arg_; }
- int pop() { size--; arg[size] = null; return op[size]; }
- void paste(JSFunction other) { for(int i=0; i<other.size; i++) add(other.line[i], other.op[i], other.arg[i]); }
- JSFunction add(int line, int op_) { return add(line, op_, null); }
- JSFunction add(int line, int op_, Object arg_) {
- if (size == op.length - 1) {
- int[] line2 = new int[op.length * 2]; System.arraycopy(this.line, 0, line2, 0, op.length); this.line = line2;
- Object[] arg2 = new Object[op.length * 2]; System.arraycopy(arg, 0, arg2, 0, arg.length); arg = arg2;
- int[] op2 = new int[op.length * 2]; System.arraycopy(op, 0, op2, 0, op.length); op = op2;
- }
- this.line[size] = line;
- op[size] = op_;
- arg[size] = arg_;
- size++;
- return this;
- }
-
-
- // Debugging //////////////////////////////////////////////////////////////////////
-
- String extendedToString() { return "[" + sourceName + ":" + firstLine + "]"; }
-
- String dump() { return dump(""); }
- private String dump(String prefix) {
- StringBuffer sb = new StringBuffer(1024);
- sb.append("\n" + sourceName + ": " + firstLine + "\n");
- for (int i=0; i < size; i++) {
- sb.append(prefix);
- sb.append(i).append(" (").append(line[i]).append("): ");
- if (op[i] < 0) sb.append(bytecodeToString[-op[i]]);
- else sb.append(codeToString[op[i]]);
- sb.append(" ");
- sb.append(arg[i] == null ? "(no arg)" : arg[i] instanceof JS ? JS.debugToString((JS)arg[i]) : arg[i]);
- if((op[i] == JF || op[i] == JT || op[i] == JMP) && arg[i] != null && arg[i] instanceof Number) {
- sb.append(" jump to ").append(i+((Number) arg[i]).intValue());
- } else if(op[i] == TRY) {
- int[] jmps = (int[]) arg[i];
- sb.append(" catch: ").append(jmps[0] < 0 ? "No catch block" : ""+(i+jmps[0]));
- sb.append(" finally: ").append(jmps[1] < 0 ? "No finally block" : ""+(i+jmps[1]));
- } else if(op[i] == NEWFUNCTION) {
- sb.append(((JSFunction) arg[i]).dump(prefix + " "));
- } else if(op[i] == NEWSCOPE) {
- int n = ((JSNumber)arg[i]).toInt();
- sb.append(" base: " + (n>>>16) + " size: " + (n&0xffff));
- }
- sb.append("\n");
- }
- return sb.toString();
- }
-
-
-}
-
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL ]
-
-package org.ibex.js;
-
-/** The JavaScript Math object */
-class JSMath extends JS {
- private static final JS E = JS.N(java.lang.Math.E);
- private static final JS PI = JS.N(java.lang.Math.PI);
- private static final JS LN10 = JS.N(java.lang.Math.log(10));
- private static final JS LN2 = JS.N(java.lang.Math.log(2));
- private static final JS LOG10E = JS.N(1/java.lang.Math.log(10));
- private static final JS LOG2E = JS.N(1/java.lang.Math.log(2));
- private static final JS SQRT1_2 = JS.N(1/java.lang.Math.sqrt(2));
- private static final JS SQRT2 = JS.N(java.lang.Math.sqrt(2));
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- switch(nargs) {
- case 0: {
- //#jswitch(method)
- case "random": return JS.N(java.lang.Math.random());
- //#end
- break;
- }
- case 1: {
- //#jswitch(method)
- case "ceil": return JS.N((long)java.lang.Math.ceil(toDouble(a0)));
- case "floor": return JS.N((long)java.lang.Math.floor(toDouble(a0)));
- case "round": return JS.N((long)java.lang.Math.round(toDouble(a0)));
- case "abs": return JS.N(java.lang.Math.abs(toDouble(a0)));
- case "sin": return JS.N(java.lang.Math.sin(toDouble(a0)));
- case "cos": return JS.N(java.lang.Math.cos(toDouble(a0)));
- case "tan": return JS.N(java.lang.Math.tan(toDouble(a0)));
- case "asin": return JS.N(java.lang.Math.asin(toDouble(a0)));
- case "acos": return JS.N(java.lang.Math.acos(toDouble(a0)));
- case "atan": return JS.N(java.lang.Math.atan(toDouble(a0)));
- case "sqrt": return JS.N(java.lang.Math.sqrt(toDouble(a0)));
- case "exp": return JS.N(java.lang.Math.exp(toDouble(a0)));
- case "log": return JS.N(java.lang.Math.log(toDouble(a0)));
- //#end
- break;
- }
- case 2: {
- //#jswitch(method)
- case "min": return JS.N(java.lang.Math.min(toDouble(a0), toDouble(a1)));
- case "max": return JS.N(java.lang.Math.max(toDouble(a0), toDouble(a1)));
- case "pow": return JS.N(java.lang.Math.pow(toDouble(a0), toDouble(a1)));
- case "atan2": return JS.N(java.lang.Math.atan2(toDouble(a0), toDouble(a1)));
- //#end
- break;
- }
- }
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
-
- public JS get(JS key) throws JSExn {
- //#jswitch(key)
- case "E": return E;
- case "LN10": return LN10;
- case "LN2": return LN2;
- case "LOG10E": return LOG10E;
- case "LOG2E": return LOG2E;
- case "PI": return PI;
- case "SQRT1_2": return SQRT1_2;
- case "SQRT2": return SQRT2;
- case "ceil": return METHOD;
- case "floor": return METHOD;
- case "round": return METHOD;
- case "min": return METHOD;
- case "max": return METHOD;
- case "pow": return METHOD;
- case "atan2": return METHOD;
- case "abs": return METHOD;
- case "sin": return METHOD;
- case "cos": return METHOD;
- case "tan": return METHOD;
- case "asin": return METHOD;
- case "acos": return METHOD;
- case "atan": return METHOD;
- case "sqrt": return METHOD;
- case "exp": return METHOD;
- case "log": return METHOD;
- case "random": return METHOD;
- //#end
- return super.get(key);
- }
-}
+++ /dev/null
-package org.ibex.js;
-
-abstract class JSNumber extends JSPrimitive {
- boolean jsequals(JS o) {
- if(o == this) return true;
- if(o instanceof JSNumber) {
- JSNumber n = (JSNumber) o;
- if(this instanceof D || n instanceof D) return n.toDouble() == toDouble();
- return n.toLong() == toLong();
- } else if(o instanceof JSString) {
- String s = ((JSString)o).s.trim();
- try {
- if(this instanceof D || s.indexOf('.') != -1) return Double.parseDouble(s) == toDouble();
- return Long.parseLong(s) == toLong();
- } catch(NumberFormatException e) {
- return false;
- }
- } else {
- return false;
- }
- }
- // FEATURE: Better hash function? (if d != (int) d then do something double specific)
- public int hashCode() { return toInt(); }
-
- abstract int toInt();
- long toLong() { return toInt(); }
- boolean toBoolean() { return toInt() != 0; }
- double toDouble() { return toLong(); }
- float toFloat() { return (float) toDouble(); }
-
- final static class I extends JSNumber {
- final int i;
- I(int i) { this.i = i; }
- int toInt() { return i; }
- public String coerceToString() { return Integer.toString(i); }
- }
-
- final static class L extends JSNumber {
- private final long l;
- L(long l) { this.l = l; }
- int toInt() { return (int) l; }
- long toLong() { return l; }
- public String coerceToString() { return Long.toString(l); }
- }
-
- final static class D extends JSNumber {
- private final double d;
- D(double d) { this.d = d; }
- int toInt() { return (int) d; }
- long toLong() { return (long) d; }
- double toDouble() { return d; }
- boolean toBoolean() { return d == d && d != 0.0; }
- public String coerceToString() { return d == (long) d ? Long.toString((long)d) : Double.toString(d); }
- }
-
- final static class B extends JSNumber {
- private final boolean b;
- B(boolean b) { this.b = b; }
- int toInt() { return b ? 1 : 0; }
- public String coerceToString() { return b ? "true" : "false"; }
- }
-}
+++ /dev/null
-package org.ibex.js;
-
-class JSPrimitive extends JS {
- public JS callMethod(JS method, JS arg0, JS arg1, JS arg2, JS[] rest, int alength) throws JSExn {
- //#jswitch(method)
- case "toFixed": throw new JSExn("toFixed() not implemented");
- case "toExponential": throw new JSExn("toExponential() not implemented");
- case "toPrecision": throw new JSExn("toPrecision() not implemented");
- case "toString": return this instanceof JSString ? this : JS.S(JS.toString(this));
- //#end
-
- String s = coerceToString();
- int slength = s.length();
-
- //#jswitch(method)
- case "substring": {
- int a = alength >= 1 ? JS.toInt(arg0) : 0;
- int b = alength >= 2 ? JS.toInt(arg1) : slength;
- if (a > slength) a = slength;
- if (b > slength) b = slength;
- if (a < 0) a = 0;
- if (b < 0) b = 0;
- if (a > b) { int tmp = a; a = b; b = tmp; }
- return JS.S(s.substring(a,b));
- }
- case "substr": {
- int start = alength >= 1 ? JS.toInt(arg0) : 0;
- int len = alength >= 2 ? JS.toInt(arg1) : Integer.MAX_VALUE;
- if (start < 0) start = slength + start;
- if (start < 0) start = 0;
- if (len < 0) len = 0;
- if (len > slength - start) len = slength - start;
- if (len <= 0) return JS.S("");
- return JS.S(s.substring(start,start+len));
- }
- case "charAt": {
- int p = alength >= 1 ? JS.toInt(arg0) : 0;
- if (p < 0 || p >= slength) return JS.S("");
- return JS.S(s.substring(p,p+1));
- }
- case "charCodeAt": {
- int p = alength >= 1 ? JS.toInt(arg0) : 0;
- if (p < 0 || p >= slength) return JS.N(Double.NaN);
- return JS.N(s.charAt(p));
- }
- case "concat": {
- StringBuffer sb = new StringBuffer(slength*2).append(s);
- for(int i=0;i<alength;i++) sb.append(i==0?arg0:i==1?arg1:i==2?arg2:rest[i-3]);
- return JS.S(sb.toString());
- }
- case "indexOf": {
- String search = alength >= 1 ? JS.toString(arg0) : "null";
- int start = alength >= 2 ? JS.toInt(arg1) : 0;
- // Java's indexOf handles an out of bounds start index, it'll return -1
- return JS.N(s.indexOf(search,start));
- }
- case "lastIndexOf": {
- String search = alength >= 1 ? JS.toString(arg0) : "null";
- int start = alength >= 2 ? JS.toInt(arg1) : 0;
- // Java's indexOf handles an out of bounds start index, it'll return -1
- return JS.N(s.lastIndexOf(search,start));
- }
- case "match": return JSRegexp.stringMatch(this,arg0);
- case "replace": return JSRegexp.stringReplace(this,arg0,arg1);
- case "search": return JSRegexp.stringSearch(this,arg0);
- case "split": return JSRegexp.stringSplit(this,arg0,arg1,alength);
- case "toLowerCase": return JS.S(s.toLowerCase());
- case "toUpperCase": return JS.S(s.toUpperCase());
- case "slice": {
- int a = alength >= 1 ? JS.toInt(arg0) : 0;
- int b = alength >= 2 ? JS.toInt(arg1) : slength;
- if (a < 0) a = slength + a;
- if (b < 0) b = slength + b;
- if (a < 0) a = 0;
- if (b < 0) b = 0;
- if (a > slength) a = slength;
- if (b > slength) b = slength;
- if (a > b) return JS.S("");
- return JS.S(s.substring(a,b));
- }
- //#end
- return super.callMethod(method,arg0,arg1,arg2,rest,alength);
- }
-
- public JS get(JS key) throws JSExn {
- //#jswitch(key)
- case "length": return JS.N(JS.toString(this).length());
- case "substring": return METHOD;
- case "charAt": return METHOD;
- case "charCodeAt": return METHOD;
- case "concat": return METHOD;
- case "indexOf": return METHOD;
- case "lastIndexOf": return METHOD;
- case "match": return METHOD;
- case "replace": return METHOD;
- case "search": return METHOD;
- case "slice": return METHOD;
- case "split": return METHOD;
- case "toLowerCase": return METHOD;
- case "toUpperCase": return METHOD;
- case "toString": return METHOD;
- case "substr": return METHOD;
- case "toPrecision": return METHOD;
- case "toExponential": return METHOD;
- case "toFixed": return METHOD;
- //#end
- return super.get(key);
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.io.*;
-import java.util.*;
-import java.lang.reflect.*;
-
-/** Automatic JS-ification via Reflection (not for use in the core) */
-public class JSReflection extends JS {
-
- public static JS wrap(Object o) throws JSExn {
- if (o == null) return null;
- if (o instanceof String) return JS.S((String)o);
- if (o instanceof Boolean) return JS.B(((Boolean)o).booleanValue());
- if (o instanceof Number) return JS.N((Number)o);
- if (o instanceof JS) return (JS)o;
- if (o instanceof Object[]) {
- // FIXME: get element type here
- }
- throw new JSExn("Reflection object tried to return a " + o.getClass().getName());
- }
-
- public static class Array extends JS {
- final Object[] arr;
- public Array(Object[] arr) { this.arr = arr; }
- // FEATURE: Add a JSCounterEnumeration
- public Enumeration keys() throws JSExn {
- return new Enumeration(null) {
- private int n = 0;
- public boolean _hasMoreElements() { return n < arr.length; }
- public JS _nextElement() {
- return n >= arr.length ? null : JS.N(n++);
- }
- };
- }
- public JS get(JS key) throws JSExn { return wrap(arr[toInt(key)]); }
- public void put(JS key, JS val) throws JSExn { throw new JSExn("can't write to org.ibex.js.Reflection.Array's"); }
- }
-
- // FIXME public static class Hash { }
- // FIXME public Enumeration keys() throws JSExn { }
-
- public JS get(JS key) throws JSExn {
- String k = toString(key);
- try {
- Field f = this.getClass().getField(k);
- return wrap(f.get(this));
- } catch (NoSuchFieldException nfe) {
- } catch (IllegalAccessException nfe) {
- } catch (SecurityException nfe) { }
-
- try {
- Method[] methods = this.getClass().getMethods();
- for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(k)) return METHOD;
- } catch (SecurityException nfe) { }
- return null;
- }
-
- public void put(JS key, JS val) throws JSExn {
- throw new JSExn("put() not supported yet");
- }
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- String k = toString(method);
- try {
- Method[] methods = this.getClass().getMethods();
- for(int j=0; j<methods.length; j++) {
- if (methods[j].getName().equals(k) && methods[j].getParameterTypes().length == nargs) {
- Object[] args = new Object[nargs];
- for(int i = 0; i<args.length; i++) {
- if (i==0) args[i] = a0;
- else if (i==1) args[i] = a1;
- else if (i==2) args[i] = a2;
- else args[i] = rest[i-3];
- }
- return wrap(methods[j].invoke(this, args));
- }
- }
- } catch (IllegalAccessException nfe) {
- } catch (InvocationTargetException it) {
- Throwable ite = it.getTargetException();
- if (ite instanceof JSExn) throw ((JSExn)ite);
- JS.warn(ite);
- throw new JSExn("unhandled reflected exception: " + ite.toString());
- } catch (SecurityException nfe) { }
- throw new JSExn("called a reflection method with the wrong number of arguments");
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import gnu.regexp.*;
-
-/** A JavaScript regular expression object */
-public class JSRegexp extends JS {
- private boolean global;
- private RE re;
- private int lastIndex;
-
- private JS pattern;
- private int flags;
-
- public JSRegexp(JS arg0, JS arg1) throws JSExn {
- if(arg0 instanceof JSRegexp) {
- JSRegexp r = (JSRegexp) arg0;
- this.global = r.global;
- this.re = r.re;
- this.lastIndex = r.lastIndex;
- this.pattern = pattern;
- this.flags = flags;
- } else {
- String pattern = JS.toString(arg0);
- String sFlags = null;
- int flags = 0;
- if(arg1 != null) sFlags = JS.toString(arg1);
- if(sFlags == null) sFlags = "";
- for(int i=0;i<sFlags.length();i++) {
- switch(sFlags.charAt(i)) {
- case 'i': flags |= RE.REG_ICASE; break;
- case 'm': flags |= RE.REG_MULTILINE; break;
- case 'g': global = true; break;
- default: throw new JSExn("Invalid flag in regexp \"" + sFlags.charAt(i) + "\"");
- }
- }
- re = newRE(pattern,flags);
- this.pattern = JS.S(pattern);
- this.flags = flags;
- }
- }
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- switch(nargs) {
- case 1: {
- //#jswitch(method)
- case "exec": {
- String s = JS.toString(a0);
- int start = global ? lastIndex : 0;
- if(start < 0 || start >= s.length()) { lastIndex = 0; return null; }
- REMatch match = re.getMatch(s,start);
- if(global) lastIndex = match == null ? s.length() : match.getEndIndex();
- return match == null ? null : matchToExecResult(match,re,s);
- }
- case "test": {
- String s = JS.toString(a0);
- if (!global) return B(re.getMatch(s) != null);
- int start = global ? lastIndex : 0;
- if(start < 0 || start >= s.length()) { lastIndex = 0; return null; }
- REMatch match = re.getMatch(s,start);
- lastIndex = match != null ? s.length() : match.getEndIndex();
- return B(match != null);
- }
- case "toString": return JS.S(a0.coerceToString());
- case "stringMatch": return stringMatch(a0,a1);
- case "stringSearch": return stringSearch(a0,a1);
- //#end
- break;
- }
- case 2: {
- //#jswitch(method)
- case "stringReplace": return stringReplace(a0, a1,a2);
- //#end
- break;
- }
- }
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
-
- public JS get(JS key) throws JSExn {
- //#jswitch(key)
- case "exec": return METHOD;
- case "test": return METHOD;
- case "toString": return METHOD;
- case "lastIndex": return N(lastIndex);
- case "source": return pattern;
- case "global": return JS.B(global);
- case "ignoreCase": return B(flags & RE.REG_ICASE);
- case "multiline": return B(flags & RE.REG_MULTILINE);
- //#end
- return super.get(key);
- }
-
- public void put(JS key, JS value) throws JSExn {
- if(JS.isString(key)) {
- if(JS.toString(key).equals("lastIndex")) {
- lastIndex = JS.toInt(value);
- return;
- }
- }
- super.put(key,value);
- }
-
- private static JS matchToExecResult(REMatch match, RE re, String s) {
- try {
- JS ret = new JS.O();
- ret.put(JS.S("index"), N(match.getStartIndex()));
- ret.put(JS.S("input"),JS.S(s));
- int n = re.getNumSubs();
- ret.put(JS.S("length"), N(n+1));
- ret.put(ZERO,JS.S(match.toString()));
- for(int i=1;i<=n;i++) ret.put(JS.N(i),JS.S(match.toString(i)));
- return ret;
- } catch (JSExn e) {
- throw new Error("this should never happen");
- }
- }
-
- String coerceToString() {
- StringBuffer sb = new StringBuffer();
- sb.append('/');
- sb.append(pattern);
- sb.append('/');
- if(global) sb.append('g');
- if((flags & RE.REG_ICASE) != 0) sb.append('i');
- if((flags & RE.REG_MULTILINE) != 0) sb.append('m');
- return sb.toString();
- }
-
- static JS stringMatch(JS o, JS arg0) throws JSExn {
- String s = JS.toString(o);
- RE re;
- JSRegexp regexp = null;
- if(arg0 instanceof JSRegexp) {
- regexp = (JSRegexp) arg0;
- re = regexp.re;
- } else {
- re = newRE(JS.toString(arg0),0);
- }
-
- if(regexp == null) {
- REMatch match = re.getMatch(s);
- return matchToExecResult(match,re,s);
- }
- if(!regexp.global) return regexp.callMethod(JS.S("exec"), o, null, null, null, 1);
-
- JSArray ret = new JSArray();
- REMatch[] matches = re.getAllMatches(s);
- for(int i=0;i<matches.length;i++) ret.addElement(JS.S(matches[i].toString()));
- regexp.lastIndex = matches.length > 0 ? matches[matches.length-1].getEndIndex() : s.length();
- return ret;
- }
-
- static JS stringSearch(JS o, JS arg0) throws JSExn {
- String s = JS.toString(o);
- RE re = arg0 instanceof JSRegexp ? ((JSRegexp)arg0).re : newRE(JS.toString(arg0),0);
- REMatch match = re.getMatch(s);
- return match == null ? N(-1) : N(match.getStartIndex());
- }
-
- static JS stringReplace(JS o, JS arg0, JS arg1) throws JSExn {
- String s = JS.toString(o);
- RE re;
- JSFunction replaceFunc = null;
- String replaceString = null;
- JSRegexp regexp = null;
- if(arg0 instanceof JSRegexp) {
- regexp = (JSRegexp) arg0;
- re = regexp.re;
- } else {
- re = newRE(arg0.toString(),0);
- }
- if(arg1 instanceof JSFunction)
- replaceFunc = (JSFunction) arg1;
- else
- replaceString = JS.toString(arg1);
- REMatch[] matches;
- if(regexp != null && regexp.global) {
- matches = re.getAllMatches(s);
- if(regexp != null) {
- if(matches.length > 0)
- regexp.lastIndex = matches[matches.length-1].getEndIndex();
- else
- regexp.lastIndex = s.length();
- }
- } else {
- REMatch match = re.getMatch(s);
- if(match != null)
- matches = new REMatch[]{ match };
- else
- matches = new REMatch[0];
- }
-
- StringBuffer sb = new StringBuffer(s.length());
- int pos = 0;
- char[] sa = s.toCharArray();
- for(int i=0;i<matches.length;i++) {
- REMatch match = matches[i];
- sb.append(sa,pos,match.getStartIndex()-pos);
- pos = match.getEndIndex();
- if(replaceFunc != null) {
- int n = (regexp == null ? 0 : re.getNumSubs());
- int numArgs = 3 + n;
- JS[] rest = new JS[numArgs - 3];
- JS a0 = JS.S(match.toString());
- JS a1 = null;
- JS a2 = null;
- for(int j=1;j<=n;j++)
- switch(j) {
- case 1: a1 = JS.S(match.toString(j)); break;
- case 2: a2 = JS.S(match.toString(j)); break;
- default: rest[j - 3] = JS.S(match.toString(j)); break;
- }
- switch(numArgs) {
- case 3:
- a1 = N(match.getStartIndex());
- a2 = JS.S(s);
- break;
- case 4:
- a2 = N(match.getStartIndex());
- rest[0] = JS.S(s);
- break;
- default:
- rest[rest.length - 2] = N(match.getStartIndex());
- rest[rest.length - 1] = JS.S(s);
- }
-
- // note: can't perform pausing operations in here
- sb.append(JS.toString(replaceFunc.call(a0, a1, a2, rest, numArgs)));
-
- } else {
- sb.append(mySubstitute(match,replaceString,s));
- }
- }
- int end = matches.length == 0 ? 0 : matches[matches.length-1].getEndIndex();
- sb.append(sa,end,sa.length-end);
- return JS.S(sb.toString());
- }
-
- private static String mySubstitute(REMatch match, String s, String source) {
- StringBuffer sb = new StringBuffer();
- int i,n;
- char c,c2;
- for(i=0;i<s.length()-1;i++) {
- c = s.charAt(i);
- if(c != '$') {
- sb.append(c);
- continue;
- }
- i++;
- c = s.charAt(i);
- switch(c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if(i < s.length()-1 && (c2 = s.charAt(i+1)) >= '0' && c2 <= '9') {
- n = (c - '0') * 10 + (c2 - '0');
- i++;
- } else {
- n = c - '0';
- }
- if(n > 0)
- sb.append(match.toString(n));
- break;
- case '$':
- sb.append('$'); break;
- case '&':
- sb.append(match.toString()); break;
- case '`':
- sb.append(source.substring(0,match.getStartIndex())); break;
- case '\'':
- sb.append(source.substring(match.getEndIndex())); break;
- default:
- sb.append('$');
- sb.append(c);
- }
- }
- if(i < s.length()) sb.append(s.charAt(i));
- return sb.toString();
- }
-
-
- static JS stringSplit(JS s_, JS arg0, JS arg1, int nargs) throws JSExn {
- String s = JS.toString(s_);
- int limit = nargs < 2 ? Integer.MAX_VALUE : JS.toInt(arg1);
- if(limit < 0) limit = Integer.MAX_VALUE;
- if(limit == 0) return new JSArray();
-
- RE re = null;
- JSRegexp regexp = null;
- String sep = null;
- JSArray ret = new JSArray();
- int p = 0;
-
- if(arg0 instanceof JSRegexp) {
- regexp = (JSRegexp) arg0;
- re = regexp.re;
- } else {
- sep = JS.toString(arg0);
- }
-
- // special case this for speed. additionally, the code below doesn't properly handle
- // zero length strings
- if(sep != null && sep.length()==0) {
- int len = s.length();
- for(int i=0;i<len;i++)
- ret.addElement(JS.S(s.substring(i,i+1)));
- return ret;
- }
-
- OUTER: while(p < s.length()) {
- if(re != null) {
- REMatch m = re.getMatch(s,p);
- if(m == null) break OUTER;
- boolean zeroLength = m.getStartIndex() == m.getEndIndex();
- ret.addElement(JS.S(s.substring(p,zeroLength ? m.getStartIndex()+1 : m.getStartIndex())));
- p = zeroLength ? p + 1 : m.getEndIndex();
- if(!zeroLength) {
- for(int i=1;i<=re.getNumSubs();i++) {
- ret.addElement(JS.S(m.toString(i)));
- if(ret.length() == limit) break OUTER;
- }
- }
- } else {
- int x = s.indexOf(sep,p);
- if(x == -1) break OUTER;
- ret.addElement(JS.S(s.substring(p,x)));
- p = x + sep.length();
- }
- if(ret.length() == limit) break;
- }
- if(p < s.length() && ret.length() != limit)
- ret.addElement(JS.S(s.substring(p)));
- return ret;
- }
-
- private static RE newRE(String pattern, int flags) throws JSExn {
- try {
- return new RE(pattern,flags,RESyntax.RE_SYNTAX_PERL5);
- } catch(REException e) {
- throw new JSExn(e.toString());
- }
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-/** Implementation of a JavaScript Scope */
-class JSScope {
-
- private final int base;
- private final JS[] vars;
- final JSScope parent;
-
- public static class Top extends JSScope {
- private final JS global;
- public Top(JS global) { super(null,0,0); this.global = global; }
- JS get(int i) throws JSExn { throw new JSExn("scope index out of range"); }
- void put(int i, JS o) throws JSExn { throw new JSExn("scope index out of range"); }
- JS getGlobal() { return global; }
- };
-
- // NOTE: We can't just set base to parent.base + parent.vars.length
- // sometimes we only access part of a parent's scope
- public JSScope(JSScope parent, int base, int size) {
- this.parent = parent;
- this.base = base;
- this.vars = new JS[size];
- }
-
- final JS get(JS i) throws JSExn {
- if(i==null) throw new NullPointerException();
- try {
- return get(JS.toInt(i));
- } catch(ArrayIndexOutOfBoundsException e) {
- throw new JSExn("scope index out of range");
- }
- }
- final void put(JS i, JS o) throws JSExn {
- if(i==null) throw new NullPointerException();
- try {
- put(JS.toInt(i),o);
- } catch(ArrayIndexOutOfBoundsException e) {
- throw new JSExn("scope index out of range");
- }
- }
- JS get(int i) throws JSExn { return i < base ? parent.get(i) : vars[i-base]; }
- void put(int i, JS o) throws JSExn { if(i < base) parent.put(i,o); else vars[i-base] = o; }
-
- JS getGlobal() { return parent.getGlobal(); }
-
- /*private JSScope parentScope;
-
- private static final JS NULL_PLACEHOLDER = new JS() { };
-
- public JSScope(JSScope parentScope) { this.parentScope = parentScope; }
- public void declare(JS s) throws JSExn { super.put(s, NULL_PLACEHOLDER); }
- public JSScope getParentScope() { return parentScope; }
-
- public JS get(JS key) throws JSExn {
- JS o = super.get(key);
- if (o != null) return o == NULL_PLACEHOLDER ? null : o;
- else return parentScope == null ? null : parentScope.get(key);
- }
-
- public boolean has(JS key) throws JSExn { return super.get(key) != null; }
- public void put(JS key, JS val) throws JSExn {
- if (parentScope != null && !has(key)) parentScope.put(key, val);
- else super.put(key, val == null ? NULL_PLACEHOLDER : val);
- }
-
- public JSScope top() {
- JSScope s = this;
- while(s.parentScope != null) s = s.parentScope;
- return s;
- }
-
- public static class Global extends JSScope {
- private final static JS NaN = N(Double.NaN);
- private final static JS POSITIVE_INFINITY = N(Double.POSITIVE_INFINITY);
-
- public Global() { super(null); }
- public Global(JSScope p) { super(p); }
-
- public void declare(JS k) throws JSExn { throw new JSExn("can't declare variables in the global scope"); }
-
- // HACK: "this" gets lost on the way back through the scope chain
- // We'll have to do something better with this when Scope is rewritten
- public JS get(JS key) throws JSExn {
- JS ret = _get(key);
- if(ret == METHOD) return new Interpreter.Stub(this,key);
- return ret;
- }
-
- public JS _get(JS key) throws JSExn {
- //#jswitch(key)
- case "NaN": return NaN;
- case "Infinity": return POSITIVE_INFINITY;
- case "undefined": return null;
- case "stringFromCharCode": return METHOD;
- case "parseInt": return METHOD;
- case "parseFloat": return METHOD;
- case "isNaN": return METHOD;
- case "isFinite": return METHOD;
- case "decodeURI": return METHOD;
- case "decodeURIComponent": return METHOD;
- case "encodeURI": return METHOD;
- case "encodeURIComponent": return METHOD;
- case "escape": return METHOD;
- case "unescape": return METHOD;
- //#end
- return super.get(key);
- }
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- //#jswitch(method)
- case "parseInt": return parseInt(a0, N(0));
- case "parseFloat": return parseFloat(a0);
- case "isNaN": { double d = toDouble(a0); return d == d ? F : T; }
- case "isFinite": { double d = toDouble(a0); return (d == d && !Double.isInfinite(d)) ? T : F; }
- case "decodeURI": throw new JSExn("unimplemented");
- case "decodeURIComponent": throw new JSExn("unimplemented");
- case "encodeURI": throw new JSExn("unimplemented");
- case "encodeURIComponent": throw new JSExn("unimplemented");
- case "escape": throw new JSExn("unimplemented");
- case "unescape": throw new JSExn("unimplemented");
- case "parseInt": return parseInt(a0, a1);
- //#end
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
-
- private JS parseInt(JS arg, JS r) throws JSExn {
- int radix = JS.toInt(r);
- String s = JS.toString(arg);
- int start = 0;
- int length = s.length();
- int sign = 1;
- long n = 0;
- if(radix != 0 && (radix < 2 || radix > 36)) return NaN;
- while(start < length && Character.isWhitespace(s.charAt(start))) start++;
- if((length >= start+1) && (s.charAt(start) == '+' || s.charAt(start) == '-')) {
- sign = s.charAt(start) == '+' ? 1 : -1;
- start++;
- }
- if(radix == 0 && length >= start+1 && s.charAt(start) == '0') {
- start++;
- if(length >= start+1 && (s.charAt(start) == 'x' || s.charAt(start) == 'X')) {
- start++;
- radix = 16;
- } else {
- radix = 8;
- if(length == start || Character.digit(s.charAt(start+1),8)==-1) return JS.ZERO;
- }
- }
- if(radix == 0) radix = 10;
- if(length == start || Character.digit(s.charAt(start),radix) == -1) return NaN;
- // try the fast way first
- try {
- String s2 = start == 0 ? s : s.substring(start);
- return JS.N(sign*Integer.parseInt(s2,radix));
- } catch(NumberFormatException e) { }
- // fall through to a slower but emca-compliant method
- for(int i=start;i<length;i++) {
- int digit = Character.digit(s.charAt(i),radix);
- if(digit < 0) break;
- n = n*radix + digit;
- if(n < 0) return NaN; // overflow;
- }
- if(n <= Integer.MAX_VALUE) return JS.N(sign*(int)n);
- return JS.N((long)sign*n);
- }
-
- private JS parseFloat(JS arg) throws JSExn {
- String s = JS.toString(arg);
- int start = 0;
- int length = s.length();
- while(start < length && Character.isWhitespace(s.charAt(0))) start++;
- int end = length;
- // as long as the string has no trailing garbage,this is fast, its slow with
- // trailing garbage
- while(start < end) {
- try {
- return JS.N(new Double(s.substring(start,length)));
- } catch(NumberFormatException e) { }
- end--;
- }
- return NaN;
- }
- }*/
-}
-
+++ /dev/null
-package org.ibex.js;
-
-import org.ibex.util.*;
-
-class JSString extends JSPrimitive {
- final String s;
- public JSString(String s) { this.s = s; }
- public int hashCode() { return s.hashCode(); }
-
- public boolean jsequals(JS o) {
- if(o == this) return true;
- if(o instanceof JSString) {
- return ((JSString)o).s.equals(s);
- } else if(o instanceof JSNumber) {
- return o.jsequals(this);
- } else {
- return false;
- }
- }
-
- private final static Hash internHash = new Hash();
- static synchronized JS intern(String s) {
- synchronized(internHash) {
- JS js = (JS)internHash.get(s);
- if(js == null) internHash.put(s,js = new Intern(s));
- return js;
- }
- }
- static class Intern extends JSString {
- public Intern(String s) { super(s); }
- protected void finalize() { synchronized(internHash) { internHash.put(s,null); } }
- }
-
- String coerceToString() { return s; }
-}
+++ /dev/null
-// Derived from org.mozilla.javascript.TokenStream [NPL]
-
-/**
- * The contents of this file are subject to the Netscape Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/NPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation.
- *
- * Contributor(s): Roger Lawrence, Mike McCabe
- */
-
-package org.ibex.js;
-import java.io.*;
-
-/** Lexes a stream of characters into a stream of Tokens */
-class Lexer implements Tokens {
-
- /** for debugging */
- public static void main(String[] s) throws IOException {
- Lexer l = new Lexer(new InputStreamReader(System.in), "stdin", 0);
- int tok = 0;
- while((tok = l.getToken()) != -1) System.out.println(codeToString[tok]);
- }
-
- /** the token that was just parsed */
- protected int op;
-
- /** the most recently parsed token, <i>regardless of pushbacks</i> */
- protected int mostRecentlyReadToken;
-
- /** if the token just parsed was a NUMBER, this is the numeric value */
- protected Number number = null;
-
- /** if the token just parsed was a NAME or STRING, this is the string value */
- protected String string = null;
-
- /** the line number of the most recently <i>lexed</i> token */
- protected int line = 0;
-
- /** the line number of the most recently <i>parsed</i> token */
- protected int parserLine = 0;
-
- /** the column number of the current token */
- protected int col = 0;
-
- /** the name of the source code file being lexed */
- protected String sourceName;
-
- private SmartReader in;
- public Lexer(Reader r, String sourceName, int line) throws IOException {
- this.sourceName = sourceName;
- this.line = line;
- this.parserLine = line;
- in = new SmartReader(r);
- }
-
-
- // Predicates ///////////////////////////////////////////////////////////////////////
-
- private static boolean isAlpha(int c) { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); }
- private static boolean isDigit(int c) { return (c >= '0' && c <= '9'); }
- private static int xDigitToInt(int c) {
- if ('0' <= c && c <= '9') return c - '0';
- else if ('a' <= c && c <= 'f') return c - ('a' - 10);
- else if ('A' <= c && c <= 'F') return c - ('A' - 10);
- else return -1;
- }
-
-
- // Token Subtype Handlers /////////////////////////////////////////////////////////
-
- private int getKeyword(String name) throws IOException {
- //#switch(name)
- case "if": return IF;
- case "lt": return LT;
- case "gt": return GT;
- case "in": return IN;
- case "do": return DO;
- case "and": return AND;
- case "or": return OR;
- case "for": return FOR;
- case "int": return RESERVED;
- case "new": return RESERVED;
- case "try": return TRY;
- case "var": return VAR;
- case "byte": return RESERVED;
- case "case": return CASE;
- case "char": return RESERVED;
- case "else": return ELSE;
- case "enum": return RESERVED;
- case "goto": return RESERVED;
- case "long": return RESERVED;
- case "null": return NULL;
- case "true": return TRUE;
- case "with": return RESERVED;
- case "void": return RESERVED;
- case "class": return RESERVED;
- case "break": return BREAK;
- case "while": return WHILE;
- case "false": return FALSE;
- case "const": return RESERVED;
- case "final": return RESERVED;
- case "super": return RESERVED;
- case "throw": return THROW;
- case "catch": return CATCH;
- case "class": return RESERVED;
- case "delete": return RESERVED;
- case "return": return RETURN;
- case "throws": return RESERVED;
- case "double": return RESERVED;
- case "assert": return ASSERT;
- case "public": return RESERVED;
- case "switch": return SWITCH;
- case "typeof": return TYPEOF;
- case "package": return RESERVED;
- case "default": return DEFAULT;
- case "finally": return FINALLY;
- case "boolean": return RESERVED;
- case "private": return RESERVED;
- case "extends": return RESERVED;
- case "abstract": return RESERVED;
- case "continue": return CONTINUE;
- case "debugger": return RESERVED;
- case "function": return FUNCTION;
- case "volatile": return RESERVED;
- case "interface": return RESERVED;
- case "protected": return RESERVED;
- case "transient": return RESERVED;
- case "implements": return RESERVED;
- case "instanceof": return RESERVED;
- case "synchronized": return RESERVED;
- case "cascade": return CASCADE;
- //#end
- return -1;
- }
-
- private int getIdentifier(int c) throws IOException {
- in.startString();
- while (Character.isJavaIdentifierPart((char)(c = in.read())));
- in.unread();
- String str = in.getString();
- int result = getKeyword(str);
- if (result == RESERVED) throw new LexerException("The reserved word \"" + str + "\" is not permitted in Ibex scripts");
- if (result != -1) return result;
- this.string = str.intern();
- return NAME;
- }
-
- private int getNumber(int c) throws IOException {
- int base = 10;
- in.startString();
- double dval = Double.NaN;
- long longval = 0;
- boolean isInteger = true;
-
- // figure out what base we're using
- if (c == '0') {
- if (Character.toLowerCase((char)(c = in.read())) == 'x') { base = 16; in.startString(); }
- else if (isDigit(c)) base = 8;
- }
-
- while (0 <= xDigitToInt(c) && !(base < 16 && isAlpha(c))) c = in.read();
- if (base == 10 && (c == '.' || c == 'e' || c == 'E')) {
- isInteger = false;
- if (c == '.') do { c = in.read(); } while (isDigit(c));
- if (c == 'e' || c == 'E') {
- c = in.read();
- if (c == '+' || c == '-') c = in.read();
- if (!isDigit(c)) throw new LexerException("float listeral did not have an exponent value");
- do { c = in.read(); } while (isDigit(c));
- }
- }
- in.unread();
-
- String numString = in.getString();
- if (base == 10 && !isInteger) {
- try { dval = (Double.valueOf(numString)).doubleValue(); }
- catch (NumberFormatException ex) { throw new LexerException("invalid numeric literal: \"" + numString + "\""); }
- } else {
- if (isInteger) {
- longval = Long.parseLong(numString, base);
- dval = (double)longval;
- } else {
- dval = Double.parseDouble(numString);
- longval = (long) dval;
- if (longval == dval) isInteger = true;
- }
- }
-
- if (!isInteger) this.number = new Double(dval);
- else if(longval >= Integer.MIN_VALUE && longval <= Integer.MAX_VALUE) this.number = new Integer((int)longval);
- else this.number = new Long(longval);
- return NUMBER;
- }
-
- private int getString(int c) throws IOException {
- StringBuffer stringBuf = null;
- int quoteChar = c;
- c = in.read();
- in.startString(); // start after the first "
- while(c != quoteChar) {
- if (c == '\n' || c == -1) throw new LexerException("unterminated string literal");
- if (c == '\\') {
- if (stringBuf == null) {
- in.unread(); // Don't include the backslash
- stringBuf = new StringBuffer(in.getString());
- in.read();
- }
- switch (c = in.read()) {
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\u000B'; break;
- case '\\': c = '\\'; break;
- case 'u': {
- int v = 0;
- for(int i=0; i<4; i++) {
- int ci = in.read();
- if (!((ci >= '0' && ci <= '9') || (ci >= 'a' && ci <= 'f') || (ci >= 'A' && ci <= 'F')))
- throw new LexerException("illegal character '" + ((char)c) + "' in \\u unicode escape sequence");
- v = (v << 8) | Integer.parseInt(ci + "", 16);
- }
- c = (char)v;
- break;
- }
- default:
- // just use the character that was escaped
- break;
- }
- }
- if (stringBuf != null) stringBuf.append((char) c);
- c = in.read();
- }
- if (stringBuf != null) this.string = stringBuf.toString().intern();
- else {
- in.unread(); // miss the trailing "
- this.string = in.getString().intern();
- in.read();
- }
- return STRING;
- }
-
- private int _getToken() throws IOException {
- int c;
- do { c = in.read(); } while (c == '\u0020' || c == '\u0009' || c == '\u000C' || c == '\u000B' || c == '\n' );
- if (c == -1) return -1;
- if (c == '\\' || Character.isJavaIdentifierStart((char)c)) return getIdentifier(c);
- if (isDigit(c) || (c == '.' && isDigit(in.peek()))) return getNumber(c);
- if (c == '"' || c == '\'') return getString(c);
- switch (c) {
- case ';': return SEMI;
- case '[': return LB;
- case ']': return RB;
- case '{': return LC;
- case '}': return RC;
- case '(': return LP;
- case ')': return RP;
- case ',': return COMMA;
- case '?': return HOOK;
- case ':': return !in.match(':') ? COLON : in.match('=') ? GRAMMAR : le(":: is not a valid token");
- case '.': return DOT;
- case '|': return in.match('|') ? OR : (in.match('=') ? ASSIGN_BITOR : BITOR);
- case '^': return in.match('=') ? ASSIGN_BITXOR : BITXOR;
- case '&': return in.match('&') ? AND : in.match('=') ? ASSIGN_BITAND : BITAND;
- case '=': return !in.match('=') ? ASSIGN : in.match('=') ? SHEQ : EQ;
- case '!': return !in.match('=') ? BANG : in.match('=') ? SHNE : NE;
- case '%': return in.match('=') ? ASSIGN_MOD : MOD;
- case '~': return BITNOT;
- case '+': return in.match('=') ? ASSIGN_ADD : in.match('+') ? (in.match('=') ? ADD_TRAP : INC) : ADD;
- case '-': return in.match('=') ? ASSIGN_SUB: in.match('-') ? (in.match('=') ? DEL_TRAP : DEC) : SUB;
- case '*': return in.match('=') ? ASSIGN_MUL : MUL;
- case '<': return !in.match('<') ? (in.match('=') ? LE : LT) : in.match('=') ? ASSIGN_LSH : LSH;
- case '>': return !in.match('>') ? (in.match('=') ? GE : GT) :
- in.match('>') ? (in.match('=') ? ASSIGN_URSH : URSH) : (in.match('=') ? ASSIGN_RSH : RSH);
- case '/':
- if (in.match('=')) return ASSIGN_DIV;
- if (in.match('/')) { while ((c = in.read()) != -1 && c != '\n'); in.unread(); return getToken(); }
- if (!in.match('*')) return DIV;
- while ((c = in.read()) != -1 && !(c == '*' && in.match('/'))) {
- if (c == '\n' || c != '/' || !in.match('*')) continue;
- if (in.match('/')) return getToken();
- throw new LexerException("nested comments are not permitted");
- }
- if (c == -1) throw new LexerException("unterminated comment");
- return getToken(); // `goto retry'
- default: throw new LexerException("illegal character: \'" + ((char)c) + "\'");
- }
- }
-
- private int le(String s) throws LexerException { if (true) throw new LexerException(s); return 0; }
-
- // SmartReader ////////////////////////////////////////////////////////////////
-
- /** a Reader that tracks line numbers and can push back tokens */
- private class SmartReader {
- PushbackReader reader = null;
- int lastread = -1;
-
- public SmartReader(Reader r) { reader = new PushbackReader(r); }
- public void unread() throws IOException { unread((char)lastread); }
- public void unread(char c) throws IOException {
- reader.unread(c);
- if(c == '\n') col = -1;
- else col--;
- if (accumulator != null) accumulator.setLength(accumulator.length() - 1);
- }
- public boolean match(char c) throws IOException { if (peek() == c) { reader.read(); return true; } else return false; }
- public int peek() throws IOException {
- int peeked = reader.read();
- if (peeked != -1) reader.unread((char)peeked);
- return peeked;
- }
- public int read() throws IOException {
- lastread = reader.read();
- if (accumulator != null) accumulator.append((char)lastread);
- if (lastread != '\n' && lastread != '\r') col++;
- if (lastread == '\n') {
- // col is -1 if we just unread a newline, this is sort of ugly
- if (col != -1) parserLine = ++line;
- col = 0;
- }
- return lastread;
- }
-
- // FEATURE: could be much more efficient
- StringBuffer accumulator = null;
- public void startString() {
- accumulator = new StringBuffer();
- accumulator.append((char)lastread);
- }
- public String getString() throws IOException {
- String ret = accumulator.toString().intern();
- accumulator = null;
- return ret;
- }
- }
-
-
- // Token PushBack code ////////////////////////////////////////////////////////////
-
- private int pushBackDepth = 0;
- private int[] pushBackInts = new int[10];
- private Object[] pushBackObjects = new Object[10];
-
- /** push back a token */
- public final void pushBackToken(int op, Object obj) {
- if (pushBackDepth >= pushBackInts.length - 1) {
- int[] newInts = new int[pushBackInts.length * 2];
- System.arraycopy(pushBackInts, 0, newInts, 0, pushBackInts.length);
- pushBackInts = newInts;
- Object[] newObjects = new Object[pushBackObjects.length * 2];
- System.arraycopy(pushBackObjects, 0, newObjects, 0, pushBackObjects.length);
- pushBackObjects = newObjects;
- }
- pushBackInts[pushBackDepth] = op;
- pushBackObjects[pushBackDepth] = obj;
- pushBackDepth++;
- }
-
- /** push back the most recently read token */
- public final void pushBackToken() { pushBackToken(op, number != null ? (Object)number : (Object)string); }
-
- /** read a token but leave it in the stream */
- public final int peekToken() throws IOException {
- int ret = getToken();
- pushBackToken();
- return ret;
- }
-
- /** read a token */
- public final int getToken() throws IOException {
- number = null;
- string = null;
- if (pushBackDepth == 0) {
- mostRecentlyReadToken = op;
- return op = _getToken();
- }
- pushBackDepth--;
- op = pushBackInts[pushBackDepth];
- if (pushBackObjects[pushBackDepth] != null) {
- number = pushBackObjects[pushBackDepth] instanceof Number ? (Number)pushBackObjects[pushBackDepth] : null;
- string = pushBackObjects[pushBackDepth] instanceof String ? (String)pushBackObjects[pushBackDepth] : null;
- }
- return op;
- }
-
- class LexerException extends IOException {
- public LexerException(String s) { super(sourceName + ":" + line + "," + col + ": " + s); }
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.io.*;
-
-/**
- * Parses a stream of lexed tokens into a tree of JSFunction's.
- *
- * There are three kinds of things we parse: blocks, statements, and
- * expressions.
- *
- * - Expressions are a special type of statement that evaluates to a
- * value (for example, "break" is not an expression, * but "3+2"
- * is). Some tokens sequences start expressions (for * example,
- * literal numbers) and others continue an expression which * has
- * already been begun (for example, '+'). Finally, some *
- * expressions are valid targets for an assignment operation; after
- * * each of these expressions, continueExprAfterAssignable() is
- * called * to check for an assignment operation.
- *
- * - A statement ends with a semicolon and does not return a value.
- *
- * - A block is a single statement or a sequence of statements
- * surrounded by curly braces.
- *
- * Each parsing method saves the parserLine before doing its actual
- * work and restores it afterwards. This ensures that parsing a
- * subexpression does not modify the line number until a token
- * *after* the subexpression has been consumed by the parent
- * expression.
- *
- * Technically it would be a better design for this class to build an
- * intermediate parse tree and use that to emit bytecode. Here's the
- * tradeoff:
- *
- * Advantages of building a parse tree:
- * - easier to apply optimizations
- * - would let us handle more sophisticated languages than JavaScript
- *
- * Advantages of leaving out the parse tree
- * - faster compilation
- * - less load on the garbage collector
- * - much simpler code, easier to understand
- * - less error-prone
- *
- * Fortunately JS is such a simple language that we can get away with
- * the half-assed approach and still produce a working, complete
- * compiler.
- *
- * The bytecode language emitted doesn't really cause any appreciable
- * semantic loss, and is itself a parseable language very similar to
- * Forth or a postfix variant of LISP. This means that the bytecode
- * can be transformed into a parse tree, which can be manipulated.
- * So if we ever want to add an optimizer, it could easily be done by
- * producing a parse tree from the bytecode, optimizing that tree,
- * and then re-emitting the bytecode. The parse tree node class
- * would also be much simpler since the bytecode language has so few
- * operators.
- *
- * Actually, the above paragraph is slightly inaccurate -- there are
- * places where we push a value and then perform an arbitrary number
- * of operations using it before popping it; this doesn't parse well.
- * But these cases are clearly marked and easy to change if we do
- * need to move to a parse tree format.
- */
-class Parser extends Lexer implements ByteCodes {
-
-
- // Constructors //////////////////////////////////////////////////////
-
- private Parser(Reader r, String sourceName, int line) throws IOException { super(r, sourceName, line); }
-
- /** for debugging */
- public static void main(String[] s) throws IOException {
- JS block = JS.fromReader("stdin", 0, new InputStreamReader(System.in));
- if (block == null) return;
- System.out.println(block);
- }
-
- // Statics ////////////////////////////////////////////////////////////
-
- static byte[] precedence = new byte[MAX_TOKEN + 1];
- static boolean[] isRightAssociative = new boolean[MAX_TOKEN + 1];
- // Use this as the precedence when we want anything up to the comma
- private final static int NO_COMMA = 2;
- static {
- isRightAssociative[ASSIGN] =
- isRightAssociative[ASSIGN_BITOR] =
- isRightAssociative[ASSIGN_BITXOR] =
- isRightAssociative[ASSIGN_BITAND] =
- isRightAssociative[ASSIGN_LSH] =
- isRightAssociative[ASSIGN_RSH] =
- isRightAssociative[ASSIGN_URSH] =
- isRightAssociative[ASSIGN_ADD] =
- isRightAssociative[ASSIGN_SUB] =
- isRightAssociative[ASSIGN_MUL] =
- isRightAssociative[ASSIGN_DIV] =
- isRightAssociative[ASSIGN_MOD] =
- isRightAssociative[ADD_TRAP] =
- isRightAssociative[DEL_TRAP] =
- true;
-
- precedence[COMMA] = 1;
- // 2 is intentionally left unassigned. we use minPrecedence==2 for comma separated lists
- precedence[ASSIGN] =
- precedence[ASSIGN_BITOR] =
- precedence[ASSIGN_BITXOR] =
- precedence[ASSIGN_BITAND] =
- precedence[ASSIGN_LSH] =
- precedence[ASSIGN_RSH] =
- precedence[ASSIGN_URSH] =
- precedence[ASSIGN_ADD] =
- precedence[ASSIGN_SUB] =
- precedence[ASSIGN_MUL] =
- precedence[ASSIGN_DIV] =
- precedence[ADD_TRAP] =
- precedence[DEL_TRAP] =
- precedence[ASSIGN_MOD] = 3;
- precedence[HOOK] = 4;
- precedence[OR] = 5;
- precedence[AND] = 6;
- precedence[BITOR] = 7;
- precedence[BITXOR] = 8;
- precedence[BITAND] = 9;
- precedence[EQ] = precedence[NE] = precedence[SHEQ] = precedence[SHNE] = 10;
- precedence[LT] = precedence[LE] = precedence[GT] = precedence[GE] = 11;
- precedence[LSH] = precedence[RSH] = precedence[URSH] = 12;
- precedence[ADD] = precedence[SUB] = 12;
- precedence[MUL] = precedence[DIV] = precedence[MOD] = 13;
- precedence[BITNOT] = precedence[BANG] = precedence[TYPEOF] = 14;
- precedence[DOT] = precedence[LB] = precedence[LP] = precedence[INC] = precedence[DEC] = 15;
- }
-
- // Local variable management
- Vec scopeStack = new Vec();
- static class ScopeInfo {
- int base;
- int end;
- int newScopeInsn;
- Hash mapping = new Hash();
- }
- Hash globalCache = new Hash();
- JS scopeKey(String name) {
- if(globalCache.get(name) != null) return null;
- for(int i=scopeStack.size()-1;i>=0;i--) {
- JS key = (JS)((ScopeInfo) scopeStack.elementAt(i)).mapping.get(name);
- if(key != null) return key;
- }
- globalCache.put(name,Boolean.TRUE);
- return null;
- }
- void scopeDeclare(String name) throws IOException {
- ScopeInfo si = (ScopeInfo) scopeStack.lastElement();
- if(si.mapping.get(name) != null) throw pe("" + name + " already declared in this scope");
- si.mapping.put(name,JS.N(si.end++));
- globalCache.put(name,null);
- }
- void scopePush(JSFunction b) {
- ScopeInfo prev = (ScopeInfo) scopeStack.lastElement();
- ScopeInfo si = new ScopeInfo();
- si.base = prev.end;
- si.end = si.base;
- si.newScopeInsn = b.size;
- scopeStack.push(si);
- b.add(parserLine, NEWSCOPE);
- }
- void scopePop(JSFunction b) {
- ScopeInfo si = (ScopeInfo) scopeStack.pop();
- b.add(parserLine, OLDSCOPE);
- b.set(si.newScopeInsn,JS.N((si.base<<16)|((si.end-si.base)<<0)));
- }
-
-
- // Parsing Logic /////////////////////////////////////////////////////////
-
- /** parse and compile a function */
- public static JSFunction fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
- JSFunction ret = new JSFunction(sourceName, firstLine, null);
- if (sourceCode == null) return ret;
- Parser p = new Parser(sourceCode, sourceName, firstLine);
- p.scopeStack.setSize(0);
- p.scopeStack.push(new ScopeInfo());
- p.scopePush(ret);
- while(true) {
- //int s = ret.size;
- if(p.peekToken() == -1) break; // FIXME: Check this logic one more time
- p.parseStatement(ret, null);
- //if (s == ret.size) break;
- }
- p.scopePop(ret);
- if(p.scopeStack.size() != 1) throw new Error("scopeStack height mismatch");
- ret.add(-1, LITERAL, null);
- ret.add(-1, RETURN);
- return ret;
- }
-
- /** gets a token and throws an exception if it is not <tt>code</tt> */
- private void consume(int code) throws IOException {
- if (getToken() != code) {
- if(code == NAME) switch(op) {
- case RETURN: case TYPEOF: case BREAK: case CONTINUE: case TRY: case THROW:
- case ASSERT: case NULL: case TRUE: case FALSE: case IN: case IF: case ELSE:
- case SWITCH: case CASE: case DEFAULT: case WHILE: case VAR: case WITH:
- case CATCH: case FINALLY:
- throw pe("Bad variable name; '" + codeToString[op].toLowerCase() + "' is a javascript keyword");
- }
- throw pe("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op]));
- }
- }
-
- /**
- * Parse the largest possible expression containing no operators
- * of precedence below <tt>minPrecedence</tt> and append the
- * bytecodes for that expression to <tt>appendTo</tt>; the
- * appended bytecodes MUST grow the stack by exactly one element.
- */
- private void startExpr(JSFunction appendTo, int minPrecedence) throws IOException {
- int saveParserLine = parserLine;
- _startExpr(appendTo, minPrecedence);
- parserLine = saveParserLine;
- }
- private void _startExpr(JSFunction appendTo, int minPrecedence) throws IOException {
- int tok = getToken();
- JSFunction b = appendTo;
-
- switch (tok) {
- case -1: throw pe("expected expression");
-
- // all of these simply push values onto the stack
- case NUMBER: b.add(parserLine, LITERAL, JS.N(number)); break;
- case STRING: b.add(parserLine, LITERAL, JSString.intern(string)); break;
- case NULL: b.add(parserLine, LITERAL, null); break;
- case TRUE: case FALSE: b.add(parserLine, LITERAL, tok == TRUE ? JS.T : JS.F); break;
-
- // (.foo) syntax
- case DOT: {
- consume(NAME);
- b.add(parserLine, GLOBALSCOPE);
- b.add(parserLine, GET, JS.S("",true));
- b.add(parserLine, LITERAL, JS.S(string,true));
- continueExprAfterAssignable(b,minPrecedence,null);
- break;
- }
-
- case LB: {
- b.add(parserLine, ARRAY, JS.ZERO); // push an array onto the stack
- int size0 = b.size;
- int i = 0;
- if (peekToken() != RB)
- while(true) { // iterate over the initialization values
- b.add(parserLine, LITERAL, JS.N(i++)); // push the index in the array to place it into
- if (peekToken() == COMMA || peekToken() == RB)
- b.add(parserLine, LITERAL, null); // for stuff like [1,,2,]
- else
- startExpr(b, NO_COMMA); // push the value onto the stack
- b.add(parserLine, PUT); // put it into the array
- b.add(parserLine, POP); // discard the value remaining on the stack
- if (peekToken() == RB) break;
- consume(COMMA);
- }
- b.set(size0 - 1, JS.N(i)); // back at the ARRAY instruction, write the size of the array
- consume(RB);
- break;
- }
- case SUB: case ADD: {
- if(peekToken() == NUMBER) { // literal
- consume(NUMBER);
- b.add(parserLine, LITERAL, JS.N(number.doubleValue() * (tok == SUB ? -1 : 1)));
- } else { // unary +/- operator
- if(tok == SUB) b.add(parserLine, LITERAL, JS.ZERO);
- // BITNOT has the same precedence as the unary +/- operators
- startExpr(b,precedence[BITNOT]);
- if(tok == ADD) b.add(parserLine, LITERAL, JS.ZERO); // HACK to force expr into a numeric context
- b.add(parserLine, SUB);
- }
- break;
- }
- case LP: { // grouping (not calling)
- startExpr(b, -1);
- consume(RP);
- break;
- }
- case INC: case DEC: { // prefix (not postfix)
- startExpr(b, precedence[tok]);
- int prev = b.size - 1;
- boolean sg = b.get(prev) == SCOPEGET;
- if (b.get(prev) == GET && b.getArg(prev) != null)
- b.set(prev, LITERAL, b.getArg(prev));
- else if(b.get(prev) == GET)
- b.pop();
- else if(!sg)
- throw pe("prefixed increment/decrement can only be performed on a valid assignment target");
- if(!sg) b.add(parserLine, GET_PRESERVE, Boolean.TRUE);
- b.add(parserLine, LITERAL, JS.N(1));
- b.add(parserLine, tok == INC ? ADD : SUB, JS.N(2));
- if(sg) {
- b.add(parserLine, SCOPEPUT, b.getArg(prev));
- } else {
- b.add(parserLine, PUT, null);
- b.add(parserLine, SWAP, null);
- b.add(parserLine, POP, null);
- }
- break;
- }
- case BANG: case BITNOT: case TYPEOF: {
- startExpr(b, precedence[tok]);
- b.add(parserLine, tok);
- break;
- }
- case LC: { // object constructor
- b.add(parserLine, OBJECT, null); // put an object on the stack
- if (peekToken() != RC)
- while(true) {
- if (peekToken() != NAME && peekToken() != STRING)
- throw pe("expected NAME or STRING");
- getToken();
- b.add(parserLine, LITERAL, JSString.intern(string)); // grab the key
- consume(COLON);
- startExpr(b, NO_COMMA); // grab the value
- b.add(parserLine, PUT); // put the value into the object
- b.add(parserLine, POP); // discard the remaining value
- if (peekToken() == RC) break;
- consume(COMMA);
- if (peekToken() == RC) break; // we permit {,,} -- I'm not sure if ECMA does
- }
- consume(RC);
- break;
- }
- case NAME: {
- JS varKey = scopeKey(string);
- if(varKey == null) {
- b.add(parserLine, GLOBALSCOPE);
- b.add(parserLine, LITERAL, JSString.intern(string));
- }
- continueExprAfterAssignable(b,minPrecedence,varKey);
- break;
- }
- case CASCADE: {
- if(peekToken() == ASSIGN) {
- consume(ASSIGN);
- startExpr(b, precedence[ASSIGN]);
- b.add(parserLine, CASCADE, JS.T);
- } else {
- b.add(parserLine, CASCADE, JS.F);
- }
- break;
- }
-
- case FUNCTION: {
- consume(LP);
- int numArgs = 0;
- JSFunction b2 = new JSFunction(sourceName, parserLine, null);
- b.add(parserLine, NEWFUNCTION, b2);
-
- // function prelude; arguments array is already on the stack
- scopePush(b2);
- scopeDeclare("arguments");
- b2.add(parserLine, SCOPEPUT,scopeKey("arguments"));
-
- while(peekToken() != RP) { // run through the list of argument names
- numArgs++;
- if (peekToken() == NAME) {
- consume(NAME); // a named argument
-
- b2.add(parserLine, DUP); // dup the args array
- b2.add(parserLine, GET, JS.N(numArgs - 1)); // retrieve it from the arguments array
- scopeDeclare(string);
- b2.add(parserLine, SCOPEPUT, scopeKey(string));
- b2.add(parserLine, POP);
- }
- if (peekToken() == RP) break;
- consume(COMMA);
- }
- consume(RP);
-
- b2.numFormalArgs = numArgs;
- b2.add(parserLine, POP); // pop off the arguments array
-
- if(peekToken() != LC)
- throw pe("JSFunctions must have a block surrounded by curly brackets");
-
- parseBlock(b2, null); // the function body
-
- scopePop(b2);
- b2.add(parserLine, LITERAL, null); // in case we "fall out the bottom", return NULL
- b2.add(parserLine, RETURN);
-
- break;
- }
- default: throw pe("expected expression, found " + codeToString[tok] + ", which cannot start an expression");
- }
-
- // attempt to continue the expression
- continueExpr(b, minPrecedence);
- }
- /*
- private Grammar parseGrammar(Grammar g) throws IOException {
- int tok = getToken();
- if (g != null)
- switch(tok) {
- case BITOR: return new Grammar.Alternative(g, parseGrammar(null));
- case ADD: return parseGrammar(new Grammar.Repetition(g, 1, Integer.MAX_VALUE));
- case MUL: return parseGrammar(new Grammar.Repetition(g, 0, Integer.MAX_VALUE));
- case HOOK: return parseGrammar(new Grammar.Repetition(g, 0, 1));
- }
- Grammar g0 = null;
- switch(tok) {
- //case NUMBER: g0 = new Grammar.Literal(number); break;
- case NAME: g0 = new Grammar.Reference(string); break;
- case STRING:
- g0 = new Grammar.Literal(string);
- if (peekToken() == DOT) {
- String old = string;
- consume(DOT);
- consume(DOT);
- consume(STRING);
- if (old.length() != 1 || string.length() != 1) throw pe("literal ranges must be single-char strings");
- g0 = new Grammar.Range(old.charAt(0), string.charAt(0));
- }
- break;
- case LP: g0 = parseGrammar(null); consume(RP); break;
- default: pushBackToken(); return g;
- }
- if (g == null) return parseGrammar(g0);
- return parseGrammar(new Grammar.Juxtaposition(g, g0));
- }
- */
- /**
- * Assuming that a complete assignable (lvalue) has just been
- * parsed and the object and key are on the stack,
- * <tt>continueExprAfterAssignable</tt> will attempt to parse an
- * expression that modifies the assignable. This method always
- * decreases the stack depth by exactly one element.
- */
- private void continueExprAfterAssignable(JSFunction b,int minPrecedence, JS varKey) throws IOException {
- int saveParserLine = parserLine;
- _continueExprAfterAssignable(b,minPrecedence,varKey);
- parserLine = saveParserLine;
- }
- private void _continueExprAfterAssignable(JSFunction b,int minPrecedence, JS varKey) throws IOException {
- if (b == null) throw new Error("got null b; this should never happen");
- int tok = getToken();
- if (minPrecedence != -1 && (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok])))
- // force the default case
- tok = -1;
- switch(tok) {
- /*
- case GRAMMAR: {
- b.add(parserLine, GET_PRESERVE);
- Grammar g = parseGrammar(null);
- if (peekToken() == LC) {
- g.action = new JSFunction(sourceName, parserLine, null);
- parseBlock((JSFunction)g.action);
- ((JSFunction)g.action).add(parserLine, LITERAL, null); // in case we "fall out the bottom", return NULL
- ((JSFunction)g.action).add(parserLine, RETURN);
- }
- b.add(parserLine, MAKE_GRAMMAR, g);
- b.add(parserLine, PUT);
- break;
- }
- */
- case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH:
- case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: case ASSIGN_ADD: case ASSIGN_SUB: case ADD_TRAP: case DEL_TRAP: {
- if (tok != ADD_TRAP && tok != DEL_TRAP)
- b.add(parserLine, varKey == null ? GET_PRESERVE : SCOPEGET, varKey);
-
- startExpr(b, precedence[tok]);
-
- if (tok != ADD_TRAP && tok != DEL_TRAP) {
- // tok-1 is always s/^ASSIGN_// (0 is BITOR, 1 is ASSIGN_BITOR, etc)
- b.add(parserLine, tok - 1, tok-1==ADD ? JS.N(2) : null);
- if(varKey == null) {
- b.add(parserLine, PUT);
- b.add(parserLine, SWAP);
- b.add(parserLine, POP);
- } else {
- b.add(parserLine, SCOPEPUT, varKey);
- }
- } else {
- if(varKey != null) throw pe("cannot place traps on local variables");
- b.add(parserLine, tok);
- }
- break;
- }
- case INC: case DEC: { // postfix
- if(varKey == null) {
- b.add(parserLine, GET_PRESERVE, Boolean.TRUE);
- b.add(parserLine, LITERAL, JS.N(1));
- b.add(parserLine, tok == INC ? ADD : SUB, JS.N(2));
- b.add(parserLine, PUT, null);
- b.add(parserLine, SWAP, null);
- b.add(parserLine, POP, null);
- b.add(parserLine, LITERAL, JS.N(1));
- b.add(parserLine, tok == INC ? SUB : ADD, JS.N(2)); // undo what we just did, since this is postfix
- } else {
- b.add(parserLine, SCOPEGET, varKey);
- b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, JS.ONE);
- b.add(parserLine, tok == INC ? ADD : SUB, JS.N(2));
- b.add(parserLine, SCOPEPUT, varKey);
- }
- break;
- }
- case ASSIGN: {
- startExpr(b, precedence[tok]);
- if(varKey == null) {
- b.add(parserLine, PUT);
- b.add(parserLine, SWAP);
- b.add(parserLine, POP);
- } else {
- b.add(parserLine, SCOPEPUT, varKey);
- }
- break;
- }
- case LP: {
- // Method calls are implemented by doing a GET_PRESERVE
- // first. If the object supports method calls, it will
- // return JS.METHOD
- b.add(parserLine, varKey == null ? GET_PRESERVE : SCOPEGET, varKey);
- int n = parseArgs(b);
- b.add(parserLine, varKey == null ? CALLMETHOD : CALL, JS.N(n));
- break;
- }
- default: {
- pushBackToken();
- if(varKey != null)
- b.add(parserLine, SCOPEGET, varKey);
- else if(b.get(b.size-1) == LITERAL && b.getArg(b.size-1) != null)
- b.set(b.size-1,GET,b.getArg(b.size-1));
- else
- b.add(parserLine, GET);
- return;
- }
- }
- }
-
-
- /**
- * Assuming that a complete expression has just been parsed,
- * <tt>continueExpr</tt> will attempt to extend this expression by
- * parsing additional tokens and appending additional bytecodes.
- *
- * No operators with precedence less than <tt>minPrecedence</tt>
- * will be parsed.
- *
- * If any bytecodes are appended, they will not alter the stack
- * depth.
- */
- private void continueExpr(JSFunction b, int minPrecedence) throws IOException {
- int saveParserLine = parserLine;
- _continueExpr(b, minPrecedence);
- parserLine = saveParserLine;
- }
- private void _continueExpr(JSFunction b, int minPrecedence) throws IOException {
- if (b == null) throw new Error("got null b; this should never happen");
- int tok = getToken();
- if (tok == -1) return;
- if (minPrecedence != -1 && (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok]))) {
- pushBackToken();
- return;
- }
-
- switch (tok) {
- case LP: { // invocation (not grouping)
- int n = parseArgs(b);
- b.add(parserLine, CALL, JS.N(n));
- break;
- }
- case BITOR: case BITXOR: case BITAND: case SHEQ: case SHNE: case LSH:
- case RSH: case URSH: case MUL: case DIV: case MOD:
- case GT: case GE: case EQ: case NE: case LT: case LE: case SUB: {
- startExpr(b, precedence[tok]);
- b.add(parserLine, tok);
- break;
- }
- case ADD: {
- int count=1;
- int nextTok;
- do {
- startExpr(b,precedence[tok]);
- count++;
- nextTok = getToken();
- } while(nextTok == tok);
- pushBackToken();
- b.add(parserLine, tok, JS.N(count));
- break;
- }
- case OR: case AND: {
- b.add(parserLine, tok == AND ? JSFunction.JF : JSFunction.JT, JS.ZERO); // test to see if we can short-circuit
- int size = b.size;
- startExpr(b, precedence[tok]); // otherwise check the second value
- b.add(parserLine, JMP, JS.N(2)); // leave the second value on the stack and jump to the end
- b.add(parserLine, LITERAL, tok == AND ?
- JS.B(false) : JS.B(true)); // target of the short-circuit jump is here
- b.set(size - 1, JS.N(b.size - size)); // write the target of the short-circuit jump
- break;
- }
- case DOT: {
- // support foo..bar syntax for foo[""].bar
- if (peekToken() == DOT) {
- string = "";
- } else {
- consume(NAME);
- }
- b.add(parserLine, LITERAL, JSString.intern(string));
- continueExprAfterAssignable(b,minPrecedence,null);
- break;
- }
- case LB: { // subscripting (not array constructor)
- startExpr(b, -1);
- consume(RB);
- continueExprAfterAssignable(b,minPrecedence,null);
- break;
- }
- case HOOK: {
- b.add(parserLine, JF, JS.ZERO); // jump to the if-false expression
- int size = b.size;
- startExpr(b, minPrecedence); // write the if-true expression
- b.add(parserLine, JMP, JS.ZERO); // if true, jump *over* the if-false expression
- b.set(size - 1, JS.N(b.size - size + 1)); // now we know where the target of the jump is
- consume(COLON);
- size = b.size;
- startExpr(b, minPrecedence); // write the if-false expression
- b.set(size - 1, JS.N(b.size - size + 1)); // this is the end; jump to here
- break;
- }
- case COMMA: {
- // pop the result of the previous expression, it is ignored
- b.add(parserLine,POP);
- startExpr(b,-1);
- break;
- }
- default: {
- pushBackToken();
- return;
- }
- }
-
- continueExpr(b, minPrecedence); // try to continue the expression
- }
-
- // parse a set of comma separated function arguments, assume LP has already been consumed
- private int parseArgs(JSFunction b) throws IOException {
- int i = 0;
- while(peekToken() != RP) {
- i++;
- if (peekToken() != COMMA) {
- startExpr(b, NO_COMMA);
- if (peekToken() == RP) break;
- }
- consume(COMMA);
- }
- consume(RP);
- return i;
- }
-
- /** Parse a block of statements which must be surrounded by LC..RC. */
- void parseBlock(JSFunction b) throws IOException { parseBlock(b, null); }
- void parseBlock(JSFunction b, String label) throws IOException {
- int saveParserLine = parserLine;
- _parseBlock(b, label);
- parserLine = saveParserLine;
- }
- void _parseBlock(JSFunction b, String label) throws IOException {
- if (peekToken() == -1) return;
- else if (peekToken() != LC) parseStatement(b, null);
- else {
- consume(LC);
- while(peekToken() != RC && peekToken() != -1) parseStatement(b, null);
- consume(RC);
- }
- }
-
- /** Parse a single statement, consuming the RC or SEMI which terminates it. */
- void parseStatement(JSFunction b, String label) throws IOException {
- int saveParserLine = parserLine;
- _parseStatement(b, label);
- parserLine = saveParserLine;
- }
- void _parseStatement(JSFunction b, String label) throws IOException {
- int tok = peekToken();
- if (tok == -1) return;
- switch(tok = getToken()) {
-
- case THROW: case ASSERT: case RETURN: {
- if (tok == RETURN && peekToken() == SEMI)
- b.add(parserLine, LITERAL, null);
- else
- startExpr(b, -1);
- b.add(parserLine, tok);
- consume(SEMI);
- break;
- }
- case BREAK: case CONTINUE: {
- if (peekToken() == NAME) consume(NAME);
- b.add(parserLine, tok, string);
- consume(SEMI);
- break;
- }
- case VAR: {
- while(true) {
- consume(NAME);
- String var = string;
- scopeDeclare(var);
- if (peekToken() == ASSIGN) { // if there is an '=' after the variable name
- consume(ASSIGN);
- startExpr(b, NO_COMMA);
- b.add(parserLine, SCOPEPUT, scopeKey(var)); // assign it
- b.add(parserLine, POP); // clean the stack
- }
- if (peekToken() != COMMA) break;
- consume(COMMA);
- }
- if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
- break;
- }
- case IF: {
- consume(LP);
- startExpr(b, -1);
- consume(RP);
-
- b.add(parserLine, JF, JS.ZERO); // if false, jump to the else-block
- int size = b.size;
- parseStatement(b, null);
-
- if (peekToken() == ELSE) {
- consume(ELSE);
- b.add(parserLine, JMP, JS.ZERO); // if we took the true-block, jump over the else-block
- b.set(size - 1, JS.N(b.size - size + 1));
- size = b.size;
- parseStatement(b, null);
- }
- b.set(size - 1, JS.N(b.size - size + 1)); // regardless of which branch we took, b[size] needs to point here
- break;
- }
- case WHILE: {
- consume(LP);
- if (label != null) b.add(parserLine, LABEL, label);
- b.add(parserLine, LOOP);
- int size = b.size;
- b.add(parserLine, POP); // discard the first-iteration indicator
- startExpr(b, -1);
- b.add(parserLine, JT, JS.N(2)); // if the while() clause is true, jump over the BREAK
- b.add(parserLine, BREAK);
- consume(RP);
- parseStatement(b, null);
- b.add(parserLine, CONTINUE); // if we fall out of the end, definately continue
- b.set(size - 1, JS.N(b.size - size + 1)); // end of the loop
- break;
- }
- case SWITCH: {
- consume(LP);
- if (label != null) b.add(parserLine, LABEL, label);
- b.add(parserLine, LOOP);
- int size0 = b.size;
- startExpr(b, -1);
- consume(RP);
- consume(LC);
- while(true)
- if (peekToken() == CASE) { // we compile CASE statements like a bunch of if..else's
- consume(CASE);
- b.add(parserLine, DUP); // duplicate the switch() value; we'll consume one copy
- startExpr(b, -1);
- consume(COLON);
- b.add(parserLine, EQ); // check if we should do this case-block
- b.add(parserLine, JF, JS.ZERO); // if not, jump to the next one
- int size = b.size;
- while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) parseStatement(b, null);
- b.set(size - 1, JS.N(1 + b.size - size));
- } else if (peekToken() == DEFAULT) {
- consume(DEFAULT);
- consume(COLON);
- while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) parseStatement(b, null);
- } else if (peekToken() == RC) {
- consume(RC);
- b.add(parserLine, BREAK); // break out of the loop if we 'fall through'
- break;
- } else {
- throw pe("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]);
- }
- b.set(size0 - 1, JS.N(b.size - size0 + 1)); // end of the loop
- break;
- }
-
- case DO: {
- if (label != null) b.add(parserLine, LABEL, label);
- b.add(parserLine, LOOP);
- int size = b.size;
- parseStatement(b, null);
- consume(WHILE);
- consume(LP);
- startExpr(b, -1);
- b.add(parserLine, JT, JS.N(2)); // check the while() clause; jump over the BREAK if true
- b.add(parserLine, BREAK);
- b.add(parserLine, CONTINUE);
- consume(RP);
- consume(SEMI);
- b.set(size - 1, JS.N(b.size - size + 1)); // end of the loop; write this location to the LOOP instruction
- break;
- }
-
- case TRY: {
- b.add(parserLine, TRY); // try bytecode causes a TryMarker to be pushed
- int tryInsn = b.size - 1;
- // parse the expression to be TRYed
- parseStatement(b, null);
- // pop the try marker. this is pushed when the TRY bytecode is executed
- b.add(parserLine, POP);
- // jump forward to the end of the catch block, start of the finally block
- b.add(parserLine, JMP);
- int successJMPInsn = b.size - 1;
-
- if (peekToken() != CATCH && peekToken() != FINALLY)
- throw pe("try without catch or finally");
-
- int catchJMPDistance = -1;
- if (peekToken() == CATCH) {
- Vec catchEnds = new Vec();
- boolean catchAll = false;
-
- catchJMPDistance = b.size - tryInsn;
-
- while(peekToken() == CATCH && !catchAll) {
- String exceptionVar;
- getToken();
- consume(LP);
- consume(NAME);
- exceptionVar = string;
- int[] writebacks = new int[] { -1, -1, -1 };
- if (peekToken() != RP) {
- // extended Ibex catch block: catch(e faultCode "foo.bar.baz")
- consume(NAME);
- b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, JSString.intern(string));
- b.add(parserLine, GET);
- b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, null);
- b.add(parserLine, EQ);
- b.add(parserLine, JT);
- writebacks[0] = b.size - 1;
- if (peekToken() == STRING) {
- consume(STRING);
- b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, string);
- b.add(parserLine, LT);
- b.add(parserLine, JT);
- writebacks[1] = b.size - 1;
- b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, string + "/"); // (slash is ASCII after dot)
- b.add(parserLine, GE);
- b.add(parserLine, JT);
- writebacks[2] = b.size - 1;
- } else {
- consume(NUMBER);
- b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, number);
- b.add(parserLine, EQ);
- b.add(parserLine, JF);
- writebacks[1] = b.size - 1;
- }
- b.add(parserLine, POP); // pop the element thats on the stack from the compare
- } else {
- catchAll = true;
- }
- consume(RP);
- // the exception is on top of the stack; put it to the chosen name
- scopePush(b);
- scopeDeclare(exceptionVar);
- b.add(parserLine, SCOPEPUT, scopeKey(exceptionVar));
- b.add(parserLine, POP);
- parseBlock(b, null);
- scopePop(b);
-
- b.add(parserLine, JMP);
- catchEnds.addElement(new Integer(b.size-1));
-
- for(int i=0; i<3; i++) if (writebacks[i] != -1) b.set(writebacks[i], JS.N(b.size-writebacks[i]));
- b.add(parserLine, POP); // pop the element thats on the stack from the compare
- }
-
- if(!catchAll)
- b.add(parserLine, THROW);
-
- for(int i=0;i<catchEnds.size();i++) {
- int n = ((Integer)catchEnds.elementAt(i)).intValue();
- b.set(n, JS.N(b.size-n));
- }
-
- // pop the try and catch markers
- b.add(parserLine,POP);
- b.add(parserLine,POP);
- }
-
- // jump here if no exception was thrown
- b.set(successJMPInsn, JS.N(b.size - successJMPInsn));
-
- int finallyJMPDistance = -1;
- if (peekToken() == FINALLY) {
- b.add(parserLine, LITERAL, null); // null FinallyData
- finallyJMPDistance = b.size - tryInsn;
- consume(FINALLY);
- parseStatement(b, null);
- b.add(parserLine,FINALLY_DONE);
- }
-
- // setup the TRY arguments
- b.set(tryInsn, new int[] { catchJMPDistance, finallyJMPDistance });
-
- break;
- }
-
- case FOR: {
- consume(LP);
-
- tok = getToken();
- boolean hadVar = false; // if it's a for..in, we ignore the VAR
- if (tok == VAR) { hadVar = true; tok = getToken(); }
- String varName = string;
- boolean forIn = peekToken() == IN; // determine if this is a for..in loop or not
- pushBackToken(tok, varName);
-
- if (forIn) {
- consume(NAME);
- consume(IN);
- startExpr(b,-1);
- consume(RP);
-
- b.add(parserLine, PUSHKEYS);
-
- int size = b.size;
- b.add(parserLine, LOOP);
- b.add(parserLine, POP);
-
- b.add(parserLine,SWAP); // get the keys enumeration object on top
- b.add(parserLine,DUP);
- b.add(parserLine,GET,JS.S("hasMoreElements"));
- int size2 = b.size;
- b.add(parserLine,JT);
- b.add(parserLine,SWAP);
- b.add(parserLine,BREAK);
- b.set(size2, JS.N(b.size - size2));
- b.add(parserLine,DUP);
- b.add(parserLine,GET,JS.S("nextElement"));
-
- scopePush(b);
-
- if(hadVar) scopeDeclare(varName);
- JS varKey = scopeKey(varName);
-
- if(varKey == null) {
- b.add(parserLine,GLOBALSCOPE);
- b.add(parserLine,SWAP);
- b.add(parserLine, LITERAL, JSString.intern(varName));
- b.add(parserLine,SWAP);
- b.add(parserLine,PUT);
- b.add(parserLine,POP);
- } else {
- b.add(parserLine, SCOPEPUT, varKey);
- }
- b.add(parserLine,POP); // pop the put'ed value
- b.add(parserLine,SWAP); // put CallMarker back into place
-
- parseStatement(b, null);
-
- scopePop(b);
- b.add(parserLine, CONTINUE);
- // jump here on break
- b.set(size, JS.N(b.size - size));
-
- b.add(parserLine, POP);
- } else {
- if (hadVar) pushBackToken(VAR, null); // yeah, this actually matters
- scopePush(b); // grab a fresh scope
-
- parseStatement(b, null); // initializer
- JSFunction e2 = // we need to put the incrementor before the test
- new JSFunction(sourceName, parserLine, null); // so we save the test here
- if (peekToken() != SEMI)
- startExpr(e2, -1);
- else
- e2.add(parserLine, JSFunction.LITERAL, JS.T); // handle the for(foo;;foo) case
- consume(SEMI);
- if (label != null) b.add(parserLine, LABEL, label);
- b.add(parserLine, LOOP);
- int size2 = b.size;
-
- b.add(parserLine, JT, JS.ZERO); // if we're on the first iteration, jump over the incrementor
- int size = b.size;
- if (peekToken() != RP) { // do the increment thing
- startExpr(b, -1);
- b.add(parserLine, POP);
- }
- b.set(size - 1, JS.N(b.size - size + 1));
- consume(RP);
-
- b.paste(e2); // ok, *now* test if we're done yet
- b.add(parserLine, JT, JS.N(2)); // break out if we don't meet the test
- b.add(parserLine, BREAK);
- parseStatement(b, null);
- b.add(parserLine, CONTINUE); // if we fall out the bottom, CONTINUE
- b.set(size2 - 1, JS.N(b.size - size2 + 1)); // end of the loop
-
- scopePop(b); // get our scope back
- }
- break;
- }
-
- case NAME: { // either a label or an identifier; this is the one place we're not LL(1)
- String possiblyTheLabel = string;
- if (peekToken() == COLON) { // label
- consume(COLON);
- parseStatement(b, possiblyTheLabel);
- break;
- } else { // expression
- pushBackToken(NAME, possiblyTheLabel);
- startExpr(b, -1);
- b.add(parserLine, POP);
- if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
- break;
- }
- }
-
- case SEMI: return; // yep, the null statement is valid
-
- case LC: { // blocks are statements too
- pushBackToken();
- scopePush(b);
- parseBlock(b, label);
- scopePop(b);
- break;
- }
-
- default: { // hope that it's an expression
- pushBackToken();
- startExpr(b, -1);
- b.add(parserLine, POP);
- if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
- break;
- }
- }
- }
-
-
- // ParserException //////////////////////////////////////////////////////////////////////
- private IOException pe(String s) { return new IOException(sourceName + ":" + line + " " + s); }
-
-}
-
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.util.*;
-import java.io.*;
-
-// FEATURE: Update for new api
-
-/** A JS interface to a Java '.properties' file; very crude */
-public class PropertyFile extends JS {
-
- /*private final Properties p = new Properties();
- private final Hash cache = new Hash(10, 3);
- private File f;
-
- private class Minion extends JS {
- private final String prefix;
- Minion(String prefix) { this.prefix = prefix; }
- public Number coerceToNumber() { return N(coerceToString()); }
- public Boolean coerceToBoolean() { return B(coerceToString().equals("true")); }
- public String coerceToString() { return (String)p.get(prefix.substring(0, prefix.length() - 1)); }
- public Enumeration keys() throws JSExn { throw new JSExn("PropertyFile.keys() not supported"); }
- public Object get(Object key) throws JSExn {
- if (toString(key).equals("")) return coerceToString();
- Object ret = p.get(prefix + escape(toString(key)));
- if (ret != null) return ret;
- return new Minion(prefix + escape(toString(key)) + ".");
- }
- public void put(Object key, Object val) throws JSExn {
- try {
- p.put(prefix + (prefix.equals("") ? "" : ".") + escape(toString(key)), toString(val));
- File fnew = new File(f.getName() + ".new");
- FileOutputStream fo = new FileOutputStream(fnew);
- p.save(fo, "");
- fo.close();
- fnew.renameTo(f);
- f = fnew;
- } catch (IOException e) { throw new JSExn(e); }
- }
- }
-
- public static String escape(String s) {
- return s.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\.", "\\\\.").replaceAll("=","\\\\="); }
- public PropertyFile(File f) throws IOException { this.f = f; this.p.load(new FileInputStream(f)); }
- public void put(Object key, Object val) throws JSExn { new Minion("").put(key, val); }
- public Enumeration keys() throws JSExn { return new Minion("").keys(); }
- public Object get(Object key) throws JSExn {
- Object ret = p.get(toString(key));
- if (ret != null) return ret;
- return new Minion(escape(toString(key)));
- }*/
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import java.io.*;
-import java.util.zip.*;
-import org.ibex.util.*;
-import org.ibex.plat.*;
-import org.ibex.net.*;
-
-/**
- * Essentiall an InputStream "factory". You can repeatedly ask a
- * Stream for an InputStream, and each InputStream you get back will
- * be totally independent of the others (ie separate stream position
- * and state) although they draw from the same data source.
- */
-// FEATURE: Should this be in org.ibex.js?
-public abstract class Stream extends JS implements JS.Cloneable {
-
- // Public Interface //////////////////////////////////////////////////////////////////////////////
-
- /*public static InputStream getInputStream(JS js) throws IOException { return ((Stream)js.unclone()).getInputStream();}*/
- public static class NotCacheableException extends Exception { }
-
- private Cache getCache = new Cache(100);
- public abstract JS _get(String key);
- public final JS get(JS key) throws JSExn {
- JS ret = (JS) getCache.get(key);
- if (ret == null) getCache.put(key, ret = _get(JS.toString(key)));
- return ret;
- }
-
- // Private Interface //////////////////////////////////////////////////////////////////////////////
-
- static String getCacheKey(JS s) throws NotCacheableException {
- if(s instanceof Stream) return ((Stream)s).getCacheKey();
- throw new NotCacheableException();
- }
-
- public abstract InputStream getInputStream() throws IOException;
- protected String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); }
-
- /** HTTP or HTTPS resource */
- // FEATURE: Only instansiate only ibex.net.HTTP, share with all substreams
- public static class HTTP extends Stream {
- private String url;
- public HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; }
- public JS _get(String key) { return new HTTP(url + "/" + key); }
- public String getCacheKey(Vec path) throws NotCacheableException { return url; }
- public InputStream getInputStream() throws IOException { return new org.ibex.net.HTTP(url).GET(); }
- }
-
- /** byte arrays */
- public static class ByteArray extends Stream {
- private byte[] bytes;
- private String cacheKey;
- public ByteArray(byte[] bytes, String cacheKey) { this.bytes = bytes; this.cacheKey = cacheKey; }
- public String getCacheKey() throws NotCacheableException {
- if (cacheKey == null) throw new NotCacheableException(); return cacheKey; }
- public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(bytes); }
- public JS _get(String key) { return null; }
- }
-
- /** a file */
- public static class File extends Stream {
- private String path;
- public File(String path) { this.path = path; }
- public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); /* already on disk */ }
- public InputStream getInputStream() throws IOException { return new FileInputStream(path); }
- public JS _get(String key) { return new File(path + java.io.File.separatorChar + key); }
- }
-
- /** "unwrap" a Zip archive */
- public static class Zip extends Stream {
- private JS parent;
- private String path;
- public Zip(JS parent) { this(parent, null); }
- public Zip(JS parent, String path) {
- while(path != null && path.startsWith("/")) path = path.substring(1);
- this.parent = parent;
- this.path = path;
- }
- public String getCacheKey() throws NotCacheableException { return getCacheKey(parent) + "!zip:"; }
- public JS _get(String key) { return new Zip(parent, path==null?key:path+'/'+key); }
- public InputStream getInputStream() throws IOException {
- InputStream pis = parent.getInputStream();
- ZipInputStream zis = new ZipInputStream(pis);
- ZipEntry ze = zis.getNextEntry();
- while(ze != null && !ze.getName().equals(path)) ze = zis.getNextEntry();
- if (ze == null) throw new IOException("requested file (" + path + ") not found in archive");
- return new KnownLength.KnownLengthInputStream(zis, (int)ze.getSize());
- }
- }
-
- /** "unwrap" a Cab archive */
- public static class Cab extends Stream {
- private JS parent;
- private String path;
- public Cab(JS parent) { this(parent, null); }
- public Cab(JS parent, String path) { this.parent = parent; this.path = path; }
- public String getCacheKey() throws NotCacheableException { return getCacheKey(parent) + "!cab:"; }
- public JS _get(String key) { return new Cab(parent, path==null?key:path+'/'+key); }
- public InputStream getInputStream() throws IOException { return new MSPack(parent.getInputStream()).getInputStream(path); }
- }
-
- /** the Builtin resource */
- public static class Builtin extends Stream {
- public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); }
- public InputStream getInputStream() throws IOException { return Platform.getBuiltinInputStream(); }
- public JS _get(String key) { return null; }
- }
-
- /** shadow resource which replaces the graft */
- public static class ProgressWatcher extends Stream {
- final JS watchee;
- JS callback;
- public ProgressWatcher(JS watchee, JS callback) { this.watchee = watchee; this.callback = callback; }
- public String getCacheKey() throws NotCacheableException { return getCacheKey(watchee); }
- public InputStream getInputStream() throws IOException {
- final InputStream is = watchee.getInputStream();
- return new FilterInputStream(is) {
- int bytesDownloaded = 0;
- public int read() throws IOException {
- int ret = super.read();
- if (ret != -1) bytesDownloaded++;
- return ret;
- }
- public int read(byte[] b, int off, int len) throws IOException {
- int ret = super.read(b, off, len);
- if (ret != 1) bytesDownloaded += ret;
- Scheduler.add(new Task() { public void perform() throws IOException, JSExn {
- callback.call(N(bytesDownloaded),
- N(is instanceof KnownLength ? ((KnownLength)is).getLength() : 0), null, null, 2);
- } });
- return ret;
- }
- };
- }
- public JS _get(String s) { return null; }
- }
-
- /** subclass from this if you want a CachedInputStream for each path */
- public static class CachedStream extends Stream {
- private JS parent;
- private boolean disk = false;
- private String key;
- private String s;
- public String getCacheKey() throws NotCacheableException { return key; }
- CachedInputStream cis = null;
- public CachedStream(JS p, String s, boolean d) throws NotCacheableException {
- this.parent = p; this.s = s; this.disk = d; this.key = getCacheKey(p);
- }
- public InputStream getInputStream() throws IOException {
- if (cis != null) return cis.getInputStream();
- if (!disk) {
- cis = new CachedInputStream(parent.getInputStream());
- } else {
- // FEATURE: Move LocalStorage into org.ibex.js or move this out
- java.io.File f = org.ibex.core.LocalStorage.Cache.getCacheFileForKey(key);
- if (f.exists()) return new FileInputStream(f);
- cis = new CachedInputStream(parent.getInputStream(), f);
- }
- return cis.getInputStream();
- }
- public JS _get(String s) { return null; }
- }
-}
+++ /dev/null
-package org.ibex.js;
-
-import java.io.*;
-
-public class Test extends JS {
- static JS.UnpauseCallback up = null;
- static String action;
-
- public static void main(String[] args) throws Exception {
- if(args.length == 0) { System.err.println("Usage Test filename"); System.exit(1); }
- JS f = JS.fromReader(args[0],1,new FileReader(args[0]));
- System.out.println(((JSFunction)f).dump());
- JS s = new JS.O();
- s.put(JS.S("sys"),new Test());
- f = JS.cloneWithNewGlobalScope(f,s);
- //JS ret = f.call(null,null,null,null,0);
- Interpreter i = new Interpreter((JSFunction)f, true, new Interpreter.JSArgs(f));
- JS ret = i.resume();
- while(up != null) {
- JS.UnpauseCallback up = Test.up; Test.up = null;
- if("throw".equals(action)) ret = up.unpause(new JSExn("this was thrown to a paused context"));
- else if("bgget".equals(action)) ret = up.unpause(JS.S("I'm returning this from a get request"));
- else {
- System.out.println("got a background put " + action);
- ret = up.unpause();
- }
- }
- System.out.println("Script returned: " + JS.toString(ret));
- }
-
- public JS get(JS key) throws JSExn {
- if(!JS.isString(key)) return null;
- if("print".equals(JS.toString(key))) return METHOD;
- if("clone".equals(JS.toString(key))) return METHOD;
- if("firethis".equals(JS.toString(key))) return METHOD;
- if("bgget".equals(JS.toString(key))) {
- action = "bgget";
- try {
- up = JS.pause();
- } catch(NotPauseableException e) {
- throw new Error("should never happen");
- }
- return null;
- }
- return super.get(key);
- }
-
- public void put(JS key, JS val) throws JSExn {
- if("bgput".equals(JS.toString(key))) {
- action = JS.toString(val);
- try {
- up = JS.pause();
- } catch(NotPauseableException e) {
- throw new Error("should never happen");
- }
- return;
- }
- if("exit".equals(JS.toString(key))) {
- System.exit(JS.toInt(val));
- return;
- }
- super.put(key,val);
- }
-
- public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- if(!JS.isString(method)) return null;
- if("print".equals(JS.toString(method))) {
- System.out.println(JS.debugToString(a0));
- return null;
- }
- if("clone".equals(JS.toString(method))) return a0 == null ? null : a0.jsclone();
- if("firethis".equals(JS.toString(method))) {
- String action = JS.toString(a0);
- JS target = a1;
- JS key = a2;
- if(action.equals("get")) return a1.getAndTriggerTraps(key);
- else if(action.equals("put")) a1.putAndTriggerTraps(key,JS.S("some value"));
- else if(action.equals("trigger")) return target.justTriggerTraps(key,JS.S("some trigger value"));
- return null;
- }
- return null;
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-/** this class contains a <tt>public static final int</tt> for each valid token */
-interface Tokens {
-
- // Token Constants //////////////////////////////////////////////////////////
-
- // arithmetic operations; also valid as bytecodes
- public static final int BITOR = 0; // |
- public static final int ASSIGN_BITOR = 1; // |=
- public static final int BITXOR = 2; // ^
- public static final int ASSIGN_BITXOR = 3; // ^=
- public static final int BITAND = 4; // &
- public static final int ASSIGN_BITAND = 5; // &=
- public static final int LSH = 6; // <<
- public static final int ASSIGN_LSH = 7; // <<=
- public static final int RSH = 8; // >>
- public static final int ASSIGN_RSH = 9; // >>=
- public static final int URSH = 10; // >>>
- public static final int ASSIGN_URSH = 11; // >>>=
- public static final int ADD = 12; // +
- public static final int ASSIGN_ADD = 13; // +=
- public static final int SUB = 14; // -
- public static final int ASSIGN_SUB = 15; // -=
- public static final int MUL = 16; // *
- public static final int ASSIGN_MUL = 17; // *=
- public static final int DIV = 18; // /
- public static final int ASSIGN_DIV = 19; // /=
- public static final int MOD = 20; // %
- public static final int ASSIGN_MOD = 21; // %=
- public static final int BITNOT = 22; // ~
- public static final int ASSIGN_BITNOT = 23; // ~=
-
- // logical operations; also valid as bytecodes
- public static final int OR = 24; // ||
- public static final int AND = 25; // &&
- public static final int BANG = 26; // !
-
- // equality operations; also valid as bytecodes
- public static final int EQ = 27; // ==
- public static final int NE = 28; // !=
- public static final int LT = 29; // <
- public static final int LE = 30; // <=
- public static final int GT = 31; // >
- public static final int GE = 32; // >=
- public static final int SHEQ = 33; // ===
- public static final int SHNE = 34; // !==
-
- // other permissible bytecode tokens
- public static final int RETURN = 35; // return
- public static final int TYPEOF = 36; // typeof
- public static final int BREAK = 37; // break keyword
- public static final int CONTINUE = 38; // continue keyword
- public static final int TRY = 39; // try
- public static final int THROW = 40; // throw
- public static final int ASSERT = 41; // assert keyword
-
- public static final int NAME = 42; // *** identifiers ***
- public static final int NUMBER = 43; // *** numeric literals ***
- public static final int STRING = 44; // *** string literals ***
- public static final int NULL = 45; // null
- public static final int THIS = 46; // this
- public static final int FALSE = 47; // false
- public static final int TRUE = 48; // true
- public static final int IN = 49; // in
-
- public static final int SEMI = 50; // ;
- public static final int LB = 51; // [
- public static final int RB = 52; // ]
- public static final int LC = 53; // {
- public static final int RC = 54; // }
- public static final int LP = 55; // (
- public static final int RP = 56; // )
- public static final int COMMA = 57; // ,
- public static final int ASSIGN = 58; // =
- public static final int HOOK = 59; // ?
- public static final int COLON = 60; // :
- public static final int INC = 61; // ++
- public static final int DEC = 62; // --
- public static final int DOT = 63; // .
- public static final int FUNCTION = 64; // function
- public static final int IF = 65; // if keyword
- public static final int ELSE = 66; // else keyword
- public static final int SWITCH = 67; // switch keyword
- public static final int CASE = 68; // case keyword
- public static final int DEFAULT = 69; // default keyword
- public static final int WHILE = 70; // while keyword
- public static final int DO = 71; // do keyword
- public static final int FOR = 72; // for keyword
- public static final int VAR = 73; // var keyword
- public static final int WITH = 74; // with keyword
- public static final int CATCH = 75; // catch keyword
- public static final int FINALLY = 76; // finally keyword
- public static final int RESERVED = 77; // reserved keyword
- public static final int GRAMMAR = 78; // the grammar-definition operator (::=)
- public static final int ADD_TRAP = 79; // the add-trap operator (++=)
- public static final int DEL_TRAP = 80; // the del-trap operator (--=)
- public static final int CASCADE = 81; // cascade expression - arg==true for write cascade
-
- public static final int MAX_TOKEN = DEL_TRAP;
-
- public final static String[] codeToString = new String[] {
- "BITOR", "ASSIGN_BITOR", "BITXOR", "ASSIGN_BITXOR", "BITAND",
- "ASSIGN_BITAND", "LSH", "ASSIGN_LSH", "RSH", "ASSIGN_RSH",
- "URSH", "ASSIGN_URSH", "ADD", "ASSIGN_ADD", "SUB",
- "ASSIGN_SUB", "MUL", "ASSIGN_MUL", "DIV", "ASSIGN_DIV", "MOD",
- "ASSIGN_MOD", "BITNOT", "ASSIGN_BITNOT", "OR", "AND", "BANG",
- "EQ", "NE", "LT", "LE", "GT", "GE", "SHEQ", "SHNE", "RETURN",
- "TYPEOF", "BREAK", "CONTINUE", "TRY", "THROW", "ASSERT", "NAME",
- "NUMBER", "STRING", "NULL", "THIS", "FALSE", "TRUE", "IN",
- "SEMI", "LB", "RB", "LC", "RC", "LP", "RP", "COMMA", "ASSIGN",
- "HOOK", "COLON", "INC", "DEC", "DOT", "FUNCTION", "IF",
- "ELSE", "SWITCH", "CASE", "DEFAULT", "WHILE", "DO", "FOR",
- "VAR", "WITH", "CATCH", "FINALLY", "RESERVED", "GRAMMAR",
- "ADD_TRAP", "DEL_TRAP", "CASCADE"
- };
-
-}
-
-
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-/**
- * This class encapsulates a single trap placed on a given node. The
- * traps for a given property name on a given box are maintained as a
- * linked list stack, with the most recently placed trap at the head
- * of the list.
- */
-final class Trap {
-
- final JS target; ///< the box on which this trap was placed
- final JS key; ///< the property that the trap was placed on
-
- final JSFunction f; ///< the function for this trap
- Trap next; ///< the next trap down the trap stack
-
- Trap(JS b, JS n, JSFunction f, Trap nx) {
- target = b; key = n; this.f = f; this.next = nx;
- }
-
- boolean isReadTrap() { return f.numFormalArgs == 0; }
- boolean isWriteTrap() { return f.numFormalArgs != 0; }
- Trap readTrap() { Trap t = this; while(t!=null && t.isWriteTrap()) t = t.next; return t; }
- Trap writeTrap() { Trap t = this; while(t!=null && t.isReadTrap()) t = t.next; return t; }
- Trap nextReadTrap() { return next == null ? null : next.readTrap(); }
- Trap nextWriteTrap() { return next == null ? null : next.writeTrap(); }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.net;
-
-import java.net.*;
-import java.io.*;
-import java.util.*;
-import org.ibex.js.*;
-import org.ibex.util.*;
-import org.ibex.plat.*;
-import org.ibex.core.*;
-import org.ibex.crypto.*;
-
-/**
- * This object encapsulates a *single* HTTP connection. Multiple requests may be pipelined over a connection (thread-safe),
- * although any IOException encountered in a request will invalidate all later requests.
- */
-public class HTTP {
-
-
- // Public Methods ////////////////////////////////////////////////////////////////////////////////////////
-
- public HTTP(String url) { this(url, false); }
- public HTTP(String url, boolean skipResolveCheck) { originalUrl = url; this.skipResolveCheck = skipResolveCheck; }
-
- /** Performs an HTTP GET request */
- public InputStream GET() throws IOException { return makeRequest(null, null); }
-
- /** Performs an HTTP POST request; content is additional headers, blank line, and body */
- public InputStream POST(String contentType, String content) throws IOException { return makeRequest(contentType, content); }
-
- public static class HTTPException extends IOException { public HTTPException(String s) { super(s); } }
-
- public static HTTP stdio = new HTTP("stdio:");
-
-
- // Statics ///////////////////////////////////////////////////////////////////////////////////////////////
-
- static Hash resolvedHosts = new Hash(); ///< cache for resolveAndCheckIfFirewalled()
- private static Hash authCache = new Hash(); ///< cache of userInfo strings, keyed on originalUrl
-
-
- // Instance Data ///////////////////////////////////////////////////////////////////////////////////////////////
-
- final String originalUrl; ///< the URL as passed to the original constructor; this is never changed
- String url = null; ///< the URL to connect to; this is munged when the url is parsed */
- String host = null; ///< the host to connect to
- int port = -1; ///< the port to connect on
- boolean ssl = false; ///< true if SSL (HTTPS) should be used
- String path = null; ///< the path (URI) to retrieve on the server
- Socket sock = null; ///< the socket
- InputStream in = null; ///< the socket's inputstream
- String userInfo = null; ///< the username and password portions of the URL
- boolean firstRequest = true; ///< true iff this is the first request to be made on this socket
- boolean skipResolveCheck = false; ///< allowed to skip the resolve check when downloading PAC script
- boolean proxied = false; ///< true iff we're using a proxy
-
- /** this is null if the current request is the first request on
- * this HTTP connection; otherwise it is a Semaphore which will be
- * released once the request ahead of us has recieved its response
- */
- Semaphore okToRecieve = null;
-
- /**
- * This method isn't synchronized; however, only one thread can be in the inner synchronized block at a time, and the rest of
- * the method is protected by in-order one-at-a-time semaphore lock-steps
- */
- private InputStream makeRequest(String contentType, String content) throws IOException {
-
- // Step 1: send the request and establish a semaphore to stop any requests that pipeline after us
- Semaphore blockOn = null;
- Semaphore releaseMe = null;
- synchronized(this) {
- try {
- connect();
- sendRequest(contentType, content);
- } catch (IOException e) {
- reset();
- throw e;
- }
- blockOn = okToRecieve;
- releaseMe = okToRecieve = new Semaphore();
- }
-
- // Step 2: wait for requests ahead of us to complete, then read the reply off the stream
- boolean doRelease = true;
- try {
- if (blockOn != null) blockOn.block();
-
- // previous call wrecked the socket connection, but we already sent our request, so we can't just retry --
- // this could cause the server to receive the request twice, which could be bad (think of the case where the
- // server call causes Amazon.com to ship you an item with one-click purchasing).
- if (in == null)
- throw new HTTPException("a previous pipelined call messed up the socket");
-
- Hashtable h = in == null ? null : parseHeaders(in);
- if (h == null) {
- if (firstRequest) throw new HTTPException("server closed the socket with no response");
- // sometimes the server chooses to close the stream between requests
- reset();
- releaseMe.release();
- return makeRequest(contentType, content);
- }
-
- String reply = h.get("STATUSLINE").toString();
-
- if (reply.startsWith("407") || reply.startsWith("401")) {
-
- if (reply.startsWith("407")) doProxyAuth(h, content == null ? "GET" : "POST");
- else doWebAuth(h, content == null ? "GET" : "POST");
-
- if (h.get("HTTP").equals("1.0") && h.get("content-length") == null) {
- if (Log.on) Log.info(this, "proxy returned an HTTP/1.0 reply with no content-length...");
- reset();
- } else {
- int cl = h.get("content-length") == null ? -1 : Integer.parseInt(h.get("content-length").toString());
- new HTTPInputStream(in, cl, releaseMe).close();
- }
- releaseMe.release();
- return makeRequest(contentType, content);
-
- } else if (reply.startsWith("2")) {
- if (h.get("HTTP").equals("1.0") && h.get("content-length") == null)
- throw new HTTPException("Ibex does not support HTTP/1.0 servers which fail to return the Content-Length header");
- int cl = h.get("content-length") == null ? -1 : Integer.parseInt(h.get("content-length").toString());
- InputStream ret = new HTTPInputStream(in, cl, releaseMe);
- if ("gzip".equals(h.get("content-encoding"))) ret = new java.util.zip.GZIPInputStream(ret);
- doRelease = false;
- return ret;
-
- } else {
- throw new HTTPException("HTTP Error: " + reply);
-
- }
-
- } catch (IOException e) { reset(); throw e;
- } finally { if (doRelease) releaseMe.release();
- }
- }
-
-
- // Safeguarded DNS Resolver ///////////////////////////////////////////////////////////////////////////
-
- /**
- * resolves the hostname and returns it as a string in the form "x.y.z.w"
- * @throws HTTPException if the host falls within a firewalled netblock
- */
- private void resolveAndCheckIfFirewalled(String host) throws HTTPException {
-
- // cached
- if (resolvedHosts.get(host) != null) return;
-
- // if all scripts are trustworthy (local FS), continue
- if (Main.originAddr == null) return;
-
- // resolve using DNS
- try {
- InetAddress addr = InetAddress.getByName(host);
- byte[] quadbyte = addr.getAddress();
- if ((quadbyte[0] == 10 ||
- (quadbyte[0] == 192 && quadbyte[1] == 168) ||
- (quadbyte[0] == 172 && (quadbyte[1] & 0xF0) == 16)) && !addr.equals(Main.originAddr))
- throw new HTTPException("security violation: " + host + " [" + addr.getHostAddress() +
- "] is in a firewalled netblock");
- return;
- } catch (UnknownHostException uhe) { }
-
- if (Platform.detectProxy() == null)
- throw new HTTPException("could not resolve hostname \"" + host + "\" and no proxy configured");
- }
-
-
- // Methods to attempt socket creation /////////////////////////////////////////////////////////////////
-
- private Socket getSocket(String host, int port, boolean ssl, boolean negotiate) throws IOException {
- Socket ret = ssl ? new SSL(host, port, negotiate) : new Socket(java.net.InetAddress.getByName(host), port);
- ret.setTcpNoDelay(true);
- return ret;
- }
-
- /** Attempts a direct connection */
- private Socket attemptDirect() {
- try {
- Log.info(this, "attempting to create unproxied socket to " +
- host + ":" + port + (ssl ? " [ssl]" : ""));
- return getSocket(host, port, ssl, true);
- } catch (IOException e) {
- if (Log.on) Log.info(this, "exception in attemptDirect(): " + e);
- return null;
- }
- }
-
- /** Attempts to use an HTTP proxy, employing the CONNECT method if HTTPS is requested */
- private Socket attemptHttpProxy(String proxyHost, int proxyPort) {
- try {
- if (Log.verbose) Log.info(this, "attempting to create HTTP proxied socket using proxy " + proxyHost + ":" + proxyPort);
- Socket sock = getSocket(proxyHost, proxyPort, ssl, false);
-
- if (!ssl) {
- if (!path.startsWith("http://")) path = "http://" + host + ":" + port + path;
- return sock;
- }
-
- PrintWriter pw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
- BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
- pw.print("CONNECT " + host + ":" + port + " HTTP/1.1\r\n\r\n");
- pw.flush();
- String s = br.readLine();
- if (s.charAt(9) != '2') throw new HTTPException("proxy refused CONNECT method: \"" + s + "\"");
- while (br.readLine().length() > 0) { };
- ((SSL)sock).negotiate();
- return sock;
-
- } catch (IOException e) {
- if (Log.on) Log.info(this, "exception in attemptHttpProxy(): " + e);
- return null;
- }
- }
-
- /**
- * Implements SOCKSv4 with v4a DNS extension
- * @see http://www.socks.nec.com/protocol/socks4.protocol
- * @see http://www.socks.nec.com/protocol/socks4a.protocol
- */
- private Socket attemptSocksProxy(String proxyHost, int proxyPort) {
-
- // even if host is already a "x.y.z.w" string, we use this to parse it into bytes
- InetAddress addr = null;
- try { addr = InetAddress.getByName(host); } catch (Exception e) { }
-
- if (Log.verbose) Log.info(this, "attempting to create SOCKSv4" + (addr == null ? "" : "a") +
- " proxied socket using proxy " + proxyHost + ":" + proxyPort);
-
- try {
- Socket sock = getSocket(proxyHost, proxyPort, ssl, false);
-
- DataOutputStream dos = new DataOutputStream(sock.getOutputStream());
- dos.writeByte(0x04); // SOCKSv4(a)
- dos.writeByte(0x01); // CONNECT
- dos.writeShort(port & 0xffff); // port
- if (addr == null) dos.writeInt(0x00000001); // bogus IP
- else dos.write(addr.getAddress()); // actual IP
- dos.writeByte(0x00); // no userid
- if (addr == null) {
- PrintWriter pw = new PrintWriter(new OutputStreamWriter(dos));
- pw.print(host);
- pw.flush();
- dos.writeByte(0x00); // hostname null terminator
- }
- dos.flush();
-
- DataInputStream dis = new DataInputStream(sock.getInputStream());
- dis.readByte(); // reply version
- byte success = dis.readByte(); // success/fail
- dis.skip(6); // ip/port
-
- if ((int)(success & 0xff) == 90) {
- if (ssl) ((SSL)sock).negotiate();
- return sock;
- }
- if (Log.on) Log.info(this, "SOCKS server denied access, code " + (success & 0xff));
- return null;
-
- } catch (IOException e) {
- if (Log.on) Log.info(this, "exception in attemptSocksProxy(): " + e);
- return null;
- }
- }
-
- /** executes the PAC script and dispatches a call to one of the other attempt methods based on the result */
- private Socket attemptPAC(org.ibex.js.JS pacFunc) {
- if (Log.verbose) Log.info(this, "evaluating PAC script");
- String pac = null;
- try {
- JS obj = pacFunc.call(JS.S(url), JS.S(host), null, null, 2);
- if (Log.verbose) Log.info(this, " PAC script returned \"" + JS.debugToString(obj) + "\"");
- pac = JS.toString(obj);
- } catch (Throwable e) {
- if (Log.on) Log.info(this, "PAC script threw exception " + e);
- return null;
- }
-
- StringTokenizer st = new StringTokenizer(pac, ";", false);
- while (st.hasMoreTokens()) {
- String token = st.nextToken().trim();
- if (Log.verbose) Log.info(this, " trying \"" + token + "\"...");
- try {
- Socket ret = null;
- if (token.startsWith("DIRECT"))
- ret = attemptDirect();
- else if (token.startsWith("PROXY"))
- ret = attemptHttpProxy(token.substring(token.indexOf(' ') + 1, token.indexOf(':')),
- Integer.parseInt(token.substring(token.indexOf(':') + 1)));
- else if (token.startsWith("SOCKS"))
- ret = attemptSocksProxy(token.substring(token.indexOf(' ') + 1, token.indexOf(':')),
- Integer.parseInt(token.substring(token.indexOf(':') + 1)));
- if (ret != null) return ret;
- } catch (Throwable e) {
- if (Log.on) Log.info(this, "attempt at \"" + token + "\" failed due to " + e + "; trying next token");
- }
- }
- if (Log.on) Log.info(this, "all PAC results exhausted");
- return null;
- }
-
-
- // Everything Else ////////////////////////////////////////////////////////////////////////////
-
- private synchronized void connect() throws IOException {
- if (originalUrl.equals("stdio:")) { in = new BufferedInputStream(System.in); return; }
- if (sock != null) {
- if (in == null) in = new BufferedInputStream(sock.getInputStream());
- return;
- }
- // grab the userinfo; gcj doesn't have java.net.URL.getUserInfo()
- String url = originalUrl;
- userInfo = url.substring(url.indexOf("://") + 3);
- userInfo = userInfo.indexOf('/') == -1 ? userInfo : userInfo.substring(0, userInfo.indexOf('/'));
- if (userInfo.indexOf('@') != -1) {
- userInfo = userInfo.substring(0, userInfo.indexOf('@'));
- url = url.substring(0, url.indexOf("://") + 3) + url.substring(url.indexOf('@') + 1);
- } else {
- userInfo = null;
- }
-
- if (url.startsWith("https:")) {
- ssl = true;
- } else if (!url.startsWith("http:")) {
- throw new IOException("HTTP only supports http/https urls");
- }
- if (url.indexOf("://") == -1) throw new IOException("URLs must contain a ://");
- String temphost = url.substring(url.indexOf("://") + 3);
- path = temphost.substring(temphost.indexOf('/'));
- temphost = temphost.substring(0, temphost.indexOf('/'));
- if (temphost.indexOf(':') != -1) {
- port = Integer.parseInt(temphost.substring(temphost.indexOf(':')+1));
- temphost = temphost.substring(0, temphost.indexOf(':'));
- } else {
- port = ssl ? 443 : 80;
- }
- if (!skipResolveCheck) resolveAndCheckIfFirewalled(temphost);
- host = temphost;
- if (Log.verbose) Log.info(this, "creating HTTP object for connection to " + host + ":" + port);
-
- Proxy pi = Platform.detectProxy();
- OUTER: do {
- if (pi != null) {
- for(int i=0; i<pi.excluded.length; i++) if (host.equals(pi.excluded[i])) break OUTER;
- if (sock == null && pi.proxyAutoConfigFunction != null) sock = attemptPAC(pi.proxyAutoConfigFunction);
- if (sock == null && ssl && pi.httpsProxyHost != null) sock = attemptHttpProxy(pi.httpsProxyHost,pi.httpsProxyPort);
- if (sock == null && pi.httpProxyHost != null) sock = attemptHttpProxy(pi.httpProxyHost, pi.httpProxyPort);
- if (sock == null && pi.socksProxyHost != null) sock = attemptSocksProxy(pi.socksProxyHost, pi.socksProxyPort);
- }
- } while (false);
- proxied = sock != null;
- if (sock == null) sock = attemptDirect();
- if (sock == null) throw new HTTPException("unable to contact host " + host);
- if (in == null) in = new BufferedInputStream(sock.getInputStream());
- }
-
- private void sendRequest(String contentType, String content) throws IOException {
- PrintWriter pw = new PrintWriter(new OutputStreamWriter(originalUrl.equals("stdio:") ?
- System.out : sock.getOutputStream()));
- if (content != null) {
- pw.print("POST " + path + " HTTP/1.0\r\n"); // FIXME chunked encoding
- int contentLength = content.substring(0, 2).equals("\r\n") ?
- content.length() - 2 :
- (content.length() - content.indexOf("\r\n\r\n") - 4);
- pw.print("Content-Length: " + contentLength + "\r\n");
- if (contentType != null) pw.print("Content-Type: " + contentType + "\r\n");
- } else {
- pw.print("GET " + path + " HTTP/1.1\r\n");
- }
-
- pw.print("User-Agent: Ibex\r\n");
- pw.print("Accept-encoding: gzip\r\n");
- pw.print("Host: " + (host + (port == 80 ? "" : (":" + port))) + "\r\n");
- if (proxied) pw.print("X-RequestOrigin: " + Main.originHost + "\r\n");
-
- if (Proxy.Authorization.authorization != null) pw.print("Proxy-Authorization: "+Proxy.Authorization.authorization2+"\r\n");
- if (authCache.get(originalUrl) != null) pw.print("Authorization: " + authCache.get(originalUrl) + "\r\n");
-
- pw.print(content == null ? "\r\n" : content);
- pw.flush();
- }
-
- private void doWebAuth(Hashtable h0, String method) throws IOException {
- if (userInfo == null) throw new HTTPException("web server demanded username/password, but none were supplied");
- Hashtable h = parseAuthenticationChallenge(h0.get("www-authenticate").toString());
-
- if (h.get("AUTHTYPE").equals("Basic")) {
- if (authCache.get(originalUrl) != null) throw new HTTPException("username/password rejected");
- authCache.put(originalUrl, "Basic " + new String(Base64.encode(userInfo.getBytes("UTF8"))));
-
- } else if (h.get("AUTHTYPE").equals("Digest")) {
- if (authCache.get(originalUrl) != null && !"true".equals(h.get("stale")))
- throw new HTTPException("username/password rejected");
- String path2 = path;
- if (path2.startsWith("http://") || path2.startsWith("https://")) {
- path2 = path2.substring(path2.indexOf("://") + 3);
- path2 = path2.substring(path2.indexOf('/'));
- }
- String A1 = userInfo.substring(0, userInfo.indexOf(':')) + ":" + h.get("realm") + ":" +
- userInfo.substring(userInfo.indexOf(':') + 1);
- String A2 = method + ":" + path2;
- authCache.put(originalUrl,
- "Digest " +
- "username=\"" + userInfo.substring(0, userInfo.indexOf(':')) + "\", " +
- "realm=\"" + h.get("realm") + "\", " +
- "nonce=\"" + h.get("nonce") + "\", " +
- "uri=\"" + path2 + "\", " +
- (h.get("opaque") == null ? "" : ("opaque=\"" + h.get("opaque") + "\", ")) +
- "response=\"" + H(H(A1) + ":" + h.get("nonce") + ":" + H(A2)) + "\", " +
- "algorithm=MD5"
- );
-
- } else {
- throw new HTTPException("unknown authentication type: " + h.get("AUTHTYPE"));
- }
- }
-
- private void doProxyAuth(Hashtable h0, String method) throws IOException {
- if (Log.on) Log.info(this, "Proxy AuthChallenge: " + h0.get("proxy-authenticate"));
- Hashtable h = parseAuthenticationChallenge(h0.get("proxy-authenticate").toString());
- String style = h.get("AUTHTYPE").toString();
- String realm = (String)h.get("realm");
-
- if (style.equals("NTLM") && Proxy.Authorization.authorization2 == null) {
- Log.info(this, "Proxy identified itself as NTLM, sending Type 1 packet");
- Proxy.Authorization.authorization2 = "NTLM " + Base64.encode(Proxy.NTLM.type1);
- return;
- }
-
- if (!realm.equals("Digest") || Proxy.Authorization.authorization2 == null || !"true".equals(h.get("stale")))
- Proxy.Authorization.getPassword(realm, style, sock.getInetAddress().getHostAddress(),
- Proxy.Authorization.authorization);
-
- if (style.equals("Basic")) {
- Proxy.Authorization.authorization2 =
- "Basic " + new String(Base64.encode(Proxy.Authorization.authorization.getBytes("UTF8")));
-
- } else if (style.equals("Digest")) {
- String A1 = Proxy.Authorization.authorization.substring(0, userInfo.indexOf(':')) + ":" + h.get("realm") + ":" +
- Proxy.Authorization.authorization.substring(Proxy.Authorization.authorization.indexOf(':') + 1);
- String A2 = method + ":" + path;
- Proxy.Authorization.authorization2 =
- "Digest " +
- "username=\"" + Proxy.Authorization.authorization.substring(0, Proxy.Authorization.authorization.indexOf(':')) +
- "\", " +
- "realm=\"" + h.get("realm") + "\", " +
- "nonce=\"" + h.get("nonce") + "\", " +
- "uri=\"" + path + "\", " +
- (h.get("opaque") == null ? "" : ("opaque=\"" + h.get("opaque") + "\", ")) +
- "response=\"" + H(H(A1) + ":" + h.get("nonce") + ":" + H(A2)) + "\", " +
- "algorithm=MD5";
-
- } else if (style.equals("NTLM")) {
- Log.info(this, "Proxy identified itself as NTLM, got Type 2 packet");
- byte[] type2 = Base64.decode(((String)h0.get("proxy-authenticate")).substring(5).trim());
- for(int i=0; i<type2.length; i += 4) {
- String log = "";
- if (i<type2.length) log += Integer.toString(type2[i] & 0xff, 16) + " ";
- if (i+1<type2.length) log += Integer.toString(type2[i+1] & 0xff, 16) + " ";
- if (i+2<type2.length) log += Integer.toString(type2[i+2] & 0xff, 16) + " ";
- if (i+3<type2.length) log += Integer.toString(type2[i+3] & 0xff, 16) + " ";
- Log.info(this, log);
- }
- // FEATURE: need to keep the connection open between type1 and type3
- // FEATURE: finish this
- //byte[] type3 = Proxy.NTLM.getResponse(
- //Proxy.Authorization.authorization2 = "NTLM " + Base64.encode(type3));
- }
- }
-
-
- // HTTPInputStream ///////////////////////////////////////////////////////////////////////////////////
-
- /** An input stream that represents a subset of a longer input stream. Supports HTTP chunking as well */
- public class HTTPInputStream extends FilterInputStream implements KnownLength {
-
- private int length = 0; ///< if chunking, numbytes left in this subset; else the remainder of the chunk
- private Semaphore releaseMe = null; ///< this semaphore will be released when the stream is closed
- boolean chunkedDone = false; ///< indicates that we have encountered the zero-length terminator chunk
- boolean firstChunk = true; ///< if we're on the first chunk, we don't pre-read a CRLF
- private int contentLength = 0; ///< the length of the entire content body; -1 if chunked
-
- HTTPInputStream(InputStream in, int length, Semaphore releaseMe) throws IOException {
- super(in);
- this.releaseMe = releaseMe;
- this.contentLength = length;
- this.length = length == -1 ? 0 : length;
- }
-
- public int getLength() { return contentLength; }
- public boolean markSupported() { return false; }
- public int read(byte[] b) throws IOException { return read(b, 0, b.length); }
- public long skip(long n) throws IOException { return read(null, -1, (int)n); }
- public int available() throws IOException {
- if (contentLength == -1) return java.lang.Math.min(super.available(), length);
- return super.available();
- }
-
- public int read() throws IOException {
- byte[] b = new byte[1];
- int ret = read(b, 0, 1);
- return ret == -1 ? -1 : b[0] & 0xff;
- }
-
- private void readChunk() throws IOException {
- if (chunkedDone) return;
- if (!firstChunk) super.skip(2); // CRLF
- firstChunk = false;
- String chunkLen = "";
- while(true) {
- int i = super.read();
- if (i == -1) throw new HTTPException("encountered end of stream while reading chunk length");
-
- // FEATURE: handle chunking extensions
- if (i == '\r') {
- super.read(); // LF
- break;
- } else {
- chunkLen += (char)i;
- }
- }
- length = Integer.parseInt(chunkLen.trim(), 16);
- if (length == 0) chunkedDone = true;
- }
-
- public int read(byte[] b, int off, int len) throws IOException {
- boolean good = false;
- try {
- if (length == 0 && contentLength == -1) {
- readChunk();
- if (chunkedDone) { good = true; return -1; }
- } else {
- if (length == 0) { good = true; return -1; }
- }
- if (len > length) len = length;
- int ret = b == null ? (int)super.skip(len) : super.read(b, off, len);
- if (ret >= 0) {
- length -= ret;
- good = true;
- }
- return ret;
- } finally {
- if (!good) reset();
- }
- }
-
- public void close() throws IOException {
- if (contentLength == -1) {
- while(!chunkedDone) {
- if (length != 0) skip(length);
- readChunk();
- }
- skip(2);
- } else {
- if (length != 0) skip(length);
- }
- if (releaseMe != null) releaseMe.release();
- }
- }
-
- void reset() {
- firstRequest = true;
- in = null;
- sock = null;
- }
-
-
- // Misc Helpers ///////////////////////////////////////////////////////////////////////////////////
-
- /** reads a set of HTTP headers off of the input stream, returning null if the stream is already at its end */
- private Hashtable parseHeaders(InputStream in) throws IOException {
- Hashtable ret = new Hashtable();
-
- // we can't use a BufferedReader directly on the input stream, since it will buffer past the end of the headers
- byte[] buf = new byte[4096];
- int buflen = 0;
- while(true) {
- int read = in.read();
- if (read == -1 && buflen == 0) return null;
- if (read == -1) throw new HTTPException("stream closed while reading headers");
- buf[buflen++] = (byte)read;
- if (buflen >= 4 && buf[buflen - 4] == '\r' && buf[buflen - 3] == '\n' &&
- buf[buflen - 2] == '\r' && buf[buflen - 1] == '\n')
- break;
- if (buflen >=2 && buf[buflen - 1] == '\n' && buf[buflen - 2] == '\n')
- break; // nice for people using stdio
- if (buflen == buf.length) {
- byte[] newbuf = new byte[buf.length * 2];
- System.arraycopy(buf, 0, newbuf, 0, buflen);
- buf = newbuf;
- }
- }
-
- BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, buflen)));
- String s = br.readLine();
- if (!s.startsWith("HTTP/")) throw new HTTPException("Expected reply to start with \"HTTP/\", got: " + s);
- ret.put("STATUSLINE", s.substring(s.indexOf(' ') + 1));
- ret.put("HTTP", s.substring(5, s.indexOf(' ')));
-
- while((s = br.readLine()) != null && s.length() > 0) {
- String front = s.substring(0, s.indexOf(':')).toLowerCase();
- String back = s.substring(s.indexOf(':') + 1).trim();
- // ugly hack: we never replace a Digest-auth with a Basic-auth (proxy + www)
- if (front.endsWith("-authenticate") && ret.get(front) != null && !back.equals("Digest")) continue;
- ret.put(front, back);
- }
- return ret;
- }
-
- private Hashtable parseAuthenticationChallenge(String s) {
- Hashtable ret = new Hashtable();
-
- s = s.trim();
- ret.put("AUTHTYPE", s.substring(0, s.indexOf(' ')));
- s = s.substring(s.indexOf(' ')).trim();
-
- while (s.length() > 0) {
- String val = null;
- String key = s.substring(0, s.indexOf('='));
- s = s.substring(s.indexOf('=') + 1);
- if (s.charAt(0) == '\"') {
- s = s.substring(1);
- val = s.substring(0, s.indexOf('\"'));
- s = s.substring(s.indexOf('\"') + 1);
- } else {
- val = s.indexOf(',') == -1 ? s : s.substring(0, s.indexOf(','));
- s = s.indexOf(',') == -1 ? "" : s.substring(s.indexOf(',') + 1);
- }
- if (s.length() > 0 && s.charAt(0) == ',') s = s.substring(1);
- s = s.trim();
- ret.put(key, val);
- }
- return ret;
- }
-
- private String H(String s) throws IOException {
- byte[] b = s.getBytes("UTF8");
- MD5 md5 = new MD5();
- md5.update(b, 0, b.length);
- byte[] out = new byte[md5.getDigestSize()];
- md5.doFinal(out, 0);
- String ret = "";
- for(int i=0; i<out.length; i++) {
- ret += "0123456789abcdef".charAt((out[i] & 0xf0) >> 4);
- ret += "0123456789abcdef".charAt(out[i] & 0x0f);
- }
- return ret;
- }
-
-
- // Proxy ///////////////////////////////////////////////////////////
-
- /** encapsulates most of the proxy logic; some is shared in HTTP.java */
- public static class Proxy {
-
- public String httpProxyHost = null; ///< the HTTP Proxy host to use
- public int httpProxyPort = -1; ///< the HTTP Proxy port to use
- public String httpsProxyHost = null; ///< seperate proxy for HTTPS
- public int httpsProxyPort = -1;
- public String socksProxyHost = null; ///< the SOCKS Proxy Host to use
- public int socksProxyPort = -1; ///< the SOCKS Proxy Port to use
- public String[] excluded = new String[] { }; ///< hosts to be excluded from proxy use; wildcards permitted
- public JS proxyAutoConfigFunction = null; ///< the PAC script
-
- public static Proxy detectProxyViaManual() {
- Proxy ret = new Proxy();
-
- ret.httpProxyHost = Platform.getEnv("http_proxy");
- if (ret.httpProxyHost != null) {
- if (ret.httpProxyHost.startsWith("http://")) ret.httpProxyHost = ret.httpProxyHost.substring(7);
- if (ret.httpProxyHost.endsWith("/"))
- ret.httpProxyHost = ret.httpProxyHost.substring(0, ret.httpProxyHost.length() - 1);
- if (ret.httpProxyHost.indexOf(':') != -1) {
- ret.httpProxyPort = Integer.parseInt(ret.httpProxyHost.substring(ret.httpProxyHost.indexOf(':') + 1));
- ret.httpProxyHost = ret.httpProxyHost.substring(0, ret.httpProxyHost.indexOf(':'));
- } else {
- ret.httpProxyPort = 80;
- }
- }
-
- ret.httpsProxyHost = Platform.getEnv("https_proxy");
- if (ret.httpsProxyHost != null) {
- if (ret.httpsProxyHost.startsWith("https://")) ret.httpsProxyHost = ret.httpsProxyHost.substring(7);
- if (ret.httpsProxyHost.endsWith("/"))
- ret.httpsProxyHost = ret.httpsProxyHost.substring(0, ret.httpsProxyHost.length() - 1);
- if (ret.httpsProxyHost.indexOf(':') != -1) {
- ret.httpsProxyPort = Integer.parseInt(ret.httpsProxyHost.substring(ret.httpsProxyHost.indexOf(':') + 1));
- ret.httpsProxyHost = ret.httpsProxyHost.substring(0, ret.httpsProxyHost.indexOf(':'));
- } else {
- ret.httpsProxyPort = 80;
- }
- }
-
- ret.socksProxyHost = Platform.getEnv("socks_proxy");
- if (ret.socksProxyHost != null) {
- if (ret.socksProxyHost.startsWith("socks://")) ret.socksProxyHost = ret.socksProxyHost.substring(7);
- if (ret.socksProxyHost.endsWith("/"))
- ret.socksProxyHost = ret.socksProxyHost.substring(0, ret.socksProxyHost.length() - 1);
- if (ret.socksProxyHost.indexOf(':') != -1) {
- ret.socksProxyPort = Integer.parseInt(ret.socksProxyHost.substring(ret.socksProxyHost.indexOf(':') + 1));
- ret.socksProxyHost = ret.socksProxyHost.substring(0, ret.socksProxyHost.indexOf(':'));
- } else {
- ret.socksProxyPort = 80;
- }
- }
-
- String noproxy = Platform.getEnv("no_proxy");
- if (noproxy != null) {
- StringTokenizer st = new StringTokenizer(noproxy, ",");
- ret.excluded = new String[st.countTokens()];
- for(int i=0; st.hasMoreTokens(); i++) ret.excluded[i] = st.nextToken();
- }
-
- if (ret.httpProxyHost == null && ret.socksProxyHost == null) return null;
- return ret;
- }
-
- public static JS proxyAutoConfigRootScope = /*new ProxyAutoConfigRootScope();*/ null; // JS:FIXME: New api
- public static JS getProxyAutoConfigFunction(String url) {
- try {
- BufferedReader br = new BufferedReader(new InputStreamReader(new HTTP(url, true).GET()));
- String s = null;
- String script = "";
- while((s = br.readLine()) != null) script += s + "\n";
- if (Log.on) Log.info(Proxy.class, "successfully retrieved WPAD PAC:");
- if (Log.on) Log.info(Proxy.class, script);
-
- // MS CARP hack
- Vector carpHosts = new Vector();
- for(int i=0; i<script.length(); i++)
- if (script.regionMatches(i, "new Node(", 0, 9)) {
- String host = script.substring(i + 10, script.indexOf('\"', i + 11));
- if (Log.on) Log.info(Proxy.class, "Detected MS Proxy Server CARP Script, Host=" + host);
- carpHosts.addElement(host);
- }
- if (carpHosts.size() > 0) {
- script = "function FindProxyForURL(url, host) {\nreturn \"";
- for(int i=0; i<carpHosts.size(); i++)
- script += "PROXY " + carpHosts.elementAt(i) + "; ";
- script += "\";\n}";
- if (Log.on) Log.info(Proxy.class, "DeCARPed PAC script:");
- if (Log.on) Log.info(Proxy.class, script);
- }
-
- JS scr = JS.fromReader("PAC script at " + url, 0, new StringReader(script));
- JS.cloneWithNewGlobalScope(scr, proxyAutoConfigRootScope).call(null, null, null, null, 0);
- return (JS)proxyAutoConfigRootScope.get(JS.S("FindProxyForURL"));
- } catch (Exception e) {
- if (Log.on) {
- Log.info(Platform.class, "WPAD detection failed due to:");
- // I have no idea what this was supposed to do
- /*if (e instanceof JSExn) {
- try {
- org.ibex.js.JSArray arr = new org.ibex.js.JSArray();
- arr.addElement(((JSExn)e).getObject());
- } catch (Exception e2) {
- Log.info(Platform.class, e);
- }
- }*/
- Log.info(Platform.class, e);
- }
- return null;
- }
- }
-
-
- // Authorization ///////////////////////////////////////////////////////////////////////////////////
-
- public static class Authorization {
-
- static public String authorization = null;
- static public String authorization2 = null;
- static public Semaphore waitingForUser = new Semaphore();
-
- public static synchronized void getPassword(final String realm, final String style,
- final String proxyIP, String oldAuth) throws IOException {
-
- // this handles cases where multiple threads hit the proxy auth at the same time -- all but one will block on the
- // synchronized keyword. If 'authorization' changed while the thread was blocked, it means that the user entered
- // a password, so we should reattempt authorization.
-
- if (authorization != oldAuth) return;
- if (Log.on) Log.info(Authorization.class, "displaying proxy authorization dialog");
- Scheduler.add(new Task() {
- public void perform() throws IOException, JSExn {
- Box b = new Box();
- Template t = null;
- // FIXME
- //Template.buildTemplate("org/ibex/builtin/proxy_authorization.ibex", Stream.getInputStream((JS)Main.builtin.get("org/ibex/builtin/proxy_authorization.ibex")), new Ibex(null));
- t.apply(b);
- b.put(JS.S("realm"), JS.S(realm));
- b.put(JS.S("proxyIP"), JS.S(proxyIP));
- }
- });
-
- waitingForUser.block();
- if (Log.on) Log.info(Authorization.class, "got proxy authorization info; re-attempting connection");
- }
- }
-
-
- // ProxyAutoConfigRootJSScope ////////////////////////////////////////////////////////////////////
-
- // FIXME: JS Update for new API
- /*public static class ProxyAutoConfigRootScope extends JSScope.Global {
-
- public ProxyAutoConfigRootScope() { super(); }
-
- public Object get(Object name) throws JSExn {
- //#switch(name)
- case "isPlainHostName": return METHOD;
- case "dnsDomainIs": return METHOD;
- case "localHostOrDomainIs": return METHOD;
- case "isResolvable": return METHOD;
- case "isInNet": return METHOD;
- case "dnsResolve": return METHOD;
- case "myIpAddress": return METHOD;
- case "dnsDomainLevels": return METHOD;
- case "shExpMatch": return METHOD;
- case "weekdayRange": return METHOD;
- case "dateRange": return METHOD;
- case "timeRange": return METHOD;
- case "ProxyConfig": return ProxyConfig;
- //#end
- return super.get(name);
- }
-
- private static final JS proxyConfigBindings = new JS.O();
- private static final JS ProxyConfig = new JS() {
- public Object get(Object name) {
- if (name.equals("bindings")) return proxyConfigBindings;
- return null;
- }
- };
-
- public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- //#switch(method)
- case "isPlainHostName": return (a0.toString().indexOf('.') == -1) ? Boolean.TRUE : Boolean.FALSE;
- case "dnsDomainIs": return (a0.toString().endsWith(a1.toString())) ? Boolean.TRUE : Boolean.FALSE;
- case "localHostOrDomainIs":
- return (a0.equals(a1) || (a0.toString().indexOf('.') == -1 && a1.toString().startsWith(a0.toString()))) ? T:F;
- case "isResolvable": try {
- return (InetAddress.getByName(a0.toString()) != null) ? Boolean.TRUE : Boolean.FALSE;
- } catch (UnknownHostException e) { return F; }
- case "isInNet":
- if (nargs != 3) return Boolean.FALSE;
- try {
- byte[] host = InetAddress.getByName(a0.toString()).getAddress();
- byte[] net = InetAddress.getByName(a1.toString()).getAddress();
- byte[] mask = InetAddress.getByName(a2.toString()).getAddress();
- return ((host[0] & mask[0]) == net[0] &&
- (host[1] & mask[1]) == net[1] &&
- (host[2] & mask[2]) == net[2] &&
- (host[3] & mask[3]) == net[3]) ?
- Boolean.TRUE : Boolean.FALSE;
- } catch (Exception e) {
- throw new JSExn("exception in isInNet(): " + e);
- }
- case "dnsResolve":
- try {
- return InetAddress.getByName(a0.toString()).getHostAddress();
- } catch (UnknownHostException e) {
- return null;
- }
- case "myIpAddress":
- try {
- return InetAddress.getLocalHost().getHostAddress();
- } catch (UnknownHostException e) {
- if (Log.on) Log.info(this, "strange... host does not know its own address");
- return null;
- }
- case "dnsDomainLevels":
- String s = a0.toString();
- int i = 0;
- while((i = s.indexOf('.', i)) != -1) i++;
- return new Integer(i);
- case "shExpMatch":
- StringTokenizer st = new StringTokenizer(a1.toString(), "*", false);
- String[] arr = new String[st.countTokens()];
- String s = a0.toString();
- for (int i=0; st.hasMoreTokens(); i++) arr[i] = st.nextToken();
- return match(arr, s, 0) ? Boolean.TRUE : Boolean.FALSE;
- case "weekdayRange":
- TimeZone tz = (nargs < 3 || a2 == null || !a2.equals("GMT")) ?
- TimeZone.getTimeZone("UTC") : TimeZone.getDefault();
- Calendar c = new GregorianCalendar();
- c.setTimeZone(tz);
- c.setTime(new java.util.Date());
- java.util.Date d = c.getTime();
- int day = d.getDay();
- String d1s = a0.toString().toUpperCase();
- int d1 = 0, d2 = 0;
- for(int i=0; i<days.length; i++) if (days[i].equals(d1s)) d1 = i;
-
- if (nargs == 1)
- return d1 == day ? Boolean.TRUE : Boolean.FALSE;
-
- String d2s = a1.toString().toUpperCase();
- for(int i=0; i<days.length; i++) if (days[i].equals(d2s)) d2 = i;
-
- return ((d1 <= d2 && day >= d1 && day <= d2) || (d1 > d2 && (day >= d1 || day <= d2))) ? T : F;
-
- case "dateRange": throw new JSExn("Ibex does not support dateRange() in PAC scripts");
- case "timeRange": throw new JSExn("Ibex does not support timeRange() in PAC scripts");
- //#end
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
- private static boolean match(String[] arr, String s, int index) {
- if (index >= arr.length) return true;
- for(int i=0; i<s.length(); i++) {
- String s2 = s.substring(i);
- if (s2.startsWith(arr[index]) && match(arr, s2.substring(arr[index].length()), index + 1)) return true;
- }
- return false;
- }
- public static String[] days = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
- }*/
-
-
- /**
- * An implementation of Microsoft's proprietary NTLM authentication protocol. This code was derived from Eric
- * Glass's work, and is copyright as follows:
- *
- * Copyright (c) 2003 Eric Glass (eglass1 at comcast.net).
- *
- * Permission to use, copy, modify, and distribute this document for any purpose and without any fee is hereby
- * granted, provided that the above copyright notice and this list of conditions appear in all copies.
- * The most current version of this document may be obtained from http://davenport.sourceforge.net/ntlm.html .
- */
- public static class NTLM {
-
- public static final byte[] type1 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00 };
-
- /**
- * Calculates the NTLM Response for the given challenge, using the
- * specified password.
- *
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- *
- * @return The NTLM Response.
- */
- public static byte[] getNTLMResponse(String password, byte[] challenge)
- throws UnsupportedEncodingException {
- byte[] ntlmHash = ntlmHash(password);
- return lmResponse(ntlmHash, challenge);
- }
-
- /**
- * Calculates the LM Response for the given challenge, using the specified
- * password.
- *
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- *
- * @return The LM Response.
- */
- public static byte[] getLMResponse(String password, byte[] challenge)
- {
- byte[] lmHash = lmHash(password);
- return lmResponse(lmHash, challenge);
- }
-
- /**
- * Calculates the NTLMv2 Response for the given challenge, using the
- * specified authentication target, username, password, target information
- * block, and client challenge.
- *
- * @param target The authentication target (i.e., domain).
- * @param user The username.
- * @param password The user's password.
- * @param targetInformation The target information block from the Type 2
- * message.
- * @param challenge The Type 2 challenge from the server.
- * @param clientChallenge The random 8-byte client challenge.
- *
- * @return The NTLMv2 Response.
- */
- public static byte[] getNTLMv2Response(String target, String user,
- String password, byte[] targetInformation, byte[] challenge,
- byte[] clientChallenge) throws UnsupportedEncodingException {
- byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
- byte[] blob = createBlob(targetInformation, clientChallenge);
- return lmv2Response(ntlmv2Hash, blob, challenge);
- }
-
- /**
- * Calculates the LMv2 Response for the given challenge, using the
- * specified authentication target, username, password, and client
- * challenge.
- *
- * @param target The authentication target (i.e., domain).
- * @param user The username.
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- * @param clientChallenge The random 8-byte client challenge.
- *
- * @return The LMv2 Response.
- */
- public static byte[] getLMv2Response(String target, String user,
- String password, byte[] challenge, byte[] clientChallenge)
- throws UnsupportedEncodingException {
- byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
- return lmv2Response(ntlmv2Hash, clientChallenge, challenge);
- }
-
- /**
- * Calculates the NTLM2 Session Response for the given challenge, using the
- * specified password and client challenge.
- *
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- * @param clientChallenge The random 8-byte client challenge.
- *
- * @return The NTLM2 Session Response. This is placed in the NTLM
- * response field of the Type 3 message; the LM response field contains
- * the client challenge, null-padded to 24 bytes.
- */
- public static byte[] getNTLM2SessionResponse(String password,
- byte[] challenge, byte[] clientChallenge) throws UnsupportedEncodingException {
- byte[] ntlmHash = ntlmHash(password);
- MD5 md5 = new MD5();
- md5.update(challenge, 0, challenge.length);
- md5.update(clientChallenge, 0, clientChallenge.length);
- byte[] sessionHash = new byte[8];
- byte[] md5_out = new byte[md5.getDigestSize()];
- md5.doFinal(md5_out, 0);
- System.arraycopy(md5_out, 0, sessionHash, 0, 8);
- return lmResponse(ntlmHash, sessionHash);
- }
-
- /**
- * Creates the LM Hash of the user's password.
- *
- * @param password The password.
- *
- * @return The LM Hash of the given password, used in the calculation
- * of the LM Response.
- */
- private static byte[] lmHash(String password) {
- /*
- byte[] oemPassword = password.toUpperCase().getBytes("UTF8");
- int length = java.lang.Math.min(oemPassword.length, 14);
- byte[] keyBytes = new byte[14];
- System.arraycopy(oemPassword, 0, keyBytes, 0, length);
- Key lowKey = createDESKey(keyBytes, 0);
- Key highKey = createDESKey(keyBytes, 7);
- byte[] magicConstant = "KGS!@#$%".getBytes("UTF8");
- Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
- des.init(Cipher.ENCRYPT_MODE, lowKey);
- byte[] lowHash = des.doFinal(magicConstant);
- des.init(Cipher.ENCRYPT_MODE, highKey);
- byte[] highHash = des.doFinal(magicConstant);
- byte[] lmHash = new byte[16];
- System.arraycopy(lowHash, 0, lmHash, 0, 8);
- System.arraycopy(highHash, 0, lmHash, 8, 8);
- return lmHash;
- */
- return null;
- }
-
- /**
- * Creates the NTLM Hash of the user's password.
- *
- * @param password The password.
- *
- * @return The NTLM Hash of the given password, used in the calculation
- * of the NTLM Response and the NTLMv2 and LMv2 Hashes.
- */
- private static byte[] ntlmHash(String password) throws UnsupportedEncodingException {
- // FIXME
- /*
- byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked");
- MD4 md4 = new MD4();
- md4.update(unicodePassword, 0, unicodePassword.length);
- byte[] ret = new byte[md4.getDigestSize()];
- return ret;
- */
- return null;
- }
-
- /**
- * Creates the NTLMv2 Hash of the user's password.
- *
- * @param target The authentication target (i.e., domain).
- * @param user The username.
- * @param password The password.
- *
- * @return The NTLMv2 Hash, used in the calculation of the NTLMv2
- * and LMv2 Responses.
- */
- private static byte[] ntlmv2Hash(String target, String user,
- String password) throws UnsupportedEncodingException {
- byte[] ntlmHash = ntlmHash(password);
- String identity = user.toUpperCase() + target.toUpperCase();
- return hmacMD5(identity.getBytes("UnicodeLittleUnmarked"), ntlmHash);
- }
-
- /**
- * Creates the LM Response from the given hash and Type 2 challenge.
- *
- * @param hash The LM or NTLM Hash.
- * @param challenge The server challenge from the Type 2 message.
- *
- * @return The response (either LM or NTLM, depending on the provided
- * hash).
- */
- private static byte[] lmResponse(byte[] hash, byte[] challenge)
- {
- /*
- byte[] keyBytes = new byte[21];
- System.arraycopy(hash, 0, keyBytes, 0, 16);
- Key lowKey = createDESKey(keyBytes, 0);
- Key middleKey = createDESKey(keyBytes, 7);
- Key highKey = createDESKey(keyBytes, 14);
- Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
- des.init(Cipher.ENCRYPT_MODE, lowKey);
- byte[] lowResponse = des.doFinal(challenge);
- des.init(Cipher.ENCRYPT_MODE, middleKey);
- byte[] middleResponse = des.doFinal(challenge);
- des.init(Cipher.ENCRYPT_MODE, highKey);
- byte[] highResponse = des.doFinal(challenge);
- byte[] lmResponse = new byte[24];
- System.arraycopy(lowResponse, 0, lmResponse, 0, 8);
- System.arraycopy(middleResponse, 0, lmResponse, 8, 8);
- System.arraycopy(highResponse, 0, lmResponse, 16, 8);
- return lmResponse;
- */
- return null;
- }
-
- /**
- * Creates the LMv2 Response from the given hash, client data, and
- * Type 2 challenge.
- *
- * @param hash The NTLMv2 Hash.
- * @param clientData The client data (blob or client challenge).
- * @param challenge The server challenge from the Type 2 message.
- *
- * @return The response (either NTLMv2 or LMv2, depending on the
- * client data).
- */
- private static byte[] lmv2Response(byte[] hash, byte[] clientData,
- byte[] challenge) {
- byte[] data = new byte[challenge.length + clientData.length];
- System.arraycopy(challenge, 0, data, 0, challenge.length);
- System.arraycopy(clientData, 0, data, challenge.length,
- clientData.length);
- byte[] mac = hmacMD5(data, hash);
- byte[] lmv2Response = new byte[mac.length + clientData.length];
- System.arraycopy(mac, 0, lmv2Response, 0, mac.length);
- System.arraycopy(clientData, 0, lmv2Response, mac.length,
- clientData.length);
- return lmv2Response;
- }
-
- /**
- * Creates the NTLMv2 blob from the given target information block and
- * client challenge.
- *
- * @param targetInformation The target information block from the Type 2
- * message.
- * @param clientChallenge The random 8-byte client challenge.
- *
- * @return The blob, used in the calculation of the NTLMv2 Response.
- */
- private static byte[] createBlob(byte[] targetInformation,
- byte[] clientChallenge) {
- byte[] blobSignature = new byte[] {
- (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00
- };
- byte[] reserved = new byte[] {
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
- };
- byte[] unknown1 = new byte[] {
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
- };
- byte[] unknown2 = new byte[] {
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
- };
- long time = System.currentTimeMillis();
- time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch.
- time *= 10000; // tenths of a microsecond.
- // convert to little-endian byte array.
- byte[] timestamp = new byte[8];
- for (int i = 0; i < 8; i++) {
- timestamp[i] = (byte) time;
- time >>>= 8;
- }
- byte[] blob = new byte[blobSignature.length + reserved.length +
- timestamp.length + clientChallenge.length +
- unknown1.length + targetInformation.length +
- unknown2.length];
- int offset = 0;
- System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length);
- offset += blobSignature.length;
- System.arraycopy(reserved, 0, blob, offset, reserved.length);
- offset += reserved.length;
- System.arraycopy(timestamp, 0, blob, offset, timestamp.length);
- offset += timestamp.length;
- System.arraycopy(clientChallenge, 0, blob, offset,
- clientChallenge.length);
- offset += clientChallenge.length;
- System.arraycopy(unknown1, 0, blob, offset, unknown1.length);
- offset += unknown1.length;
- System.arraycopy(targetInformation, 0, blob, offset,
- targetInformation.length);
- offset += targetInformation.length;
- System.arraycopy(unknown2, 0, blob, offset, unknown2.length);
- return blob;
- }
-
- /**
- * Calculates the HMAC-MD5 hash of the given data using the specified
- * hashing key.
- *
- * @param data The data for which the hash will be calculated.
- * @param key The hashing key.
- *
- * @return The HMAC-MD5 hash of the given data.
- */
- private static byte[] hmacMD5(byte[] data, byte[] key) {
- byte[] ipad = new byte[64];
- byte[] opad = new byte[64];
- for (int i = 0; i < 64; i++) {
- ipad[i] = (byte) 0x36;
- opad[i] = (byte) 0x5c;
- }
- for (int i = key.length - 1; i >= 0; i--) {
- ipad[i] ^= key[i];
- opad[i] ^= key[i];
- }
- byte[] content = new byte[data.length + 64];
- System.arraycopy(ipad, 0, content, 0, 64);
- System.arraycopy(data, 0, content, 64, data.length);
- MD5 md5 = new MD5();
- md5.update(content, 0, content.length);
- data = new byte[md5.getDigestSize()];
- md5.doFinal(data, 0);
- content = new byte[data.length + 64];
- System.arraycopy(opad, 0, content, 0, 64);
- System.arraycopy(data, 0, content, 64, data.length);
- md5 = new MD5();
- md5.update(content, 0, content.length);
- byte[] ret = new byte[md5.getDigestSize()];
- md5.doFinal(ret, 0);
- return ret;
- }
-
- /**
- * Creates a DES encryption key from the given key material.
- *
- * @param bytes A byte array containing the DES key material.
- * @param offset The offset in the given byte array at which
- * the 7-byte key material starts.
- *
- * @return A DES encryption key created from the key material
- * starting at the specified offset in the given byte array.
- */
- /*
- private static Key createDESKey(byte[] bytes, int offset) {
- byte[] keyBytes = new byte[7];
- System.arraycopy(bytes, offset, keyBytes, 0, 7);
- byte[] material = new byte[8];
- material[0] = keyBytes[0];
- material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1);
- material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2);
- material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3);
- material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4);
- material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5);
- material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6);
- material[7] = (byte) (keyBytes[6] << 1);
- oddParity(material);
- return new SecretKeySpec(material, "DES");
- }
- */
-
- /**
- * Applies odd parity to the given byte array.
- *
- * @param bytes The data whose parity bits are to be adjusted for
- * odd parity.
- */
- private static void oddParity(byte[] bytes) {
- for (int i = 0; i < bytes.length; i++) {
- byte b = bytes[i];
- boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^
- (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^
- (b >>> 1)) & 0x01) == 0;
- if (needsParity) {
- bytes[i] |= (byte) 0x01;
- } else {
- bytes[i] &= (byte) 0xfe;
- }
- }
- }
-
- }
- }
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.net;
-
-import java.io.*;
-import java.util.*;
-import org.ibex.js.*;
-import org.ibex.util.*;
-import org.ibex.crypto.*;
-
-/**
- * A partial RPC-style SOAP 1.1 client. Implemented from the SOAP 1.1
- * Spec and Dave Winer's "SOAP for Busy Developers". This class
- * extends XMLRPC in order to share some networking logic.
- *
- * Currently unsupported features/hacks:
- * <ul><li> Multi-ref data and circular references
- * <li> 'Document Style'
- * <li> WSDL support
- * </ul>
- */
-public class SOAP extends XMLRPC {
-
- /** the desired content of the SOAPAction header */
- String action = null;
-
- /** the namespace to use */
- String nameSpace = null;
-
- /** When you get a property from an SOAP, it just returns another SOAP with the property name tacked onto methodname. */
- public Object get(Object name) {
- return new SOAP(url, (method.equals("") ? "" : method + ".") + name.toString(), this, action, nameSpace); }
-
-
- // Methods to Recieve and parse SOAP Responses ////////////////////////////////////////////////////
-
- public void startElement(String name, String[] keys, Object[] vals, int line, int col) {
-
- content.reset();
- if (name.equals("SOAP-ENV:Envelope")) return;
- if (name.equals("SOAP-ENV:Body")) return;
- if (name.equals("SOAP-ENV:Fault")) fault = true;
-
- // add a generic struct; we'll change this if our type is different
- objects.addElement(new JS.O());
-
- for(int i=0; i<keys.length; i++) {
- String key = keys[i];
- String value = vals[i].toString();
- if (key.endsWith("ype")) {
- if (value.endsWith("boolean")) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(Boolean.FALSE);
- } else if (value.endsWith("int")) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new Integer(0));
- } else if (value.endsWith("double")) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new Double(0.0));
- } else if (value.endsWith("string")) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement("");
- } else if (value.endsWith("base64")) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new byte[] { });
- } else if (value.endsWith("null")) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(null);
- } else if (value.endsWith("arrayType") || value.endsWith("JSArray") || key.endsWith("arrayType")) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new JSArray());
- }
- }
- }
- }
-
- public void endElement(String name, int line, int col) {
-
- if (name.equals("SOAP-ENV:Envelope")) return;
- if (name.equals("SOAP-ENV:Body")) return;
-
- if (content.size() > 0 && content.toString().trim().length() > 0) {
-
- // remove ourselves
- Object me = objects.elementAt(objects.size() - 1);
-
- if (fault || me instanceof String) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new String(content.getBuf(), 0, content.size()).intern());
- content.reset();
-
- } else if (me instanceof byte[]) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new Stream.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size())), null));
- content.reset();
-
- } else if (me instanceof Integer) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new Integer(new String(content.getBuf(), 0, content.size())));
- content.reset();
-
- } else if (me instanceof Boolean) {
- objects.removeElementAt(objects.size() - 1);
- String s = new String(content.getBuf(), 0, content.size()).trim();
- if (s.equals("1") || s.equals("true")) objects.addElement(Boolean.TRUE);
- else objects.addElement(Boolean.FALSE);
- content.reset();
-
- } else if (me instanceof Double) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new Double(new String(content.getBuf(), 0, content.size())));
- content.reset();
-
- } else {
- // okay, we got PCDATA for what is supposedly a
- // struct... somebody's not adding their type info...
- String s = new String(content.getBuf(), 0, content.size()).trim();
- boolean hasdot = false;
- for(int i=0; i<s.length(); i++) {
- if (s.charAt(i) == '.') hasdot = true;
- if (!Character.isDigit(s.charAt(i))) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(s);
- return;
- }
- }
- if (hasdot) {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new Double(s));
- } else {
- objects.removeElementAt(objects.size() - 1);
- objects.addElement(new Integer(s));
- }
- content.reset();
- }
-
- }
-
- // remove ourselves
- JS me = (JS) objects.elementAt(objects.size() - 1);
-
- // find our parent
- Object parent = objects.size() > 1 ? objects.elementAt(objects.size() - 2) : null;
-
- // we want to fold stuff back into the fault object
- if (objects.size() < 2) return;
-
- // our parent "should" be an aggregate type -- add ourselves to it.
- // FIXME: Can we get away without JSArray being public?
- /*if (parent != null && parent instanceof JSArray) {
- objects.removeElementAt(objects.size() - 1);
- ((JSArray)parent).addElement(me);
-
- } else */ if (parent != null && parent instanceof JS) {
- objects.removeElementAt(objects.size() - 1);
- try {
- ((JS)parent).put(JS.S(name), me);
- } catch (JSExn e) {
- throw new Error("this should never happen");
- }
-
- }
-
- }
-
- /** Appends the SOAP representation of <code>o</code> to <code>sb</code> */
- void appendObject(String name, JS o, StringBuffer sb) throws JSExn {
- // JS:FIXME: Update for new api
- /*
- if (o instanceof Number) {
- if ((double)((Number)o).intValue() == ((Number)o).doubleValue()) {
- sb.append(" <" + name + " xsi:type=\"xsd:int\">");
- sb.append(((Number)o).intValue());
- sb.append("</" + name + ">\r\n");
- } else {
- sb.append(" <" + name + " xsi:type=\"xsd:double\">");
- sb.append(o);
- sb.append("</" + name + ">\r\n");
- }
-
- } else if (o instanceof Boolean) {
- sb.append(" <" + name + " xsi:type=\"xsd:boolean\">");
- sb.append(((Boolean)o).booleanValue() ? "true" : "false");
- sb.append("</" + name + ">\r\n");
-
- } else if (o instanceof Stream) {
- try {
- sb.append(" <" + name + " xsi:type=\"SOAP-ENC:base64\">\r\n");
- InputStream is = ((Stream)o).getInputStream();
- byte[] buf = new byte[54];
- while(true) {
- int numread = is.read(buf, 0, 54);
- if (numread == -1) break;
- byte[] writebuf = buf;
- if (numread < buf.length) {
- writebuf = new byte[numread];
- System.arraycopy(buf, 0, writebuf, 0, numread);
- }
- sb.append(" ");
- sb.append(new String(Base64.encode(writebuf)));
- sb.append("\r\n");
- }
- sb.append(((Boolean)o).booleanValue() ? "1" : "0");
- sb.append("</" + name + ">\r\n");
- } catch (IOException e) {
- if (Log.on) Log.info(this, "caught IOException while attempting to send a ByteStream via SOAP");
- if (Log.on) Log.info(this, e);
- throw new JSExn("caught IOException while attempting to send a ByteStream via SOAP");
- }
-
- } else if (o instanceof String) {
- sb.append(" <" + name + " xsi:type=\"xsd:string\">");
- String s = (String)o;
- if (s.indexOf('<') == -1 && s.indexOf('&') == -1) {
- sb.append(s);
- } else {
- char[] cbuf = s.toCharArray();
- while(true) {
- int oldi = 0, i=0;
- while(i < cbuf.length && cbuf[i] != '<' && cbuf[i] != '&') i++;
- sb.append(cbuf, oldi, i);
- if (i == cbuf.length) break;
- if (cbuf[i] == '<') sb.append("<");
- else if (cbuf[i] == '&') sb.append("&");
- i = oldi = i + 1;
- }
- }
- sb.append("</" + name + ">\r\n");
-
- } else if (o instanceof JSArray) {
- JSArray a = (JSArray)o;
- sb.append(" <" + name + " SOAP-ENC:arrayType=\"xsd:ur-type[" + a.length() + "]\">");
- for(int i=0; i<a.length(); i++) appendObject("item", a.elementAt(i), sb);
- sb.append("</" + name + ">\r\n");
-
- } else if (o instanceof JS) {
- JS j = (JS)o;
- sb.append(" <" + name + ">");
- Enumeration e = j.keys();
- while(e.hasMoreElements()) {
- Object key = e.nextElement();
- appendObject((String)key, j.get(key), sb);
- }
- sb.append("</" + name + ">\r\n");
-
- }*/
- }
-
- protected String buildRequest(JS[] args) throws JSExn, IOException {
- // build up the request
- StringBuffer content = new StringBuffer();
- content.append("SOAPAction: " + action + "\r\n\r\n");
- content.append("<?xml version=\"1.0\"?>\r\n");
- content.append("<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\r\n");
- content.append(" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\r\n");
- content.append(" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n");
- content.append(" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"\r\n");
- content.append(" xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\">\r\n");
- content.append("<SOAP-ENV:Body>\r\n");
- content.append(" <");
- content.append(method);
- content.append(nameSpace != null ? " xmlns=\"" + nameSpace + "\"" : "");
- content.append(">\r\n");
- if (args.length > 0) {
- Enumeration e = args[0].keys();
- while(e.hasMoreElements()) {
- JS key = e.nextElement();
- appendObject(JS.toString(key), args[0].get(key), content);
- }
- }
- content.append(" </" + method + "></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n");
- return content.toString();
- }
-
- public SOAP(String url, String methodname, String action, String nameSpace) {
- super(url, methodname);
- this.action = action;
- this.nameSpace = nameSpace;
- }
- public SOAP(String url, String methodname, SOAP httpSource, String action, String nameSpace) {
- super(url, methodname, httpSource);
- this.action = action;
- this.nameSpace = nameSpace;
- }
-
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.net;
-
-import java.io.*;
-import java.util.*;
-import org.ibex.js.*;
-import org.ibex.util.*;
-import org.ibex.crypto.*;
-
-/**
- * An XML-RPC client implemented as a JavaScript Host Object. See the
- * Ibex spec for information on its behavior.
- *
- * NOTE: this client is EXTREMELY lenient in the responses it will
- * accept; there are many, many invalid responses that it will
- * successfully parse and return. Do NOT use this to determine the
- * validity of your server.
- *
- * This client conforms to <a href="http://www.xmlrpc.com/spec">The
- * XML-RPC Spec</a>, subject to these limitations:
- * <ol>
- * <li> XMLRPC cannot invoke methods that require a <base64/> argument
- * <li> if a return value contains a <base64/>, it will be returned as a string
- * <li> The decision to pass a number as <i4/> or <double/> is based
- * entirely on whether or not the argument is fractional. Thus, it
- * is impossible to pass a non-fractional number to an xmlrpc
- * method that insists on being called with a <double/> element. We
- * hope that most xml-rpc servers will be able to automatically
- * convert.
- * </ol>
- */
-public class XMLRPC extends JS {
-
- public XMLRPC(String url, String method) {
- this.http = url.startsWith("stdio:") ? HTTP.stdio : new HTTP(url);
- this.url = url;
- this.method = method;
- }
- public XMLRPC(String url, String method, XMLRPC httpSource) {
- this.http = httpSource.http; this.url = url; this.method = method; }
- public Object get(Object name) {
- return new XMLRPC(url, (method.equals("") ? "" : method + ".") + name.toString(), this); }
-
-
- /** this holds character content as we read it in -- since there is only one per instance, we don't support mixed content */
- protected AccessibleCharArrayWriter content = new AccessibleCharArrayWriter(100);
- protected String url = null; ///< the url to connect to
- protected String method = null; ///< the method name to invoke on the remove server
- protected HTTP http = null; ///< the HTTP connection to use
- private Hash tracker; ///< used to detect multi-ref data
- protected boolean fault = false; ///< True iff the return value is a fault (and should be thrown as an exception)
-
-
- /** The object stack. As we process xml elements, pieces of the
- * return value are pushed onto and popped off of this stack.
- *
- * The general protocol is that any time a <value> tag is
- * encountered, an empty String ("") is pushed onto the stack. If
- * the <value/> node has content (either an anonymous
- * string or some other XML node), that content replaces the
- * empty string.
- *
- * If an <array> tag is encountered, a null is pushed onto the
- * stack. When a </data> is encountered, we search back on the
- * stack to the last null, replace it with a NativeJSArray, and
- * insert into it all elements above it on the stack.
- *
- * If a <struct> tag is encountered, a JSect is pushed
- * onto the stack. If a <name> tag is encountered, its CDATA is
- * pushed onto the stack. When a </member> is encountered, the
- * name (second element on stack) and value (top of stack) are
- * popped off the stack and inserted into the struct (third
- * element on stack).
- */
- protected Vec objects = null;
-
-
- // Recieve ////////////////////////////////////////////////////////////////
-
- private class Helper extends XML {
- public Helper() { super(BUFFER_SIZE); }
-
- public void startElement(XML.Element c) {
- content.reset();
- //#switch(c.getLocalName())
- case "fault": fault = true;
- case "struct": objects.setElementAt(new JS.O(), objects.size() - 1);
- case "array": objects.setElementAt(null, objects.size() - 1);
- case "value": objects.addElement("");
- //#end
- }
-
- public void endElement(XML.Element c) {
- //#switch(c.getLocalName())
- case "int": objects.setElementAt(JS.N(Integer.parseInt(new String(content.getBuf(), 0, content.size()))), objects.size() - 1);
- case "i4": objects.setElementAt(JS.N(Integer.parseInt(new String(content.getBuf(), 0, content.size()))), objects.size() - 1);
- case "boolean": objects.setElementAt(content.getBuf()[0] == '1' ? JS.T : JS.F, objects.size() - 1);
- case "string": objects.setElementAt(JS.S(new String(content.getBuf(), 0, content.size())), objects.size() - 1);
- case "double": objects.setElementAt(JS.N(Double.parseDouble(new String(content.getBuf(), 0, content.size()))), objects.size() - 1);
- case "base64":
- objects.setElementAt(new Stream.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size())),
- null), objects.size() - 1);
- case "name": objects.addElement(JS.S(new String(content.getBuf(), 0, content.size())));
- case "value": if ("".equals(objects.lastElement()))
- objects.setElementAt(JS.S(new String(content.getBuf(), 0, content.size())), objects.size() - 1);
- case "dateTime.iso8601":
- String s = new String(content.getBuf(), 0, content.size());
-
- // strip whitespace
- int i=0;
- while(Character.isWhitespace(s.charAt(i))) i++;
- if (i > 0) s = s.substring(i);
-
- try {
- JSDate nd = new JSDate();
- double date = JSDate.date_msecFromDate(Double.valueOf(s.substring(0, 4)).doubleValue(),
- Double.valueOf(s.substring(4, 6)).doubleValue() - 1,
- Double.valueOf(s.substring(6, 8)).doubleValue(),
- Double.valueOf(s.substring(9, 11)).doubleValue(),
- Double.valueOf(s.substring(12, 14)).doubleValue(),
- Double.valueOf(s.substring(15, 17)).doubleValue(),
- (double)0
- );
- nd.setTime(JSDate.internalUTC(date));
- objects.setElementAt(nd, objects.size() - 1);
-
- } catch (Exception e) {
- throw new RuntimeException("ibex.net.rpc.xml.recieve.malformedDateTag" +
- "the server sent a <dateTime.iso8601> tag which was malformed: " + s);
- }
- case "member":
- JS memberValue = (JS) objects.elementAt(objects.size() - 1);
- String memberName = (String)objects.elementAt(objects.size() - 2);
- JS struct = (JS)objects.elementAt(objects.size() - 3);
- try {
- struct.put(JS.S(memberName), memberValue);
- } catch (JSExn e) {
- throw new Error("this should never happen");
- }
- objects.setSize(objects.size() - 2);
- case "data":
- int i;
- for(i=objects.size() - 1; objects.elementAt(i) != null; i--);
- JS arr = new JSArray();
- try {
- for(int j = i + 1; j<objects.size(); j++) arr.put(JS.N(j - i - 1), (JS)objects.elementAt(j));
- } catch (JSExn e) {
- throw new Error("this should never happen");
- }
- objects.setElementAt(arr, i);
- objects.setSize(i + 1);
- //#end
- content.reset();
- }
-
- public void characters(char[] ch, int start, int length) {
- try { content.write(ch, start, length); }
- catch (Exception e) {
- if (Log.on) Log.info(this, "Exception in XMLRPC.content() -- this should never happen");
- if (Log.on) Log.info(this, e);
- }
- }
-
- public void whitespace(char[] ch, int start, int length) {}
- }
-
- // Send ///////////////////////////////////////////////////////////////////////////
-
- protected String buildRequest(JS[] args) throws JSExn, IOException {
- StringBuffer content = new StringBuffer();
- content.append("\r\n");
- content.append("<?xml version=\"1.0\"?>\n");
- content.append(" <methodCall>\n");
- content.append(" <methodName>");
- content.append(method);
- content.append("</methodName>\n");
- content.append(" <params>\n");
- for(int i=0; i<args.length; i++) {
- content.append(" <param>\n");
- appendObject(args[i], content);
- content.append(" </param>\n");
- }
- content.append(" </params>\n");
- content.append(" </methodCall>");
- return content.toString();
- }
-
- /** Appends the XML-RPC representation of <code>o</code> to <code>sb</code> */
- void appendObject(JS o, StringBuffer sb) throws JSExn {
- // JS:FIXME: Update for new api
- throw new Error("FIXME");
- /*if (o == null) {
- throw new JSExn("attempted to send a null value via XML-RPC");
-
- } else if (o instanceof Number) {
- if ((double)((Number)o).intValue() == ((Number)o).doubleValue()) {
- sb.append(" <value><i4>");
- sb.append(((Number)o).intValue());
- sb.append("</i4></value>\n");
- } else {
- sb.append(" <value><double>");
- sb.append(o);
- sb.append("</double></value>\n");
- }
-
- } else if (o instanceof Boolean) {
- sb.append(" <value><boolean>");
- sb.append(((Boolean)o).booleanValue() ? "1" : "0");
- sb.append("</boolean></value>\n");
-
- } else if (o instanceof Stream) {
- try {
- sb.append(" <value><base64>\n");
- InputStream is = ((Stream)o).getInputStream();
- byte[] buf = new byte[54];
- while(true) {
- int numread = is.read(buf, 0, 54);
- if (numread == -1) break;
- byte[] writebuf = buf;
- if (numread < buf.length) {
- writebuf = new byte[numread];
- System.arraycopy(buf, 0, writebuf, 0, numread);
- }
- sb.append(" ");
- sb.append(new String(Base64.encode(writebuf)));
- sb.append("\n");
- }
- sb.append("\n </base64></value>\n");
- } catch (IOException e) {
- if (Log.on) Log.info(this, "caught IOException while attempting to send a ByteStream via XML-RPC");
- if (Log.on) Log.info(this, e);
- throw new JSExn("caught IOException while attempting to send a ByteStream via XML-RPC");
- }
-
- } else if (o instanceof String) {
- sb.append(" <value><string>");
- String s = (String)o;
- if (s.indexOf('<') == -1 && s.indexOf('&') == -1) {
- sb.append(s);
- } else {
- char[] cbuf = s.toCharArray();
- int oldi = 0, i=0;
- while(true) {
- while(i < cbuf.length && cbuf[i] != '<' && cbuf[i] != '&') i++;
- sb.append(cbuf, oldi, i - oldi);
- if (i >= cbuf.length) break;
- if (cbuf[i] == '<') sb.append("<");
- else if (cbuf[i] == '&') sb.append("&");
- i = oldi = i + 1;
- if (i >= cbuf.length) break;
- }
- }
- sb.append("</string></value>\n");
-
- } else if (o instanceof JSDate) {
- sb.append(" <value><dateTime.iso8601>");
- java.util.Date d = new java.util.Date(((JSDate)o).getRawTime());
- sb.append(d.getYear() + 1900);
- if (d.getMonth() + 1 < 10) sb.append('0');
- sb.append(d.getMonth() + 1);
- if (d.getDate() < 10) sb.append('0');
- sb.append(d.getDate());
- sb.append('T');
- if (d.getHours() < 10) sb.append('0');
- sb.append(d.getHours());
- sb.append(':');
- if (d.getMinutes() < 10) sb.append('0');
- sb.append(d.getMinutes());
- sb.append(':');
- if (d.getSeconds() < 10) sb.append('0');
- sb.append(d.getSeconds());
- sb.append("</dateTime.iso8601></value>\n");
-
- } else if (o instanceof JSArray) {
- if (tracker.get(o) != null) throw new JSExn("attempted to send multi-ref data structure via XML-RPC");
- tracker.put(o, Boolean.TRUE);
- sb.append(" <value><array><data>\n");
- JSArray a = (JSArray)o;
- for(int i=0; i<a.length(); i++) appendObject(a.elementAt(i), sb);
- sb.append(" </data></array></value>\n");
-
- } else if (o instanceof JS) {
- if (tracker.get(o) != null) throw new JSExn("attempted to send multi-ref data structure via XML-RPC");
- tracker.put(o, Boolean.TRUE);
- JS j = (JS)o;
- sb.append(" <value><struct>\n");
- Enumeration e = j.keys();
- while(e.hasMoreElements()) {
- Object key = e.nextElement();
- sb.append(" <member><name>" + key + "</name>\n");
- appendObject(j.get(key), sb);
- sb.append(" </member>\n");
- }
- sb.append(" </struct></value>\n");
-
- } else {
- throw new JSExn("attempt to send object of type " + o.getClass().getName() + " via XML-RPC");
-
- }*/
- }
-
-
- // Call Sequence //////////////////////////////////////////////////////////////////////////
-
- public final JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- final JS[] args = new JS[nargs];
- for(int i=0;i<nargs;i++) args[i]= i==0?a0:i==1?a1:i==2?a2:rest[i-3];
- try {
- final JS.UnpauseCallback callback = JS.pause();
- new java.lang.Thread() { public void run() { call(callback,args); } }.start();
- return null; // doesn't matter since we paused
- } catch (NotPauseableException npe) {
- throw new JSExn("cannot invoke an XML-RPC call in the foreground thread");
- }
- }
-
- final void call(final JS.UnpauseCallback callback, JS[] args) {
- try {
- if (Log.rpc) Log.info(this, "call to " + url + " : " + method);
- if (tracker == null) tracker = new Hash();
- if (objects == null) objects = new Vec();
- String request = buildRequest(args);
- if (Log.rpc) Log.info(this, "send:\n" + request);
- InputStream is = http.POST("text/xml", request);
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
- try {
- new Helper().parse(br);
- final JSExn exn = fault ? new JSExn(objects.elementAt(0).toString()) : null;
- final JS result = fault ? null : objects.size() == 0 ? null : (JS) objects.elementAt(0);
- Scheduler.add(new Task() { public void perform() throws JSExn { if(fault) callback.unpause(exn); else callback.unpause(result); }});
- } finally {
- tracker.clear();
- objects.setSize(0);
- }
- } catch (final JSExn e) {
- Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(e); }});
- } catch (final IOException e) {
- final Exception e2 = e;
- Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2.toString())); }});
- } catch (final XML.Exn e) {
- final Exception e2 = e;
- Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2.toString())); }});
- }
- }
-}
protected Scheduler _getScheduler() { return new DarwinScheduler(); }
protected native void runApplicationEventLoop();
- private class DarwinScheduler extends org.ibex.util.Scheduler {
+ private class DarwinScheduler extends org.ibex.core.Scheduler {
public void run() {
new Thread() { public void run() { defaultRun(); } }.start();
runApplicationEventLoop();
/** Linux with an X11 display */
public class Linux extends X11 {
- public static void main(String[] args) throws Exception { org.ibex.Main.main(args); }
+ public static void main(String[] args) throws Exception { org.ibex.core.Main.main(args); }
private native void fixEnvironment();
public Linux() {
HTTP.Proxy ret = new HTTP.Proxy();
if (container[2] != null) {
- ret.proxyAutoConfigFunction = HTTP.Proxy.getProxyAutoConfigFunction(container[2]);
+ // FIXME!!!
+ //ret.proxyAutoConfigFunction = HTTP.Proxy.getProxyAutoConfigFunction(container[2]);
if (ret.proxyAutoConfigFunction != null) return ret;
}
((Win32Picture)source).init();
drawPicture(source, dx, dy, cx1, cy1, cx2, cy2, 0, false);
}
- public void drawGlyph(org.ibex.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) {
+ public void drawGlyph(org.ibex.graphics.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) {
Win32Picture p = ((Win32Picture)((Platform.DefaultGlyph)source).getPicture());
p.init();
drawPicture(p, dx, dy, cx1, cy1, cx2, cy2, rgb, true);
+++ /dev/null
-package org.ibex.util;
-
-import java.io.*;
-
-public class AccessibleCharArrayWriter extends CharArrayWriter {
- public char[] getBuf() { return buf; }
- public AccessibleCharArrayWriter(int i) { super(i); }
-}
-
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-// FEATURE: private void intersection() { }
-// FEATURE: private void union() { }
-// FEATURE: private void subset() { }
-// FEATURE: grow if we run out of slots
-
-// FEATURE: Add the cached_index stuff back in
-
-/** a weight-balanced tree with fake leaves */
-public class BalancedTree {
- // Instance Variables ///////////////////////////////////////////////////////////////////
-
- private int root = 0; ///< the slot of the root element
-
- private int cached_index = -1;
- private int cached_slot = -1;
-
- // Public API //////////////////////////////////////////////////////////////////////////
-
- /** the number of elements in the tree */
- public final int treeSize() {
- synchronized(BalancedTree.class) {
- return root == 0 ? 0 : size[root];
- }
- }
-
- /** clamps index to [0..treeSize()] and inserts object o *before* the specified index */
- public final void insertNode(int index, Object o) {
- synchronized(BalancedTree.class) {
- if(o == null) throw new Error("can't insert nulls in the balanced tree");
- cached_slot = cached_index = -1;
- if (index < 0) index = 0;
- if (index > treeSize()) index = treeSize();
- int arg = allocateSlot(o);
- if (root != 0) {
- insert(index, arg, root, 0, false, false);
- } else {
- root = arg;
- left[arg] = right[arg] = parent[arg] = 0;
- size[arg] = 1;
- }
- }
- }
-
- /** clamps index to [0..treeSize()-1] and replaces the object at that index with object o */
- public final void replaceNode(int index, Object o) {
- synchronized(BalancedTree.class) {
- if(o == null) throw new Error("can't insert nulls in the balanced tree");
- cached_slot = cached_index = -1;
- if(root == 0) throw new Error("called replaceNode() on an empty tree");
- if (index < 0) index = 0;
- if (index >= treeSize()) index = treeSize() - 1;
- int arg = allocateSlot(o);
- insert(index, arg, root, 0, true, false);
- }
- }
-
- /** returns the index of o; runs in O((log n)^2) time unless cache hit */
- public final int indexNode(Object o) {
- synchronized(BalancedTree.class) {
- if(o == null) return -1;
- if (cached_slot != -1 && objects[cached_slot] == o) return cached_index;
-
- int slot = getSlot(o);
- if(slot == -1) return -1;
-
- int index = 0;
- while(true) {
- // everything to the left is before us so add that to the index
- index += sizeof(left[slot]);
- // we are before anything on the right
- while(left[parent[slot]] == slot) slot = parent[slot];
- // we end of the first node who isn't on the left, go to the node that has as its child
- slot = parent[slot];
- // if we just processed the root we're done
- if(slot == 0) break;
- // count the node we're currently on towards the index
- index++;
- }
- return index;
- }
- }
-
- /** returns the object at index; runs in O(log n) time unless cache hit */
- public final Object getNode(int index) {
- synchronized(BalancedTree.class) {
- if (index == cached_index) return objects[cached_slot];
-
- if (cached_index != -1) {
- int distance = Math.abs(index - cached_index);
- // if the in-order distance between the cached node and the
- // target node is less than log(n), it's probably faster to
- // search directly.
- if ((distance < 16) && ((2 << distance) < treeSize())) {
- while(cached_index > index) { cached_slot = prev(cached_slot); cached_index--; }
- while(cached_index < index) { cached_slot = next(cached_slot); cached_index++; }
- return objects[cached_slot];
- }
- }
- /*
- cached_index = index;
- cached_slot = get(index, root);
- return objects[cached_slot];
- */
- return objects[get(index, root)];
- }
- }
-
- /** deletes the object at index, returning the deleted object */
- public final Object deleteNode(int index) {
- synchronized(BalancedTree.class) {
- cached_slot = cached_index = -1;
- // FIXME: left[], right[], size[], and parent[] aren't getting cleared properly somewhere in here where a node had two children
- int del = delete(index, root, 0);
- left[del] = right[del] = size[del] = parent[del] = 0;
- Object ret = objects[del];
- objects[del] = null;
- return ret;
- }
- }
-
- public final void clear() {
- synchronized(BalancedTree.class) {
- if(root == 0) return;
- int i = leftmost(root);
- do {
- int next = next(i);
- objects[i] = null;
- left[i] = right[i] = size[i] = parent[i] = 0;
- i = next;
- } while(i != 0);
- root = 0;
- }
- }
-
- // Node Data /////////////////////////////////////////////////////////////////////////
-
- private final static int NUM_SLOTS = 64 * 1024;
- // FEATURE: GROW - private final static int MAX_SLOT_DISTANCE = 32;
-
- /**
- * Every object inserted into *any* tree gets a "slot" in this
- * array. The slot is determined by hashcode modulo the length of
- * the array, with quadradic probing to resolve collisions. NOTE
- * that the "slot" of a node is NOT the same as its index.
- * Furthermore, if an object is inserted into multiple trees, that
- * object will have multiple slots.
- */
- private static Object[] objects = new Object[NUM_SLOTS];
-
- /// These two arrays hold the left and right children of each
- /// slot; in other words, left[x] is the *slot* of the left child
- /// of the node in slot x.
- ///
- /// If x has no left child, then left[x] is -1 multiplied by the
- /// slot of the node that precedes x; if x is the first node, then
- /// left[x] is 0. The right[] array works the same way.
- ///
- private static int[] left = new int[NUM_SLOTS];
- private static int[] right = new int[NUM_SLOTS];
-
- /// The parent of this node (0 if it is the root node)
- private static int[] parent = new int[NUM_SLOTS];
-
- ///< the number of descendants of this node *including the node itself*
- private static int[] size = new int[NUM_SLOTS];
-
-
- // Slot Management //////////////////////////////////////////////////////////////////////
-
- /** if alloc == false returns the slot holding object o. if alloc is true returns a new slot for obejct o */
- private int getSlot(Object o, boolean alloc) {
- // we XOR with our own hashcode so that we don't get tons of
- // collisions when a single Object is inserted into multiple
- // trees
- int dest = Math.abs(o.hashCode() ^ this.hashCode()) % objects.length;
- Object search = alloc ? null : o;
- int odest = dest;
- boolean plus = true;
- int tries = 1;
- if(dest == 0) dest=1;
- while (objects[dest] != search || !(alloc || root(dest) == root)) {
- dest = Math.abs((odest + (plus ? 1 : -1) * tries * tries) % objects.length);
- if (dest == 0) dest=1;
- if (plus) tries++;
- plus = !plus;
- // FEATURE: GROW - if(tries > MAX_SLOT_DISTANCE) return -1;
- }
- return dest;
- }
-
- /** returns the slots holding object o */
- private int getSlot(Object o) { return getSlot(o,false); }
-
- /** allocates a new slot holding object o*/
- private int allocateSlot(Object o) {
- int slot = getSlot(o, true);
- // FEATURE: GROW - if(slot == -1) throw new Error("out of slots");
- objects[slot] = o;
- return slot;
- }
-
-
-
- // Helpers /////////////////////////////////////////////////////////////////////////
-
- // FEATURE: These might be faster if they aren't recursive
- private final int leftmost(int slot) { return left[slot] <= 0 ? slot : leftmost(left[slot]); }
- private final int rightmost(int slot) { return right[slot] <= 0 ? slot : rightmost(right[slot]); }
- private final int sizeof(int slot) { return slot <= 0 ? 0 : size[slot]; }
- private final int root(int slot) { return parent[slot] == 0 ? slot : root(parent[slot]); }
-
- private int next(int node) {
- if(right[node] > 0) {
- node = right[node];
- while(left[node] > 0) node = left[node];
- return node;
- } else {
- int p = parent[node];
- while(right[p] == node) { node = p; p = parent[node]; };
- return p;
- }
- }
-
- private int prev(int node) {
- if(left[node] > 0) {
- node = left[node];
- while(right[node] > 0) node = right[node];
- return node;
- } else {
- int p = parent[node];
- while(left[p] == node) { node = p; p = parent[node]; }
- return p;
- }
- }
-
- // Rotation and Balancing /////////////////////////////////////////////////////////////
-
- // p p
- // | |
- // b d
- // / \ / \
- // a d < == > b e
- // / \ / \
- // c e a c
- // FIXME might be doing too much work here
- private void rotate(boolean toTheLeft, int b, int p) {
- int[] left = toTheLeft ? BalancedTree.left : BalancedTree.right;
- int[] right = toTheLeft ? BalancedTree.right : BalancedTree.left;
- int d = right[b];
- int c = left[d];
- if (d == 0) throw new Error("rotation error");
- left[d] = b;
- right[b] = c;
-
- parent[b] = d;
- parent[d] = p;
- if(c != 0) parent[c] = b;
-
- if (p == 0) root = d;
- else if (left[p] == b) left[p] = d;
- else if (right[p] == b) right[p] = d;
- else throw new Error("rotate called with invalid parent");
- size[b] = 1 + sizeof(left[b]) + sizeof(right[b]);
- size[d] = 1 + sizeof(left[d]) + sizeof(right[d]);
- }
-
- private void balance(int slot, int p) {
- if (slot <= 0) return;
- size[slot] = 1 + sizeof(left[slot]) + sizeof(right[slot]);
- if (sizeof(left[slot]) - 1 > 2 * sizeof(right[slot])) rotate(false, slot, p);
- else if (sizeof(left[slot]) * 2 < sizeof(right[slot]) - 1) rotate(true, slot, p);
- }
-
-
-
- // Insert /////////////////////////////////////////////////////////////////////////
-
- private void insert(int index, int arg, int slot, int p, boolean replace, boolean wentLeft) {
- int diff = slot == 0 ? 0 : index - sizeof(left[slot]);
- if (slot != 0 && diff != 0) {
- if (diff < 0) insert(index, arg, left[slot], slot, replace, true);
- else insert(index - sizeof(left[slot]) - 1, arg, right[slot], slot, replace, false);
- balance(slot, p);
- return;
- }
-
- if (size[arg] != 0) throw new Error("double insertion");
-
- // we are replacing an existing node
- if (replace) {
- if (diff != 0) throw new Error("this should never happen"); // since we already clamped the index
- if (p == 0) root = arg;
- else if (left[p] == slot) left[p] = arg;
- else if (right[p] == slot) right[p] = arg;
- else throw new Error("should never happen");
- left[arg] = left[slot];
- right[arg] = right[slot];
- size[arg] = size[slot];
- parent[arg] = parent[slot];
- if(left[slot] != 0) parent[left[slot]] = arg;
- if(right[slot] != 0) parent[right[slot]] = arg;
- objects[slot] = null;
- left[slot] = right[slot] = size[slot] = parent[slot] = 0;
-
- // we become the child of a former leaf
- } else if (slot == 0) {
- int[] left = wentLeft ? BalancedTree.left : BalancedTree.right;
- int[] right = wentLeft ? BalancedTree.right : BalancedTree.left;
- // FEATURE: Might be doing too much work here
- left[arg] = slot;
- right[arg] = 0;
- parent[arg] = p;
- left[p] = arg;
- balance(arg, p);
-
- // we take the place of a preexisting node
- } else {
- left[arg] = left[slot]; // steal slot's left subtree
- left[slot] = 0;
- right[arg] = slot; // make slot our right subtree
- parent[arg] = parent[slot];
- parent[slot] = arg;
- if(left[arg] != 0) parent[left[arg]] = arg;
- if (slot == root) {
- root = arg;
- balance(slot, arg);
- balance(arg, 0);
- } else {
- if (left[p] == slot) left[p] = arg;
- else if (right[p] == slot) right[p] = arg;
- else throw new Error("should never happen");
- balance(slot, arg);
- balance(arg, p);
- }
- }
- }
-
-
- // Retrieval //////////////////////////////////////////////////////////////////////
-
- private int get(int index, int slot) {
- int diff = index - sizeof(left[slot]);
- if (diff > 0) return get(diff - 1, right[slot]);
- else if (diff < 0) return get(index, left[slot]);
- else return slot;
- }
-
-
- // Deletion //////////////////////////////////////////////////////////////////////
-
- private int delete(int index, int slot, int p) {
- int diff = index - sizeof(left[slot]);
- if (diff < 0) {
- int ret = delete(index, left[slot], slot);
- balance(slot, p);
- return ret;
-
- } else if (diff > 0) {
- int ret = delete(diff - 1, right[slot], slot);
- balance(slot, p);
- return ret;
-
- // we found the node to delete
- } else {
-
- // fast path: it has no children
- if (left[slot] == 0 && right[slot] == 0) {
- if (p == 0) root = 0;
- else {
- int[] side = left[p] == slot ? left : right;
- side[p] = side[slot]; // fix parent's pointer
- }
-
- // fast path: it has no left child, so we replace it with its right child
- } else if (left[slot] == 0) {
- if (p == 0) root = right[slot];
- else (left[p] == slot ? left : right)[p] = right[slot]; // fix parent's pointer
- parent[right[slot]] = p;
- left[leftmost(right[slot])] = left[slot]; // fix our successor-leaf's fake right ptr
- balance(right[slot], p);
-
- // fast path; it has no right child, so we replace it with its left child
- } else if (right[slot] == 0) {
- if (p == 0) root = left[slot];
- else (left[p] == slot ? left : right)[p] = left[slot]; // fix parent's pointer
- parent[left[slot]] = p;
- right[rightmost(left[slot])] = right[slot]; // fix our successor-leaf's fake right ptr
- balance(left[slot], p);
-
- // node to be deleted has two children, so we replace it with its left child's rightmost descendant
- } else {
- int left_childs_rightmost = delete(sizeof(left[slot]) - 1, left[slot], slot);
- left[left_childs_rightmost] = left[slot];
- right[left_childs_rightmost] = right[slot];
- if(left[slot] != 0) parent[left[slot]] = left_childs_rightmost;
- if(right[slot] != 0) parent[right[slot]] = left_childs_rightmost;
- parent[left_childs_rightmost] = parent[slot];
- if (p == 0) root = left_childs_rightmost;
- else (left[p] == slot ? left : right)[p] = left_childs_rightmost; // fix parent's pointer
- balance(left_childs_rightmost, p);
- }
-
- return slot;
- }
- }
-
- protected void finalize() { clear(); }
-
- public void printTree() {
- if(root == 0) System.err.println("Tree is empty");
- else printTree(root,0,false);
- }
-
- private void printTree(int node,int indent,boolean l) {
- for(int i=0;i<indent;i++) System.err.print(" ");
- if(node == 0) System.err.println("None");
- else {
- System.err.print("" + node + ": " + objects[node]);
- System.err.println(" Parent: " + parent[node] + " Size: " + size[node]);
- printTree(left[node],indent+1,true);
- printTree(right[node],indent+1,false);
- }
- }
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-import java.io.*;
-import java.util.*;
-import java.util.zip.*;
-
-/** Reads a CAB file structure */
-public class CAB {
-
- /** reads a CAB file, parses it, and returns an InputStream representing the named file */
- public static InputStream getFileInputStream(InputStream is, String fileName) throws IOException, EOFException {
- return getFileInputStream(is, 0, fileName);
- }
-
- public static InputStream getFileInputStream(InputStream is, int skipHeaders, String fileName) throws IOException, EOFException {
- DataInputStream dis = new DataInputStream(is);
- CFHEADER h = new CFHEADER();
-
- while (skipHeaders > 0) { CFHEADER.seekMSCF(dis); skipHeaders--; }
-
- try {
- h.read(dis);
- } catch (CFHEADER.BogusHeaderException bhe) {
- throw new EOFException();
- }
-
- for(int i=0; i<h.folders.length; i++) {
- CFFOLDER f = new CFFOLDER(h);
- try {
- f.read(dis);
- } catch (CFFOLDER.UnsupportedCompressionTypeException ucte) {
- throw ucte;
- }
- }
-
- for(int i=0; i<h.files.length; i++) {
- CFFILE f = new CFFILE(h);
- f.read(dis);
- }
-
- for(int i=0; i<h.folders.length; i++) {
- InputStream is2 = new CFFOLDERInputStream(h.folders[i], dis);
- for(int j=0; j<h.folders[i].files.size(); j++) {
- CFFILE file = (CFFILE)h.folders[i].files.elementAt(j);
- if (file.fileName.equals(fileName)) return new LimitStream(is2, file.fileSize);
- byte[] b = new byte[file.fileSize];
- }
- }
-
- return null;
- }
-
- private static class LimitStream extends FilterInputStream {
- int limit;
- public LimitStream(InputStream is, int limit) {
- super(is);
- this.limit = limit;
- }
- public int read() throws IOException {
- if (limit == 0) return -1;
- int ret = super.read();
- if (ret != -1) limit--;
- return ret;
- }
- public int read(byte[] b, int off, int len) throws IOException {
- if (len > limit) len = limit;
- if (limit == 0) return -1;
- int ret = super.read(b, off, len);
- limit -= ret;
- return ret;
- }
- }
-
- /** Encapsulates a CFHEADER entry */
- public static class CFHEADER {
- byte[] reserved1 = new byte[4]; // reserved
- int fileSize = 0; // size of this cabinet file in bytes
- byte[] reserved2 = new byte[4]; // reserved
- int offsetOfFirstCFFILEEntry; // offset of the first CFFILE entry
- byte[] reserved3 = new byte[4]; // reserved
- byte versionMinor = 3; // cabinet file format version, minor
- byte versionMajor = 1; // cabinet file format version, major
- boolean prevCAB = false; // true iff there is a cabinet before this one in a sequence
- boolean nextCAB = false; // true iff there is a cabinet after this one in a sequence
- boolean hasReserved = false; // true iff the cab has per-{cabinet, folder, block} reserved areas
- int setID = 0; // must be the same for all cabinets in a set
- int indexInCabinetSet = 0; // number of this cabinet file in a set
- byte perCFFOLDERReservedSize = 0; // (optional) size of per-folder reserved area
- byte perDatablockReservedSize = 0; // (optional) size of per-datablock reserved area
- byte[] perCabinetReservedArea = null; // per-cabinet reserved area
- String previousCabinet = null; // name of previous cabinet file in a set
- String previousDisk = null; // name of previous disk in a set
- String nextCabinet = null; // name of next cabinet in a set
- String nextDisk = null; // name of next disk in a set
-
- CFFOLDER[] folders = new CFFOLDER[0];
- CFFILE[] files = new CFFILE[0];
-
- int readCFFOLDERs = 0; // the number of folders read in so far
- int readCFFILEs = 0; // the number of folders read in so far
-
- public void print(PrintStream ps) {
- ps.println("CAB CFFILE CFHEADER v" + ((int)versionMajor) + "." + ((int)versionMinor));
- ps.println(" total file size = " + fileSize);
- ps.println(" offset of first file = " + offsetOfFirstCFFILEEntry);
- ps.println(" total folders = " + folders.length);
- ps.println(" total files = " + files.length);
- ps.println(" flags = 0x" +
- Integer.toString((prevCAB ? 0x1 : 0x0) |
- (nextCAB ? 0x2 : 0x0) |
- (hasReserved ? 0x4 : 0x0), 16) + " [ " +
- (prevCAB ? "prev " : "") +
- (nextCAB ? "next " : "") +
- (hasReserved ? "reserve_present " : "") + "]");
- ps.println(" set id = " + setID);
- ps.println(" index in set = " + indexInCabinetSet);
- ps.println(" header reserved area #1 =" +
- " 0x" + Integer.toString(reserved1[0], 16) +
- " 0x" + Integer.toString(reserved1[1], 16) +
- " 0x" + Integer.toString(reserved1[2], 16) +
- " 0x" + Integer.toString(reserved1[3], 16));
- ps.println(" header reserved area #2 =" +
- " 0x" + Integer.toString(reserved2[0], 16) +
- " 0x" + Integer.toString(reserved2[1], 16) +
- " 0x" + Integer.toString(reserved2[2], 16) +
- " 0x" + Integer.toString(reserved2[3], 16));
- ps.println(" header reserved area #3 =" +
- " 0x" + Integer.toString(reserved3[0], 16) +
- " 0x" + Integer.toString(reserved3[1], 16) +
- " 0x" + Integer.toString(reserved3[2], 16) +
- " 0x" + Integer.toString(reserved3[3], 16));
- if (hasReserved) {
- if (perCabinetReservedArea != null) {
- ps.print(" per-cabinet reserved area = ");
- for(int i=0; i<perCabinetReservedArea.length; i++)
- ps.print(((perCabinetReservedArea[i] & 0xff) < 16 ? "0" : "") +
- Integer.toString(perCabinetReservedArea[i] & 0xff, 16) + " ");
- ps.println();
- }
- ps.println(" per folder reserved area = " + perCFFOLDERReservedSize + " bytes");
- ps.println(" per block reserved area = " + perDatablockReservedSize + " bytes");
- }
- }
-
- public String toString() {
- return
- "[ CAB CFFILE CFHEADER v" +
- ((int)versionMajor) + "." + ((int)versionMinor) + ", " +
- fileSize + " bytes, " +
- folders.length + " folders, " +
- files.length + " files] ";
- }
-
- /** fills in all fields in the header and positions the stream at the first folder */
- public void read(DataInputStream dis) throws IOException, BogusHeaderException {
- seekMSCF(dis);
- dis.readFully(reserved1);
-
- byte[] headerHashable = new byte[28];
- dis.readFully(headerHashable);
- DataInputStream hhis = new DataInputStream(new ByteArrayInputStream(headerHashable));
-
- fileSize = readLittleInt(hhis);
- hhis.readFully(reserved2);
- offsetOfFirstCFFILEEntry = readLittleInt(hhis);
- hhis.readFully(reserved3);
- versionMinor = hhis.readByte();
- versionMajor = hhis.readByte();
- folders = new CFFOLDER[readLittleShort(hhis)];
- files = new CFFILE[readLittleShort(hhis)];
- int flags = readLittleShort(hhis);
- prevCAB = (flags & 0x0001) != 0;
- nextCAB = (flags & 0x0002) != 0;
- hasReserved = (flags & 0x0004) != 0;
- setID = readLittleShort(hhis);
- indexInCabinetSet = readLittleShort(hhis);
-
- if (offsetOfFirstCFFILEEntry < 0 || fileSize < 0) {
- throw new BogusHeaderException();
- }
-
- if (hasReserved) {
- perCabinetReservedArea = new byte[readLittleShort(dis)];
- perCFFOLDERReservedSize = dis.readByte();
- perDatablockReservedSize = dis.readByte();
- if (perCabinetReservedArea.length > 0)
- dis.readFully(perCabinetReservedArea);
- }
-
- try {
- if (prevCAB) {
- previousCabinet = readZeroTerminatedString(dis);
- previousDisk = readZeroTerminatedString(dis);
- }
- if (nextCAB) {
- nextCabinet = readZeroTerminatedString(dis);
- nextDisk = readZeroTerminatedString(dis);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new BogusHeaderException();
- }
- }
-
- public static void seekMSCF(DataInputStream dis) throws EOFException, IOException
- {
- int state;
- // skip up to and including the 'MSCF' signature
- state = 0;
- while (state != 4) {
- // M
- while (state == 0 && dis.readByte() != 0x4D) { }
- state = 1;
- // S
- switch (dis.readByte()) {
- case 0x53 : state = 2; break;
- case 0x4D : state = 1; continue;
- default : state = 0; continue;
- }
- // C
- if (dis.readByte() == 0x43) { state = 3; }
- else { state = 0; continue; }
- // F
- if (dis.readByte() == 0x46) { state = 4; }
- else { state = 0; }
- }
- }
-
- public static class BogusHeaderException extends IOException {}
- }
-
- /** Encapsulates a CFFOLDER entry */
- public static class CFFOLDER {
- public static final int COMPRESSION_NONE = 0;
- public static final int COMPRESSION_MSZIP = 1;
- public static final int COMPRESSION_QUANTUM = 2;
- public static final int COMPRESSION_LZX = 3;
-
- int firstBlockOffset = 0; // offset of first data block within this folder
- int numBlocks = 0; // number of data blocks
- int compressionType = 0; // compression type for this folder
- byte[] reservedArea = null; // per-folder reserved area
- int indexInCFHEADER = 0; // our index in CFHEADER.folders
- Vector files = new Vector();
-
- private CFHEADER header = null;
-
- public CFFOLDER(CFHEADER header) { this.header = header; }
-
- public String toString() {
- return "[ CAB CFFOLDER, " + numBlocks + " data blocks, compression type " +
- compressionName(compressionType) +
- ", " + reservedArea.length + " bytes of reserved data ]";
- }
-
- public void read(DataInputStream dis) throws IOException, UnsupportedCompressionTypeException {
- firstBlockOffset = readLittleInt(dis);
- numBlocks = readLittleShort(dis);
- compressionType = readLittleShort(dis) & 0x000F;
- if (compressionType != COMPRESSION_MSZIP) {
- throw new UnsupportedCompressionTypeException(compressionType);
- }
- reservedArea = new byte[header.perCFFOLDERReservedSize];
- if (reservedArea.length > 0) dis.readFully(reservedArea);
- indexInCFHEADER = header.readCFFOLDERs++;
- header.folders[indexInCFHEADER] = this;
- }
-
- public static String compressionName(int type) {
- switch (type) {
- case COMPRESSION_NONE:
- return "NONE";
- case COMPRESSION_MSZIP:
- return "MSZIP";
- case COMPRESSION_QUANTUM:
- return "QUANTUM";
- case COMPRESSION_LZX:
- return "LZX";
- default:
- return "<Unknown type " + type + ">";
- }
- }
-
- public static class UnsupportedCompressionTypeException extends IOException {
- private int compressionType;
-
- UnsupportedCompressionTypeException(int type) {
- compressionType = type;
- }
- public String toString() {
- return "UnsupportedCompressionTypeException: no support for compression type " + compressionName(compressionType);
- }
- }
- }
-
- /** Encapsulates a CFFILE entry */
- public static class CFFILE {
- int fileSize = 0; // size of this file
- int uncompressedOffsetInCFFOLDER = 0; // offset of this file within the folder, not accounting for compression
- int folderIndex = 0; // index of the CFFOLDER we belong to
- Date date = null; // modification date
- int attrs = 0; // attrs
- boolean readOnly = false; // read-only flag
- boolean hidden = false; // hidden flag
- boolean system = false; // system flag
- boolean arch = false; // archive flag
- boolean runAfterExec = false; // true if file should be run during extraction
- boolean UTFfileName = false; // true if filename is UTF-encoded
- String fileName = null; // filename
- int indexInCFHEADER = 0; // our index in CFHEADER.files
- CFFOLDER folder = null; // the folder we belong to
- private CFHEADER header = null;
- File myFile;
-
- public CFFILE(CFHEADER header) { this.header = header; }
-
- public CFFILE(File f, String pathName) throws IOException {
- fileSize = (int)f.length();
- folderIndex = 0;
- date = new java.util.Date(f.lastModified());
- fileName = pathName;
- myFile = f;
- }
-
- public String toString() {
- return "[ CAB CFFILE: " + fileName + ", " + fileSize + " bytes [ " +
- (readOnly ? "readonly " : "") +
- (system ? "system " : "") +
- (hidden ? "hidden " : "") +
- (arch ? "arch " : "") +
- (runAfterExec ? "run_after_exec " : "") +
- (UTFfileName ? "UTF_filename " : "") +
- "]";
- }
-
- public void read(DataInputStream dis) throws IOException {
- fileSize = readLittleInt(dis);
- uncompressedOffsetInCFFOLDER = readLittleInt(dis);
- folderIndex = readLittleShort(dis);
- readLittleShort(dis); // date
- readLittleShort(dis); // time
- attrs = readLittleShort(dis);
- readOnly = (attrs & 0x1) != 0;
- hidden = (attrs & 0x2) != 0;
- system = (attrs & 0x4) != 0;
- arch = (attrs & 0x20) != 0;
- runAfterExec = (attrs & 0x40) != 0;
- UTFfileName = (attrs & 0x80) != 0;
- fileName = readZeroTerminatedString(dis);
-
- indexInCFHEADER = header.readCFFILEs++;
- header.files[indexInCFHEADER] = this;
- folder = header.folders[folderIndex];
- folder.files.addElement(this);
- }
- }
-
-
-
-
- // Compressing Input and Output Streams ///////////////////////////////////////////////
-
- /** an InputStream that decodes CFDATA blocks belonging to a CFFOLDER */
- private static class CFFOLDERInputStream extends InputStream {
- CFFOLDER folder;
- DataInputStream dis;
- InputStream iis = null;
-
- byte[] compressed = new byte[128 * 1024];
- byte[] uncompressed = new byte[256 * 1024];
-
- public CFFOLDERInputStream(CFFOLDER f, DataInputStream dis) {
- this.folder = f;
- this.dis = dis;
- }
-
- InputStream readBlock() throws IOException {
- int compressedBytes = readLittleShort(dis);
- int unCompressedBytes = readLittleShort(dis);
- byte[] reserved = new byte[/*folder.header.perDatablockReservedSize*/0];
- if (reserved.length > 0) dis.readFully(reserved);
- if (dis.readByte() != 0x43) throw new CABException("malformed block header");
- if (dis.readByte() != 0x4B) throw new CABException("malformed block header");
-
- dis.readFully(compressed, 0, compressedBytes - 2);
-
- Inflater i = new Inflater(true);
- i.setInput(compressed, 0, compressedBytes - 2);
-
- if (unCompressedBytes > uncompressed.length) uncompressed = new byte[unCompressedBytes];
- try { i.inflate(uncompressed, 0, uncompressed.length);
- } catch (DataFormatException dfe) {
- dfe.printStackTrace();
- throw new CABException(dfe.toString());
- }
- return new ByteArrayInputStream(uncompressed, 0, unCompressedBytes);
- }
-
- public int available() throws IOException { return iis == null ? 0 : iis.available(); }
- public void close() throws IOException { iis.close(); }
- public void mark(int i) { }
- public boolean markSupported() { return false; }
- public void reset() { }
-
- public long skip(long l) throws IOException {
- if (iis == null) iis = readBlock();
- int ret = 0;
- while (l > ret) {
- long numread = iis.skip(l - ret);
- if (numread == 0 || numread == -1) iis = readBlock();
- else ret += numread;
- }
- return ret;
- }
-
- public int read(byte[] b, int off, int len) throws IOException {
- if (iis == null) iis = readBlock();
- int ret = 0;
- while (len > ret) {
- int numread = iis.read(b, off + ret, len - ret);
- if (numread == 0 || numread == -1) iis = readBlock();
- else ret += numread;
- }
- return ret;
- }
-
- public int read() throws IOException {
- if (iis == null) iis = readBlock();
- int ret = iis.read();
- if (ret == -1) {
- iis = readBlock();
- ret = iis.read();
- }
- return ret;
- }
- }
-
-
-
- // Misc Stuff //////////////////////////////////////////////////////////////
-
- public static String readZeroTerminatedString(DataInputStream dis) throws IOException {
- int numBytes = 0;
- byte[] b = new byte[256];
- while(true) {
- byte next = dis.readByte();
- if (next == 0x0) return new String(b, 0, numBytes);
- b[numBytes++] = next;
- }
- }
-
- public static int readLittleInt(DataInputStream dis) throws IOException {
- int lowest = (int)(dis.readByte() & 0xff);
- int low = (int)(dis.readByte() & 0xff);
- int high = (int)(dis.readByte() & 0xff);
- int highest = (int)(dis.readByte() & 0xff);
- return (highest << 24) | (high << 16) | (low << 8) | lowest;
- }
-
- public static int readLittleShort(DataInputStream dis) throws IOException {
- int low = (int)(dis.readByte() & 0xff);
- int high = (int)(dis.readByte() & 0xff);
- return (high << 8) | low;
- }
-
- public static class CABException extends IOException {
- public CABException(String s) { super(s); }
- }
-
-
- /** scratch space for isToByteArray() */
- static byte[] workspace = new byte[16 * 1024];
-
- /** Trivial method to completely read an InputStream */
- public static synchronized byte[] isToByteArray(InputStream is) throws IOException {
- int pos = 0;
- while (true) {
- int numread = is.read(workspace, pos, workspace.length - pos);
- if (numread == -1) break;
- else if (pos + numread < workspace.length) pos += numread;
- else {
- pos += numread;
- byte[] temp = new byte[workspace.length * 2];
- System.arraycopy(workspace, 0, temp, 0, workspace.length);
- workspace = temp;
- }
- }
- byte[] ret = new byte[pos];
- System.arraycopy(workspace, 0, ret, 0, pos);
- return ret;
- }
-
-
-}
-
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-/*
-
-Bug report from a user:
-
-I looked at your Cache.java and tried to make good use of it, but I was
-out of luck - it wouldn't run here. Digging deeper into the code, I came
-across something that might be considered a bug. But maybe it's just a
-feature :-)
-
-
-Starting with an empty cache, Cache.put() immediately followed by
-Cache.get() on same keys / same object will set Node lru back to null in
-Node.remove() which is called in get().
-
-Assuming this put()-get() sequence is fixed, it will fill the cache, but
-lru will remain null.
-
-When cache is filled 100%, we have, at the end of the get(), where
-size>maxSize is checked, a state that mru == lru == n (from
-if(lru==null) thus deleteting the newly inserted object. Oops.
-
-
-Hope I made this clear enough. Maybe it's not a problem in xwt due to a
-different usage scheme of the cache.
-
-
-
-*/
-
-package org.ibex.util;
-
-// FIXME needs to be a weak hash
-
-/**
- * A Hash table with a fixed size; drops extraneous elements. Uses
- * LRU strategy.
- */
-public class Cache extends Hash {
-
- /** head of list is the mru; tail is the lru */
- Node mru = null;
- Node lru = null;
-
- private int maxSize;
- private Cache() { }
- public Cache(int maxSize) {
- super(maxSize * 2, 3);
- this.maxSize = maxSize;
- }
-
- /** A doubly-linked list */
- private class Node {
- final Object val;
- final Object k1;
- final Object k2;
- public Node(Object k1, Object k2, Object val) { this.k1 = k1; this.k2 = k2; this.val = val; }
- Node next = null;
- Node prev = null;
- void remove() {
- if (this == lru) lru = prev;
- if (this == mru) mru = next;
- if (next != null) next.prev = prev;
- if (prev != null) prev.next = next;
- next = prev = null;
- }
- void placeAfter(Node n) {
- remove();
- if (n == null) return;
- next = n.next;
- if (n.next != null) n.next.prev = this;
- n.next = this;
- prev = n;
- }
- void placeBefore(Node n) {
- remove();
- if (n == null) return;
- next = n;
- prev = n.prev;
- n.prev = this;
- if (prev != null) prev.next = this;
- }
- }
-
- public void clear() {
- lru = null;
- super.clear();
- }
-
- public void remove(Object k1, Object k2) {
- Object o = super.get(k1, k2);
- if (o != null) ((Node)o).remove();
- super.remove(k1, k2);
- }
-
- public Object get(Object k1, Object k2) {
- Node n = (Node)super.get(k1, k2);
- if (n == null) return null;
- n.remove();
- n.placeBefore(mru);
- mru = n;
- return n.val;
- }
-
- public void put(Object k1, Object k2, Object v) {
- Node n = new Node(k1, k2, v);
- if (lru == null) {
- lru = mru = n;
- } else {
- n.placeBefore(mru);
- mru = n;
- }
- if (super.get(k1, k2) != null) remove(k1, k2);
- super.put(k1, k2, n);
- if (size > maxSize) remove(lru.k1, lru.k2);
- }
-
-}
-
-
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-import java.io.*;
-
-// FEATURE: don't use a byte[] if we have a diskCache file
-/**
- * Wraps around an InputStream, caching the stream in a byte[] as it
- * is read and permitting multiple simultaneous readers
- */
-public class CachedInputStream {
-
- boolean filling = false; ///< true iff some thread is blocked on us waiting for input
- boolean eof = false; ///< true iff end of stream has been reached
- byte[] cache = new byte[1024 * 128];
- int size = 0;
- final InputStream is;
- File diskCache;
-
- public CachedInputStream(InputStream is) { this(is, null); }
- public CachedInputStream(InputStream is, File diskCache) {
- this.is = is;
- this.diskCache = diskCache;
- }
- public InputStream getInputStream() throws IOException {
- if (diskCache != null && diskCache.exists()) return new FileInputStream(diskCache);
- return new SubStream();
- }
-
- public void grow(int newLength) {
- if (newLength < cache.length) return;
- byte[] newCache = new byte[cache.length + 2 * (newLength - cache.length)];
- System.arraycopy(cache, 0, newCache, 0, size);
- cache = newCache;
- }
-
- synchronized void fillCache(int howMuch) throws IOException {
- if (filling) { try { wait(); } catch (InterruptedException e) { }; return; }
- filling = true;
- grow(size + howMuch);
- int ret = is.read(cache, size, howMuch);
- if (ret == -1) {
- eof = true;
- // FIXME: probably a race here
- if (diskCache != null && !diskCache.exists())
- try {
- File cacheFile = new File(diskCache + ".incomplete");
- FileOutputStream cacheFileStream = new FileOutputStream(cacheFile);
- cacheFileStream.write(cache, 0, size);
- cacheFileStream.close();
- cacheFile.renameTo(diskCache);
- } catch (IOException e) {
- Log.info(this, "exception thrown while writing disk cache");
- Log.info(this, e);
- }
- }
- else size += ret;
- filling = false;
- notifyAll();
- }
-
- private class SubStream extends InputStream implements KnownLength {
- int pos = 0;
- public int available() { return Math.max(0, size - pos); }
- public long skip(long n) throws IOException { pos += (int)n; return n; } // FEATURE: don't skip past EOF
- public int getLength() { return eof ? size : is instanceof KnownLength ? ((KnownLength)is).getLength() : 0; }
- public int read() throws IOException { // FEATURE: be smarter here
- byte[] b = new byte[1];
- int ret = read(b, 0, 1);
- return ret == -1 ? -1 : b[0]&0xff;
- }
- public int read(byte[] b, int off, int len) throws IOException {
- synchronized(CachedInputStream.this) {
- while (pos >= size && !eof) fillCache(pos + len - size);
- if (eof && pos == size) return -1;
- int count = Math.min(size - pos, len);
- System.arraycopy(cache, pos, b, off, count);
- pos += count;
- return count;
- }
- }
- }
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-/** a simple interface for callbacks*/
-public interface Callback {
-
- public abstract Object call(Object arg);
-
-}
+++ /dev/null
-// Copyright (C) 2004 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-package org.ibex.util;
-import java.util.*;
-
-public class CounterEnumeration implements Enumeration {
- public final int max;
- private int cur = 0;
- public CounterEnumeration(int i) { max = i; }
- public void reset() { cur = 0; }
- public boolean hasMoreElements() { return cur < max; }
- public Object nextElement() { return new Integer(cur++); }
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-/**
- * A general-purpose data structure for holding a list of rectangular
- * regions that need to be repainted, with intelligent coalescing.
- *
- * DirtyList will unify two regions A and B if the smallest rectangle
- * enclosing both A and B occupies no more than epsilon + Area_A +
- * Area_B. Failing this, if two corners of A fall within B, A will be
- * shrunk to exclude the union of A and B.
- */
-public class DirtyList {
-
- /** The dirty regions (each one is an int[4]). */
- private int[][] dirties = new int[10][];
-
- /** The number of dirty regions */
- private int numdirties = 0;
-
- /** See class comment */
- private static final int epsilon = 50 * 50;
-
- public int num() { return numdirties; }
-
- /** grows the array */
- private void grow() {
- int[][] newdirties = new int[dirties.length * 2][];
- System.arraycopy(dirties, 0, newdirties, 0, numdirties);
- dirties = newdirties;
- }
-
- /** Add a new rectangle to the dirty list; returns false if the
- * region fell completely within an existing rectangle or set of
- * rectangles (ie did not expand the dirty area)
- */
- public synchronized boolean dirty(int x, int y, int w, int h) {
- if (numdirties == dirties.length) grow();
-
- // we attempt the "lossless" combinations first
- for(int i=0; i<numdirties; i++) {
- int[] cur = dirties[i];
-
- // new region falls completely within existing region
- if (x >= cur[0] && y >= cur[1] && x + w <= cur[0] + cur[2] && y + h <= cur[1] + cur[3]) {
- return false;
-
- // existing region falls completely within new region
- } else if (x <= cur[0] && y <= cur[1] && x + w >= cur[0] + cur[2] && y + h >= cur[1] + cur[3]) {
- dirties[i][2] = 0;
- dirties[i][3] = 0;
-
- // left end of new region falls within existing region
- } else if (x >= cur[0] && x < cur[0] + cur[2] && y >= cur[1] && y + h <= cur[1] + cur[3]) {
- w = x + w - (cur[0] + cur[2]);
- x = cur[0] + cur[2];
- i = -1; continue;
-
- // right end of new region falls within existing region
- } else if (x + w > cur[0] && x + w <= cur[0] + cur[2] && y >= cur[1] && y + h <= cur[1] + cur[3]) {
- w = cur[0] - x;
- i = -1; continue;
-
- // top end of new region falls within existing region
- } else if (x >= cur[0] && x + w <= cur[0] + cur[2] && y >= cur[1] && y < cur[1] + cur[3]) {
- h = y + h - (cur[1] + cur[3]);
- y = cur[1] + cur[3];
- i = -1; continue;
-
- // bottom end of new region falls within existing region
- } else if (x >= cur[0] && x + w <= cur[0] + cur[2] && y + h > cur[1] && y + h <= cur[1] + cur[3]) {
- h = cur[1] - y;
- i = -1; continue;
-
- // left end of existing region falls within new region
- } else if (dirties[i][0] >= x && dirties[i][0] < x + w && dirties[i][1] >= y && dirties[i][1] + dirties[i][3] <= y + h) {
- dirties[i][2] = dirties[i][2] - (x + w - dirties[i][0]);
- dirties[i][0] = x + w;
- i = -1; continue;
-
- // right end of existing region falls within new region
- } else if (dirties[i][0] + dirties[i][2] > x && dirties[i][0] + dirties[i][2] <= x + w &&
- dirties[i][1] >= y && dirties[i][1] + dirties[i][3] <= y + h) {
- dirties[i][2] = x - dirties[i][0];
- i = -1; continue;
-
- // top end of existing region falls within new region
- } else if (dirties[i][0] >= x && dirties[i][0] + dirties[i][2] <= x + w && dirties[i][1] >= y && dirties[i][1] < y + h) {
- dirties[i][3] = dirties[i][3] - (y + h - dirties[i][1]);
- dirties[i][1] = y + h;
- i = -1; continue;
-
- // bottom end of existing region falls within new region
- } else if (dirties[i][0] >= x && dirties[i][0] + dirties[i][2] <= x + w &&
- dirties[i][1] + dirties[i][3] > y && dirties[i][1] + dirties[i][3] <= y + h) {
- dirties[i][3] = y - dirties[i][1];
- i = -1; continue;
- }
-
- }
-
- // then we attempt the "lossy" combinations
- for(int i=0; i<numdirties; i++) {
- int[] cur = dirties[i];
- if (w > 0 && h > 0 && cur[2] > 0 && cur[3] > 0 &&
- ((max(x + w, cur[0] + cur[2]) - min(x, cur[0])) *
- (max(y + h, cur[1] + cur[3]) - min(y, cur[1])) <
- w * h + cur[2] * cur[3] + epsilon)) {
- int a = min(cur[0], x);
- int b = min(cur[1], y);
- int c = max(x + w, cur[0] + cur[2]) - min(cur[0], x);
- int d = max(y + h, cur[1] + cur[3]) - min(cur[1], y);
- dirties[i][2] = 0;
- dirties[i][3] = 0;
- return dirty(a, b, c, d);
- }
- }
-
- dirties[numdirties++] = new int[] { x, y, w, h };
- return true;
- }
-
- /** Returns true if there are no regions that need repainting */
- public boolean empty() { return (numdirties == 0); }
-
- /**
- * Atomically returns the list of dirty rectangles as an array of
- * four-int arrays and clears the internal dirty-rectangle
- * list. Note that some of the regions returned may be null, or
- * may have zero height or zero width, and do not need to be
- * repainted.
- */
- public synchronized int[][] flush() {
- if (numdirties == 0) return null;
- int[][] ret = dirties;
- for(int i=numdirties; i<ret.length; i++) ret[i] = null;
- dirties = new int[dirties.length][];
- numdirties = 0;
- return ret;
- }
-
- /** included here so that it can be inlined */
- private static final int min(int a, int b) {
- if (a<b) return a;
- else return b;
- }
-
- /** included here so that it can be inlined */
- private static final int max(int a, int b) {
- if (a>b) return a;
- else return b;
- }
-
- /** included here so that it can be inlined */
- private static final int min(int a, int b, int c) {
- if (a<=b && a<=c) return a;
- else if (b<=c && b<=a) return b;
- else return c;
- }
-
- /** included here so that it can be inlined */
- private static final int max(int a, int b, int c) {
- if (a>=b && a>=c) return a;
- else if (b>=c && b>=a) return b;
- else return c;
- }
-
- /** included here so that it can be inlined */
- private static final int bound(int a, int b, int c) {
- if (a > b) return a;
- if (c < b) return c;
- return b;
- }
-
-}
+++ /dev/null
-package org.ibex.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * BrowserLauncher is a class that provides one static method, openURL, which opens the default
- * web browser for the current user of the system to the given URL. It may support other
- * protocols depending on the system -- mailto, ftp, etc. -- but that has not been rigorously
- * tested and is not guaranteed to work.
- * <p>
- * Yes, this is platform-specific code, and yes, it may rely on classes on certain platforms
- * that are not part of the standard JDK. What we're trying to do, though, is to take something
- * that's frequently desirable but inherently platform-specific -- opening a default browser --
- * and allow programmers (you, for example) to do so without worrying about dropping into native
- * code or doing anything else similarly evil.
- * <p>
- * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant systems without
- * modification or a need for additional libraries. All classes that are required on certain
- * platforms to allow this to run are dynamically loaded at runtime via reflection and, if not
- * found, will not cause this to do anything other than returning an error when opening the
- * browser.
- * <p>
- * There are certain system requirements for this class, as it's running through Runtime.exec(),
- * which is Java's way of making a native system call. Currently, this requires that a Macintosh
- * have a Finder which supports the GURL event, which is true for Mac OS 8.0 and 8.1 systems that
- * have the Internet Scripting AppleScript dictionary installed in the Scripting Additions folder
- * in the Extensions folder (which is installed by default as far as I know under Mac OS 8.0 and
- * 8.1), and for all Mac OS 8.5 and later systems. On Windows, it only runs under Win32 systems
- * (Windows 95, 98, and NT 4.0, as well as later versions of all). On other systems, this drops
- * back from the inherently platform-sensitive concept of a default browser and simply attempts
- * to launch Netscape via a shell command.
- * <p>
- * This code is Copyright 1999-2001 by Eric Albert (ejalbert@cs.stanford.edu) and may be
- * redistributed or modified in any form without restrictions as long as the portion of this
- * comment from this paragraph through the end of the comment is not removed. The author
- * requests that he be notified of any application, applet, or other binary that makes use of
- * this code, but that's more out of curiosity than anything and is not required. This software
- * includes no warranty. The author is not repsonsible for any loss of data or functionality
- * or any adverse or unexpected effects of using this software.
- * <p>
- * Credits:
- * <br>Steven Spencer, JavaWorld magazine (<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java Tip 66</a>)
- * <br>Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea Cantatore,
- * Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk
- *
- * @author Eric Albert (<a href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
- * @version 1.4b1 (Released June 20, 2001)
- */
-public class EjAlbertBrowserLauncher {
-
- /**
- * The Java virtual machine that we are running on. Actually, in most cases we only care
- * about the operating system, but some operating systems require us to switch on the VM. */
- private static int jvm;
-
- /** The browser for the system */
- private static Object browser;
-
- /**
- * Caches whether any classes, methods, and fields that are not part of the JDK and need to
- * be dynamically loaded at runtime loaded successfully.
- * <p>
- * Note that if this is <code>false</code>, <code>openURL()</code> will always return an
- * IOException.
- */
- private static boolean loadedWithoutErrors;
-
- /** The com.apple.mrj.MRJFileUtils class */
- private static Class mrjFileUtilsClass;
-
- /** The com.apple.mrj.MRJOSType class */
- private static Class mrjOSTypeClass;
-
- /** The com.apple.MacOS.AEDesc class */
- private static Class aeDescClass;
-
- /** The <init>(int) method of com.apple.MacOS.AETarget */
- private static Constructor aeTargetConstructor;
-
- /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
- private static Constructor appleEventConstructor;
-
- /** The <init>(String) method of com.apple.MacOS.AEDesc */
- private static Constructor aeDescConstructor;
-
- /** The findFolder method of com.apple.mrj.MRJFileUtils */
- private static Method findFolder;
-
- /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
- private static Method getFileCreator;
-
- /** The getFileType method of com.apple.mrj.MRJFileUtils */
- private static Method getFileType;
-
- /** The openURL method of com.apple.mrj.MRJFileUtils */
- private static Method openURLm;
-
- /** The makeOSType method of com.apple.MacOS.OSUtils */
- private static Method makeOSType;
-
- /** The putParameter method of com.apple.MacOS.AppleEvent */
- private static Method putParameter;
-
- /** The sendNoReply method of com.apple.MacOS.AppleEvent */
- private static Method sendNoReply;
-
- /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
- private static Object kSystemFolderType;
-
- /** The keyDirectObject AppleEvent parameter type */
- private static Integer keyDirectObject;
-
- /** The kAutoGenerateReturnID AppleEvent code */
- private static Integer kAutoGenerateReturnID;
-
- /** The kAnyTransactionID AppleEvent code */
- private static Integer kAnyTransactionID;
-
- /** The linkage object required for JDirect 3 on Mac OS X. */
- private static Object linkage;
-
- /** The framework to reference on Mac OS X */
- private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
-
- /** JVM constant for MRJ 2.0 */
- private static final int MRJ_2_0 = 0;
-
- /** JVM constant for MRJ 2.1 or later */
- private static final int MRJ_2_1 = 1;
-
- /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
- private static final int MRJ_3_0 = 3;
-
- /** JVM constant for MRJ 3.1 */
- private static final int MRJ_3_1 = 4;
-
- /** JVM constant for any Windows NT JVM */
- private static final int WINDOWS_NT = 5;
-
- /** JVM constant for any Windows 9x JVM */
- private static final int WINDOWS_9x = 6;
-
- /** JVM constant for any other platform */
- private static final int OTHER = -1;
-
- /**
- * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep non-U.S. English
- * systems from working properly.
- */
- private static final String FINDER_TYPE = "FNDR";
-
- /**
- * The creator code of the Finder on a Macintosh, which is needed to send AppleEvents to the
- * application.
- */
- private static final String FINDER_CREATOR = "MACS";
-
- /** The name for the AppleEvent type corresponding to a GetURL event. */
- private static final String GURL_EVENT = "GURL";
-
- /**
- * The first parameter that needs to be passed into Runtime.exec() to open the default web
- * browser on Windows.
- */
- private static final String FIRST_WINDOWS_PARAMETER = "/c";
-
- /** The second parameter for Runtime.exec() on Windows. */
- private static final String SECOND_WINDOWS_PARAMETER = "start";
-
- /**
- * The third parameter for Runtime.exec() on Windows. This is a "title"
- * parameter that the command line expects. Setting this parameter allows
- * URLs containing spaces to work.
- */
- private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
-
- /**
- * The shell parameters for Netscape that opens a given URL in an already-open copy of Netscape
- * on many command-line systems.
- */
- private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
- private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
- private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
-
- /**
- * The message from any exception thrown throughout the initialization process.
- */
- private static String errorMessage;
-
- /**
- * An initialization block that determines the operating system and loads the necessary
- * runtime data.
- */
- static {
- loadedWithoutErrors = true;
- String osName = System.getProperty("os.name");
- if (osName.startsWith("Mac OS")) {
- String mrjVersion = System.getProperty("mrj.version");
- String majorMRJVersion = mrjVersion.substring(0, 3);
- try {
- double version = Double.valueOf(majorMRJVersion).doubleValue();
- if (version == 2) {
- jvm = MRJ_2_0;
- } else if (version >= 2.1 && version < 3) {
- // Assume that all 2.x versions of MRJ work the same. MRJ 2.1 actually
- // works via Runtime.exec() and 2.2 supports that but has an openURL() method
- // as well that we currently ignore.
- jvm = MRJ_2_1;
- } else if (version == 3.0) {
- jvm = MRJ_3_0;
- } else if (version >= 3.1) {
- // Assume that all 3.1 and later versions of MRJ work the same.
- jvm = MRJ_3_1;
- } else {
- loadedWithoutErrors = false;
- errorMessage = "Unsupported MRJ version: " + version;
- }
- } catch (NumberFormatException nfe) {
- loadedWithoutErrors = false;
- errorMessage = "Invalid MRJ version: " + mrjVersion;
- }
- } else if (osName.startsWith("Windows")) {
- if (osName.indexOf("9") != -1) {
- jvm = WINDOWS_9x;
- } else {
- jvm = WINDOWS_NT;
- }
- } else {
- jvm = OTHER;
- }
-
- if (loadedWithoutErrors) { // if we haven't hit any errors yet
- loadedWithoutErrors = loadClasses();
- }
- }
-
- /**
- * This class should be never be instantiated; this just ensures so.
- */
- private EjAlbertBrowserLauncher() { }
-
- /**
- * Called by a static initializer to load any classes, fields, and methods required at runtime
- * to locate the user's web browser.
- * @return <code>true</code> if all intialization succeeded
- * <code>false</code> if any portion of the initialization failed
- */
- private static boolean loadClasses() {
- switch (jvm) {
- case MRJ_2_0:
- try {
- Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
- Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
- Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
- Class aeClass = Class.forName("com.apple.MacOS.ae");
- aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
-
- aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class [] { int.class });
- appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class[] { int.class, int.class, aeTargetClass, int.class, int.class });
- aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] { String.class });
-
- makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class [] { String.class });
- putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class[] { int.class, aeDescClass });
- sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[] { });
-
- Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject");
- keyDirectObject = (Integer) keyDirectObjectField.get(null);
- Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID");
- kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
- Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID");
- kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (NoSuchFieldException nsfe) {
- errorMessage = nsfe.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_2_1:
- try {
- mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
- mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
- Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
- kSystemFolderType = systemFolderField.get(null);
- findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass });
- getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class });
- getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchFieldException nsfe) {
- errorMessage = nsfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (SecurityException se) {
- errorMessage = se.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_3_0:
- try {
- Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
- Constructor constructor = linker.getConstructor(new Class[]{ Class.class });
- linkage = constructor.newInstance(new Object[] { EjAlbertBrowserLauncher.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- } catch (InvocationTargetException ite) {
- errorMessage = ite.getMessage();
- return false;
- } catch (InstantiationException ie) {
- errorMessage = ie.getMessage();
- return false;
- } catch (IllegalAccessException iae) {
- errorMessage = iae.getMessage();
- return false;
- }
- break;
- case MRJ_3_1:
- try {
- mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
- openURLm = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { String.class });
- } catch (ClassNotFoundException cnfe) {
- errorMessage = cnfe.getMessage();
- return false;
- } catch (NoSuchMethodException nsme) {
- errorMessage = nsme.getMessage();
- return false;
- }
- break;
- default:
- break;
- }
- return true;
- }
-
- /**
- * Attempts to locate the default web browser on the local system. Caches results so it
- * only locates the browser once for each use of this class per JVM instance.
- * @return The browser for the system. Note that this may not be what you would consider
- * to be a standard web browser; instead, it's the application that gets called to
- * open the default web browser. In some cases, this will be a non-String object
- * that provides the means of calling the default browser.
- */
- private static Object locateBrowser() {
- if (browser != null) {
- return browser;
- }
- switch (jvm) {
- case MRJ_2_0:
- try {
- Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
- Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
- Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
- Object appleEvent = appleEventConstructor.newInstance(new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });
- // Don't set browser = appleEvent because then the next time we call
- // locateBrowser(), we'll get the same AppleEvent, to which we'll already have
- // added the relevant parameter. Instead, regenerate the AppleEvent every time.
- // There's probably a way to do this better; if any has any ideas, please let
- // me know.
- return appleEvent;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InstantiationException ie) {
- browser = null;
- errorMessage = ie.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getMessage();
- return browser;
- }
- case MRJ_2_1:
- File systemFolder;
- try {
- systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
- } catch (IllegalArgumentException iare) {
- browser = null;
- errorMessage = iare.getMessage();
- return browser;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
- return browser;
- }
- String[] systemFolderFiles = systemFolder.list();
- // Avoid a FilenameFilter because that can't be stopped mid-list
- for(int i = 0; i < systemFolderFiles.length; i++) {
- try {
- File file = new File(systemFolder, systemFolderFiles[i]);
- if (!file.isFile()) {
- continue;
- }
- // We're looking for a file with a creator code of 'MACS' and
- // a type of 'FNDR'. Only requiring the type results in non-Finder
- // applications being picked up on certain Mac OS 9 systems,
- // especially German ones, and sending a GURL event to those
- // applications results in a logout under Multiple Users.
- Object fileType = getFileType.invoke(null, new Object[] { file });
- if (FINDER_TYPE.equals(fileType.toString())) {
- Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
- if (FINDER_CREATOR.equals(fileCreator.toString())) {
- browser = file.toString(); // Actually the Finder, but that's OK
- return browser;
- }
- }
- } catch (IllegalArgumentException iare) {
- browser = browser;
- errorMessage = iare.getMessage();
- return null;
- } catch (IllegalAccessException iae) {
- browser = null;
- errorMessage = iae.getMessage();
- return browser;
- } catch (InvocationTargetException ite) {
- browser = null;
- errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
- return browser;
- }
- }
- browser = null;
- break;
- case MRJ_3_0:
- case MRJ_3_1:
- browser = ""; // Return something non-null
- break;
- case WINDOWS_NT:
- browser = "cmd.exe";
- break;
- case WINDOWS_9x:
- browser = "command.com";
- break;
- case OTHER:
- default:
- browser = "netscape";
- break;
- }
- return browser;
- }
-
- /**
- * Attempts to open the default web browser to the given URL.
- * @param url The URL to open
- * @throws IOException If the web browser could not be located or does not run
- */
- public static void openURL(String url) throws IOException {
- if (!loadedWithoutErrors) {
- throw new IOException("Exception in finding browser: " + errorMessage);
- }
- Object browser = locateBrowser();
- if (browser == null) {
- throw new IOException("Unable to locate browser: " + errorMessage);
- }
-
- switch (jvm) {
- case MRJ_2_0:
- Object aeDesc = null;
- try {
- aeDesc = aeDescConstructor.newInstance(new Object[] { url });
- putParameter.invoke(browser, new Object[] { keyDirectObject, aeDesc });
- sendNoReply.invoke(browser, new Object[] { });
- } catch (InvocationTargetException ite) {
- throw new IOException("InvocationTargetException while creating AEDesc: " + ite.getMessage());
- } catch (IllegalAccessException iae) {
- throw new IOException("IllegalAccessException while building AppleEvent: " + iae.getMessage());
- } catch (InstantiationException ie) {
- throw new IOException("InstantiationException while creating AEDesc: " + ie.getMessage());
- } finally {
- aeDesc = null; // Encourage it to get disposed if it was created
- browser = null; // Ditto
- }
- break;
- case MRJ_2_1:
- Runtime.getRuntime().exec(new String[] { (String) browser, url } );
- break;
- case MRJ_3_0:
- int[] instance = new int[1];
- int result = ICStart(instance, 0);
- if (result == 0) {
- int[] selectionStart = new int[] { 0 };
- byte[] urlBytes = url.getBytes();
- int[] selectionEnd = new int[] { urlBytes.length };
- result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes,
- urlBytes.length, selectionStart,
- selectionEnd);
- if (result == 0) {
- // Ignore the return value; the URL was launched successfully
- // regardless of what happens here.
- ICStop(instance);
- } else {
- throw new IOException("Unable to launch URL: " + result);
- }
- } else {
- throw new IOException("Unable to create an Internet Config instance: " + result);
- }
- break;
- case MRJ_3_1:
- try {
- openURLm.invoke(null, new Object[] { url });
- } catch (InvocationTargetException ite) {
- throw new IOException("InvocationTargetException while calling openURL: " + ite.getMessage());
- } catch (IllegalAccessException iae) {
- throw new IOException("IllegalAccessException while calling openURL: " + iae.getMessage());
- }
- break;
- case WINDOWS_NT:
- case WINDOWS_9x:
- // Add quotes around the URL to allow ampersands and other special
- // characters to work.
- Process process = Runtime.getRuntime().exec(new String[] { (String) browser,
- FIRST_WINDOWS_PARAMETER,
- SECOND_WINDOWS_PARAMETER,
- THIRD_WINDOWS_PARAMETER,
- '"' + url + '"' });
- // This avoids a memory leak on some versions of Java on Windows.
- // That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
- try {
- process.waitFor();
- process.exitValue();
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
- }
- break;
- case OTHER:
- // Assume that we're on Unix and that Netscape is installed
-
- // First, attempt to open the URL in a currently running session of Netscape
- process = Runtime.getRuntime().exec(new String[] { (String) browser,
- NETSCAPE_REMOTE_PARAMETER,
- NETSCAPE_OPEN_PARAMETER_START +
- url +
- NETSCAPE_OPEN_PARAMETER_END });
- try {
- int exitCode = process.waitFor();
- if (exitCode != 0) { // if Netscape was not open
- Runtime.getRuntime().exec(new String[] { (String) browser, url });
- }
- } catch (InterruptedException ie) {
- throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
- }
- break;
- default:
- // This should never occur, but if it does, we'll try the simplest thing possible
- Runtime.getRuntime().exec(new String[] { (String) browser, url });
- break;
- }
- }
-
- /**
- * Methods required for Mac OS X. The presence of native methods does not cause
- * any problems on other platforms.
- */
- /*
- private native static int ICStart(int[] instance, int signature);
- private native static int ICStop(int[] instance);
- private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len,
- int[] selectionStart, int[] selectionEnd);
- */
- private static int ICStart(int[] instance, int signature) { return 0; }
- private static int ICStop(int[] instance) { return 0; }
- private static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len,
- int[] selectionStart, int[] selectionEnd) { return 0; }
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-import java.util.*;
-import java.io.*;
-
-/** provides commands to urlencode and urldecode strings, making sure
- * to escape sequences which have special meanings in filenames */
-public class FileNameEncoder {
-
- private static final char[] hex =
- new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
- public static String encode(String s) {
- StringBuffer sb = new StringBuffer();
- try {
- byte[] b = s.getBytes("UTF-8");
- for(int i=0; i<b.length; i++) {
- char c = (char)(b[i] & 0xff);
- if (c == File.separatorChar || c < 32 || c > 126 || c == '%' || (i == 0 && c == '.'))
- sb.append("%" + hex[(b[i] & 0xf0) >> 8] + hex[b[i] & 0xf]);
- else sb.append(c);
- }
- return sb.toString();
- } catch (UnsupportedEncodingException uee) {
- throw new Error("this should never happen; Java spec mandates UTF-8 support");
- }
- }
-
- public static String decode(String s) {
- StringBuffer sb = new StringBuffer();
- byte[] b = new byte[s.length() * 2];
- int bytes = 0;
- for(int i=0; i<s.length(); i++) {
- char c = s.charAt(i);
- if (c == '%') b[bytes++] = (byte)Integer.parseInt(("" + s.charAt(++i) + s.charAt(++i)), 16);
- else b[bytes++] = (byte)c;
- }
- try {
- return new String(b, 0, bytes, "UTF-8");
- } catch (UnsupportedEncodingException uee) {
- throw new Error("this should never happen; Java spec mandates UTF-8 support");
- }
- }
-}
+++ /dev/null
-package org.ibex.util;
-
-import org.ibex.js.*;
-
-public abstract class Grammar extends JS {
-
- public JS action = null;
-
- // FIXME: Updae for new api
-
- // means we call()ed a Grammar that hasn't been bound to a scope yet
- /*public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- throw new Error("this should never happen");
- }
-
- private static Object NULL = new Object();
-
- public abstract int match(String s, int start, Hash v, JSScope scope) throws JSExn;
- public int matchAndWrite(final String s, final int start, Hash v, JSScope scope, String key) throws JSExn {
- final Hash v2 = new Hash();
- final int ret = match(s, start, v2, scope);
- Object result = ret == -1 ? NULL : action == null ?
- s.substring(start, ret) :
- JS.cloneWithNewParentScope(action, new JSScope(scope) {
- public Object get(Object key) throws JSExn {
- Object val = v2.get(key);
- if (val == NULL) return null;
- if (val != null) return val;
- if (key.equals("whole")) return s.substring(start, ret);
- return super.get(key);
- }
- }).call(null, null, null, null, 0);
- if (key != null) {
- Object old = v.get(key);
- if (old == null || old == NULL) { }
- else if (old instanceof JSArray) { if (result != NULL) { ((JSArray)old).addElement(result); result = old; } }
- else if (result != NULL) { JSArray j = new JSArray(); j.addElement(old); j.addElement(result); result = j; }
- v.put(key, result);
- }
- return ret;
- }
-
- public static class Alternative extends Grammar {
- private Grammar r1, r2;
- public Alternative(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; }
- public int match(String s, int start, Hash v, JSScope r) throws JSExn {
- int s1 = r1.match(s, start, v, r);
- if (s1 != -1) return s1;
- int s2 = r2.match(s, start, v, r);
- if (s2 != -1) return s2;
- return -1;
- }
- }
-
- public static class Juxtaposition extends Grammar {
- private Grammar r1, r2;
- public Juxtaposition(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; }
- public int match(String s, int start, Hash v, JSScope r) throws JSExn {
- int s1 = r1.match(s, start, v, r);
- if (s1 == -1) return -1;
- int s2 = r2.match(s, s1, v, r);
- if (s2 == -1) return -1;
- return s2;
- }
- }
-
- public static class Repetition extends Grammar {
- private Grammar r1;
- private int min, max;
- public Repetition(Grammar r1, int min, int max) { this.r1 = r1; this.min = min; this.max = max; }
- public int match(String s, int start, Hash v, JSScope r) throws JSExn {
- int i;
- for(i=0; i<max; i++) {
- start = r1.match(s, start, v, r);
- if (start == -1) return -1;
- }
- if (i < min) return -1;
- return start;
- }
- }
-
- public static class Literal extends Grammar {
- String str;
- public Literal(String str) { this.str = str; }
- public int match(String s, int start, Hash v, JSScope r) {
- if (!s.regionMatches(start, str, 0, str.length())) return -1;
- return start + str.length();
- }
- }
-
- public static class Range extends Grammar {
- char min, max;
- public Range(char min, char max) { this.min = min; this.max = max; }
- public int match(String s, int start, Hash v, JSScope r) throws JSExn {
- if (!(s.charAt(start) >= min && s.charAt(start) <= max)) return -1;
- return start + 1;
- }
- }
-
- public static class Reference extends Grammar {
- String key;
- public Reference(String key) { this.key = key; }
- public int match(String s, int start, Hash v, JSScope scope) throws JSExn {
- return ((Grammar)scope.get(key)).matchAndWrite(s, start, v, scope, key);
- }
- }*/
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-import java.util.*;
-
-/** Implementation of an unsynchronized hash table, with one or two
- * keys, using Radke's quadradic residue linear probing instead of
- * buckets to minimize object count (less allocations, faster GC).
- * See C. Radke, Communications of the ACM, 1970, 103-105
- *
- * Not threadsafe.
- */
-public class Hash {
- /** this object is inserted as key in a slot when the
- * corresponding value is removed -- this ensures that the
- * probing sequence for any given key remains the same even if
- * other keys are removed.
- */
- private static Object placeholder = new Object();
-
- /** the number of entries with at least one non-null key */
- private int usedslots = 0;
-
- /** the number of entries with non-null values */
- protected int size = 0;
-
- /** when num_slots < loadFactor * size, rehash into a bigger table */
- private final int loadFactor;
-
- /** primary keys */
- private Object[] keys1 = null;
-
- /** secondary keys; null if no secondary key has ever been added */
- private Object[] keys2 = null;
-
- /** the values for the table */
- private Object[] vals = null;
-
- /** the number of entries with a non-null value */
- public int size() { return size; }
-
- /** empties the table */
- public void clear() {
- size = 0;
- usedslots = 0;
- for(int i=0; i<vals.length; i++) {
- vals[i] = null;
- keys1[i] = null;
- if (keys2 != null) keys2[i] = null;
- }
- }
-
- /** returns all the primary keys in the table */
- public Enumeration keys() { return new HashEnum(); }
-
- public Hash() { this(25, 3); }
- public Hash(int initialcapacity, int loadFactor) {
- // using a pseudoprime in the form 4x+3 ensures full coverage
- initialcapacity = initialcapacity / 4;
- initialcapacity = 4 * initialcapacity + 3;
- keys1 = new Object[initialcapacity];
- vals = new Object[initialcapacity];
- this.loadFactor = loadFactor;
- }
-
- public void remove(Object k1) { remove(k1, null); }
- public void remove(Object k1, Object k2) { put_(k1, k2, null); }
-
- private void rehash() {
- Object[] oldkeys1 = keys1;
- Object[] oldkeys2 = keys2;
- Object[] oldvals = vals;
- keys1 = new Object[oldvals.length * 2];
- keys2 = oldkeys2 == null ? null : new Object[oldvals.length * 2];
- vals = new Object[oldvals.length * 2];
- size = 0;
- usedslots = 0;
- for(int i=0; i<oldvals.length; i++)
- if (((oldkeys1[i] != null && oldkeys1[i] != placeholder) || (oldkeys2 != null && oldkeys2[i] != null)) && oldvals[i] != null)
- put_(oldkeys1[i], oldkeys2 == null ? null : oldkeys2[i], oldvals[i]);
- }
-
- public Object get(Object k1) { return get(k1, null); }
- public Object get(Object k1, Object k2) {
- if (k2 != null && keys2 == null) return null;
- int hash = (k1 == null ? 0 : k1.hashCode()) ^ (k2 == null ? 0 : k2.hashCode());
- int dest = Math.abs(hash) % vals.length;
- int odest = dest;
- int tries = 1;
- boolean plus = true;
- while (keys1[dest] != null || (keys2 != null && keys2[dest] != null)) {
- Object hk1 = keys1[dest];
- Object hk2 = keys2 == null ? null : keys2[dest];
- if ((k1 == hk1 || (k1 != null && hk1 != null && k1.equals(hk1))) &&
- (k2 == hk2 || (k2 != null && hk2 != null && k2.equals(hk2)))) {
- return vals[dest];
- }
- dest = Math.abs((odest + (plus ? 1 : -1 ) * tries * tries) % vals.length);
- if (plus) tries++;
- plus = !plus;
- }
- return null;
- }
-
- public void put(Object k1, Object v) { put(k1, null, v); }
- public void put(Object k1, Object k2, Object v) { put_(k1, k2, v); }
- private void put_(Object k1, Object k2, Object v) {
- if (usedslots * loadFactor > vals.length) rehash();
- int hash = (k1 == null ? 0 : k1.hashCode()) ^ (k2 == null ? 0 : k2.hashCode());
- int dest = Math.abs(hash) % vals.length;
- int odest = dest;
- boolean plus = true;
- int tries = 1;
- while (true) {
- Object hk1 = keys1[dest];
- Object hk2 = keys2 == null ? null : keys2[dest];
- if (hk1 == null && hk2 == null) { // empty slot
- if (v == null) return;
- size++;
- usedslots++;
- break;
- }
-
- if ((k1 == hk1 || (k1 != null && hk1 != null && k1.equals(hk1))) && // replacing former entry
- (k2 == hk2 || (k2 != null && hk2 != null && k2.equals(hk2)))) {
-
- // we don't actually remove things from the table; rather, we insert a placeholder
- if (v == null) {
- k1 = placeholder;
- k2 = null;
- size--;
- }
- break;
- }
-
- dest = Math.abs((odest + (plus ? 1 : -1 ) * tries * tries) % vals.length);
- if (plus) tries++;
- plus = !plus;
- }
-
- keys1[dest] = k1;
- if (k2 != null && keys2 == null) keys2 = new Object[keys1.length];
- if (keys2 != null) keys2[dest] = k2;
- vals[dest] = v;
- }
-
- private class HashEnum implements java.util.Enumeration {
- private int iterator;
-
- public HashEnum() { findNext(); }
-
- private void findNext() {
- while(iterator < keys1.length && (keys1[iterator] == null || keys1[iterator] == placeholder)) iterator++;
- }
-
- public boolean hasMoreElements() {
- return iterator < keys1.length;
- }
-
- public Object nextElement() {
- if (iterator == keys1.length) throw new NoSuchElementException();
- Object o = keys1[iterator];
- iterator++;
- findNext();
- return o;
- }
- }
-}
-
-
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-import java.io.*;
-
-public class InputStreamToByteArray {
-
- /** scratch space for isToByteArray() */
- private static byte[] workspace = new byte[16 * 1024];
-
- /** Trivial method to completely read an InputStream */
- public static synchronized byte[] convert(InputStream is) throws IOException {
- int pos = 0;
- while (true) {
- int numread = is.read(workspace, pos, workspace.length - pos);
- if (numread == -1) break;
- else if (pos + numread < workspace.length) pos += numread;
- else {
- pos += numread;
- byte[] temp = new byte[workspace.length * 2];
- System.arraycopy(workspace, 0, temp, 0, workspace.length);
- workspace = temp;
- }
- }
- byte[] ret = new byte[pos];
- System.arraycopy(workspace, 0, ret, 0, pos);
- return ret;
- }
-
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-import java.io.*;
-
-/** a generic interface for things that "know" their length */
-public interface KnownLength {
-
- public abstract int getLength();
-
- public static class KnownLengthInputStream extends FilterInputStream implements KnownLength {
- int length;
- public int getLength() { return length; }
- public KnownLengthInputStream(java.io.InputStream parent, int length) {
- super(parent);
- this.length = length;
- }
- }
-
-}
+++ /dev/null
-package org.ibex.util;
-import java.io.*;
-
-public class LineReader {
-
- private int MAXBUF = 1024 * 16;
- char[] buf = new char[MAXBUF];
- int buflen = 0;
- Reader r;
- Vec pushback = new Vec();
-
- public LineReader(Reader r) { this.r = r; }
-
- public void pushback(String s) { pushback.push(s); }
-
- public String readLine() throws IOException {
- while(true) {
- if (pushback.size() > 0) return (String)pushback.pop();
- for(int i=0; i<buflen; i++) {
- if (buf[i] == '\n') {
- String ret;
- if (buf[i-1] == '\r') ret = new String(buf, 0, i-1);
- else ret = new String(buf, 0, i);
- System.arraycopy(buf, i+1, buf, 0, buflen - (i+1));
- buflen -= i+1;
- return ret;
- }
- }
- if (buflen == MAXBUF) {
- char[] buf2 = new char[MAXBUF*2];
- System.arraycopy(buf, 0, buf2, 0, buflen);
- buf = buf2;
- MAXBUF *= 2;
- }
- int numread = r.read(buf, buflen, MAXBUF - buflen);
- if (numread == -1) {
- if (buflen == 0) return null;
- String ret = new String(buf, 0, buflen);
- buflen = 0;
- return ret;
- } else {
- buflen += numread;
- }
- }
- }
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-import org.ibex.js.*;
-import java.io.*;
-import java.util.*;
-import java.net.*;
-
-/** easy to use logger */
-public class Log {
-
- public static boolean on = System.getProperty("ibex.log.on", "true").equals("true");
- public static boolean color = System.getProperty("ibex.log.color", "true").equals("true");
- public static boolean verbose = System.getProperty("ibex.log.verbose", "false").equals("true");
- public static boolean logDates = System.getProperty("ibex.log.dates", "false").equals("true");
- public static boolean notes = System.getProperty("ibex.log.notes.on", "true").equals("true");
- public static int maximumNoteLength = Integer.parseInt(System.getProperty("ibex.log.notes.maximumLength", (1024 * 32)+""));
- public static boolean rpc = false;
- public static Date lastDate = null;
-
- public static PrintStream logstream = System.err;
-
- public static void flush() { logstream.flush(); }
- public static void email(String address) { throw new Error("FIXME not supported"); }
- public static void file(String filename) throws IOException {
- // FIXME security
- logstream = new PrintStream(new FileOutputStream(filename));
- }
- public static void tcp(String host, int port) throws IOException {
- // FIXME security
- logstream = new PrintStream(new Socket(InetAddress.getByName(host), port).getOutputStream());
- }
-
- private static Hashtable threadAnnotations = new Hashtable();
- public static void setThreadAnnotation(String s) { threadAnnotations.put(Thread.currentThread(), s); }
-
- /**
- * Notes can be used to attach log messages to the current thread
- * if you're not sure you want them in the log just yet.
- * Originally designed for retroactively logging socket-level
- * conversations only if an error is encountered
- */
- public static void note(String s) {
- if (!notes) return;
- StringBuffer notebuf = notebuf();
- notebuf.append(s);
- if (notebuf.length() > maximumNoteLength) {
- notebuf.reverse();
- notebuf.setLength(maximumNoteLength * 3 / 4);
- notebuf.reverse();
- }
- }
- public static void clearnotes() { if (!notes) return; notebuf().setLength(0); }
- private static Hashtable notebufs = new Hashtable();
- private static StringBuffer notebuf() {
- StringBuffer ret = (StringBuffer)notebufs.get(Thread.currentThread());
- if (ret == null) {
- ret = new StringBuffer(16 * 1024);
- notebufs.put(Thread.currentThread(), ret);
- }
- return ret;
- }
-
- /** true iff nothing has yet been logged */
- public static boolean firstMessage = true;
-
- /** message can be a String or a Throwable */
- public static synchronized void echo(Object o, Object message) { log(o, message, ECHO); }
- public static synchronized void diag(Object o, Object message) { log(o, message, DIAGNOSTIC); }
- public static synchronized void debug(Object o, Object message) { log(o, message, DEBUG); }
- public static synchronized void info(Object o, Object message) { log(o, message, INFO); }
- public static synchronized void warn(Object o, Object message) { log(o, message, WARN); }
- public static synchronized void error(Object o, Object message) { log(o, message, ERROR); }
-
- // these two logging levels serve ONLY to change the color; semantically they are the same as DEBUG
- private static final int DIAGNOSTIC = -2;
- private static final int ECHO = -1;
-
- // the usual log4j levels, minus FAIL (we just throw an Error in that case)
- public static final int DEBUG = 0;
- public static final int INFO = 1;
- public static final int WARN = 2;
- public static final int ERROR = 3;
- public static final int SILENT = Integer.MAX_VALUE;
- public static int level = INFO;
-
- private static final int BLUE = 34;
- private static final int GREEN = 32;
- private static final int CYAN = 36;
- private static final int RED = 31;
- private static final int PURPLE = 35;
- private static final int BROWN = 33;
- private static final int GRAY = 37;
-
- private static String colorize(int color, boolean bright, String s) {
- if (!Log.color) return s;
- return
- "\033[40;" + (bright?"1;":"") + color + "m" +
- s +
- "\033[0m";
- }
-
- private static String lastClassName = null;
- private static synchronized void log(Object o, Object message, int level) {
- if (level < Log.level) return;
- if (firstMessage && !logDates) {
- firstMessage = false;
- logstream.println(colorize(GREEN, false, "==========================================================================="));
-
- // FIXME later: causes problems with method pruning
- //diag(Log.class, "Logging enabled at " + new java.util.Date());
-
- if (color) diag(Log.class, "logging messages in " +
- colorize(BLUE, true, "c") +
- colorize(RED, true, "o") +
- colorize(CYAN, true, "l") +
- colorize(GREEN, true, "o") +
- colorize(PURPLE, true, "r"));
- }
-
- String classname;
- if (o instanceof Class) {
- classname = ((Class)o).getName();
- if (classname.indexOf('.') != -1) classname = classname.substring(classname.lastIndexOf('.') + 1);
- }
- else if (o instanceof String) classname = (String)o;
- else classname = o.getClass().getName();
-
- if (classname.equals(lastClassName)) classname = "";
- else lastClassName = classname;
-
- if (classname.length() > (logDates ? 14 : 20)) classname = classname.substring(0, (logDates ? 14 : 20));
- while (classname.length() < (logDates ? 14 : 20)) classname = " " + classname;
- classname = classname + (classname.trim().length() == 0 ? " " : ": ");
- classname = colorize(GRAY, true, classname);
- classname = classname.replace('$', '.');
-
- if (logDates) {
- Date d = new Date();
- if (lastDate == null || d.getYear() != lastDate.getYear() || d.getMonth() != lastDate.getMonth() || d.getDay() != lastDate.getDay()) {
- String now = new java.text.SimpleDateFormat("EEE dd MMM yyyy").format(d);
- logstream.println();
- logstream.println(colorize(GRAY, false, "=== " + now + " =========================================================="));
- }
- java.text.DateFormat df = new java.text.SimpleDateFormat("[EEE HH:mm:ss] ");
- classname = df.format(d) + classname;
- lastDate = d;
- }
-
- String annot = (String)threadAnnotations.get(Thread.currentThread());
- if (annot != null) classname += annot;
-
- if (message instanceof Throwable) {
- if (level < ERROR) level = WARN;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ((Throwable)message).printStackTrace(new PrintStream(baos));
- if (notes && notebuf().length() > 0) {
- PrintWriter pw = new PrintWriter(baos);
- pw.println();
- pw.println("Thread notes:");
- pw.println(notebuf().toString());
- clearnotes();
- pw.flush();
- }
- byte[] b = baos.toByteArray();
- BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(b)));
- String s = null;
- try {
- String m = "";
- while((s = br.readLine()) != null) m += s + "\n";
- if (m.length() > 0) log(o, m.substring(0, m.length() - 1), level);
- } catch (IOException e) {
- // FEATURE: use org.ibex.io.Stream's here
- logstream.println(colorize(RED, true, "Logger: exception thrown by ByteArrayInputStream; this should not happen"));
- }
- lastClassName = "";
- return;
- }
-
- String str = message.toString();
- if (str.indexOf('\n') != -1) lastClassName = "";
- while(str.indexOf('\t') != -1)
- str = str.substring(0, str.indexOf('\t')) + " " + str.substring(str.indexOf('\t') + 1);
-
- classname = colorize(GRAY, false, classname);
- int levelcolor = GRAY;
- boolean bright = true;
- switch (level) {
- case DIAGNOSTIC: levelcolor = GREEN; bright = false; break;
- case ECHO: levelcolor = BLUE; bright = true; break;
- case DEBUG: levelcolor = BROWN; bright = true; break;
- case INFO: levelcolor = GRAY; bright = false; break;
- case WARN: levelcolor = BROWN; bright = false; break;
- case ERROR: levelcolor = RED; bright = true; break;
- }
-
- while(str.indexOf('\n') != -1) {
- logstream.println(classname + colorize(levelcolor, bright, str.substring(0, str.indexOf('\n'))));
- classname = logDates ? " " : " ";
- classname = colorize(GRAY,false,classname);
- str = str.substring(str.indexOf('\n') + 1);
- }
- logstream.println(classname + colorize(levelcolor, bright, str));
- }
-
- // FIXME: Update for new api
- /*public static void recursiveLog(String indent, String name, Object o) throws JSExn {
- if (!name.equals("")) name += " : ";
-
- if (o == null) {
- JS.log(indent + name + "<null>");
-
- } else if (o instanceof JSArray) {
- JS.log(indent + name + "<array>");
- JSArray na = (JSArray)o;
- for(int i=0; i<na.length(); i++)
- recursiveLog(indent + " ", i + "", na.elementAt(i));
-
- } else if (o instanceof JS) {
- JS.log(indent + name + "<object>");
- JS s = (JS)o;
- Enumeration e = s.keys();
- while(e.hasMoreElements()) {
- Object key = e.nextElement();
- if (key != null)
- recursiveLog(indent + " ", key.toString(),
- (key instanceof Integer) ?
- s.get(((Integer)key)) : s.get(key.toString()));
- }
- } else {
- JS.log(indent + name + o);
-
- }
- }*/
-
-}
+++ /dev/null
-/*
-UserInfo:
- On start:
- 0: Addr of CAB/EXE
- 1: Length of CAB/EXE
- On Edit:
- 2: Addr of output_table array
-
-Exit codes:
- 0: Success
- 1: Internal Error
- 2: Invalid CAB
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/fcntl.h>
-
-#include "mspack.h"
-
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX_MEMBERS 64
-
-char *xstrdup(const char *s) {
- char *ret = strdup(s);
- if(ret == NULL) exit(1);
- return ret;
-}
-
-typedef struct {
- char *addr;
- int pos;
- int size;
- int length;
- int writable;
-} mem_buf_t;
-
-static mem_buf_t *cab_mem_buf = NULL;
-
-static void mem_buf_grow(mem_buf_t *buf,size_t newsize) {
- size_t new_len;
- char *p;
- if(buf->length < 0) exit(1);
- if(newsize <= buf->length) return;
- new_len = MAX(buf->length ? buf->length*2 : 65536,newsize);
- p = realloc(buf->addr,new_len);
- if(p == NULL) exit(1);
- buf->addr = p;
- buf->length = new_len;
-}
-
-static struct {
- char *filename;
- mem_buf_t buf;
-} write_buf_table[MAX_MEMBERS];
-
-static struct {
- char *filename;
- char *data;
- int length;
-} output_table[MAX_MEMBERS+1];
-
-static struct mspack_file *my_open(struct mspack_system *sys, char *filename, int mode) {
- mem_buf_t *buf = NULL;
- int i;
- if(strcmp(filename,"/dev/cab")==0) {
- if(mode != MSPACK_SYS_OPEN_READ) return NULL;
- buf = cab_mem_buf;
- } else {
- if(mode != MSPACK_SYS_OPEN_WRITE) return NULL;
-
- for(i=0;i<MAX_MEMBERS;i++) {
- if(write_buf_table[i].filename == NULL) {
- write_buf_table[i].filename = xstrdup(filename);
- buf = &write_buf_table[i].buf;
- buf->writable = 1;
- break;
- }
- }
- }
-
- return (struct mspack_file *) buf;
-}
-
-static void my_close(struct mspack_file *buf_) {
- mem_buf_t *buf = (mem_buf_t*) buf_;
- /* NO OP */
-}
-
-static int my_read(struct mspack_file *buf_, void *out, int count) {
- mem_buf_t *buf = (mem_buf_t*) buf_;
- count = MIN(buf->size - buf->pos, count);
- memcpy(out,buf->addr + buf->pos,count);
- buf->pos += count;
- return count;
-}
-
-static int my_write(struct mspack_file *buf_, void *in, int count) {
- mem_buf_t *buf = (mem_buf_t*) buf_;
- if(!buf->writable) return -1;
- if(buf->length < buf->pos + count) mem_buf_grow(buf,buf->pos + count);
- memcpy(buf->addr+buf->pos,in,count);
- buf->pos += count;
- buf->size = MAX(buf->size,buf->pos);
- return count;
-}
-
-static int my_seek(struct mspack_file *buf_, off_t off, int mode) {
- mem_buf_t *buf = (mem_buf_t*) buf_;
- int newpos;
- switch(mode) {
- case MSPACK_SYS_SEEK_START: newpos = off; break;
- case MSPACK_SYS_SEEK_CUR: newpos = buf->pos + off; break;
- case MSPACK_SYS_SEEK_END: newpos = buf->size - off; break;
- default: return -1;
- }
- if(newpos < 0) return -1;
- if(newpos > buf->size) {
- if(!buf->writable) return -1;
- if(newpos > buf->length)
- mem_buf_grow(buf,newpos);
- }
- buf->pos = newpos;
- return 0;
-}
-
-static off_t my_tell(struct mspack_file *buf_) {
- mem_buf_t *buf = (mem_buf_t*) buf_;
- return buf ? buf->pos : 0;
-}
-
-// FEATURE: Remove this to possibly avoid pulling in stdio from libc
-// (it may be getting pulled in anyway from malloc or something)
-static void my_message(struct mspack_file *file, char *format, ...) {
- va_list ap;
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- va_end(ap);
- fputc((int) '\n', stderr);
- fflush(stderr);
-}
-
-static void *my_alloc(struct mspack_system *sys, size_t size) { return malloc(size); }
-static void my_free(void *p) { free(p); }
-static void my_copy(void *src, void *dest, size_t bytes) { memcpy(dest, src, bytes); }
-
-static struct mspack_system my_system = {
- &my_open,
- &my_close,
- &my_read,
- &my_write,
- &my_seek,
- &my_tell,
- &my_message,
- &my_alloc,
- &my_free,
- &my_copy,
- NULL
-};
-
-extern char *user_info[1024];
-
-int mspack_main() {
- struct mscab_decompressor *decomp;
- struct mscabd_cabinet *cab;
- struct mscabd_file *file;
- mem_buf_t mem_buf;
- size_t size = (size_t)user_info[1];
- int i;
-
- mem_buf.addr = user_info[0];
- mem_buf.pos = mem_buf.writable = 0;
- mem_buf.length = -1;
- mem_buf.size = size;
-
- cab_mem_buf = &mem_buf;
-
- decomp = mspack_create_cab_decompressor(&my_system);
- if(!decomp) exit(1);
-
- cab = decomp->search(decomp,"/dev/cab");
- if(!cab) exit(2);
-
- for(file = cab->files;file;file=file->next)
- decomp->extract(decomp,file,file->filename);
-
- decomp->close(decomp,cab);
- mspack_destroy_cab_decompressor(decomp);
-
- for(i=0;i<MAX_MEMBERS && write_buf_table[i].filename;i++) {
- output_table[i].filename = write_buf_table[i].filename;
- output_table[i].data = write_buf_table[i].buf.addr;
- output_table[i].length = write_buf_table[i].buf.size;
- }
-
- user_info[2] = (char*) output_table;
-
- return 0;
-}
+++ /dev/null
-package org.ibex.util;
-
-import org.ibex.core.Main;
-import org.ibex.util.*;
-import java.io.*;
-import org.ibex.nestedvm.*;
-import org.ibex.nestedvm.Runtime;
-
-public class MSPack {
- private static byte[] image;
-
- private String[] fileNames;
- private int[] lengths;
- private byte[][] data;
-
- public static class MSPackException extends IOException { public MSPackException(String s) { super(s); } }
-
- public MSPack(InputStream cabIS) throws IOException {
- try {
- Runtime vm = (Runtime)Class.forName("org.ibex.util.MIPSApps").newInstance();
- byte[] cab = InputStreamToByteArray.convert(cabIS);
- int cabAddr = vm.sbrk(cab.length);
- if(cabAddr < 0) throw new MSPackException("sbrk failed");
-
- vm.copyout(cab,cabAddr,cab.length);
-
- vm.setUserInfo(0,cabAddr);
- vm.setUserInfo(1,cab.length);
-
- int status = vm.run(new String[]{ "mspack"} );
- if(status != 0) throw new MSPackException("mspack.mips failed (" + status + ")");
-
- /*static struct {
- char *filename;
- char *data;
- int length;
- } output_table[MAX_MEMBERS+1]; */
-
- int filesTable = vm.getUserInfo(2);
- int count=0;
- while(vm.memRead(filesTable+count*12) != 0) count++;
-
- fileNames = new String[count];
- data = new byte[count][];
- lengths = new int[count];
-
- for(int i=0,addr=filesTable;i<count;i++,addr+=12) {
- int length = vm.memRead(addr+8);
- data[i] = new byte[length];
- lengths[i] = length;
- fileNames[i] = vm.cstring(vm.memRead(addr));
- System.out.println("" + fileNames[i]);
- vm.copyin(vm.memRead(addr+4),data[i],length);
- }
- } catch(Runtime.ExecutionException e) {
- e.printStackTrace();
- throw new MSPackException("mspack.mips crashed");
- } catch(Exception e) {
- throw new MSPackException(e.toString());
- }
- }
-
- public String[] getFileNames() { return fileNames; }
- public int[] getLengths() { return lengths; }
- public InputStream getInputStream(int index) {
- return new KnownLength.KnownLengthInputStream(new ByteArrayInputStream(data[index]), data[index].length);
- }
- public InputStream getInputStream(String fileName) {
- for(int i=0;i<fileNames.length;i++) {
- if(fileName.equalsIgnoreCase(fileNames[i])) return getInputStream(i);
- }
- return null;
- }
-
- public static void main(String[] args) throws IOException {
- MSPack pack = new MSPack(new FileInputStream(args[0]));
- String[] files = pack.getFileNames();
- for(int i=0;i<files.length;i++)
- System.out.println(i + ": " + files[i] + ": " + pack.getLengths()[i]);
- System.out.println("Writing " + files[files.length-1]);
- InputStream is = pack.getInputStream(files.length-1);
- OutputStream os = new FileOutputStream(files[files.length-1]);
- int n;
- byte[] buf = new byte[4096];
- while((n = is.read(buf)) != -1) os.write(buf,0,n);
- os.close();
- is.close();
- }
-}
-
+++ /dev/null
-package org.ibex.util;
-import java.util.*;
-import java.io.*;
-import java.util.zip.*;
-import org.apache.bcel.*;
-import org.apache.bcel.generic.*;
-import org.apache.bcel.classfile.*;
-import org.apache.bcel.util.*;
-
-public class NanoGoat {
-
- public static final boolean deleteMethods = false;
- public static SyntheticRepository repo = null;
- public static HashSet dest = new HashSet();
- public static HashSet constructed = new HashSet();
- public static String outdir = ".";
- public static Hashtable subclasses = new Hashtable();
- public static Hashtable uponconstruction = new Hashtable();
- public static Hashtable mark_if_constructed = new Hashtable();
- public static int level = 0;
-
- public NanoGoat() { }
-
- public void loadAllMethods(String classname) throws Exception {
- visitJavaClass(repo.loadClass(classname));
- Method[] meths = getMethods(repo.loadClass(classname));
- for(int i=0; i<meths.length; i++)
- visitJavaMethod(repo.loadClass(classname), meths[i]);
- }
-
- public void loadAllStaticMethods(String classname) throws Exception {
- visitJavaClass(repo.loadClass(classname));
- Method[] meths = getMethods(repo.loadClass(classname));
- for(int i=0; i<meths.length; i++)
- if (meths[i].isStatic())
- visitJavaMethod(repo.loadClass(classname), meths[i]);
- }
-
- public void loadMethod(String classAndMethodName) throws Exception {
- String classname = classAndMethodName.substring(0, classAndMethodName.lastIndexOf('.'));
- String methodname = classAndMethodName.substring(classAndMethodName.lastIndexOf('.') + 1);
- if (classname.endsWith("." + methodname)) methodname = "<init>";
- visitJavaClass(repo.loadClass(classname));
- Method[] meths = getMethods(repo.loadClass(classname));
- for(int i=0; i<meths.length; i++)
- if (meths[i].getName().equals(methodname))
- visitJavaMethod(repo.loadClass(classname), meths[i]);
- }
- public static void main(String[] args) throws Exception {
- int start = 1;
- repo = SyntheticRepository.getInstance(new ClassPath(args[0]));
-
- NanoGoat bcp = new NanoGoat();
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- for(String s = br.readLine(); s != null; s = br.readLine()) {
- s = s.trim();
- if (s.length() == 0) continue;
- try {
- if (s.endsWith("$")) s = s.substring(0, s.length() - 1);
- if (s.endsWith(".class")) {
- bcp.visitJavaClass(repo.loadClass(s.substring(0, s.length() - 6)));
- } else {
- JavaClass cl = repo.loadClass(s.substring(0, s.lastIndexOf('.')));;
- bcp.visitJavaClass(cl);
- bcp.loadMethod(s);
- Field[] fields = cl.getFields();
- for(int j=0; j<fields.length; j++) {
- if (fields[j].getName().equals(s.substring(s.lastIndexOf('.') + 1)))
- bcp.visitJavaField(fields[j], cl);
- }
- }
- } catch (Exception e) {
- System.out.println("WARNING: couldn't load class for " + s);
- e.printStackTrace();
- }
- }
-
- System.out.println("\n\n======================================================================\n");
-
- // we call start(), but the VM calls run()...
- bcp.loadMethod("java.lang.Thread.run");
- bcp.loadAllMethods("java.lang.SecurityContext");
- bcp.loadAllMethods("java.lang.ThreadDeath");
- bcp.loadMethod("java.lang.Thread.run"); // we call start(), but the VM calls run()...
- bcp.loadMethod("java.lang.ref.Reference.enqueue"); // the GC calls this directly
- bcp.loadAllMethods("gnu.gcj.runtime.StringBuffer"); // the compiler emits calls directly to this class
- bcp.loadAllMethods("gnu.gcj.convert.Input_UTF8"); // retrieved via reflection
- bcp.loadAllMethods("gnu.gcj.convert.Output_UTF8"); // retrieved via reflection
- bcp.loadMethod("gnu.gcj.convert.BytesToUnicode.done"); // called by natString
- bcp.loadAllStaticMethods("java.lang.reflect.Modifier"); // used all over natClass...
-
- // the Interpreter.run() method's switchblock is too complex...
- bcp.loadAllMethods("org.ibex.js.Interpreter$TryMarker");
- bcp.loadAllMethods("org.ibex.js.Interpreter$CatchMarker");
- bcp.loadAllMethods("org.ibex.js.Interpreter$LoopMarker");
- bcp.loadAllMethods("org.ibex.js.Interpreter$FinallyData");
- bcp.loadAllMethods("org.ibex.js.Interpreter$CallMarker");
- bcp.loadAllMethods("org.ibex.js.Interpreter");
- bcp.loadAllMethods("org.ibex.js.Interpreter$1");
- bcp.loadAllMethods("org.ibex.js.Interpreter$Stub");
- bcp.loadAllMethods("org.ibex.js.Trap$TrapScope");
- bcp.loadMethod("org.ibex.js.JSScope.top");
- bcp.loadAllMethods("org.ibex.Picture$1");
- bcp.loadAllMethods("org.ibex.Ibex$Blessing");
- bcp.loadAllMethods("org.ibex.util.SSL$entropySpinner");
- bcp.loadAllMethods("org.ibex.HTTP$HTTPInputStream");
- bcp.visitJavaClass(repo.loadClass("org.ibex.util.SSL"));
-
- bcp.loadAllMethods("java.util.Hashtable$HashIterator");
- bcp.loadMethod("java.util.SimpleTimeZone.useDaylightTime");
- bcp.visitJavaClass(repo.loadClass("gnu.gcj.runtime.FinalizerThread"));
- bcp.visitJavaClass(repo.loadClass("gnu.gcj.runtime.FirstThread"));
-
- // to ensure we get all the stuff that might be called from CNI
- bcp.loadAllMethods("org.ibex.plat.Linux");
- bcp.loadAllMethods("org.ibex.plat.X11");
- bcp.loadAllMethods("org.ibex.plat.GCJ");
- bcp.loadAllMethods("org.ibex.plat.POSIX");
- bcp.loadAllMethods("org.ibex.plat.X11$X11Surface");
- bcp.loadAllMethods("org.ibex.plat.X11$X11PixelBuffer");
- bcp.loadAllMethods("org.ibex.plat.X11$X11Picture");
- bcp.loadAllMethods("org.ibex.Surface");
- bcp.loadAllMethods("org.ibex.Picture");
- bcp.loadAllMethods("org.ibex.PixelBuffer");
-
- // primary entry point
- bcp.loadMethod("org.ibex.plat.Linux.main");
- System.out.println();
-
- System.out.println("Dumping...");
- ZipFile zf = new ZipFile(args[0]);
- ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(args[0] + ".tmp"));
- Enumeration e = zf.entries();
- while(e.hasMoreElements()) {
- ZipEntry ze = ((ZipEntry)e.nextElement());
- String ss = ze.getName();
- if (!ss.endsWith(".class")) continue;
- ss = ss.substring(0, ss.length() - 6);
- ss = ss.replace('/', '.');
- dump(repo.loadClass(ss), zos);
- }
- zos.close();
- zf.close();
- new File(args[0] + ".tmp").renameTo(new File(args[0] + ".pruned"));
- }
-
- public static void dump(JavaClass clazz, ZipOutputStream zos) throws Exception {
- if (!dest.contains(clazz)) return;
-
- ConstantPoolGen newcpg = new ConstantPoolGen(clazz.getConstantPool());
- ClassGen cg = new ClassGen(clazz);
- InstructionFactory factory = new InstructionFactory(cg, newcpg);
- cg.setMajor(46);
- cg.setMinor(0);
- cg.setConstantPool(newcpg);
-
- boolean isconstructed = false;
- Method[] methods = getMethods(clazz);
- for(int i=0; i<methods.length; i++)
- if (dest.contains(methods[i]) && methods[i].getName().equals("<init>"))
- isconstructed = true;
-
- // we can only prune static fields (to avoid altering object layout, which is hardcoded into
- // CNI code), but that's okay since instance fields don't contribute to binary size
- Field[] fields = clazz.getFields();
- for(int i=0; i<fields.length; i++) {
- if ((!dest.contains(fields[i]) && fields[i].isStatic()) ||
- ((!(constructed.contains(clazz))) && !fields[i].isStatic())) {
- System.out.println(" pruning field " + clazz.getClassName() + "." + fields[i].getName());
- // FIXME this confuses gcj in jar-at-a-time mode
- //cg.removeField(fields[i]);
- }
- }
-
- int numMethods = 0;
- boolean good = false;
- for(int i=0; i<methods.length; i++) {
- if (dest.contains(methods[i]) && (isconstructed || methods[i].isStatic())) {
- good = true;
- } else {
- if (methods[i].getCode() == null) {
- System.out.println(" empty codeblock: " + clazz.getClassName() + "." + methods[i].getName());
- } else {
- System.out.println(" pruning " +(isconstructed?"":"unconstructed")+ " method " +
- clazz.getClassName() + "." + methods[i].getName());
- if (deleteMethods) { cg.removeMethod(methods[i]); continue; }
- MethodGen mg = new MethodGen(methods[i], clazz.getClassName(), newcpg);
- mg.removeExceptions();
- InstructionList il = new InstructionList();
- mg.setInstructionList(il);
- InstructionHandle ih_0 = il.append(factory.createNew("java.lang.UnsatisfiedLinkError"));
- il.append(InstructionConstants.DUP);
- il.append(factory.createInvoke("java.lang.UnsatisfiedLinkError",
- "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
- il.append(InstructionConstants.ATHROW);
- mg.setMaxStack();
- mg.setMaxLocals();
- mg.removeExceptions();
- mg.removeLocalVariables();
- mg.removeExceptionHandlers();
- mg.removeLineNumbers();
- cg.replaceMethod(methods[i], mg.getMethod());
- il.dispose();
- }
- }
- }
-
- // FIXME: chain up to superclass' <clinit>... that might remove the need for this hack
- // FIXME: gcj compiling in jar-at-a-time mode can't be convinced to let classes outside the jar override
- // the ones inside the jar
- good = true;
-
- if (!good && !clazz.isAbstract() && !clazz.isInterface()) {
- System.out.println("DROPPING " + clazz.getClassName());
- JavaClass[] ifaces = clazz.getInterfaces();
- String[] ifacestrings = new String[ifaces.length];
- for(int i=0; i<ifaces.length; i++) ifacestrings[i] = ifaces[i].getClassName();
- cg = new ClassGen(clazz.getClassName(),
- clazz.getSuperClass().getClassName(),
- clazz.getFileName(),
- clazz.getAccessFlags(),
- ifacestrings,
- newcpg);
- } else {
- System.out.println("dumping " + clazz.getClassName());
- }
- FilterOutputStream noclose = new FilterOutputStream(zos) { public void close() throws IOException { flush(); } };
- zos.putNextEntry(new ZipEntry(clazz.getClassName().replace('.', '/')+".class"));
- cg.getJavaClass().dump(noclose);
- noclose.flush();
- }
-
- public JavaClass sig2class(String sig) throws Exception {
- if (sig == null) return null;
- while (sig.length() > 0 && (sig.charAt(0) == 'L' || sig.charAt(0) == '[')) {
- if (sig.charAt(0) == 'L') sig = sig.substring(1, sig.length() - 1);
- else if (sig.charAt(0) == '[') sig = sig.substring(1, sig.length());
- }
- if (sig.length() <= 1) return null;
- if (sig.equals("<null object>")) return null;
- if (sig.startsWith("<return address")) return null;
- return repo.loadClass(sig);
- }
- public void load(String sig) throws Exception {
- if (sig == null) return;
- while (sig.length() > 0 && (sig.charAt(0) == 'L' || sig.charAt(0) == '[')) {
- if (sig.charAt(0) == 'L') sig = sig.substring(1, sig.length() - 1);
- else if (sig.charAt(0) == '[') sig = sig.substring(1, sig.length());
- }
- if (sig.length() <= 1) return;
- if (sig.equals("<null object>")) return;
- if (sig.startsWith("<return address")) return;
- visitJavaClass(repo.loadClass(sig));
- }
- public void load(Type t) throws Exception {
- if (t == null) return;
- if (t instanceof ArrayType) load(((ArrayType)t).getElementType());
- if (!(t instanceof ObjectType)) return;
- load(((ObjectType)t).getClassName());
- }
-
- public String getMethodSignature(Method m, ConstantPoolGen cpg) throws Exception { return m.getName() + m.getSignature(); }
- public String getMethodSignature(InvokeInstruction ii, ConstantPoolGen cpg) throws Exception {
- String sig = "";
- Type[] argtypes = ii.getArgumentTypes(cpg);
- for(int j=0; j<argtypes.length; j++) sig += argtypes[j].getSignature();
- return ii.getMethodName(cpg) + "(" + sig + ")" + ii.getReturnType(cpg).getSignature();
- }
-
- public void visitJavaMethod(JavaClass jc, Method method) throws Exception {
- visitJavaClass(jc);
- if (jc.getClassName().indexOf("SharedLib") != -1) return;
- if (jc.getClassName().indexOf("Datagram") != -1) return;
- if (jc.getClassName().startsWith("java.io.Object")) return;
- if (jc.getClassName().startsWith("java.util.jar.")) return;
- if (jc.getClassName().startsWith("java.net.Inet6")) return;
-
- // gcj bug; gcj can't compile this method from a .class file input; I have no idea why
- if (jc.getClassName().equals("java.lang.System") && method.getName().equals("runFinalizersOnExit")) return;
-
- // we know these can't be constructed
- if (method.getName().equals("<init>") && jc.getClassName().startsWith("java.lang.reflect.")) return;
-
- if (dest.contains(method)) return;
- dest.add(method);
-
- if (method.getName().equals("<clinit>") && jc.getSuperClass() != null)
- loadMethod(jc.getSuperClass().getClassName() + ".<clinit>");
-
- if (method.isStatic() || method.getName().equals("<init>")) loadMethod(jc.getClassName() + ".<clinit>");
- if (method.getName().equals("<init>")) {
- // FIXME: generalize to all perinstancemethods
- constructed.add(jc);
- HashSet hs = (HashSet)uponconstruction.get(jc);
- if (hs != null) {
- Iterator it = hs.iterator();
- while(it.hasNext()) visitJavaMethod(jc, (Method)it.next());
- }
- loadMethod(jc.getClassName() + ".equals");
- loadMethod(jc.getClassName() + ".hashCode");
- loadMethod(jc.getClassName() + ".toString");
- loadMethod(jc.getClassName() + ".finalize");
- loadMethod(jc.getClassName() + ".clone");
- }
-
- ConstantPoolGen cpg = new ConstantPoolGen(method.getConstantPool());
- if (!method.isStatic() && !constructed.contains(jc)) {
- HashSet hs = (HashSet)uponconstruction.get(jc);
- if (hs == null) uponconstruction.put(jc, hs = new HashSet());
- hs.add(method);
- markMethodInSubclasses(jc, method, cpg);
- dest.remove(method);
- return;
- }
-
- level += 2;
- for(int i=0; i<level; i++) System.out.print(" ");
- System.out.print(jc.getClassName() + "." + getMethodSignature(method, cpg));
- markMethodInSubclasses(jc, method, cpg);
- if (method.getCode() == null) { System.out.println(); level -= 2; return; }
- byte[] code = method.getCode().getCode();
- InstructionList il = new InstructionList(code);
- InstructionHandle[] instructions = il.getInstructionHandles();
- System.out.println(" [" + instructions.length + " instructions]");
- for(int i=0; i<instructions.length; i++){
- Instruction instr = instructions[i].getInstruction();;
- if (instr instanceof Select) {
- InstructionHandle[] ih2 = ((Select)instr).getTargets();
- InstructionHandle[] ih3 = new InstructionHandle[instructions.length + ih2.length];
- System.arraycopy(instructions, 0, ih3, 0, instructions.length);
- System.arraycopy(ih2, 0, ih3, instructions.length, ih2.length);
- instructions = ih3;
- }
- if (instr instanceof LoadClass) {
- ObjectType ot = (ObjectType)((LoadClass)instr).getLoadClassType(cpg);
- if (ot != null) loadMethod(ot.getClassName() + ".<clinit>");
- }
- if (instr instanceof CPInstruction) load(((CPInstruction)instr).getType(cpg));
- if (instr instanceof TypedInstruction) load(((TypedInstruction)instr).getType(cpg));
- if (instr instanceof NEW) loadMethod(((NEW)instr).getLoadClassType(cpg).getClassName() + ".<init>");
- if (instr instanceof org.apache.bcel.generic.FieldOrMethod)
- load(((org.apache.bcel.generic.FieldOrMethod)instr).getClassType(cpg));
- if (instr instanceof org.apache.bcel.generic.FieldInstruction) {
- load(((org.apache.bcel.generic.FieldInstruction)instr).getFieldType(cpg));
- load(((org.apache.bcel.generic.FieldInstruction)instr).getType(cpg));
- String fieldName = ((org.apache.bcel.generic.FieldInstruction)instr).getFieldName(cpg);
- JavaClass jc2 = repo.loadClass(((ObjectType)((org.apache.bcel.generic.FieldInstruction)instr).
- getLoadClassType(cpg)).getClassName());
- Field[] fields = jc2.getFields();
- for(int j=0; j<fields.length; j++) if (fields[j].getName().equals(fieldName)) visitJavaField(fields[j], jc2);
- }
- if (instr instanceof InvokeInstruction) {
- InvokeInstruction ii = (InvokeInstruction)instr;
- String ii_sig = getMethodSignature(ii, cpg);
- JavaClass c = sig2class(ii.getLoadClassType(cpg).getSignature());
-
- load(ii.getType(cpg));
- Method[] meths = getMethods(c);
- boolean good = false;
- for(int i2=0; i2<meths.length; i2++) {
- if (getMethodSignature(meths[i2], cpg).equals(ii_sig)) {
- visitJavaMethod(c, meths[i2]);
- good = true;
- break;
- }
- }
- if (!good) throw new Exception("couldn't find method " + getMethodSignature(ii, cpg) + " in " + c.getClassName());
- }
- }
- Type[] argtypes = method.getArgumentTypes();
- for(int i=0; i<argtypes.length; i++) load(argtypes[i]);
- if (method.getExceptionTable() != null) {
- String[] exntypes = method.getExceptionTable().getExceptionNames();
- for(int i=0; i<exntypes.length; i++) load(exntypes[i]);
- }
- level -= 2;
- }
-
- public void visitJavaField(Field field, JavaClass clazz) throws Exception {
- if (dest.contains(field)) return;
- dest.add(field);
- if (field.isStatic()) loadMethod(clazz.getClassName() + ".<clinit>");
- }
-
- public void visitJavaClass(JavaClass clazz) throws Exception {
- if (dest.contains(clazz)) return;
- dest.add(clazz);
-
- ConstantPoolGen cpg = new ConstantPoolGen(clazz.getConstantPool());
- level += 2;
- for(int i=0; i<level; i++) System.out.print(" ");
- System.out.println(clazz.getClassName() + ".class");
-
- JavaClass superclass = clazz.getSuperClass();
- for(JavaClass sup = superclass; sup != null; sup = sup.getSuperClass()) {
- if (subclasses.get(sup) == null) subclasses.put(sup, new HashSet());
- ((HashSet)subclasses.get(sup)).add(clazz);
- }
- JavaClass[] interfaces = clazz.getAllInterfaces();
- for(int i=0; i<interfaces.length; i++) {
- if (subclasses.get(interfaces[i]) == null) subclasses.put(interfaces[i], new HashSet());
- ((HashSet)subclasses.get(interfaces[i])).add(clazz);
- }
-
- for(JavaClass sup = superclass; sup != null; sup = sup.getSuperClass()) {
- visitJavaClass(sup);
- remarkMethods(sup, clazz, cpg);
- }
- for(int i=0; i<interfaces.length; i++) {
- visitJavaClass(interfaces[i]);
- remarkMethods(interfaces[i], clazz, cpg);
- }
-
- Field[] fields = clazz.getFields();
- for(int i=0; i<fields.length; i++) {
- if (!fields[i].isStatic()) visitJavaField(fields[i], clazz);
- else {
- Type t = fields[i].getType();
- if (t instanceof ObjectType) load(t);
- }
- }
- level -= 2;
- }
-
- public void markMethodInSubclasses(JavaClass c, Method m, JavaClass subclass, ConstantPoolGen cpg) throws Exception {
- if (m.isStatic()) return;
- if (m.getName().equals("<init>")) return;
- if (m.getName().equals("equals")) return;
- if (m.getName().equals("hashCode")) return;
- if (m.getName().equals("clone")) return;
- if (m.getName().equals("finalize")) return;
- if (m.getName().equals("toString")) return;
- String sig = getMethodSignature(m, cpg);
- Method[] submethods = getMethods(subclass);
- for(int j=0; j<submethods.length; j++)
- if (getMethodSignature(submethods[j], cpg).equals(sig))
- visitJavaMethod(subclass, submethods[j]);
- }
- public void markMethodInSubclasses(JavaClass c, Method m, ConstantPoolGen cpg) throws Exception {
- if (m.isStatic()) return;
- if (m.getName().equals("<init>")) return;
- HashSet s = (HashSet)subclasses.get(c);
- if (s == null) return;
- Object[] subclasses = s.toArray();
- for(int i=0; i<subclasses.length; i++) {
- JavaClass subclass = (JavaClass)subclasses[i];
- if (subclass == c) continue;
- markMethodInSubclasses(c, m, subclass, cpg);
- }
- }
-
- public void remarkMethods(JavaClass c, ConstantPoolGen cpg) throws Exception {
- Method[] meths =getMethods(c);
- for(int j=0; j<meths.length; j++)
- if (dest.contains(meths[j]) ||
- (uponconstruction.get(c) != null && ((HashSet)uponconstruction.get(c)).contains(meths[j])))
- markMethodInSubclasses(c, meths[j], cpg);
- }
-
- public void remarkMethods(JavaClass c, JavaClass target, ConstantPoolGen cpg) throws Exception {
- Method[] meths = getMethods(c);
- for(int j=0; j<meths.length; j++)
- if (dest.contains(meths[j]) ||
- (uponconstruction.get(c) != null && ((HashSet)uponconstruction.get(c)).contains(meths[j])))
- markMethodInSubclasses(c, meths[j], target, cpg);
- }
-
- public static Hashtable methodsHashtable = new Hashtable();
- public static Method[] getMethods(JavaClass c) {
- Method[] ret = (Method[])methodsHashtable.get(c);
- if (ret == null) methodsHashtable.put(c, ret = c.getMethods());
- return ret;
- }
-
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-/** packs 8-bit bytes into a String of 7-bit chars (to avoid the UTF-8 non-ASCII penalty) */
-public class PackBytesIntoString {
-
- public static String pack(byte[] b, int off, int len) throws IllegalArgumentException {
- if (len % 7 != 0) throw new IllegalArgumentException("len must be a multiple of 7");
- StringBuffer ret = new StringBuffer();
- for(int i=off; i<off+len; i += 7) {
- long l = 0;
- for(int j=6; j>=0; j--) {
- l <<= 8;
- l |= (b[i + j] & 0xff);
- }
- for(int j=0; j<8; j++) {
- ret.append((char)(l & 0x7f));
- l >>= 7;
- }
- }
- return ret.toString();
- }
-
- public static byte[] unpack(String s) throws IllegalArgumentException {
- if (s.length() % 8 != 0) throw new IllegalArgumentException("string length must be a multiple of 8");
- byte[] ret = new byte[(s.length() / 8) * 7];
- for(int i=0; i<s.length(); i += 8) {
- long l = 0;
- for(int j=7; j>=0; j--) {
- l <<= 7;
- l |= (s.charAt(i + j) & 0x7fL);
- }
- for(int j=0; j<7; j++) {
- ret[(i / 8) * 7 + j] = (byte)(l & 0xff);
- l >>= 8;
- }
- }
- return ret;
- }
-}
-
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-import gnu.regexp.*;
-import java.util.*;
-import java.io.*;
-
-/**
- * A VERY crude, inefficient Java preprocessor
- *
- * //#define FOO bar baz -- replace all instances of token FOO with "bar baz"
- * //#replace foo/bar baz/bop -- DUPLICATE everything between here and //#end,
- * replacing foo with bar and baz with bop in the *second* copy
- * //#switch(EXPR) -- switch on strings
- * case "case1":
- * //#end
- *
- * Replacements are done on a token basis. Tokens are defined as a
- * sequence of characters which all belong to a single class. The
- * two character classes are:
- *
- * - [a-zA-Z0-9_]
- * - all other non-whitespace characters
- */
-public class Preprocessor {
-
- public static String replaceAll(String source, String regexp, String replaceWith) {
- try {
- RE re = new RE(regexp, 0, RESyntax.RE_SYNTAX_PERL5);
- return (String)re.substituteAll(source, replaceWith);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- public static void main(String[] args) throws Exception {
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
-
- // process stdin to stdout
- Preprocessor cc = new Preprocessor(br, bw);
- Vector err = cc.process();
- bw.flush();
-
- // handle errors
- boolean errors = false;
- for (int i=0; i < err.size(); i++) { if (err.get(i) instanceof Error) errors = true; System.err.println(err.get(i)); }
- if (errors) throw new Exception();
- }
-
- private Reader r;
- private Writer w;
- private LineNumberReader in;
- private PrintWriter out;
-
- private Hashtable replace = new Hashtable();
- private Hashtable[] repeatreplaces = null;
- private Vector sinceLastRepeat = null;
- private Vector err = new Vector();
-
- private int enumSwitch = 0; // number appended to variable used in switch implementation
-
-
- public Preprocessor(Reader reader, Writer writer) {
- setReader(reader);
- setWriter(writer);
- }
-
- public void setReader(Reader reader) { r = reader; if (r != null) in = new LineNumberReader(r); }
- public Reader getReader() { return r; }
-
- public void setWriter(Writer writer) { w = writer; if (w != null) out = new PrintWriter(w); }
- public Writer getWriter() { return w; }
-
-
- /** process data from reader, write to writer, return vector of errors */
- public Vector process() throws IOException {
- err.clear();
-
- String s = null;
-PROCESS:
- while((s = in.readLine()) != null) {
- if (sinceLastRepeat != null) sinceLastRepeat.addElement(s);
- String trimmed = s.trim();
-
- if (trimmed.startsWith("//#define ")) {
- if (trimmed.length() == 9 || trimmed.charAt(9) != ' ') {
- err.add(new Error("#define badly formed, ignored")); continue PROCESS;
- }
- int keyStart = indexOfNotWS(trimmed, 9);
- if (keyStart == -1) {
- err.add(new Error("#define requires KEY")); continue PROCESS;
- }
- int keyEnd = indexOfWS(trimmed, keyStart);
-
- int macroStart = trimmed.indexOf('(');
- int macroEnd = trimmed.indexOf(')');
- if (macroStart > keyEnd) {
- // no macro is defined, just make sure something dumb like KEYNA)ME hasn't been done
- if (macroEnd < keyEnd) { err.add(new Error("#define key contains invalid char: ')'")); continue PROCESS; }
- macroStart = macroEnd = -1;
- }
-
- if (macroStart == 0) {
- err.add(new Error("#define macro requires name")); continue PROCESS;
- } else if (macroStart > 0) {
- if (macroStart > macroEnd) { err.add(new Error("#define macro badly formed")); continue PROCESS; }
- if (macroStart+1 == macroEnd) { err.add(new Error("#define macro requires property name")); continue PROCESS; }
-
- JSFunctionMacro fm = new JSFunctionMacro();
- String key = trimmed.substring(keyStart, macroStart);
- String unbound = trimmed.substring(macroStart +1, macroEnd);
- int unboundDiv = unbound.indexOf(',');
- if (unboundDiv == -1) {
- fm.unbound1 = unbound;
- } else {
- fm.unbound1 = unbound.substring(0, unboundDiv);
- fm.unbound2 = unbound.substring(unboundDiv +1);
- if (fm.unbound1.length() == 0) { err.add(new Error("#define macro property 1 requires name")); continue PROCESS; }
- if (fm.unbound2.length() == 0) { err.add(new Error("#define macro property 1 requires name")); continue PROCESS; }
- }
- fm.expression = trimmed.substring(keyEnd).trim();
- replace.put(key, fm);
- } else {
- String key = trimmed.substring(keyStart, keyEnd);
- String val = trimmed.substring(keyEnd).trim();
- replace.put(key, val);
- }
- out.print("\n"); // preserve line numbers
-
- } else if (trimmed.startsWith("//#repeat ")) {
- trimmed = trimmed.substring(9);
- while(trimmed.charAt(trimmed.length() - 1) == '\\') {
- String s2 = in.readLine().trim();
- if (s2.startsWith("//")) s2 = s2.substring(2).trim();
- trimmed = trimmed.substring(0, trimmed.length() - 1) + " " + s2;
- out.print("\n"); // preserve line numbers
- }
- StringTokenizer st = new StringTokenizer(trimmed, " ");
- repeatreplaces = null;
- while (st.hasMoreTokens()) {
- String tok = st.nextToken().trim();
- String key = tok.substring(0, tok.indexOf('/'));
- String vals = tok.substring(tok.indexOf('/') + 1);
- StringTokenizer st2 = new StringTokenizer(vals,"/");
- if(repeatreplaces == null) {
- repeatreplaces = new Hashtable[st2.countTokens()];
- for(int i=0;i<repeatreplaces.length;i++) repeatreplaces[i] = (Hashtable) replace.clone();
- }
- for(int i=0;st2.hasMoreTokens() && i<repeatreplaces.length;i++)
- repeatreplaces[i].put(key, st2.nextToken());
- }
- sinceLastRepeat = new Vector();
- out.print("\n"); // preserve line numbers
-
- } else if (trimmed.startsWith("//#end")) {
- if (sinceLastRepeat == null) { err.add(new Warning("#end orphaned")); continue PROCESS; }
- Hashtable save = replace;
- out.print("\n");
- for(int i=0;i<repeatreplaces.length;i++) {
- replace = repeatreplaces[i];
- for(int j=0; j<sinceLastRepeat.size() - 1; j++) out.print(processLine((String)sinceLastRepeat.elementAt(j), true));
- }
- sinceLastRepeat = null;
- replace = save;
-
- } else if (trimmed.startsWith("//#switch") || trimmed.startsWith("//#jswitch")) {
- boolean jswitch = trimmed.startsWith("//#jswitch");
- int expStart = trimmed.indexOf('(') +1;
- if (expStart < 1) { err.add(new Error("expected ( in #switch")); continue PROCESS; }
- int expEnd = trimmed.lastIndexOf(')');
- if (expEnd == -1) { err.add(new Error("expected ) in #switch")); continue PROCESS; }
- if (expEnd - expStart <= 1) { err.add(new Error("badly formed #switch statement")); continue PROCESS; }
- String expr = trimmed.substring(expStart, expEnd);
-
- if(jswitch) {
- out.print("final org.ibex.js.JS ccSwitchExpr"+enumSwitch+" = " + expr + ";");
- out.print("if(org.ibex.js.JS.isString(ccSwitchExpr"+enumSwitch+")) {");
- out.print("final String ccSwitch"+enumSwitch+" = org.ibex.js.JS.toString(ccSwitchExpr"+enumSwitch+");");
- } else {
- out.print("final String ccSwitch"+enumSwitch+" = "+expr+"; ");
- }
- out.print("SUCCESS:do { switch(ccSwitch"+enumSwitch+".length()) {\n");
-
- Hashtable[] byLength = new Hashtable[255];
- String key = null;
- String Default = null;
- for(trimmed = in.readLine().trim(); !trimmed.startsWith("//#end"); trimmed = in.readLine().trim()) {
- if (trimmed.startsWith("default:")) {
- Default = processLine(trimmed.substring(8), false);
- continue;
- }
- if (trimmed.startsWith("case ")) {
- // find key
- int strStart = trimmed.indexOf('\"') +1;
- if (strStart < 1) { err.add(new Error("expected opening of String literal")); continue PROCESS; }
- int strEnd = trimmed.indexOf('\"', strStart);
- if (strEnd == -1) { err.add(new Error("expected closing of String literal")); continue PROCESS; }
- key = trimmed.substring(strStart, strEnd);
-
- Hashtable thisCase = (Hashtable)byLength[key.length()];
- if (thisCase == null) byLength[key.length()] = thisCase = new Hashtable();
- thisCase.put(key, "");
-
- // find end of case definition
- int caseEnd = trimmed.indexOf(':', strEnd) +1;
- if (caseEnd < 1) { err.add(new Error("expected :")); continue PROCESS; }
- trimmed = trimmed.substring(caseEnd);
- }
-
- if (key != null) {
- Hashtable hash = byLength[key.length()];
- hash.put(key, (String)hash.get(key) + replaceAll(processLine(trimmed, false), "//[^\"]*$", "").trim() + "\n");
- } else {
- out.print(processLine(trimmed, false));
- }
- }
-
- for(int i=0; i<255; i++) {
- if (byLength[i] == null) continue;
- out.print("case " + i + ": { switch(ccSwitch"+enumSwitch+".charAt(0)) { ");
- buildTrie("", byLength[i]);
- out.print("}; break; } ");
- }
- out.print("} "); /* switch */
- if (Default != null) out.print(" " + Default);
- out.print(" } while(false);\n"); /* OUTER */
- if(jswitch) out.print("}");
- enumSwitch++;
-
- } else {
- out.print(processLine(s, false));
- }
- }
-
- return err;
- }
-
- private void buildTrie(String prefix, Hashtable cases) {
- Enumeration caseKeys = cases.keys();
- Vec keys = new Vec();
- while(caseKeys.hasMoreElements()) keys.addElement(caseKeys.nextElement());
- keys.sort(new Vec.CompareFunc() { public int compare(Object a, Object b) {
- return ((String)a).compareTo((String)b);
- } } );
-
- for(int i=0; i<keys.size(); i++) {
- if (!((String)keys.elementAt(i)).startsWith(prefix)) continue;
- String prefixPlusOne = ((String)keys.elementAt(i)).substring(0, prefix.length() + 1);
- if (i<keys.size()-1 && prefixPlusOne.equals((((String)keys.elementAt(i + 1)).substring(0, prefix.length() + 1)))) {
- out.print("case \'" + prefixPlusOne.charAt(prefixPlusOne.length() - 1) + "\': { ");
- out.print("switch(ccSwitch"+enumSwitch+".charAt(" + (prefix.length()+1) + ")) { ");
- buildTrie(prefixPlusOne, cases);
- out.print("} break; } ");
- while(i<keys.size() && prefixPlusOne.equals(((String)keys.elementAt(i)).substring(0, prefix.length() + 1))) i++;
- if (i<keys.size()) { i--; continue; }
- } else {
- out.print("case \'" + prefixPlusOne.charAt(prefixPlusOne.length() - 1) + "\': ");
- String code = (String)cases.get(keys.elementAt(i));
- code = code.substring(0, code.length());
- String key = (String)keys.elementAt(i);
- out.print("if (\""+key+"\".equals(ccSwitch"+enumSwitch+")) { if (true) do { " + code + " } while(false); break SUCCESS; } break; ");
- }
- }
- }
-
- private String processLine(String s, boolean deleteLineEndings) throws IOException {
- if (deleteLineEndings && s.indexOf("//") != -1) s = s.substring(0, s.indexOf("//"));
- String ret = "";
- for(int i=0; i<s.length(); i++) {
- char c = s.charAt(i);
- if (!Character.isLetter(c) && !Character.isDigit(c) && c != '_') {
- ret += c;
- continue;
- }
- int j;
- for(j = i; j < s.length(); j++) {
- c = s.charAt(j);
- if (!Character.isLetter(c) && !Character.isDigit(c) && c != '_') break;
- }
- String tok = s.substring(i, j);
- Object val = replace.get(tok);
- if (val == null) {
- ret += tok;
- i = j - 1;
- } else if (val instanceof JSFunctionMacro) {
- if (s.charAt(j) != '(') { ret += tok; i = j - 1; continue; }
- ret += ((JSFunctionMacro)val).process(s.substring(j+1, s.indexOf(')', j)));
- i = s.indexOf(')', j);
- } else {
- ret += val;
- i = j - 1;
- }
- }
- if (!deleteLineEndings) ret += "\n";
- return ret;
- }
-
- private static int indexOfWS(String s) { return indexOfWS(s, 0); }
- private static int indexOfWS(String s, int beginIndex) {
- if (s == null || beginIndex >= s.length()) return -1;
- for (; beginIndex < s.length(); beginIndex++) {
- if (s.charAt(beginIndex) == ' ') return beginIndex;
- }
- return s.length();
- }
-
- private static int indexOfNotWS(String s) { return indexOfWS(s, 0); }
- private static int indexOfNotWS(String s, int beginIndex) {
- if (s == null || beginIndex >= s.length()) return -1;
- for (; beginIndex < s.length(); beginIndex++) {
- if (s.charAt(beginIndex) != ' ') return beginIndex;
- }
- return -1;
- }
-
- public class Warning {
- protected String msg;
- protected int line;
-
- public Warning() { msg = ""; }
- public Warning(String m) { msg = m; if (in != null) line = in.getLineNumber(); }
-
- public String toString() { return "WARNING Line "+line+": "+msg; }
- }
-
- public class Error extends Warning {
- public Error() { super(); }
- public Error(String m) { super(m); }
- public String toString() { return "ERROR Line "+line+": "+msg; }
- }
-
- public static class JSFunctionMacro {
- public String unbound1 = null;
- public String unbound2 = null;
- public String expression = null;
- public String process(String args) {
- String bound1 = null;
- String bound2 = null;
- if (unbound2 == null) {
- bound1 = args;
- return replaceAll(expression, unbound1, bound1);
- } else {
- bound1 = args.substring(0, args.indexOf(','));
- bound2 = args.substring(args.indexOf(',') + 1);
- return replaceAll(replaceAll(expression, unbound1, bound1), unbound2, bound2);
- }
- }
- }
-}
-
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-/** A simple synchronized queue, implemented as an array */
-public class Queue {
-
- public Queue(int initiallength) { vec = new Object[initiallength]; }
-
- /** The store */
- private Object[] vec;
-
- /** The index of the first node in the queue */
- private int first = 0;
-
- /** The number of elements in the queue; INVARAINT: size <= vec.length */
- private int size = 0;
-
- /** Grow the queue, if needed */
- private void grow(int newlength) {
- Object[] newvec = new Object[newlength];
- if (first + size > vec.length) {
- System.arraycopy(vec, first, newvec, 0, vec.length - first);
- System.arraycopy(vec, 0, newvec, vec.length - first, size - (vec.length - first));
- } else {
- System.arraycopy(vec, first, newvec, 0, size);
- }
- first = 0;
- vec = newvec;
- }
-
- /** The number of elements in the queue */
- public int size() { return size; }
-
- /** Empties the queue */
- public synchronized void flush() {
- first = 0;
- size = 0;
- for(int i=0; i<vec.length; i++) vec[i] = null;
- }
-
- /** Add an element to the front of the queue */
- public synchronized void prepend(Object o) {
- if (size == vec.length) grow(vec.length * 2);
- first--;
- if (first < 0) first += vec.length;
- vec[first] = o;
- size++;
- if (size == 1) notify();
- }
-
- /** Add an element to the back of the queue */
- public synchronized void append(Object o) {
- if (size == vec.length) grow(vec.length * 2);
- if (first + size >= vec.length) vec[first + size - vec.length] = o;
- else vec[first + size] = o;
- size++;
- if (size == 1) notify();
- }
-
- /** Remove and return and element from the queue, blocking if empty. */
- public Object remove() { return remove(true); }
-
- /** Remove and return an element from the queue, blocking if
- <tt>block</tt> is true and the queue is empty. */
- public synchronized Object remove(boolean block) {
-
- while (size == 0 && block) {
- try { wait(); } catch (InterruptedException e) { }
- }
-
- if (!block && size == 0) return null;
- Object ret = vec[first];
- first++;
- size--;
- if (first >= vec.length) first = 0;
- return ret;
- }
-
- /** Returns the top element in the queue without removing it */
- public synchronized Object peek() {
- if (size == 0) return null;
- return vec[first];
- }
-
-}
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.util;
-
-import java.io.IOException;
-
-import org.ibex.js.*;
-import org.ibex.util.*;
-import org.ibex.graphics.*;
-import org.ibex.plat.*;
-
-/** Implements cooperative multitasking */
-public class Scheduler {
-
- // Public API Exposed to org.ibex /////////////////////////////////////////////////
-
- private static Scheduler singleton;
- private static String taskDesc(Task t) { return t instanceof JS ? JS.debugToString((JS)t) : t.toString(); }
- public static void add(Task t) { Log.debug(Scheduler.class, "scheduling " + taskDesc(t)); Scheduler.runnable.append(t); }
- public static void init() { if (singleton == null) (singleton = Platform.getScheduler()).run(); }
-
- private static Task current = null;
-
- private static volatile boolean rendering = false;
- private static volatile boolean again = false;
-
- /** synchronizd so that we can safely call it from an event-delivery thread, in-context */
- public static void renderAll() {
- if (rendering) { again = true; return; }
- synchronized(Scheduler.class) {
- try {
- rendering = true;
- do {
- // FEATURE: this could be cleaner
- again = false;
- for(int i=0; i<Surface.allSurfaces.size(); i++) {
- Surface s = ((Surface)Surface.allSurfaces.elementAt(i));
- do { s.render(); } while(s.abort);
- }
- } while(again);
- } finally {
- rendering = false;
- }
- }
- }
-
-
-
- // API which must be supported by subclasses /////////////////////////////////////
-
- /**
- * SCHEDULER INVARIANT: all scheduler implementations MUST invoke
- * Surface.renderAll() after performing a Task if no tasks remain
- * in the queue. A scheduler may choose to invoke
- * Surface.renderAll() more often than that if it so chooses.
- */
- public void run() { defaultRun(); }
- public Scheduler() { }
-
-
- // Default Implementation //////////////////////////////////////////////////////
-
- protected static Queue runnable = new Queue(50);
- public void defaultRun() {
- while(true) {
- current = (Task)runnable.remove(true);
- try {
- // FIXME hideous
- synchronized(this) {
- for(int i=0; i<Surface.allSurfaces.size(); i++) {
- Surface s = (Surface)Surface.allSurfaces.elementAt(i);
- if (current instanceof JS) {
- s._mousex = Integer.MAX_VALUE;
- s._mousey = Integer.MAX_VALUE;
- } else {
- s._mousex = s.mousex;
- s._mousey = s.mousey;
- }
- }
- Log.debug(Scheduler.class, "performing " + taskDesc(current));
- current.perform();
- }
- renderAll();
- } catch (JSExn e) {
- Log.info(Scheduler.class, "a JavaScript thread spawned with ibex.thread() threw an exception:");
- Log.info(Scheduler.class,e);
- } catch (Exception e) {
- Log.info(Scheduler.class, "a Task threw an exception which was caught by the scheduler:");
- Log.info(Scheduler.class, e);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- // if an Error is thrown it will cause the engine to quit
- }
- }
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-/** Simple implementation of a blocking, counting semaphore. */
-public class Semaphore {
-
- private int val = 0;
-
- /** Decrement the counter, blocking if zero. */
- public synchronized void block() {
- while(val == 0) {
- try {
- wait();
- } catch (InterruptedException e) {
- } catch (Throwable e) {
- if (Log.on) Log.info(this, "Exception in Semaphore.block(); this should never happen");
- if (Log.on) Log.info(this, e);
- }
- }
- val--;
- }
-
- /** Incremenet the counter. */
- public synchronized void release() {
- val++;
- notify();
- }
-
-}
+++ /dev/null
-package org.ibex.util;
-import java.io.* ;
-import java.util.* ;
-
-public class Simplex {
-
- public final static short FAIL = -1;
-
- public final static short NULL = 0;
- public final static short FALSE = 0;
- public final static short TRUE = 1;
-
- public final static short DEFNUMINV = 50;
-
- /* solve status values */
- public final static short OPTIMAL = 0;
- public final static short MILP_FAIL = 1;
- public final static short INFEASIBLE = 2;
- public final static short UNBOUNDED = 3;
- public final static short FAILURE = 4;
- public final static short RUNNING = 5;
-
- /* lag_solve extra status values */
- public final static short FEAS_FOUND = 6;
- public final static short NO_FEAS_FOUND = 7;
- public final static short BREAK_BB = 8;
-
- public final static short FIRST_NI = 0;
- public final static short RAND_NI = 1;
-
- public final static short LE = 0;
- public final static short EQ = 1;
- public final static short GE = 2;
- public final static short OF = 3;
-
- public final static short MAX_WARN_COUNT = 20;
-
- public final static float DEF_INFINITE = (float)1e24; /* limit for dynamic range */
- public final static float DEF_EPSB = (float)5.01e-7; /* for rounding RHS values to 0 determine
- infeasibility basis */
- public final static float DEF_EPSEL = (float)1e-8; /* for rounding other values (vectors) to 0 */
- public final static float DEF_EPSD = (float)1e-6; /* for rounding reduced costs to zero */
- public final static float DEF_EPSILON = (float)1e-3; /* to determine if a float value is integer */
-
- public final static float PREJ = (float)1e-3; /* pivot reject (try others first) */
-
- public final static int ETA_START_SIZE = 10000; /* start size of array Eta. Realloced if needed */
-
- static class Ref {
- float value;
- public Ref(float v) { value = v; }
- }
-
- //public static class Simplex {
- /* Globals used by solver */
- short JustInverted;
- short Status;
- short Doiter;
- short DoInvert;
- short Break_bb;
-
- public short active; /*TRUE if the globals point to this structure*/
- public short debug; /* ## Print B&B information */
- public short trace; /* ## Print information on pivot selection */
- public int rows; /* Nr of constraint rows in the problem */
- int rows_alloc; /* The allocated memory for Rows sized data */
- int columns_alloc;
- int sum; /* The size of the variables + the slacks */
- int sum_alloc;
- int non_zeros; /* The number of elements in the sparce matrix*/
- int mat_alloc; /* The allocated size for matrix sized
- structures */
- MatrixArray mat; /* mat_alloc :The sparse matrix */
- MatrixArray alternate_mat; /* mat_alloc :The sparse matrix */
- int[] col_end; /* columns_alloc+1 :Cend[i] is the index of the
- first element after column i.
- column[i] is stored in elements
- col_end[i-1] to col_end[i]-1 */
- int[] col_no; /* mat_alloc :From Row 1 on, col_no contains the
- column nr. of the
- nonzero elements, row by row */
- short row_end_valid; /* true if row_end & col_no are valid */
- int[] row_end; /* rows_alloc+1 :row_end[i] is the index of the
- first element in Colno after row i */
- float[] orig_rh; /* rows_alloc+1 :The RHS after scaling & sign
- changing, but before `Bound transformation' */
- float[] rh; /* rows_alloc+1 :As orig_rh, but after Bound
- transformation */
- float[] rhs; /* rows_alloc+1 :The RHS of the curent simplex
- tableau */
- float[] orig_upbo; /* sum_alloc+1 :Bound before transformations */
- float[] orig_lowbo; /* " " */
- float[] upbo; /* " " :Upper bound after transformation
- & B&B work*/
- float[] lowbo; /* " " :Lower bound after transformation
- & B&B work */
-
- short basis_valid; /* TRUE is the basis is still valid */
- int[] bas; /* rows_alloc+1 :The basis column list */
- short[] basis; /* sum_alloc+1 : basis[i] is TRUE if the column
- is in the basis */
- short[] lower; /* " " :TRUE is the variable is at its
- lower bound (or in the basis), it is FALSE
- if the variable is at its upper bound */
-
- short eta_valid; /* TRUE if current Eta structures are valid */
- int eta_alloc; /* The allocated memory for Eta */
- int eta_size; /* The number of Eta columns */
- int num_inv; /* The number of float pivots */
- int max_num_inv; /* ## The number of float pivots between
- reinvertions */
- float[] eta_value; /* eta_alloc :The Structure containing the
- values of Eta */
- int[] eta_row_nr; /* " " :The Structure containing the Row
- indexes of Eta */
- int[] eta_col_end; /* rows_alloc + MaxNumInv : eta_col_end[i] is
- the start index of the next Eta column */
-
- short bb_rule; /* what rule for selecting B&B variables */
-
- short break_at_int; /* TRUE if stop at first integer better than
- break_value */
- float break_value;
-
- float obj_bound; /* ## Objective function bound for speedup of
- B&B */
- int iter; /* The number of iterations in the simplex
- solver () */
- int total_iter; /* The total number of iterations (B&B) (ILP)*/
- int max_level; /* The Deepest B&B level of the last solution */
- int total_nodes; /* total number of nodes processed in b&b */
- public float[] solution; /* sum_alloc+1 :The Solution of the last LP,
- 0 = The Optimal Value,
- 1..rows The Slacks,
- rows+1..sum The Variables */
- public float[] best_solution; /* " " :The Best 'Integer' Solution */
- float[] duals; /* rows_alloc+1 :The dual variables of the
- last LP */
-
- short maximise; /* TRUE if the goal is to maximise the
- objective function */
- short floor_first; /* TRUE if B&B does floor bound first */
- short[] ch_sign; /* rows_alloc+1 :TRUE if the Row in the matrix
- has changed sign
- (a`x > b, x>=0) is translated to
- s + -a`x = -b with x>=0, s>=0) */
-
- int nr_lagrange; /* Nr. of Langrangian relaxation constraints */
- float[][]lag_row; /* NumLagrange, columns+1:Pointer to pointer of
- rows */
- float[] lag_rhs; /* NumLagrange :Pointer to pointer of Rhs */
- float[] lambda; /* NumLagrange :Lambda Values */
- short[] lag_con_type; /* NumLagrange :TRUE if constraint type EQ */
- float lag_bound; /* the lagrangian lower bound */
-
- short valid; /* Has this lp pased the 'test' */
- float infinite; /* ## numercal stuff */
- float epsilon; /* ## */
- float epsb; /* ## */
- float epsd; /* ## */
- float epsel; /* ## */
-
- int Rows;
- int columns;
- int Sum;
- int Non_zeros;
- int Level;
- MatrixArray Mat;
- int[] Col_no;
- int[] Col_end;
- int[] Row_end;
- float[] Orig_rh;
- float[] Rh;
- float[] Rhs;
- float[] Orig_upbo;
- float[] Orig_lowbo;
- float[] Upbo;
- float[] Lowbo;
- int[] Bas;
- short[] Basis;
- short[] Lower;
- int Eta_alloc;
- int Eta_size;
- float[] Eta_value;
- int[] Eta_row_nr;
- int[] Eta_col_end;
- int Num_inv;
- float[] Solution;
- public float[] Best_solution;
- float Infinite;
- float Epsilon;
- float Epsb;
- float Epsd;
- float Epsel;
-
- float TREJ;
- float TINV;
-
- short Maximise;
- short Floor_first;
- float Extrad;
-
- int Warn_count; /* used in CHECK version of rounding macro */
-
- public Simplex (int nrows, int ncolumns, int matalloc) {
- int nsum;
- nsum=nrows+ncolumns;
- rows=nrows;
- columns=ncolumns;
- sum=nsum;
- rows_alloc=rows;
- columns_alloc=columns;
- sum_alloc=sum;
- mat_alloc=matalloc;
- eta_alloc=10000;
- max_num_inv=DEFNUMINV;
- col_no = new int[mat_alloc];
- col_end = new int[columns + 1];
- row_end = new int[rows + 1];
- orig_rh = new float[rows + 1];
- rh = new float[rows + 1];
- rhs = new float[rows + 1];
- orig_upbo = new float[sum + 1];
- upbo = new float[sum + 1];
- orig_lowbo = new float[sum + 1];
- lowbo = new float[sum + 1];
- bas = new int[rows+1];
- basis = new short[sum + 1];
- lower = new short[sum + 1];
- eta_value = new float[eta_alloc];
- eta_row_nr = new int[eta_alloc];
- eta_col_end = new int[rows_alloc + max_num_inv];
- solution = new float[sum + 1];
- best_solution = new float[sum + 1];
- duals = new float[rows + 1];
- ch_sign = new short[rows + 1];
- mat = new MatrixArray(mat_alloc);
- alternate_mat = new MatrixArray(mat_alloc);
- }
-
- public void init(int ncolumns) {
- int nsum;
- int nrows = 0;
- nsum=nrows+ncolumns;
- active=FALSE;
- debug=FALSE;
- trace=FALSE;
- rows=nrows;
- columns=ncolumns;
- sum=nsum;
- obj_bound=DEF_INFINITE;
- infinite=DEF_INFINITE;
- epsilon=DEF_EPSILON;
- epsb=DEF_EPSB;
- epsd=DEF_EPSD;
- epsel=DEF_EPSEL;
- non_zeros=0;
-
- for(int i = 0; i < col_end.length; i++) col_end[i] = 0;
- for(int i = 0; i < rows + 1; i++) row_end[i] = 0;
- for(int i = 0; i < rows + 1; i++) orig_rh[i] = 0;
- for(int i = 0; i < rows + 1; i++) rh[i] = 0;
- for(int i = 0; i < rows + 1; i++) rhs[i] = 0;
- for(int i = 0; i <= sum; i++) orig_upbo[i]=infinite;
- for(int i = 0; i < sum + 1; i++) upbo[i] = 0;
- for(int i = 0; i < sum + 1; i++) orig_lowbo[i] = 0;
- for(int i = 0; i < sum + 1; i++) lowbo[i] = 0;
- for(int i = 0; i <= rows; i++) bas[i] = 0;
- for(int i = 0; i <= sum; i++) basis[i] = 0;
- for(int i = 0; i <= rows; i++) { bas[i]=i; basis[i]=TRUE; }
- for(int i = rows + 1; i <= sum; i++) basis[i]=FALSE;
- for(int i = 0 ; i <= sum; i++) lower[i]=TRUE;
- for(int i = 0; i <= sum; i++) solution[i] = 0;
- for(int i = 0; i <= sum; i++) best_solution[i] = 0;
- for(int i = 0; i <= rows; i++) duals[i] = 0;
- for(int i = 0; i <= rows; i++) ch_sign[i] = FALSE;
-
- row_end_valid=FALSE;
- bb_rule=FIRST_NI;
- break_at_int=FALSE;
- break_value=0;
- iter=0;
- total_iter=0;
- basis_valid=TRUE;
- eta_valid=TRUE;
- eta_size=0;
- nr_lagrange=0;
- maximise = FALSE;
- floor_first = TRUE;
- valid = FALSE;
- }
-
- public void setObjective(float[] row, boolean maximize) {
- for(int i=row.length-1; i>0; i--) row[i] = row[i-1];
- row[0] = (float)0.0;
- for(int j = 1; j <= columns; j++) {
- int Row = 0;
- int column = j;
- float Value = row[j];
- int elmnr, lastelm;
-
- if(Row > rows || Row < 0) throw new Error("row out of range");
- if(column > columns || column < 1) throw new Error("column out of range");
-
- if (basis[column] == TRUE && Row > 0) basis_valid = FALSE;
- eta_valid = FALSE;
- elmnr = col_end[column-1];
- while((elmnr < col_end[column]) ? (get_row_nr(mat, elmnr) != Row) : false) elmnr++;
- if((elmnr != col_end[column]) ? (get_row_nr(mat, elmnr) == Row) : false ) {
- if (ch_sign[Row] != FALSE) set_value(mat, elmnr, -Value);
- else set_value(mat, elmnr, Value);
- } else {
- /* check if more space is needed for matrix */
- if (non_zeros + 1 > mat_alloc) throw new Error("not enough mat space; this should not happen");
- /* Shift the matrix */
- lastelm=non_zeros;
- for(int i = lastelm; i > elmnr ; i--) {
- set_row_nr(mat,i,get_row_nr(mat,i-1));
- set_value(mat,i,get_value(mat,i-1));
- }
- for(int i = column; i <= columns; i++) col_end[i]++;
- /* Set new element */
- set_row_nr(mat,elmnr, Row);
- if (ch_sign[Row] != FALSE) set_value(mat, elmnr, -Value);
- else set_value(mat, elmnr, Value);
- row_end_valid=FALSE;
- non_zeros++;
- if (active != FALSE) Non_zeros=non_zeros;
- }
- }
- if (maximize) {
- if (maximise == FALSE) {
- for(int i = 0; i < non_zeros; i++)
- if(get_row_nr(mat, i)==0)
- set_value(mat, i, get_value(mat,i)* (float)-1.0);
- eta_valid=FALSE;
- }
- maximise=TRUE;
- ch_sign[0]=TRUE;
- if (active != FALSE) Maximise=TRUE;
- } else {
- if (maximise==TRUE) {
- for(int i = 0; i < non_zeros; i++)
- if(get_row_nr(mat, i)==0)
- set_value(mat, i, get_value(mat,i) * (float)-1.0);
- eta_valid=FALSE;
- }
- maximise=FALSE;
- ch_sign[0]=FALSE;
- if (active != FALSE) Maximise=FALSE;
- }
- }
-
- public void add_constraint(float[] row, short constr_type, float rh) {
- for(int i=row.length-1; i>0; i--) row[i] = row[i-1];
- row[0] = (float)0.0;
-
- MatrixArray newmat;
- int elmnr;
- int stcol;
-
- newmat = alternate_mat;
- for(int i = 0; i < non_zeros; i++) { set_row_nr(newmat,i, 0); set_value(newmat, i, 0); }
- for(int i = 1; i <= columns; i++) if (row[i]!=0) non_zeros++;
- if (non_zeros > mat_alloc) throw new Error("not enough mat space; this should not happen");
- rows++;
- sum++;
- if(rows > rows_alloc) throw new Error("not enough rows; this should never happen");
- if(constr_type==GE) ch_sign[rows] = TRUE;
- else ch_sign[rows] = FALSE;
-
- elmnr = 0;
- stcol = 0;
- for(int i = 1; i <= columns; i++) {
- for(int j = stcol; j < col_end[i]; j++) {
- set_row_nr(newmat,elmnr, get_row_nr(mat, j));
- set_value(newmat, elmnr, get_value(mat,j));
- elmnr++;
- }
- if(((i>=1 && i< columns && row[i]!=0)?TRUE:FALSE) != FALSE) {
- if(ch_sign[rows] != FALSE) set_value(newmat, elmnr, -row[i]);
- else set_value(newmat, elmnr, row[i]);
- set_row_nr(newmat,elmnr, rows);
- elmnr++;
- }
- stcol=col_end[i];
- col_end[i]=elmnr;
- }
-
- alternate_mat = mat;
- mat = newmat;
-
- for(int i = sum ; i > rows; i--) {
- orig_upbo[i]=orig_upbo[i-1];
- orig_lowbo[i]=orig_lowbo[i-1];
- basis[i]=basis[i-1];
- lower[i]=lower[i-1];
- }
-
- for(int i = 1 ; i <= rows; i++) if(bas[i] >= rows) bas[i]++;
-
- if(constr_type==LE || constr_type==GE) orig_upbo[rows]=infinite;
- else if(constr_type==EQ) orig_upbo[rows]=0;
- else throw new Error("Wrong constraint type\n");
- orig_lowbo[rows]=0;
-
- if(constr_type==GE && rh != 0) orig_rh[rows]=-rh;
- else orig_rh[rows]=rh;
-
- row_end_valid=FALSE;
-
- bas[rows]=rows;
- basis[rows]=TRUE;
- lower[rows]=TRUE;
-
- if (active != FALSE) set_globals();
- eta_valid=FALSE;
- }
-
- public void bound_sum(int column1, int column2, float bound, short type, float[] scratch) {
- for(int i=0; i<scratch.length; i++) scratch[i] = (float)0.0;
- scratch[column1] = (float)1.0;
- scratch[column2] = (float)1.0;
- add_constraint(scratch, type, bound);
- for(int i=0; i<scratch.length; i++) scratch[i] = (float)0.0;
- }
-
- public void bound_difference(int column1, int column2, float bound, short type, float[] scratch) {
- for(int i=0; i<scratch.length; i++) scratch[i] = (float)0.0;
- scratch[column1] = (float)1.0;
- scratch[column2] = (float)-1.0;
- add_constraint(scratch, type, bound);
- for(int i=0; i<scratch.length; i++) scratch[i] = (float)0.0;
- }
-
- public void set_upbo(int column, float value) {
- if(column > columns || column < 1) throw new Error("column out of range");
- if(value < orig_lowbo[rows + column]) throw new Error("UpperBound must be >= lowerBound");
- eta_valid = FALSE;
- orig_upbo[rows+column] = value;
- }
-
- public void set_lowbo(int column, float value) {
- if(column > columns || column < 1) throw new Error("column out of range");
- if(value > orig_upbo[rows + column]) throw new Error("UpperBound must be >= lowerBound");
- eta_valid = FALSE;
- orig_lowbo[rows+column] = value;
- }
-
- public void set_rh(int row, float value) {
- if(row > rows || row < 0) throw new Error("Row out of Range");
- if(row == 0) throw new Error("Warning: attempt to set RHS of objective function, ignored");
- if (ch_sign[row] != FALSE) orig_rh[row] = -value;
- else orig_rh[row] = value;
- eta_valid = FALSE;
- }
-
- public void set_rh_vec(float[] rh) {
- for(int i=1; i <= rows; i++)
- if (ch_sign[i] != FALSE) orig_rh[i]=-rh[i];
- else orig_rh[i]=rh[i];
- eta_valid=FALSE;
- }
-
-
- public void set_constr_type(int row, short con_type) {
- if (row > rows || row < 1) throw new Error("Row out of Range");
- switch(con_type) {
- case EQ:
- orig_upbo[row]=0;
- basis_valid=FALSE;
- if (ch_sign[row] != FALSE) {
- for(int i = 0; i < non_zeros; i++)
- if (get_row_nr(mat, i)==row) set_value(mat, i, get_value(mat,i) * (float)-1);
- eta_valid=FALSE;
- ch_sign[row]=FALSE;
- if (orig_rh[row]!=0) orig_rh[row]*=-1;
- }
- break;
- case LE:
- orig_upbo[row]=infinite;
- basis_valid=FALSE;
- if (ch_sign[row] != FALSE) {
- for(int i = 0; i < non_zeros; i++)
- if (get_row_nr(mat, i)==row) set_value(mat, i, get_value(mat,i) * (float)-1);
- eta_valid=FALSE;
- ch_sign[row]=FALSE;
- if (orig_rh[row]!=0) orig_rh[row]*=-1;
- }
- break;
- case GE:
- orig_upbo[row]=infinite;
- basis_valid=FALSE;
- if (ch_sign[row] == FALSE) {
- for(int i = 0; i < non_zeros; i++)
- if (get_row_nr(mat, i)==row) set_value(mat, i, get_value(mat,i) * (float)-1);
- eta_valid=FALSE;
- ch_sign[row]=TRUE;
- if (orig_rh[row]!=0) orig_rh[row]*=-1;
- }
- break;
- default: throw new Error("Constraint type not (yet) implemented");
- }
- }
-
- void set_globals() {
- Rows = rows;
- columns = columns;
- Sum = Rows + columns;
- Non_zeros = non_zeros;
- Mat = mat;
- Col_no = col_no;
- Col_end = col_end;
- Row_end = row_end;
- Rh = rh;
- Rhs = rhs;
- Orig_rh = orig_rh;
- Orig_upbo = orig_upbo;
- Orig_lowbo = orig_lowbo;
- Upbo = upbo;
- Lowbo = lowbo;
- Bas = bas;
- Basis = basis;
- Lower = lower;
- Eta_alloc = eta_alloc;
- Eta_size = eta_size;
- Num_inv = num_inv;
- Eta_value = eta_value;
- Eta_row_nr = eta_row_nr;
- Eta_col_end = eta_col_end;
- Solution = solution;
- Best_solution = best_solution;
- Infinite = infinite;
- Epsilon = epsilon;
- Epsb = epsb;
- Epsd = epsd;
- Epsel = epsel;
- TREJ = TREJ;
- TINV = TINV;
- Maximise = maximise;
- Floor_first = floor_first;
- active = TRUE;
- }
-
- private void ftran(int start, int end, float[] pcol) {
- int k, r;
- float theta;
- for(int i = start; i <= end; i++) {
- k = Eta_col_end[i] - 1;
- r = Eta_row_nr[k];
- theta = pcol[r];
- if (theta != 0) for(int j = Eta_col_end[i - 1]; j < k; j++)
- pcol[Eta_row_nr[j]] += theta * Eta_value[j];
- pcol[r] *= Eta_value[k];
- }
- for(int i = 0; i <= Rows; i++) round(pcol[i], Epsel);
- }
-
- private void btran(float[] row) {
- int k;
- float f;
- for(int i = Eta_size; i >= 1; i--) {
- f = 0;
- k = Eta_col_end[i] - 1;
- for(int j = Eta_col_end[i - 1]; j <= k; j++) f += row[Eta_row_nr[j]] * Eta_value[j];
- f = round(f, Epsel);
- row[Eta_row_nr[k]] = f;
- }
- }
-
- static int[] num = new int[65535];
- static int[] rownum = new int[65535];
- static int[] colnum = new int[65535];
-
- short Isvalid() {
- int row_nr;
- if (row_end_valid == FALSE) {
- for(int i = 0; i <= rows; i++) { num[i] = 0; rownum[i] = 0; }
- for(int i = 0; i < non_zeros; i++) rownum[get_row_nr(mat, i)]++;
- row_end[0] = 0;
- for(int i = 1; i <= rows; i++) row_end[i] = row_end[i - 1] + rownum[i];
- for(int i = 1; i <= columns; i++)
- for(int j = col_end[i - 1]; j < col_end[i]; j++) {
- row_nr = get_row_nr(mat, j);
- if (row_nr != 0) {
- num[row_nr]++;
- col_no[row_end[row_nr - 1] + num[row_nr]] = i;
- }
- }
- row_end_valid = TRUE;
- }
- if (valid != FALSE) return(TRUE);
- for(int i = 0; i <= rows; i++) rownum[i] = 0;
- for(int i = 0; i <= columns; i++) colnum[i] = 0;
- for(int i = 1 ; i <= columns; i++)
- for(int j = col_end[i - 1]; j < col_end[i]; j++) {
- colnum[i]++;
- rownum[get_row_nr(mat, j)]++;
- }
- for(int i = 1; i <= columns; i++)
- if (colnum[i] == 0)
- throw new Error("Warning: Variable " + i + " not used in any constaints\n");
- valid = TRUE;
- return(TRUE);
- }
-
- private void resize_eta() {
- Eta_alloc *= 2;
- throw new Error("eta undersized; this should never happen");
- /*
- float[] db_ptr = Eta_value;
- Eta_value = new float[Eta_alloc];
- System.arraycopy(db_ptr, 0, Eta_value, 0, db_ptr.length);
- eta_value = Eta_value;
-
- int[] int_ptr = Eta_row_nr;
- Eta_row_nr = new int[Eta_alloc];
- System.arraycopy(int_ptr, 0, Eta_row_nr, 0, int_ptr.length);
- eta_row_nr = Eta_row_nr;
- */
- }
-
- private void condensecol(int row_nr, float[] pcol) {
- int elnr;
- elnr = Eta_col_end[Eta_size];
- if (elnr + Rows + 2 > Eta_alloc) resize_eta();
- for(int i = 0; i <= Rows; i++)
- if (i != row_nr && pcol[i] != 0) {
- Eta_row_nr[elnr] = i;
- Eta_value[elnr] = pcol[i];
- elnr++;
- }
- Eta_row_nr[elnr] = row_nr;
- Eta_value[elnr] = pcol[row_nr];
- elnr++;
- Eta_col_end[Eta_size + 1] = elnr;
- }
-
- private void addetacol() {
- int k;
- float theta;
- int j = Eta_col_end[Eta_size];
- Eta_size++;
- k = Eta_col_end[Eta_size];
- theta = 1 / (float) Eta_value[k - 1];
- Eta_value[k - 1] = theta;
- for(int i = j; i < k - 1; i++) Eta_value[i] *= -theta;
- JustInverted = FALSE;
- }
-
- private void setpivcol(short lower, int varin, float[] pcol) {
- int colnr;
- float f;
- if (lower != FALSE) f = 1;
- else f = -1;
- for(int i = 0; i <= Rows; i++) pcol[i] = 0;
- if (varin > Rows) {
- colnr = varin - Rows;
- for(int i = Col_end[colnr - 1]; i < Col_end[colnr]; i++) pcol[get_row_nr(Mat, i)] = get_value(Mat,i) * f;
- pcol[0] -= Extrad * f;
- } else {
- if (lower != FALSE) pcol[varin] = 1;
- else pcol[varin] = -1;
- }
- ftran(1, Eta_size, pcol);
- }
-
- private void minoriteration(int colnr, int row_nr) {
- int k, wk, varin, varout, elnr;
- float piv = 0, theta;
- varin = colnr + Rows;
- elnr = Eta_col_end[Eta_size];
- wk = elnr;
- Eta_size++;
- if (Extrad != 0) {
- Eta_row_nr[elnr] = 0;
- Eta_value[elnr] = -Extrad;
- elnr++;
- }
- for(int j = Col_end[colnr - 1] ; j < Col_end[colnr]; j++) {
- k = get_row_nr(Mat, j);
- if (k == 0 && Extrad != 0) Eta_value[Eta_col_end[Eta_size -1]] += get_value(Mat,j);
- else if (k != row_nr) {
- Eta_row_nr[elnr] = k;
- Eta_value[elnr] = get_value(Mat,j);
- elnr++;
- } else {
- piv = get_value(Mat,j);
- }
- }
- Eta_row_nr[elnr] = row_nr;
- Eta_value[elnr] = 1 / (float) piv;
- elnr++;
- theta = Rhs[row_nr] / (float) piv;
- Rhs[row_nr] = theta;
- for(int i = wk; i < elnr - 1; i++) Rhs[Eta_row_nr[i]] -= theta * Eta_value[i];
- varout = Bas[row_nr];
- Bas[row_nr] = varin;
- Basis[varout] = FALSE;
- Basis[varin] = TRUE;
- for(int i = wk; i < elnr - 1; i++) Eta_value[i] /= - (float) piv;
- Eta_col_end[Eta_size] = elnr;
- }
-
- private void rhsmincol(float theta, int row_nr, int varin) {
- int varout;
- float f;
- if (row_nr > Rows + 1) {
- System.err.println("Error: rhsmincol called with row_nr: " + row_nr + ", rows: " + Rows + "\n");
- System.err.println("This indicates numerical instability\n");
- }
- int j = Eta_col_end[Eta_size];
- int k = Eta_col_end[Eta_size + 1];
- for(int i = j; i < k; i++) {
- f = Rhs[Eta_row_nr[i]] - theta * Eta_value[i];
- f = round(f, Epsb);
- Rhs[Eta_row_nr[i]] = f;
- }
- Rhs[row_nr] = theta;
- varout = Bas[row_nr];
- Bas[row_nr] = varin;
- Basis[varout] = FALSE;
- Basis[varin] = TRUE;
- }
-
- private static int[] rownum_ = new int[65535];
- private static int[] colnum_ = new int[65535];
- private static int[] col = new int[65535];
- private static int[] row = new int[65535];
- private static float[] pcol = new float[65535];
- private static short[] frow = new short[65535];
- private static short[] fcol = new short[65535];
-
- void invert() {
- int v, wk, numit, varnr, row_nr, colnr, varin;
- float theta;
-
- for(int i = 0; i <= Rows; i++) rownum_[i] = 0;
- for(int i = 0; i <= Rows; i++) col[i] = 0;
- for(int i = 0; i <= Rows; i++) row[i] = 0;
- for(int i = 0; i <= Rows; i++) pcol[i] = 0;
- for(int i = 0; i <= Rows; i++) frow[i] = TRUE;
- for(int i = 0; i < columns; i++) fcol[i] = FALSE;
- for(int i = 0; i <= columns; i++) colnum_[i] = 0;
-
- for(int i = 0; i <= Rows; i++)
- if (Bas[i] > Rows) fcol[Bas[i] - Rows - 1] = TRUE;
- else frow[Bas[i]] = FALSE;
-
- for(int i = 1; i <= Rows; i++)
- if (frow[i] != FALSE)
- for(int j = Row_end[i - 1] + 1; j <= Row_end[i]; j++) {
- wk = Col_no[j];
- if (fcol[wk - 1] != FALSE) {
- colnum_[wk]++;
- rownum_[i - 1]++;
- }
- }
-
- for(int i = 1; i <= Rows; i++) Bas[i] = i;
- for(int i = 1; i <= Rows; i++) Basis[i] = TRUE;
- for(int i = 1; i <= columns; i++) Basis[i + Rows] = FALSE;
- for(int i = 0; i <= Rows; i++) Rhs[i] = Rh[i];
- for(int i = 1; i <= columns; i++) {
- varnr = Rows + i;
- if (Lower[varnr] == FALSE) {
- theta = Upbo[varnr];
- for(int j = Col_end[i - 1]; j < Col_end[i]; j++)
- Rhs[get_row_nr(Mat, j)] -= theta * get_value(Mat,j);
- }
- }
- for(int i = 1; i <= Rows; i++) if (Lower[i] == FALSE) Rhs[i] -= Upbo[i];
- Eta_size = 0;
- v = 0;
- row_nr = 0;
- Num_inv = 0;
- numit = 0;
- while(v < Rows) {
- int j;
- row_nr++;
- if (row_nr > Rows) row_nr = 1;
- v++;
- if (rownum_[row_nr - 1] == 1)
- if (frow[row_nr] != FALSE) {
- v = 0;
- j = Row_end[row_nr - 1] + 1;
- while(fcol[Col_no[j] - 1] == FALSE) j++;
- colnr = Col_no[j];
- fcol[colnr - 1] = FALSE;
- colnum_[colnr] = 0;
- for(j = Col_end[colnr - 1]; j < Col_end[colnr]; j++)
- if (frow[get_row_nr(Mat, j)] != FALSE)
- rownum_[get_row_nr(Mat, j) - 1]--;
- frow[row_nr] = FALSE;
- minoriteration(colnr, row_nr);
- }
- }
- v = 0;
- colnr = 0;
- while(v < columns) {
- int j;
- colnr++;
- if (colnr > columns) colnr = 1;
- v++;
- if (colnum_[colnr] == 1)
- if (fcol[colnr - 1] != FALSE) {
- v = 0;
- j = Col_end[colnr - 1] + 1;
- while(frow[get_row_nr(Mat, j - 1)] == FALSE) j++;
- row_nr = get_row_nr(Mat, j - 1);
- frow[row_nr] = FALSE;
- rownum_[row_nr - 1] = 0;
- for(j = Row_end[row_nr - 1] + 1; j <= Row_end[row_nr]; j++)
- if (fcol[Col_no[j] - 1] != FALSE)
- colnum_[Col_no[j]]--;
- fcol[colnr - 1] = FALSE;
- numit++;
- col[numit - 1] = colnr;
- row[numit - 1] = row_nr;
- }
- }
- for(int j = 1; j <= columns; j++)
- if (fcol[j - 1] != FALSE) {
- fcol[j - 1] = FALSE;
- setpivcol(Lower[Rows + j], j + Rows, pcol);
- row_nr = 1;
- while((frow[row_nr] == FALSE || pcol[row_nr] == FALSE) && row_nr <= Rows)
- row_nr++; /* this sometimes sets row_nr to Rows + 1 and makes
- rhsmincol crash. Solved in 2.0? MB */
- if (row_nr == Rows + 1) throw new Error("Inverting failed");
- frow[row_nr] = FALSE;
- condensecol(row_nr, pcol);
- theta = Rhs[row_nr] / (float) pcol[row_nr];
- rhsmincol(theta, row_nr, Rows + j);
- addetacol();
- }
- for(int i = numit - 1; i >= 0; i--) {
- colnr = col[i];
- row_nr = row[i];
- varin = colnr + Rows;
- for(int j = 0; j <= Rows; j++) pcol[j] = 0;
- for(int j = Col_end[colnr - 1]; j < Col_end[colnr]; j++) pcol[get_row_nr(Mat, j)] = get_value(Mat,j);
- pcol[0] -= Extrad;
- condensecol(row_nr, pcol);
- theta = Rhs[row_nr] / (float) pcol[row_nr];
- rhsmincol(theta, row_nr, varin);
- addetacol();
- }
- for(int i = 1; i <= Rows; i++) Rhs[i] = round(Rhs[i], Epsb);
- JustInverted = TRUE;
- DoInvert = FALSE;
- }
-
- private short colprim(Ref colnr, short minit, float[] drow) {
- int varnr;
- float f, dpiv;
- dpiv = -Epsd;
- colnr.value = 0;
- if (minit == FALSE) {
- for(int i = 1; i <= Sum; i++) drow[i] = 0;
- drow[0] = 1;
- btran(drow);
- for(int i = 1; i <= columns; i++) {
- varnr = Rows + i;
- if (Basis[varnr] == FALSE)
- if (Upbo[varnr] > 0) {
- f = 0;
- for(int j = Col_end[i - 1]; j < Col_end[i]; j++) f += drow[get_row_nr(Mat, j)] * get_value(Mat,j);
- drow[varnr] = f;
- }
- }
- for(int i = 1; i <= Sum; i++) drow[i] = round(drow[i], Epsd);
- }
- for(int i = 1; i <= Sum; i++)
- if (Basis[i] == FALSE)
- if (Upbo[i] > 0) {
- if (Lower[i] != FALSE) f = drow[i];
- else f = -drow[i];
- if (f < dpiv) {
- dpiv = f;
- colnr.value = i;
- }
- }
- if (colnr.value == 0) {
- Doiter = FALSE;
- DoInvert = FALSE;
- Status = OPTIMAL;
- }
- return(colnr.value > 0 ? (short)1 : (short)0);
- }
-
- private short rowprim(int colnr, Ref row_nr, Ref theta, float[] pcol) {
- float f = 0, quot;
- row_nr.value = 0;
- theta.value = Infinite;
- for(int i = 1; i <= Rows; i++) {
- f = pcol[i];
- if (Math.abs(f) < TREJ) f = 0;
- if (f != 0) {
- quot = 2 * Infinite;
- if (f > 0) quot = Rhs[i] / (float) f;
- else if (Upbo[Bas[i]] < Infinite) quot = (Rhs[i] - Upbo[Bas[i]]) / (float) f;
- round(quot, Epsel);
- if (quot < theta.value) {
- theta.value = quot;
- row_nr.value = i;
- }
- }
- }
- if (row_nr.value == 0)
- for(int i = 1; i <= Rows; i++) {
- f = pcol[i];
- if (f != 0) {
- quot = 2 * Infinite;
- if (f > 0) quot = Rhs[i] / (float) f;
- else if (Upbo[Bas[i]] < Infinite) quot = (Rhs[i] - Upbo[Bas[i]]) / (float) f;
- quot = round(quot, Epsel);
- if (quot < theta.value) {
- theta.value = quot;
- row_nr.value = i;
- }
- }
- }
-
- if (theta.value < 0) throw new Error("Warning: Numerical instability, qout = " + theta.value);
- if (row_nr.value == 0) {
- if (Upbo[colnr] == Infinite) {
- Doiter = FALSE;
- DoInvert = FALSE;
- Status = UNBOUNDED;
- } else {
- int i = 1;
- while(pcol[i] >= 0 && i <= Rows) i++;
- if (i > Rows) {
- Lower[colnr] = FALSE;
- Rhs[0] += Upbo[colnr]*pcol[0];
- Doiter = FALSE;
- DoInvert = FALSE;
- } else if (pcol[i]<0) {
- row_nr.value = i;
- }
- }
- }
- if (row_nr.value > 0) Doiter = TRUE;
- return((row_nr.value > 0) ? (short)1 : (short)0);
- }
-
- private short rowdual(Ref row_nr) {
- int i;
- float f, g, minrhs;
- short artifs;
- row_nr.value = 0;
- minrhs = -Epsb;
- i = 0;
- artifs = FALSE;
- while(i < Rows && artifs == FALSE) {
- i++;
- f = Upbo[Bas[i]];
- if (f == 0 && (Rhs[i] != 0)) {
- artifs = TRUE;
- row_nr.value = i;
- } else {
- if (Rhs[i] < f - Rhs[i]) g = Rhs[i];
- else g = f - Rhs[i];
- if (g < minrhs) {
- minrhs = g;
- row_nr.value = i;
- }
- }
- }
- return(row_nr.value > 0 ? (short)1 : (short)0);
- }
-
- private short coldual(int row_nr, Ref colnr, short minit, float[] prow, float[] drow) {
- int r, varnr;
- float theta, quot, pivot, d, f, g;
- Doiter = FALSE;
- if (minit == FALSE) {
- for(int i = 0; i <= Rows; i++) {
- prow[i] = 0;
- drow[i] = 0;
- }
- drow[0] = 1;
- prow[row_nr] = 1;
- for(int i = Eta_size; i >= 1; i--) {
- d = 0;
- f = 0;
- r = Eta_row_nr[Eta_col_end[i] - 1];
- for(int j = Eta_col_end[i - 1]; j < Eta_col_end[i]; j++) {
- /* this is where the program consumes most cpu time */
- f += prow[Eta_row_nr[j]] * Eta_value[j];
- d += drow[Eta_row_nr[j]] * Eta_value[j];
- }
- f = round(f, Epsel);
- prow[r] = f;
- d = round(d, Epsel);
- drow[r] = d;
- }
- for(int i = 1; i <= columns; i++) {
- varnr = Rows + i;
- if (Basis[varnr] == FALSE) {
- d = - Extrad * drow[0];
- f = 0;
- for(int j = Col_end[i - 1]; j < Col_end[i]; j++) {
- d = d + drow[get_row_nr(Mat, j)] * get_value(Mat,j);
- f = f + prow[get_row_nr(Mat, j)] * get_value(Mat,j);
- }
- drow[varnr] = d;
- prow[varnr] = f;
- }
- }
- for(int i = 0; i <= Sum; i++) {
- prow[i] = round(prow[i], Epsel);
- drow[i] = round(drow[i], Epsd);
- }
- }
- if (Rhs[row_nr] > Upbo[Bas[row_nr]]) g = -1;
- else g = 1;
- pivot = 0;
- colnr.value = 0;
- theta = Infinite;
- for(int i = 1; i <= Sum; i++) {
- if (Lower[i] != FALSE) d = prow[i] * g;
- else d = -prow[i] * g;
- if ((d < 0) && (Basis[i] == FALSE) && (Upbo[i] > 0)) {
- if (Lower[i] == FALSE) quot = -drow[i] / (float) d;
- else quot = drow[i] / (float) d;
- if (quot < theta) {
- theta = quot;
- pivot = d;
- colnr.value = i;
- } else if ((quot == theta) && (Math.abs(d) > Math.abs(pivot))) {
- pivot = d;
- colnr.value = i;
- }
- }
- }
- if (colnr.value > 0) Doiter = TRUE;
- return(colnr.value > 0 ? (short)1 : (short)0);
- }
-
- private void iteration(int row_nr, int varin, Ref theta, float up, Ref minit, Ref low, short primal,float[] pcol) {
- int k, varout;
- float f;
- float pivot;
- iter++;
- minit.value = theta.value > (up + Epsb) ? 1 : 0;
- if (minit.value != 0) {
- theta.value = up;
- low.value = low.value == 0 ? 1 : 0;
- }
- k = Eta_col_end[Eta_size + 1];
- pivot = Eta_value[k - 1];
- for(int i = Eta_col_end[Eta_size]; i < k; i++) {
- f = Rhs[Eta_row_nr[i]] - theta.value * Eta_value[i];
- f = round(f, Epsb);
- Rhs[Eta_row_nr[i]] = f;
- }
- if (minit.value == 0) {
- Rhs[row_nr] = theta.value;
- varout = Bas[row_nr];
- Bas[row_nr] = varin;
- Basis[varout] = FALSE;
- Basis[varin] = TRUE;
- if (primal != FALSE && pivot < 0) Lower[varout] = FALSE;
- if (low.value == 0 && up < Infinite) {
- low.value = TRUE;
- Rhs[row_nr] = up - Rhs[row_nr];
- for(int i = Eta_col_end[Eta_size]; i < k; i++) Eta_value[i] = -Eta_value[i];
- }
- addetacol();
- Num_inv++;
- }
- }
-
- static float[] drow = new float[65535];
- static float[] prow = new float[65535];
- static float[] Pcol = new float[65535];
-
- private int solvelp() {
- int varnr;
- float f = 0, theta = 0;
- short primal;
- short minit;
- int colnr, row_nr;
- colnr = 0;
- row_nr = 0;
- short flag;
- Ref ref1, ref2, ref3;
- ref1 = new Ref(0);
- ref2 = new Ref(0);
- ref3 = new Ref(0);
-
- for(int i = 0; i <= Sum; i++) { drow[i] = 0; prow[i] = 0; }
- for(int i = 0; i <= Rows; i++) Pcol[i] = 0;
- iter = 0;
- minit = FALSE;
- Status = RUNNING;
- DoInvert = FALSE;
- Doiter = FALSE;
- primal = TRUE;
- for(int i = 0; i != Rows && primal != FALSE;) {
- i++;
- primal = (Rhs[i] >= 0 && Rhs[i] <= Upbo[Bas[i]]) ? (short)1: (short)0;
- }
- if (primal == FALSE) {
- drow[0] = 1;
- for(int i = 1; i <= Rows; i++) drow[i] = 0;
- Extrad = 0;
- for(int i = 1; i <= columns; i++) {
- varnr = Rows + i;
- drow[varnr] = 0;
- for(int j = Col_end[i - 1]; j < Col_end[i]; j++)
- if (drow[get_row_nr(Mat, j)] != 0)
- drow[varnr] += drow[get_row_nr(Mat, j)] * get_value(Mat,j);
- if (drow[varnr] < Extrad) Extrad = drow[varnr];
- }
- } else {
- Extrad = 0;
- }
- minit = FALSE;
- while(Status == RUNNING) {
- Doiter = FALSE;
- DoInvert = FALSE;
- construct_solution(Solution);
- if (primal != FALSE) {
- ref1.value = colnr;
- flag = colprim(ref1, minit, drow);
- colnr = (int)ref1.value;
- if (flag != FALSE) {
- setpivcol(Lower[colnr], colnr, Pcol);
- ref1.value = row_nr;
- ref2.value = theta;
- flag = rowprim(colnr, ref1, ref2, Pcol);
- row_nr = (int)ref1.value;
- theta = ref2.value;
- if (flag != FALSE) condensecol(row_nr, Pcol);
- }
- } else {
- if (minit == FALSE) {
- ref1.value = row_nr;
- flag = rowdual(ref1);
- row_nr = (int)ref1.value;
- }
- if (row_nr > 0) {
- ref1.value = colnr;
- flag = coldual(row_nr, ref1, minit, prow, drow);
- colnr = (int)ref1.value;
- if (flag != FALSE) {
- setpivcol(Lower[colnr], colnr, Pcol);
- /* getting div by zero here ... MB */
- if (Pcol[row_nr] == 0) {
- throw new Error("An attempt was made to divide by zero (Pcol[" + row_nr + "])");
- } else {
- condensecol(row_nr, Pcol);
- f = Rhs[row_nr] - Upbo[Bas[row_nr]];
- if (f > 0) {
- theta = f / (float) Pcol[row_nr];
- if (theta <= Upbo[colnr])
- Lower[Bas[row_nr]] = (Lower[Bas[row_nr]] == FALSE)? (short)1:(short)0;
- } else theta = Rhs[row_nr] / (float) Pcol[row_nr];
- }
- } else Status = INFEASIBLE;
- } else {
- primal = TRUE;
- Doiter = FALSE;
- Extrad = 0;
- DoInvert = TRUE;
- }
- }
- if (Doiter != FALSE) {
- ref1.value = theta;
- ref2.value = minit;
- ref3.value = Lower[colnr];
- iteration(row_nr, colnr, ref1, Upbo[colnr], ref2, ref3, primal, Pcol);
- theta = ref1.value;
- minit = (short)ref2.value;
- Lower[colnr] = (short)ref3.value;
- }
- if (Num_inv >= max_num_inv) DoInvert = TRUE;
- if (DoInvert != FALSE) invert();
- }
- total_iter += iter;
- return(Status);
- }
-
- private void construct_solution(float[] sol) {
- float f;
- int basi;
- for(int i = 0; i <= Rows; i++) sol[i] = 0;
- for(int i = Rows + 1; i <= Sum; i++) sol[i] = Lowbo[i];
- for(int i = 1; i <= Rows; i++) {
- basi = Bas[i];
- if (basi > Rows) sol[basi] += Rhs[i];
- }
- for(int i = Rows + 1; i <= Sum; i++)
- if (Basis[i] == FALSE && Lower[i] == FALSE)
- sol[i] += Upbo[i];
- for(int j = 1; j <= columns; j++) {
- f = sol[Rows + j];
- if (f != 0)
- for(int i = Col_end[j - 1]; i < Col_end[j]; i++)
- sol[get_row_nr(Mat, i)] += f * get_value(Mat,i);
- }
- for(int i = 0; i <= Rows; i++) {
- if (Math.abs(sol[i]) < Epsb) sol[i] = 0;
- else if (ch_sign[i] != FALSE) sol[i] = -sol[i];
- }
- }
-
- private void calculate_duals() {
- for(int i = 1; i <= Rows; i++) duals[i] = 0;
- duals[0] = 1;
- btran(duals);
- for(int i = 1; i <= Rows; i++) {
- if (basis[i] != FALSE) duals[i] = 0;
- else if ( ch_sign[0] == ch_sign[i]) duals[i] = -duals[i];
- }
- }
-
- private static Random rdm = new Random();
-
- private int milpsolve(float[] upbo, float[] lowbo, short[] sbasis, short[] slower, int[] sbas) {
- int failure, notint, is_worse;
- float theta, tmpfloat;
- notint = 0;
-
- if (Break_bb != FALSE) return(BREAK_BB);
- Level++;
- total_nodes++;
- if (Level > max_level) max_level = Level;
- System.arraycopy(upbo, 0, Upbo, 0, Sum + 1);
- System.arraycopy(lowbo, 0, Lowbo, 0, Sum + 1);
- System.arraycopy(sbasis, 0, Basis, 0, Sum + 1);
- System.arraycopy(slower, 0, Lower, 0, Sum + 1);
- System.arraycopy(sbas, 0, Bas, 0, Rows + 1);
- System.arraycopy(Orig_rh, 0, Rh, 0, Rows + 1);
- if (eta_valid == FALSE) {
- for(int i = 1; i <= columns; i++)
- if (Lowbo[Rows + i] != 0) {
- theta = Lowbo[ Rows + i];
- if (Upbo[Rows + i]<Infinite) Upbo[Rows + i] -= theta;
- for(int j = Col_end[i - 1]; j < Col_end[i]; j++) Rh[get_row_nr(Mat, j)] -= theta * get_value(Mat,j);
- }
- invert();
- eta_valid = TRUE;
- }
- failure = solvelp();
- if (failure == OPTIMAL) {
- construct_solution(Solution);
- /* if this solution is worse than the best sofar, this branch must die */
- if (Maximise != FALSE) is_worse = (Solution[0] <= Best_solution[0]) ? 1:0;
- else is_worse = (Solution[0] >= Best_solution[0]) ? 1:0;
- if (is_worse != FALSE) {
- Level--;
- return(MILP_FAIL);
- }
- /* check if solution contains enough ints */
- if (bb_rule == FIRST_NI) {
- notint = 0;
- int i = Rows + 1;
- while(i <= Sum && notint == 0) i++;
- }
- if (bb_rule == RAND_NI) {
- int nr_not_int, select_not_int;
- nr_not_int = 0;
- for(int i = Rows + 1; i <= Sum; i++)
- if (nr_not_int == 0) notint = 0;
- else {
- select_not_int=(rdm.nextInt() % nr_not_int) + 1;
- i = Rows + 1;
- while(select_not_int > 0) i++;
- notint = i - 1;
- }
- }
- if (notint != FALSE) throw new Error("integer linear programming not supported");
- if (Maximise != FALSE) is_worse = (Solution[0] < Best_solution[0]) ? 1:0;
- else is_worse = (Solution[0] > Best_solution[0]) ? 1:0;
- if (is_worse == FALSE) {
- System.arraycopy(Solution, 0, Best_solution, 0, Sum + 1);
- calculate_duals();
- if (break_at_int != FALSE) {
- if (Maximise != FALSE && (Best_solution[0] > break_value)) Break_bb = TRUE;
- if (Maximise == FALSE && (Best_solution[0] < break_value)) Break_bb = TRUE;
- }
- }
- }
- Level--;
- return(failure);
- }
-
- public int solve() {
- int result = FAILURE;
- if (active == FALSE) set_globals();
- total_iter = 0;
- max_level = 1;
- total_nodes = 0;
- if (Isvalid() != FALSE) {
- if (Maximise != FALSE && obj_bound == Infinite) Best_solution[0]=-Infinite;
- else if (Maximise == FALSE && obj_bound==-Infinite) Best_solution[0] = Infinite;
- else Best_solution[0] = obj_bound;
- Level = 0;
- if (basis_valid == FALSE) {
- for(int i = 0; i <= rows; i++) {
- basis[i] = TRUE;
- bas[i] = i;
- }
- for(int i = rows+1; i <= sum; i++) basis[i] = FALSE;
- for(int i = 0; i <= sum; i++) lower[i] = TRUE;
- basis_valid = TRUE;
- }
- eta_valid = FALSE;
- Break_bb = FALSE;
- result = milpsolve(Orig_upbo, Orig_lowbo, Basis, Lower, Bas);
- eta_size = Eta_size;
- eta_alloc = Eta_alloc;
- num_inv = Num_inv;
- }
- for(int i = 0; i < maxmat; i++) { set_row_nr(mat,i, 0); set_value(mat, i, 0); }
- for(int i = 0; i < maxmat; i++) col_no[i] = 0;
-
- // FIXME: not sure about this
- for(int i = 0; i < Eta_size; i++) eta_value[i] = 0;
- for(int i = 0; i < Eta_size; i++) eta_row_nr[i] = 0;
- for(int i = 0; i < Eta_size; i++) eta_col_end[i] = 0;
-
- maxmat = 0;
- return(result);
- }
-
- private int maxmat = 0;
- private final static float round( float val, float eps) { return (Math.abs(val) < eps) ? 0 : val; }
- int get_row_nr(MatrixArray m, int i) { return m.row_nr[i]; }
- void set_row_nr(MatrixArray m, int i, int val) { m.row_nr[i] = val; maxmat = Math.max(i, maxmat); }
- float get_value(MatrixArray m, int i) { return m.value[i]; }
- void set_value(MatrixArray m, int i, float val) { m.value[i] = val; maxmat = Math.max(i, maxmat); }
- public static class MatrixArray {
- public int[] row_nr;
- public float[] value;
- public final int length;
- public MatrixArray(int length) { row_nr = new int[length]; value = new float[length]; this.length = length; }
- }
-
-}
-
+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.util;
-import java.io.IOException;
-import org.ibex.js.*;
-
-public interface Task {
- public abstract void perform() throws IOException, JSExn;
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-import java.io.*;
-
-/**
- * An unsynchronized Vector implementation; same semantics as
- * java.util.Vector. Useful for JDK1.1 platforms that don't have
- * java.util.ArrayList.
- *
- * May contain nulls.
- *
- * @see java.util.Vector
- */
-public final class Vec implements Serializable {
-
- private Object[] store;
- private int size = 0;
-
- public Vec() { this(10); }
- public Vec(int i) { store = new Object[i]; }
- public Vec(int i, Object[] store) { size = i; this.store = store; }
-
- private void grow() { grow(store.length * 2); }
- private void grow(int newsize) {
- Object[] newstore = new Object[newsize];
- System.arraycopy(store, 0, newstore, 0, size);
- store = newstore;
- }
-
- public void removeAllElements() {
- for(int i=0; i<size; i++) store[i] = null;
- size = 0;
- }
-
- public void toArray(Object[] o) {
- for(int i=0; i<size; i++)
- o[i] = store[i];
- }
-
- public int indexOf(Object o) {
- for(int i=0; i<size; i++)
- if (o == null ? store[i] == null : store[i].equals(o)) return i;
-
- return -1;
- }
-
- public void addElement(Object o) {
- if (size >= store.length - 1) grow();
- store[size++] = o;
- }
-
- public Object peek() {
- return lastElement();
- }
-
- public Object elementAt(int i) {
- return store[i];
- }
-
- public Object lastElement() {
- if (size == 0) return null;
- return store[size - 1];
- }
-
- public void push(Object o) { addElement(o); }
- public Object pop() {
- Object ret = lastElement();
- if (size > 0) store[size--] = null;
- return ret;
- }
-
- public int size() { return size; }
-
- public void setSize(int newSize) {
- if (newSize < 0) throw new RuntimeException("tried to set size to negative value");
- if (newSize > store.length) grow(newSize * 2);
- if (newSize < size)
- for(int i=newSize; i<size; i++)
- store[i] = null;
- size = newSize;
- }
-
- public void copyInto(Object[] out) {
- for(int i=0; i<size; i++)
- out[i] = store[i];
- }
-
- public void fromArray(Object[] in) {
- setSize(in.length);
- for(int i=0; i<size; i++)
- store[i] = in[i];
- }
-
- public void removeElementAt(int i) {
- if (i >= size || i < 0) throw new RuntimeException("tried to remove an element outside the vector's limits");
- for(int j=i; j<size - 1; j++)
- store[j] = store[j + 1];
- setSize(size - 1);
- }
-
- public void setElementAt(Object o, int i) {
- if (i >= size) setSize(i);
- store[i] = o;
- }
-
- public void removeElement(Object o) {
- int idx = indexOf(o);
- if (idx != -1) removeElementAt(idx);
- }
-
- public void insertElementAt(Object o, int at) {
- if (size == store.length) grow();
- for(int i=size; i>at; i--)
- store[i] = store[i-1];
- store[at] = o;
- size++;
- }
-
- public interface CompareFunc {
- public int compare(Object a, Object b);
- }
-
- public void sort(CompareFunc c) {
- sort(this, null, c, 0, size-1);
- }
-
- public static void sort(Vec a, Vec b, CompareFunc c) {
- if (b != null && a.size != b.size) throw new IllegalArgumentException("Vec a and b must be of equal size");
- sort(a, b, c, 0, a.size-1);
- }
-
- private static final void sort(Vec a, Vec b, CompareFunc c, int start, int end) {
- Object tmpa, tmpb = null;
- if(start >= end) return;
- if(end-start <= 6) {
- for(int i=start+1;i<=end;i++) {
- tmpa = a.store[i];
- if (b != null) tmpb = b.store[i];
- int j;
- for(j=i-1;j>=start;j--) {
- if(c.compare(a.store[j],tmpa) <= 0) break;
- a.store[j+1] = a.store[j];
- if (b != null) b.store[j+1] = b.store[j];
- }
- a.store[j+1] = tmpa;
- if (b != null) b.store[j+1] = tmpb;
- }
- return;
- }
-
- Object pivot = a.store[end];
- int lo = start - 1;
- int hi = end;
-
- do {
- while(c.compare(a.store[++lo],pivot) < 0) { }
- while((hi > lo) && c.compare(a.store[--hi],pivot) > 0) { }
- swap(a, lo,hi);
- if (b != null) swap(b, lo,hi);
- } while(lo < hi);
-
- swap(a, lo,end);
- if (b != null) swap(b, lo,end);
-
- sort(a, b, c, start, lo-1);
- sort(a, b, c, lo+1, end);
- }
-
- private static final void swap(Vec vec, int a, int b) {
- if(a != b) {
- Object tmp = vec.store[a];
- vec.store[a] = vec.store[b];
- vec.store[b] = tmp;
- }
- }
-
- public static final void sortInts(int[] a, int start, int end) {
- int tmpa;
- if(start >= end) return;
- if(end-start <= 6) {
- for(int i=start+1;i<=end;i++) {
- tmpa = a[i];
- int j;
- for(j=i-1;j>=start;j--) {
- if(a[j] <= tmpa) break;
- a[j+1] = a[j];
- }
- a[j+1] = tmpa;
- }
- return;
- }
- int pivot = a[end];
- int lo = start - 1;
- int hi = end;
- do {
- while(a[++lo] < pivot) { }
- while((hi > lo) && a[--hi] > pivot) { }
- swapInts(a, lo, hi);
- } while(lo < hi);
- swapInts(a, lo, end);
- sortInts(a, start, lo-1);
- sortInts(a, lo+1, end);
- }
- private static final void swapInts(int[] vec, int a, int b) {
- if(a != b) {
- int tmp = vec[a];
- vec[a] = vec[b];
- vec[b] = tmp;
- }
- }
-
-
-
- // just a cut-and-paste copy of Vec with int storage
- public static class Int {
- private int[] store;
- private int size = 0;
-
- public Int() { this(10); }
- public Int(int i) { store = new int[i]; }
- public Int(int i, int[] store) { size = i; this.store = store; }
-
- private void grow() { grow(store.length * 2); }
- private void grow(int newsize) {
- int[] newstore = new int[newsize];
- System.arraycopy(store, 0, newstore, 0, size);
- store = newstore;
- }
-
- public void removeAllElements() {
- for(int i=0; i<size; i++) store[i] = 0;
- size = 0;
- }
-
- public void toArray(int[] o) {
- for(int i=0; i<size; i++)
- o[i] = store[i];
- }
-
- public int[] dump() { int[] o = new int[size]; toArray(o); return o; }
-
- public int indexOf(int o) {
- for(int i=0; i<size; i++)
- if (o == store[i]) return i;
-
- return -1;
- }
-
- public void addElement(int o) {
- if (size >= store.length - 1) grow();
- store[size++] = o;
- }
-
- public int peek() {
- return lastElement();
- }
-
- public int elementAt(int i) {
- return store[i];
- }
-
- public int lastElement() {
- if (size == 0) return 0;
- return store[size - 1];
- }
-
- public void push(int o) { addElement(o); }
- public int pop() {
- int ret = lastElement();
- if (size > 0) store[size--] = 0;
- return ret;
- }
-
- public int size() { return size; }
-
- public void setSize(int newSize) {
- if (newSize < 0) throw new RuntimeException("tried to set size to negative value");
- if (newSize > store.length) grow(newSize * 2);
- if (newSize < size)
- for(int i=newSize; i<size; i++)
- store[i] = 0;
- size = newSize;
- }
-
- public void copyInto(int[] out) {
- for(int i=0; i<size; i++)
- out[i] = store[i];
- }
-
- public void fromArray(int[] in) {
- setSize(in.length);
- for(int i=0; i<size; i++)
- store[i] = in[i];
- }
-
- public void removeElementAt(int i) {
- if (i >= size || i < 0) throw new RuntimeException("tried to remove an element outside the vector's limits");
- for(int j=i; j<size - 1; j++)
- store[j] = store[j + 1];
- setSize(size - 1);
- }
-
- public void setElementAt(int o, int i) {
- if (i >= size) setSize(i);
- store[i] = o;
- }
-
- public void removeElement(int o) {
- int idx = indexOf(o);
- if (idx != -1) removeElementAt(idx);
- }
-
- public void insertElementAt(int o, int at) {
- if (size == store.length) grow();
- for(int i=size; i>at; i--)
- store[i] = store[i-1];
- store[at] = o;
- size++;
- }
-
- public void sort() { sort(this, null, 0, size-1); }
-
- public static void sort(Vec.Int a, Vec.Int b) {
- if (b != null && a.size != b.size) throw new IllegalArgumentException("Vec.Int a and b must be of equal size");
- sort(a, b, 0, a.size-1);
- }
-
- private static final void sort(Vec.Int a, Vec.Int b, int start, int end) {
- int tmpa, tmpb = 0;
- if(start >= end) return;
- if(end-start <= 6) {
- for(int i=start+1;i<=end;i++) {
- tmpa = a.store[i];
- if (b != null) tmpb = b.store[i];
- int j;
- for(j=i-1;j>=start;j--) {
- if((a.store[j]-tmpa) <= 0) break;
- a.store[j+1] = a.store[j];
- if (b != null) b.store[j+1] = b.store[j];
- }
- a.store[j+1] = tmpa;
- if (b != null) b.store[j+1] = tmpb;
- }
- return;
- }
-
- int pivot = a.store[end];
- int lo = start - 1;
- int hi = end;
-
- do {
- while((a.store[++lo]-pivot) < 0) { }
- while((hi > lo) && (a.store[--hi]-pivot) > 0) { }
- swap(a, lo,hi);
- if (b != null) swap(b, lo,hi);
- } while(lo < hi);
-
- swap(a, lo,end);
- if (b != null) swap(b, lo,end);
-
- sort(a, b, start, lo-1);
- sort(a, b, lo+1, end);
- }
-
- private static final void swap(Vec.Int vec, int a, int b) {
- if(a != b) {
- int tmp = vec.store[a];
- vec.store[a] = vec.store[b];
- vec.store[b] = tmp;
- }
- }
-
- public static final void sortInts(int[] a, int start, int end) {
- int tmpa;
- if(start >= end) return;
- if(end-start <= 6) {
- for(int i=start+1;i<=end;i++) {
- tmpa = a[i];
- int j;
- for(j=i-1;j>=start;j--) {
- if(a[j] <= tmpa) break;
- a[j+1] = a[j];
- }
- a[j+1] = tmpa;
- }
- return;
- }
-
- int pivot = a[end];
- int lo = start - 1;
- int hi = end;
-
- do {
- while(a[++lo] < pivot) { }
- while((hi > lo) && a[--hi] > pivot) { }
- swapInts(a, lo, hi);
- } while(lo < hi);
- swapInts(a, lo, end);
- sortInts(a, start, lo-1);
- sortInts(a, lo+1, end);
- }
-
- private static final void swapInts(int[] vec, int a, int b) {
- if(a != b) {
- int tmp = vec[a];
- vec[a] = vec[b];
- vec[b] = tmp;
- }
- }
- }
-
-
-
- public static final void sortFloats(float[] a, int start, int end) {
- float tmpa;
- if(start >= end) return;
- if(end-start <= 6) {
- for(int i=start+1;i<=end;i++) {
- tmpa = a[i];
- int j;
- for(j=i-1;j>=start;j--) {
- if(a[j] <= tmpa) break;
- a[j+1] = a[j];
- }
- a[j+1] = tmpa;
- }
- return;
- }
- float pivot = a[end];
- int lo = start - 1;
- int hi = end;
- do {
- while(a[++lo] < pivot) { }
- while((hi > lo) && a[--hi] > pivot) { }
- swapFloats(a, lo, hi);
- } while(lo < hi);
- swapFloats(a, lo, end);
- sortFloats(a, start, lo-1);
- sortFloats(a, lo+1, end);
- }
- private static final void swapFloats(float[] vec, int a, int b) {
- if(a != b) {
- float tmp = vec[a];
- vec[a] = vec[b];
- vec[b] = tmp;
- }
- }
-}
+++ /dev/null
-// Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
-//
-// You may modify, copy, and redistribute this code under the terms of
-// the GNU Library Public License version 2.1, with the exception of
-// the portion of clause 6a after the semicolon (aka the "obnoxious
-// relink clause")
-
-package org.ibex.util;
-
-import java.io.Reader;
-import java.io.IOException;
-import java.io.EOFException;
-
-/**
- * An Event-Driving, Non-Validating XML Parser with Namespace support.
- *
- * A subclass can implement the abstract functions for receiving details
- * about an xml file as it is parsed. To initate a parse, use the parse()
- * function.
- *
- * <h3>Implementation Notes</h3>
- * <p>As the parser traverses into an element, it adds it to the linked list
- * called <tt>elements</tt>. However, <tt>elements</tt> has been pre-filled
- * with instances of the Element inner class. So in the vast majority of
- * cases, the pointer current is moved along one, and the values for the
- * new element are filled into the current object.</p>
- *
- * <p>This parser supports all the unicode ranges required by the XML
- * Specification. However, it is optimised for well-formed ASCII documents.
- * Documents containing unicode Names and Attributes will take much longer
- * to process, and invalid documents (badly formed Names or invalid attributes)
- * will be run through a test on every single unicode character range before
- * being declared invalid.</p>
- *
- * <ul>
- * <li>Each time the buffer offset <tt>off</tt> is moved, the length
- * <tt>len</tt> must be decreased.</li>
- * <li>Each time the buffer length is decreased, it must be checked to make
- * sure it is >0.</li>
- * <li><i>error</i> is defined as a Validity Constraint Violation and
- * is recoverable</li>
- * <li><i>fatal error</i> is defined as a Well-formedness Constraint
- * Violation and is not recoverable</li>
- * </ul>
- *
- * @author David Crawshaw
- * @see <a href="http://w3.org/TR/REC-xml">XML Specification</a>
- * @see <a href="http://w3.org/TR/REC-xml-names">XML Namespaces</a>
- */
-public abstract class XML
-{
- /////////////////////////////////////////////////////////////////////////////////////////////
- // XML Parser
- /////////////////////////////////////////////////////////////////////////////////////////////
-
- public static final int BUFFER_SIZE = 255;
-
- /** static pool of XML.Element instances shared by all XML Parsers. */
- private static final Queue elements = new Queue(30);
-
- private static final char[] single_amp = new char[] { '&' };
- private static final char[] single_apos = new char[] { '\'' };
- private static final char[] single_gt = new char[] { '>' };
- private static final char[] single_lt = new char[] { '<' };
- private static final char[] single_quot = new char[] { '"' };
-
- private int line;
- private int col;
-
- private Reader in;
- private char[] buf;
- private int off;
- private int base; // base+off == distance into the stream
- private int len;
-
- private Element current;
-
- // used in readEntity() to process a single character without creating a new array
- private char[] singlechar = new char[1];
-
-
- public XML() { this(BUFFER_SIZE); }
-
- public XML(int bSize) {
- buf = new char[bSize];
-
- current = (Element)elements.remove(false);
- if (current == null) current = new Element();
- }
-
- /** Returns the line number at the beginning of the last process call. */
- public int getLine() { return line; }
-
- /** Returns the column number at the beginning of the last process call. */
- public int getCol() { return col; }
-
- /** Returns the global file offset at the beginning of the last process call. */
- public int getGlobalOffset() { return base + off; }
-
- /**
- * Parse given input and call the abstract event functions.
- *
- * Careful with threading, as this function is not synchronized.
- */
- public final void parse(Reader reader) throws IOException, Exn {
- in = reader;
- off = len = 0;
- line = col = 1;
-
- clear(); // clean up possible mid-way linked-list element
-
- try {
- // process the stream
- while (true) {
- if (!buffer(1)) {
- if (current.qName == null) break;
- throw new Exn("reached eof without closing <"+current.qName+"> element", Exn.WFC, getLine(), getCol());
- }
-
- if (buf[off] == '<') readTag();
- readChars(current.qName != null);
- }
- } finally { clear(); } // clean up elements
- }
-
- /** remove any leftover elements from the linked list and queue them */
- private final void clear() {
- for (Element last = current; current.parent != null; ) {
- current = current.parent;
- last.clear();
- elements.append(last);
- }
- current.clear();
- }
-
- /** reads in a tag. expects <tt>buf[off] == '<'</tt> */
- private final void readTag() throws IOException, Exn {
- // Start Tag '<' Name (S Attribute)* S? '>'
- boolean starttag = true;
-
- // End Tag '</' Name S? '>'
- boolean endtag = false;
-
- // if (starttag & endtag) then: EmptyElemTag '<' Name (S Attribute)* S? '/>'
-
- // Position in the name of the ':' namespace prefix
- int prefix = -1;
-
- int namelen = 0;
-
- col++; off++; len--;
- if (!buffer(1)) throw new EOFException("Unexpected EOF processing element tag");
-
- // work out what we can from the beginning of the tag
- char s = buf[off];
- if (s == '!') {
- // definitions here don't necessarily conform to xml spec (as DTDs not yet implemented)
- col++; off++; len--;
- if (!buffer(4)) throw new EOFException("Unexpected EOF processing <! element");
-
- boolean bad = false;
- switch (buf[off]) {
- case '-':
- if (buf[off+1] != '-') { bad = true; break; }
- col += 2; off += 2; len -= 2;
-
- // Comment '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
- readChars(false, "-->", false);
- col += 3; off += 3; len -= 3;
- break;
-
- // we don't care about the following definitions
-
- case 'A':
- if (!buffer(7)
- || buf[off+1] != 'T' || buf[off+2] != 'T' || buf[off+3] != 'L'
- || buf[off+4] != 'I' || buf[off+5] != 'S' || buf[off+6] != 'T') {
- bad = true; break;
- }
- col += 7; off += 7; len -= 7;
-
- // ATTLIST '<!ATTLIST' (Char* - '>') '>'
- readChars(false, ">", true);
- col++; off++; len--;
- break;
- case 'D':
- if (!buffer(7)
- || buf[off+1] != 'O' || buf[off+2] != 'C' || buf[off+3] != 'T'
- || buf[off+4] != 'Y' || buf[off+5] != 'P' || buf[off+6] != 'E') {
- bad = true; break;
- }
- col += 7; off += 7; len -= 7;
-
- // DTD '<!DOCTYPE' (Char* - '>') '>'
- readChars(false, ">", true);
- col++; off++; len--;
- break;
- case 'E':
- if (!buffer(7)) {
- bad = true;
- } else if (buf[off+1] == 'L' && buf[off+2] == 'E' && buf[off+3] == 'M'
- && buf[off+4] == 'E' && buf[off+5] == 'N' && buf[off+6] == 'T') {
- // ELEMENT '<!ELEMENT' (Char* - '>') '>'
- readChars(false, ">", true);
- col++; off++; len--;
-
- } else if (buf[off+1] == 'N' && buf[off+2] == 'T' && buf[off+3] == 'I'
- && buf[off+4] == 'T' && buf[off+5] == 'Y') {
- // ENTITY '<!ENTITY' (Char* - '>') '>'
- readChars(false, ">", true);
- col++; off++; len--;
-
- } else {
- bad = true;
- }
- break;
-
- case 'N':
- if (!buffer(8)
- || buf[off+1] != 'O' || buf[off+2] != 'T' || buf[off+3] != 'A' || buf[off+4] != 'T'
- || buf[off+5] != 'I' || buf[off+6] != 'O' || buf[off+7] != 'N') {
- bad = true; break;
- }
- col += 8; off += 8; len -= 8;
- // NOTATION '<!NOTATION' (Char* - '>') '>'
- readChars(false, ">", true);
- col++; off++; len--;
-
- break;
- default: bad = true;
- }
-
- if (bad) throw new Exn("element tag start character is invalid", Exn.MARKUP, getLine(), getCol());
-
- } else if (s == '?') {
- // PI (Ignored) '<?' (Char* - (Char* '?>' Char*)) '?>'
- col++; off++; len--;
- readChars(false, "?>", true);
- if (!buffer(2)) throw new EOFException("Unexpected EOF at end of Processing Instruction");
- col += 2; off += 2; len -= 2;
-
- } else if (s == '[') {
- if (!buffer(7)
- || buf[off+1] != 'C' || buf[off+2] != 'D' || buf[off+3] != 'A'
- || buf[off+4] != 'T' || buf[off+5] != 'A' || buf[off+6] != '[') {
- col++; off--; len++;
- // Conditional '<![' (Char* - (Char* ']]>' Char*)) ']]>'
- readChars(false, "]]>", false);
- } else {
- col += 7; off += 7; len -=7;
- // CDATA '<![CDATA[' (Char* - (Char* ']]>' Char*)) ']]>'
- readChars(true, "]]>", false);
- }
- col += 3; off += 3; len -= 3;
- } else {
- if (s == '/') {
- // End Tag '</' Name S? '>'
- starttag = false;
- endtag = true;
-
- col++; off++; len--;
- if (!buffer(1)) throw new EOFException("Unexpected EOF processing end tag");
- s = buf[off];
- }
-
- if (!Name(s)) throw new Exn("invalid starting character in element name", Exn.MARKUP, getLine(), getCol());
-
- // find the element name (defined in XML Spec: section 2.3)
- for (namelen = 0; ; namelen++) {
- if (!buffer(namelen+1)) throw new EOFException("Unexpected EOF in element tag name");
-
- s = buf[off+namelen];
-
- if (S(s) || s == '>') {
- break;
- } else if (s == '/') {
- endtag = true;
- break;
- } else if (s == ':' && namelen > 0 && prefix < 1) {
- // we have a definition of the prefix range available
- prefix = namelen;
- } else if (!NameChar(s)) {
- throw new Exn("element name contains invalid character", Exn.MARKUP, getLine(), getCol());
- }
- }
-
- // process name (based on calculated region)
- if (namelen < 1) throw new Exn("element name is null", Exn.MARKUP, getLine(), getCol());
-
- // we have marked out the name region, so turn it into a string and move on
- String qName = new String(buf, off, namelen);
-
- col += namelen; off += namelen; len -= namelen;
-
- if (starttag) {
- // create the in-memory element representation of this beast
- // if current.qName == null then this is the root element we're dealing with
- if (current.qName != null) {
- Element next = (Element)elements.remove(false);
- if (next == null) next = new Element();
- //next.clear(); // TODO: remove as elements now checked as they're added to the queue
- next.parent = current;
- current = next;
- }
-
- current.qName = qName;
-
- if (prefix > 0) {
- current.prefix = current.qName.substring(0, prefix);
- current.localName = current.qName.substring(prefix+1);
- } else {
- current.prefix = null;
- current.localName = current.qName;
- }
-
- // process attributes
- readWhitespace();
- if (!buffer(1)) throw new EOFException("Unexpected EOF - processing attributes part 1");
- while (buf[off] != '/' && buf[off] != '>') {
- readAttribute();
- if (!buffer(1)) throw new EOFException("Unexpected EOF - processing attributes part 2");
- readWhitespace();
- }
-
- // work out the uri of this element
- current.uri = current.getUri(current.getPrefix());
- if (current.getUri().equals("") && current.getPrefix() != null)
- current.addError(new Exn("undefined prefix '"+current.getPrefix()+"'", Exn.NC, getLine(), getCol()));
-
- } else {
- // this is an end-of-element tag
- if (!qName.equals(current.getQName())) throw new Exn(
- "end tag </"+qName+"> does not line up with start tag <"+current.getQName()+">", Exn.WFC, getLine(), getCol()
- );
- }
-
- // deal with whitespace
- readWhitespace();
-
- // process tag close
- if (!buffer(1)) throw new EOFException("Unexpected EOF before end of tag");
- if (buf[off] == '/') {
- endtag = true;
- off++; len--; col++;
- }
- if (!buffer(1)) throw new EOFException("Unexpected EOF before end of endtag");
- if (buf[off] == '>') {
- off++; len--; col++;
- } else {
- throw new Exn("missing '>' character from element '"+qName+"'", Exn.MARKUP, getLine(), getCol());
- }
-
- // send element signals
- if (starttag) startElement(current);
- if (endtag) {
- endElement(current);
-
- // we just closed an element, so remove it from the element 'stack'
- if (current.getParent() == null) {
- // we just finished the root element
- current.clear();
- } else {
- Element last = current;
- current = current.parent;
- last.clear();
- elements.append(last);
- }
- }
- }
- }
-
- /** reads in an attribute of an element. expects Name(buf[off]) */
- private final void readAttribute() throws IOException, Exn {
- int ref = 0;
- int prefix = 0;
- String n, v, p, u; // attribute name, value, prefix and uri respectively
- n = v = p = u = null;
- char s;
-
- // find the element name (defined in XML Spec: section 2.3)
- for (ref= 0; ; ref++) {
- if (!buffer(ref+1)) throw new EOFException("Unexpected EOF in read attribute loop part 1");
-
- s = buf[off+ref];
-
- if (s == '=' || S(s)) {
- break;
- } else if (s == ':' && ref > 0 && prefix < 1) {
- // we have a definition of the prefix range available
- prefix = ref+1;
- } else if (!NameChar(s)) {
- throw new Exn("attribute name contains invalid characters", Exn.MARKUP, getLine(), getCol());
- }
- }
-
- // determine prefix and key name
- if (prefix > 0) {
- p = new String(buf, off, prefix-1);
- col += prefix; off += prefix; len -= prefix; ref -= prefix;
- }
- n = new String(buf, off, ref);
- col += ref; off += ref; len -= ref;
-
- // find name/value divider ('=')
- readWhitespace();
- if (!buffer(1)) throw new EOFException("Unexpected EOF before attribute '=' divider");
- if (buf[off] != '=') throw new Exn("attribute name not followed by '=' sign", Exn.MARKUP, getLine(), getCol());
-
- col++; off++; len--;
- readWhitespace();
-
- if (!buffer(1)) throw new EOFException("Unexpected EOF after attribute '=' divider");
-
- char wrap;
- if (buf[off] == '\'' || buf[off] == '"') {
- wrap = buf[off];
- } else {
- throw new Exn("attribute '"+n+"' must have attribute wrapped in ' or \"", Exn.MARKUP, getLine(), getCol());
- }
- col++; off++; len--;
-
- // find the attribute value
- attval: for (ref = 0; ; ref++) {
- if (!buffer(ref+1)) throw new EOFException("Unexpected EOF in attribute value");
-
- if (buf[off+ref] == wrap) {
- break attval;
- } else if (buf[off+ref] == '<') {
- throw new Exn("attribute value for '"+n+"' must not contain '<'", Exn.WFC, getLine(), getCol());
- }
- }
-
- v = new String(buf, off, ref);
- col += ref; off += ref; len -= ref;
-
- // remove end wrapper character
- col++; off++; len--;
-
- // process attribute
- if (p != null && p.equals("xmlns")) {
- current.addUri(n, v);
- } else if (n.equals("xmlns")) {
- if (current.getUri().equals("")) {
- current.addUri("", v);
- } else {
- current.addError(new Exn("default namespace definition repeated", Exn.NC, getLine(), getCol()));
- }
- } else {
- // find attribute uri
- u = current.getUri(p);
- if (p != null && u.equals("")) current.addError(new Exn("undefined attribute prefix '"+p+"'", Exn.NC, getLine(), getCol()));
-
- // check to see if attribute is a repeat
- for (int i=0; current.len > i; i++) if (n.equals(current.getAttrKey(i)) && u.equals(current.getAttrUri(i))) throw new Exn(
- "attribute name '"+n+"' may not appear more than once in the same element tag", Exn.WFC, getLine(), getCol()
- );
-
- current.addAttr(n, v, u);
- }
- }
-
- /** reads an entity and processes out its value. expects buf[off] == '&' */
- private final void readEntity() throws IOException, Exn {
- off++; len--;
- if (!buffer(2)) throw new EOFException("Unexpected EOF reading entity");
-
- boolean unknown = false;
- switch (buf[off]) {
- case '#':
- off++; len--;
-
- int radix;
- if (buf[off] == 'x') { off++; len--; radix = 16; } else { radix = 10; }
- int c = 0;
-
- // read in each char, then shift total value to the left and add the extra
- // style of loop is slightly different from all the others, as this should run a limited number of times
- findchar: while (true) {
- if (!buffer(1)) throw new EOFException("Unexpected EOF reading entity");
- int d = Character.digit(buf[off], radix);
- if (d == -1) {
- if (buf[off] != ';') throw new Exn("illegal characters in entity reference", Exn.WFC, getLine(), getCol());
- off++; len--; col++;
- break findchar;
- }
- c = (c * radix) + d;
-
- off++; len--;
- }
-
- singlechar[0] = Character.forDigit(c, radix);
- characters(singlechar, 0, 1);
- break;
-
- case 'a':
- if (buffer(4) && buf[off+1] == 'm' && buf[off+2] == 'p' && buf[off+3] == ';') {
- characters(single_amp, 0, 1); // &
- off += 4; len -= 4; col++;
- } else if (buffer(5) && buf[off+1] == 'p' && buf[off+2] == 'o' && buf[off+3] == 's' && buf[off+4] == ';') {
- characters(single_apos, 0, 1); // '
- off += 5; len -= 5; col++;
- } else {
- unknown = true;
- }
- break;
-
- case 'g':
- if (buffer(3) && buf[off+1] == 't' && buf[off+2] == ';') {
- characters(single_gt, 0, 1); // >
- off += 3; len -= 3; col++;
- } else {
- unknown = true;
- }
- break;
-
- case 'l':
- if (buffer(3) && buf[off+1] == 't' && buf[off+2] == ';') {
- characters(single_lt, 0, 1); // <
- off += 3; len -= 3; col++;
- } else {
- unknown = true;
- }
- break;
-
- case 'q':
- if (buffer(5) && buf[off+1] == 'u' && buf[off+2] == 'o' && buf[off+3] == 't' && buf[off+4] == ';') {
- characters(single_quot, 0, 1); // "
- off += 5; len -= 5; col++;
- } else {
- unknown = true;
- }
- break;
-
- // TODO: check a parser-level Hash of defined entities
- }
-
- if (unknown) throw new Exn("unknown entity (<!ENTITY> not supported)", Exn.WFC, getLine(), getCol());
- }
-
- /** reads until the passed string is encountered. */
- private final void readChars(boolean p, String match, boolean entities) throws IOException, Exn {
- int ref;
- char[] end = match.toCharArray();
-
- for (boolean more = true; more;) {
- if (!buffer(1)) return;
-
- buf: for (ref = 0; ref < len; ref++) {
- switch (buf[off+ref]) {
- case '\r': // windows or macos9 newline
- // normalise and process
- buf[off+ref] = '\n'; ref++;
- if (p) characters(buf, off, ref);
- off += ref; len -= ref; ref = -1;
- line++; col = 1;
-
- // windows double-char newline; skip the next char
- if (!buffer(1)) return;
- if (buf[off] == '\n') { off++; len--; }
- break;
-
- case '\n': // unix newline
- ref++;
- if (p) characters(buf, off, ref);
- off += ref; len -= ref; ref = -1;
- line++; col = 1;
- break;
-
- case '&': // entity
- if (entities) {
- if (p) {
- if (ref > 0) characters(buf, off, ref);
- off += ref; len -= ref; ref = -1;
- readEntity();
- }
- break;
- }
-
- default:
- if (!buffer(ref+end.length)) continue buf;
- for (int i=0; end.length > i; i++) if (end[i] != buf[off+ref+i]) continue buf;
- more = false;
- break buf;
- }
- }
-
- if (p && ref > 0) characters(buf, off, ref);
- off += ref; len -= ref; col += ref;
- }
- }
-
- /**
- * reads until a <tt><</tt> symbol is encountered
- * @param p If true call the characters(char[],int,int) funciton for the processed characters
- */
- private final void readChars(boolean p) throws IOException, Exn {
- int ref;
-
- for (boolean more = true; more;) {
- if (!buffer(1)) return;
-
- buf: for (ref = 0; ref < len; ref++) {
- switch (buf[off+ref]) {
- case '\r': // windows or macos9 newline
- // normalise and process
- buf[off+ref] = '\n'; ref++;
- if (p) characters(buf, off, ref);
- off += ref; len -= ref; ref = -1;
- line++; col = 1;
-
- // windows double-char newline; skip the next char
- if (!buffer(1)) return;
- if (buf[off] == '\n') { off++; len--; }
- break;
-
- case '\n': // unix newline
- ref++;
- if (p) characters(buf, off, ref);
- off += ref; len -= ref; ref = -1;
- line++; col = 1;
- break;
-
- case '&': // entity
- if (p) {
- if (ref > 0) characters(buf, off, ref);
- off += ref; len -= ref; ref = -1;
- readEntity();
- }
- break;
-
- case '<': // end of chars section
- more = false;
- break buf;
- }
- }
-
- if (p && ref > 0) characters(buf, off, ref);
- off += ref; len -= ref; col += ref;
- }
- }
-
- /** reads until a non-whitespace symbol is encountered */
- private final void readWhitespace() throws IOException, Exn {
- int ref;
-
- for (boolean more = true; more;) {
- if (!buffer(1)) return;
-
- buf: for (ref = 0; ref < len; ref++) {
- switch (buf[off+ref]) {
- case '\r': // windows or macos9 newline
- // normalise and process
- buf[off+ref] = '\n';
- whitespace(buf, off, ++ref);
- off += ref; len -= ref; ref = -1;
- line++; col = 1;
-
- // windows double-char newline; skip the next char
- if (!buffer(1)) return;
- if (buf[off] == '\n') { off++; len--; }
- break;
-
- case '\n': // unix newline
- whitespace(buf, off, ++ref);
- off += ref; len -= ref; ref = -1;
- line++; col = 1;
- break;
-
- case ' ': // space
- case '\t': // tab
- break;
-
- default: // end of whitespace
- more = false;
- break buf;
- }
- }
-
- off += ref; len -= ref; col += ref;
- }
- }
-
- /**
- * attempt to fill the buffer.
- *
- * @param min Minimum number of characters to read (even if we have to block to do it).
- * @return return false if min can't be reached.
- */
- private final boolean buffer(int min) throws IOException {
- if (len > min) return true;
-
- if (buf.length - (off+len) >= min) {
- // plenty of space left on the end of the buffer
- } else if (off >= min) {
- // moving offset data to start will leave enough free space on the end
- System.arraycopy(buf, off, buf, 0, len);
- base += off;
- off = 0;
- } else {
- // buffer size will have to be increased
- char[] newbuf = new char[buf.length * 2];
- System.arraycopy(buf, off, newbuf, 0, len);
- buf = newbuf;
- base += off;
- off = 0;
- }
-
- while (min > len) {
- int newlen = in.read(buf, off+len, buf.length-(off+len));
- if (newlen < 0) return false;
- len += newlen;
- }
-
- return true;
- }
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////
- // Abstract SAX-Like Interface
- /////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Called when the start of an element is processed.
- *
- * <p><b>DO NOT</b> store a reference to the Element object, as
- * they are reused by XML Parser.</p>
- */
- public abstract void startElement(Element e) throws Exn;
-
- /**
- * Represents up to a line of character data.
- *
- * <p>Newlines are all normalised to the Unix \n as per the XML Spec,
- * and a newline will only appear as the last character in the passed
- * array segment.</p>
- *
- * <p>XML.getLine() and XML.getCol() report the position at the
- * beginning of this character segment, which can be processed in a
- * line-by-line fashion due to the above newline restriction.</p>
- */
- public abstract void characters(char[] ch, int start, int length) throws Exn, IOException;
-
- /** Represents up to a line of ignorable whitespace. */
- public abstract void whitespace(char[] ch, int start, int length) throws Exn, IOException;
-
- /** Represents the end of an Element. */
- public abstract void endElement(Element e) throws Exn, IOException;
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////
- // Inner Classes for Parser Support
- /////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Represents an element in an XML document. Stores a reference to its
- * parent, forming a one-way linked list.
- *
- * Element objects are reused, so client code making use of them must
- * drop their references after the specific element process function
- * has returned.
- */
- public static final class Element {
-
- private static final int DEFAULT_ATTR_SIZE = 10;
-
- protected Element parent = null;
-
- protected String uri = null;
- protected String localName = null;
- protected String qName = null;
- protected String prefix = null;
-
- protected Hash urimap = new Hash(3,3);
-
- protected String[] keys = new String[DEFAULT_ATTR_SIZE];
- protected String[] vals = new String[DEFAULT_ATTR_SIZE];
- protected String[] uris = new String[DEFAULT_ATTR_SIZE];
- protected int len = 0;
-
- protected Exn[] errors = new Exn[] {};
-
- /** Parent of current element. */
- public Element getParent() { return parent; }
-
- /** Qualified Name of current element. XML Namespace Spec 14-Jan-1999 [6] */
- public String getQName() { return qName; }
-
- /** LocalPart of current element. XML Namespace Spec 14-Jan-1999 [8] */
- public String getLocalName() { return localName; }
-
- /** Prefix of current element. Substring of qName. XML Namespace Spec 14-Jan-1999 [7] */
- public String getPrefix() { return prefix; }
-
- // HACK
- public Hash getUriMap() {
- Hash map = new Hash();
- for (Element e = this; e != null; e = e.getParent()) {
- java.util.Enumeration en = e.urimap.keys();
- while(en.hasMoreElements()) {
- String key = (String)en.nextElement();
- String val = getUri(key);
- map.put(key, val);
- }
- }
- return map;
- }
-
- /** URI of current tag. XML Namespace Spec 14-Jan-1999 section 1 */
- public String getUri() { return getUri(prefix); }
-
- /** URI of a given prefix. Never returns null, instead gives "". */
- public String getUri(String p) {
- String ret = null;
- for (Element e = this; e != null && ret == null; e = e.getParent()) {
- ret = (String)e.urimap.get(p == null ? "" : p);
- }
- return ret == null ? "" : ret;
- }
-
- /** An array of attribute names. */
- public String getAttrKey(int pos) { return len > pos ? keys[pos] : null; }
-
- /** An array of attribute values. */
- public String getAttrVal(int pos) { return len > pos ? vals[pos] : null; }
-
- /** An array of attribute uris. */
- public String getAttrUri(int pos) { return len > pos ? uris[pos] : null; }
-
- /** Current number of attributes in the element. */
- public int getAttrLen() { return len; }
-
- /** Poor performance, but easier to use when speed is not a concern */
- public Hash getAttrHash() {
- Hash ret = new Hash(getAttrLen() * 2, 3);
- for(int i=0; i<len; i++)
- ret.put(getAttrKey(i), getAttrVal(i));
- return ret;
- }
-
- /** Poor performance, but easier to use */
- public String getAttrVal(String key) {
- for(int i=0; i<len; i++) if (keys[i].equals(key)) return vals[i];
- return null;
- }
-
- /** An array of non-fatal errors related to this element. */
- public Exn[] getErrors() { return errors; }
-
- protected Element() { }
-
- /** Add (replace if exists in current element) a Namespace prefix/uri map. */
- public void addUri(String name, String value) {
- urimap.put(name, value);
- }
-
- /** Add an attribute. */
- protected void addAttr(String key, String val, String uri) {
- if (len == keys.length) {
- // increase the size of the attributes arrays
- String[] newkeys = new String[keys.length*2];
- String[] newvals = new String[vals.length*2];
- String[] newuris = new String[uris.length*2];
- System.arraycopy(keys, 0, newkeys, 0, keys.length);
- System.arraycopy(vals, 0, newvals, 0, vals.length);
- System.arraycopy(uris, 0, newuris, 0, uris.length);
- keys = newkeys; vals = newvals; uris = newuris;
- }
-
- keys[len] = key;
- vals[len] = val;
- uris[len] = uri;
- len++;
- }
-
- /** Add an error. */
- protected void addError(Exn e) {
- // it doesn't really matter about continually expanding the array, as this case is quite rare
- Exn[] newe = new Exn[errors.length+1];
- System.arraycopy(errors, 0, newe, 0, errors.length);
- newe[errors.length] = e;
- errors = newe;
- }
-
- /** Empty out all the data from the Element. */
- protected void clear() {
- parent = null;
- uri = localName = qName = prefix = null;
- urimap.clear();
-
- if (keys.length != vals.length || vals.length != uris.length) {
- keys = new String[DEFAULT_ATTR_SIZE];
- vals = new String[DEFAULT_ATTR_SIZE];
- uris = new String[DEFAULT_ATTR_SIZE];
- } else {
- for (int i=0; keys.length > i; i++) { keys[i] = null; vals[i] = null; uris[i] = null; };
- }
- len = 0;
-
- errors = new Exn[] {};
- }
- }
-
- /** Parse or Structural Error */
- public static class Exn extends Exception {
- /** Violation of Markup restrictions in XML Specification - Fatal Error */
- public static final int MARKUP = 1;
-
- /** Well-Formedness Constraint Violation - Fatal Error */
- public static final int WFC = 2;
-
- /** Namespace Constraint Violation - Recoverable Error */
- public static final int NC = 3;
-
- /** Schema Violation - Fatal Error */
- public static final int SCHEMA = 4;
-
- private String error;
- private int type;
- private int line;
- private int col;
-
- public Exn(String e) { this(e, MARKUP, -1, -1); }
-
- public Exn(String e, int type, int line, int col) {
- this.error = e;
- this.type = type;
- this.line = line;
- this.col = col;
- }
-
- public int getType() { return this.type; }
- public int getLine() { return this.line; }
- public int getCol() { return this.col; }
- public String getMessage() { return this.error + (line >= 0 && col >= 0 ? " at " + line + ":" + col: ""); }
- }
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////
- // Static Support Functions for the XML Specification
- /////////////////////////////////////////////////////////////////////////////////////////////
-
- // attempt to avoid these functions unless you *expect* the input to fall in the given range.
-
- /** First Character of Name - XML Specification 1.0 [5] */
- private static final boolean Name(char c) {
- return BaseCharAscii(c) || c == '_' || c == ':' || Letter(c);
- }
-
- /** NameChar - XML Specification 1.0 [4] */
- private static final boolean NameChar(char c) {
- return BaseCharAscii(c) || c == '.' || c == '-' || c == '_' || c == ':'
- || Digit(c) || Letter(c) || Extender(c); // TODO: || CombiningChar(c);
- }
-
- /** BaseChar - XMl Specification 1.0 [84] */
- private static final boolean Letter(char c) {
- return BaseChar(c) || Ideographic(c);
- }
-
- /** Elements of BaseChar that exist in ASCII. */
- private static final boolean BaseCharAscii(char c) {
- return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A');
- }
-
- /** Char - XML Specification 1.0 [2] */
- private static final boolean Char(char c) {
- // u000A == r and u000D == n, but the javac compiler can't handle the \ u form
- return c == '\u0009' || c == '\r' || c == '\n'
- || (c >= '\u0020' && c <= '\uD7FF')
- || (c >= '\uE000' && c <= '\uFFFD');
- }
-
- /** BaseChar - XML Specification 1.0 [85] */
- private static final boolean BaseChar(char c) {
- return BaseCharAscii(c) || (c >= '\u00C0' && c <= '\u00D6')
- || (c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131')
- || (c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E')
- || (c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5')
- || (c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1')
- || (c == '\u0386') || (c >= '\u0388' && c <= '\u038A') || (c == '\u038C')
- || (c >= '\u038E' && c <= '\u03A1') || (c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6')
- || (c == '\u03DA') || (c == '\u03DC') || (c == '\u03DE')
- || (c == '\u03E0')
- || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F')
- || (c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4')
- || (c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB')
- || (c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556')
- || (c == '\u0559')
- || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2')
- || (c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7')
- || (c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3')
- || (c == '\u06D5')
- || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939')
- || (c == '\u093D')
- || (c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990')
- || (c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0')
- || (c == '\u09B2')
- || (c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DF' && c <= '\u09E1') || (c >= '\u09F0' && c <= '\u09F1')
- || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') || (c >= '\u0A13' && c <= '\u0A28')
- || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') || (c >= '\u0A35' && c <= '\u0A36')
- || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C')
- || (c == '\u0A5E')
- || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B')
- || (c == '\u0A8D')
- || (c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0')
- || (c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9')
- || (c == '\u0ABD')
- || (c == '\u0AE0')
- || (c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28')
- || (c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39')
- || (c == '\u0B3D')
- || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') || (c >= '\u0B85' && c <= '\u0B8A')
- || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') || (c >= '\u0B99' && c <= '\u0B9A')
- || (c == '\u0B9C')
- || (c >= '\u0B9E' && c <= '\u0B9F') || (c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA')
- || (c >= '\u0BAE' && c <= '\u0BB5') || (c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C')
- || (c >= '\u0C0E' && c <= '\u0C10') || (c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33')
- || (c >= '\u0C35' && c <= '\u0C39') || (c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C')
- || (c >= '\u0C8E' && c <= '\u0C90') || (c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3')
- || (c >= '\u0CB5' && c <= '\u0CB9')
- || (c == '\u0CDE')
- || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') || (c >= '\u0D0E' && c <= '\u0D10')
- || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') || (c >= '\u0D60' && c <= '\u0D61')
- || (c >= '\u0E01' && c <= '\u0E2E')
- || (c == '\u0E30')
- || (c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82')
- || (c == '\u0E84')
- || (c >= '\u0E87' && c <= '\u0E88')
- || (c == '\u0E8A')
- || (c == '\u0E8D')
- || (c >= '\u0E94' && c <= '\u0E97') || (c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3')
- || (c == '\u0EA5')
- || (c == '\u0EA7')
- || (c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE')
- || (c == '\u0EB0')
- || (c >= '\u0EB2' && c <= '\u0EB3')
- || (c == '\u0EBD')
- || (c >= '\u0EC0' && c <= '\u0EC4') || (c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69')
- || (c >= '\u10A0' && c <= '\u10C5') || (c >= '\u10D0' && c <= '\u10F6')
- || (c == '\u1100')
- || (c >= '\u1102' && c <= '\u1103') || (c >= '\u1105' && c <= '\u1107')
- || (c == '\u1109')
- || (c >= '\u110B' && c <= '\u110C') || (c >= '\u110E' && c <= '\u1112')
- || (c == '\u113C')
- || (c == '\u113E')
- || (c == '\u1140')
- || (c == '\u114C')
- || (c == '\u114E')
- || (c == '\u1150')
- || (c >= '\u1154' && c <= '\u1155')
- || (c == '\u1159')
- || (c >= '\u115F' && c <= '\u1161')
- || (c == '\u1163')
- || (c == '\u1165')
- || (c == '\u1167')
- || (c == '\u1169')
- || (c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173')
- || (c == '\u1175')
- || (c == '\u119E')
- || (c == '\u11A8')
- || (c == '\u11AB')
- || (c >= '\u11AE' && c <= '\u11AF') || (c >= '\u11B7' && c <= '\u11B8')
- || (c == '\u11BA')
- || (c >= '\u11BC' && c <= '\u11C2')
- || (c == '\u11EB')
- || (c == '\u11F0')
- || (c == '\u11F9')
- || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') || (c >= '\u1F00' && c <= '\u1F15')
- || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') || (c >= '\u1F48' && c <= '\u1F4D')
- || (c >= '\u1F50' && c <= '\u1F57')
- || (c == '\u1F59')
- || (c == '\u1F5B')
- || (c == '\u1F5D')
- || (c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC')
- || (c == '\u1FBE')
- || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') || (c >= '\u1FD0' && c <= '\u1FD3')
- || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') || (c >= '\u1FF2' && c <= '\u1FF4')
- || (c >= '\u1FF6' && c <= '\u1FFC')
- || (c == '\u2126')
- || (c >= '\u212A' && c <= '\u212B')
- || (c == '\u212E')
- || (c >= '\u2180' && c <= '\u2182') || (c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA')
- || (c >= '\u3105' && c <= '\u312C') || (c >= '\uAC00' && c <= '\uD7A3');
- }
-
- /** BaseChar - XMl Specification 1.0 [86] */
- private static final boolean Ideographic(char c) {
- return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029');
- }
-
- /** CombiningChar - XMl Specification 1.0 [87] */
- /*private static final boolean CombiningChar(char c) {
- return (c >= '\u0300' && c <= '\u0345')
- || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') || (c >= '\u0591' && c <= '\u05A1')
- || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD')
- || (c == '\u05BF')
- || (c >= '\u05C1' && c <= '\u05C2')
- || (c == '\u05C4')
- || (c >= '\u064B' && c <= '\u0652')
- || (c == '\u0670')
- || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4')
- || (c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903')
- || (c == '\u093C')
- || (c >= '\u093E' && c <= '\u094C')
- || (c == '\u094D')
- || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') || (c >= '\u0981' && c <= '\u0983')
- || (c == '\u09BC')
- || (c == '\u09BE')
- || (c == '\u09BF')
- || (c >= '\u09C0' && c <= '\u09C4') || (c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD')
- || (c == '\u09D7')
- || (c >= '\u09E2' && c <= '\u09E3')
- || (c == '\u0A02')
- || (c == '\u0A3C')
- || (c == '\u0A3E')
- || (c == '\u0A3F')
- || (c >= '\u0A40' && c <= '\u0A42') || (c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D')
- || (c >= '\u0A70' && c <= '\u0A71') || (c >= '\u0A81' && c <= '\u0A83')
- || (c == '\u0ABC')
- || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') || (c >= '\u0ACB' && c <= '\u0ACD')
- || (c >= '\u0B01' && c <= '\u0B03')
- || (c == '\u0B3C')
- || (c >= '\u0B3E' && c <= '\u0B43') || (c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D')
- || (c >= '\u0B56' && c <= '\u0B57') || (c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2')
- || (c >= '\u0BC6' && c <= '\u0BC8') || (c >= '\u0BCA' && c <= '\u0BCD')
- || (c == '\u0BD7')
- || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') || (c >= '\u0C46' && c <= '\u0C48')
- || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') || (c >= '\u0C82' && c <= '\u0C83')
- || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') || (c >= '\u0CCA' && c <= '\u0CCD')
- || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') || (c >= '\u0D3E' && c <= '\u0D43')
- || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D')
- || (c == '\u0D57')
- || (c == '\u0E31')
- || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E')
- || (c == '\u0EB1')
- || (c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD')
- || (c >= '\u0F18' && c <= '\u0F19')
- || (c == '\u0F35')
- || (c == '\u0F37')
- || (c == '\u0F39')
- || (c == '\u0F3E')
- || (c == '\u0F3F')
- || (c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95')
- || (c == '\u0F97')
- || (c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7')
- || (c == '\u0FB9')
- || (c >= '\u20D0' && c <= '\u20DC')
- || (c == '\u20E1')
- || (c >= '\u302A' && c <= '\u302F')
- || (c == '\u3099')
- || (c == '\u309A');
- }*/
-
- /** Digit - XMl Specification 1.0 [88] */
- private static final boolean Digit(char c) {
- return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9')
- || (c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F')
- || (c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF')
- || (c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F')
- || (c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29');
- }
-
- /** Extender - XMl Specification 1.0 [89] */
- private static final boolean Extender(char c) {
- return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387'
- || c == '\u0640' || c == '\u0E46' || c == '\u0EC6' || c == '\u3005'
- || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') || (c >= '\u30FC' && c <= '\u30FE');
- }
-
- /** Whitespace - XML Specification 1.0 [3] */
- private static final boolean S(char c) {
- return c == '\u0020' || c == '\u0009' || c == '\r' || c == '\n';
- }
-}