From ac84b5a03467c0853c7275105712ece6c71be1f1 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 27 Dec 2004 10:28:45 +0000 Subject: [PATCH] [re]-merged in Brians stuff darcs-hash:20041227102845-5007d-e25e78c33aebc6b9a6e3a8fcbcf46e3b5f33fa2d.gz --- src/gnu/gcj/RawData.java | 3 + src/org/ibex/core/Box.java | 12 +- src/org/ibex/core/Ibex.java | 30 +- src/org/ibex/core/Scheduler.java | 2 +- src/org/ibex/core/Stream.java | 15 +- src/org/ibex/graphics/Font.java | 1 + src/org/ibex/graphics/MSPack.java | 2 +- src/org/ibex/js/ByteCodes.java | 99 -- src/org/ibex/js/Directory.java | 118 -- src/org/ibex/js/Interpreter.java | 705 ------------ src/org/ibex/js/JS.java | 319 ----- src/org/ibex/js/JSArray.java | 266 ----- src/org/ibex/js/JSDate.java | 1247 -------------------- src/org/ibex/js/JSExn.java | 52 - src/org/ibex/js/JSFunction.java | 119 -- src/org/ibex/js/JSMath.java | 86 -- src/org/ibex/js/JSNumber.java | 62 - src/org/ibex/js/JSPrimitive.java | 109 -- src/org/ibex/js/JSReflection.java | 89 -- src/org/ibex/js/JSRegexp.java | 343 ------ src/org/ibex/js/JSScope.java | 187 --- src/org/ibex/js/JSString.java | 35 - src/org/ibex/js/Lexer.java | 400 ------- src/org/ibex/js/Parser.java | 1049 ----------------- src/org/ibex/js/PropertyFile.java | 53 - src/org/ibex/js/Stream.java | 166 --- src/org/ibex/js/Test.java | 83 -- src/org/ibex/js/Tokens.java | 121 -- src/org/ibex/js/Trap.java | 28 - src/org/ibex/net/HTTP.java | 1304 --------------------- src/org/ibex/net/SOAP.java | 285 ----- src/org/ibex/net/XMLRPC.java | 345 ------ src/org/ibex/plat/Darwin.java | 2 +- src/org/ibex/plat/Linux.java | 2 +- src/org/ibex/plat/Win32.java | 5 +- src/org/ibex/util/AccessibleCharArrayWriter.java | 9 - src/org/ibex/util/BalancedTree.java | 433 ------- src/org/ibex/util/CAB.java | 501 -------- src/org/ibex/util/Cache.java | 126 -- src/org/ibex/util/CachedInputStream.java | 88 -- src/org/ibex/util/Callback.java | 15 - src/org/ibex/util/CounterEnumeration.java | 17 - src/org/ibex/util/DirtyList.java | 181 --- src/org/ibex/util/EjAlbertBrowserLauncher.java | 589 ---------- src/org/ibex/util/FileNameEncoder.java | 50 - src/org/ibex/util/Grammar.java | 107 -- src/org/ibex/util/Hash.java | 176 --- src/org/ibex/util/InputStreamToByteArray.java | 35 - src/org/ibex/util/KnownLength.java | 25 - src/org/ibex/util/LineReader.java | 46 - src/org/ibex/util/Log.java | 241 ---- src/org/ibex/util/MSPack.c | 202 ---- src/org/ibex/util/MSPack.java | 90 -- src/org/ibex/util/NanoGoat.java | 475 -------- src/org/ibex/util/PackBytesIntoString.java | 47 - src/org/ibex/util/Preprocessor.java | 358 ------ src/org/ibex/util/Queue.java | 91 -- src/org/ibex/util/Scheduler.java | 95 -- src/org/ibex/util/Semaphore.java | 35 - src/org/ibex/util/Simplex.java | 1345 ---------------------- src/org/ibex/util/Task.java | 8 - src/org/ibex/util/Vec.java | 454 -------- src/org/ibex/util/XML.java | 1174 ------------------- 63 files changed, 41 insertions(+), 14716 deletions(-) create mode 100644 src/gnu/gcj/RawData.java delete mode 100644 src/org/ibex/js/ByteCodes.java delete mode 100644 src/org/ibex/js/Directory.java delete mode 100644 src/org/ibex/js/Interpreter.java delete mode 100644 src/org/ibex/js/JS.java delete mode 100644 src/org/ibex/js/JSArray.java delete mode 100644 src/org/ibex/js/JSDate.java delete mode 100644 src/org/ibex/js/JSExn.java delete mode 100644 src/org/ibex/js/JSFunction.java delete mode 100644 src/org/ibex/js/JSMath.java delete mode 100644 src/org/ibex/js/JSNumber.java delete mode 100644 src/org/ibex/js/JSPrimitive.java delete mode 100644 src/org/ibex/js/JSReflection.java delete mode 100644 src/org/ibex/js/JSRegexp.java delete mode 100644 src/org/ibex/js/JSScope.java delete mode 100644 src/org/ibex/js/JSString.java delete mode 100644 src/org/ibex/js/Lexer.java delete mode 100644 src/org/ibex/js/Parser.java delete mode 100644 src/org/ibex/js/PropertyFile.java delete mode 100644 src/org/ibex/js/Stream.java delete mode 100644 src/org/ibex/js/Test.java delete mode 100644 src/org/ibex/js/Tokens.java delete mode 100644 src/org/ibex/js/Trap.java delete mode 100644 src/org/ibex/net/HTTP.java delete mode 100644 src/org/ibex/net/SOAP.java delete mode 100644 src/org/ibex/net/XMLRPC.java delete mode 100644 src/org/ibex/util/AccessibleCharArrayWriter.java delete mode 100644 src/org/ibex/util/BalancedTree.java delete mode 100644 src/org/ibex/util/CAB.java delete mode 100644 src/org/ibex/util/Cache.java delete mode 100644 src/org/ibex/util/CachedInputStream.java delete mode 100644 src/org/ibex/util/Callback.java delete mode 100644 src/org/ibex/util/CounterEnumeration.java delete mode 100644 src/org/ibex/util/DirtyList.java delete mode 100644 src/org/ibex/util/EjAlbertBrowserLauncher.java delete mode 100644 src/org/ibex/util/FileNameEncoder.java delete mode 100644 src/org/ibex/util/Grammar.java delete mode 100644 src/org/ibex/util/Hash.java delete mode 100644 src/org/ibex/util/InputStreamToByteArray.java delete mode 100644 src/org/ibex/util/KnownLength.java delete mode 100644 src/org/ibex/util/LineReader.java delete mode 100644 src/org/ibex/util/Log.java delete mode 100644 src/org/ibex/util/MSPack.c delete mode 100644 src/org/ibex/util/MSPack.java delete mode 100644 src/org/ibex/util/NanoGoat.java delete mode 100644 src/org/ibex/util/PackBytesIntoString.java delete mode 100644 src/org/ibex/util/Preprocessor.java delete mode 100644 src/org/ibex/util/Queue.java delete mode 100644 src/org/ibex/util/Scheduler.java delete mode 100644 src/org/ibex/util/Semaphore.java delete mode 100644 src/org/ibex/util/Simplex.java delete mode 100644 src/org/ibex/util/Task.java delete mode 100644 src/org/ibex/util/Vec.java delete mode 100644 src/org/ibex/util/XML.java diff --git a/src/gnu/gcj/RawData.java b/src/gnu/gcj/RawData.java new file mode 100644 index 0000000..3293970 --- /dev/null +++ b/src/gnu/gcj/RawData.java @@ -0,0 +1,3 @@ +package gnu.gcj; +public class RawData { +} diff --git a/src/org/ibex/core/Box.java b/src/org/ibex/core/Box.java index 96aa0a0..677fe0c 100644 --- a/src/org/ibex/core/Box.java +++ b/src/org/ibex/core/Box.java @@ -57,7 +57,7 @@ public final class Box extends JS.O implements Task { 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); } } @@ -443,7 +443,7 @@ public final class Box extends JS.O implements Task { 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) @@ -469,7 +469,7 @@ public final class Box extends JS.O implements Task { 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; @@ -527,7 +527,7 @@ public final class Box extends JS.O implements Task { 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)); @@ -555,7 +555,7 @@ public final class Box extends JS.O implements Task { 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(); @@ -684,7 +684,7 @@ public final class Box extends JS.O implements Task { 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); diff --git a/src/org/ibex/core/Ibex.java b/src/org/ibex/core/Ibex.java index 447ee1d..9427c20 100644 --- a/src/org/ibex/core/Ibex.java +++ b/src/org/ibex/core/Ibex.java @@ -59,7 +59,7 @@ public final class Ibex extends JS implements JS.Cloneable { // 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; @@ -129,7 +129,7 @@ public final class Ibex extends JS implements JS.Cloneable { } 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; @@ -144,7 +144,7 @@ public final class Ibex extends JS implements JS.Cloneable { 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 @@ -156,21 +156,21 @@ public final class Ibex extends JS implements JS.Cloneable { 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); @@ -200,12 +200,12 @@ public final class Ibex extends JS implements JS.Cloneable { //#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))); @@ -247,7 +247,7 @@ public final class Ibex extends JS implements JS.Cloneable { // 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; @@ -256,7 +256,7 @@ public final class Ibex extends JS implements JS.Cloneable { 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); @@ -269,7 +269,7 @@ public final class Ibex extends JS implements JS.Cloneable { 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; @@ -283,7 +283,7 @@ public final class Ibex extends JS implements JS.Cloneable { 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); diff --git a/src/org/ibex/core/Scheduler.java b/src/org/ibex/core/Scheduler.java index e4c85fa..f6c0774 100644 --- a/src/org/ibex/core/Scheduler.java +++ b/src/org/ibex/core/Scheduler.java @@ -1,5 +1,5 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex.util; +package org.ibex.core; import java.io.IOException; diff --git a/src/org/ibex/core/Stream.java b/src/org/ibex/core/Stream.java index 40fc71f..24f96c4 100644 --- a/src/org/ibex/core/Stream.java +++ b/src/org/ibex/core/Stream.java @@ -1,10 +1,11 @@ // 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.*; /** @@ -13,7 +14,7 @@ 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 ////////////////////////////////////////////////////////////////////////////// @@ -38,11 +39,11 @@ public abstract class Stream extends JS.Cloneable { /** 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 */ @@ -59,7 +60,7 @@ public abstract class Stream extends JS.Cloneable { 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); } @@ -88,6 +89,7 @@ public abstract class Stream extends JS.Cloneable { } /** "unwrap" a Cab archive */ + /* public static class Cab extends Stream { private Stream parent; private String path; @@ -97,6 +99,7 @@ public abstract class Stream extends JS.Cloneable { 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 { diff --git a/src/org/ibex/graphics/Font.java b/src/org/ibex/graphics/Font.java index 96c65c4..619e5b7 100644 --- a/src/org/ibex/graphics/Font.java +++ b/src/org/ibex/graphics/Font.java @@ -4,6 +4,7 @@ import org.ibex.util.*; 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; diff --git a/src/org/ibex/graphics/MSPack.java b/src/org/ibex/graphics/MSPack.java index 6236df6..971bf79 100644 --- a/src/org/ibex/graphics/MSPack.java +++ b/src/org/ibex/graphics/MSPack.java @@ -1,4 +1,4 @@ -package org.ibex.util; +package org.ibex.graphics; import org.ibex.core.Main; import org.ibex.util.*; diff --git a/src/org/ibex/js/ByteCodes.java b/src/org/ibex/js/ByteCodes.java deleted file mode 100644 index 84c5926..0000000 --- a/src/org/ibex/js/ByteCodes.java +++ /dev/null @@ -1,99 +0,0 @@ -// 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" - }; -} diff --git a/src/org/ibex/js/Directory.java b/src/org/ibex/js/Directory.java deleted file mode 100644 index 98469d5..0000000 --- a/src/org/ibex/js/Directory.java +++ /dev/null @@ -1,118 +0,0 @@ -// 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 copy 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= 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> 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); - } - } - } - } -} diff --git a/src/org/ibex/js/JS.java b/src/org/ibex/js/JS.java deleted file mode 100644 index e81c4cf..0000000 --- a/src/org/ibex/js/JS.java +++ /dev/null @@ -1,319 +0,0 @@ -// 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 '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; } - } - - -} diff --git a/src/org/ibex/js/JSArray.java b/src/org/ibex/js/JSArray.java deleted file mode 100644 index a9483d0..0000000 --- a/src/org/ibex/js/JSArray.java +++ /dev/null @@ -1,266 +0,0 @@ -// 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 '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= 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--) 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 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 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 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= 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; } -} - - diff --git a/src/org/ibex/js/JSExn.java b/src/org/ibex/js/JSExn.java deleted file mode 100644 index 2afcef1..0000000 --- a/src/org/ibex/js/JSExn.java +++ /dev/null @@ -1,52 +0,0 @@ -// 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; iunpauseable 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>>16) + " size: " + (n&0xffff)); - } - sb.append("\n"); - } - return sb.toString(); - } - - -} - diff --git a/src/org/ibex/js/JSMath.java b/src/org/ibex/js/JSMath.java deleted file mode 100644 index 32d730d..0000000 --- a/src/org/ibex/js/JSMath.java +++ /dev/null @@ -1,86 +0,0 @@ -// 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); - } -} diff --git a/src/org/ibex/js/JSNumber.java b/src/org/ibex/js/JSNumber.java deleted file mode 100644 index 8137cbc..0000000 --- a/src/org/ibex/js/JSNumber.java +++ /dev/null @@ -1,62 +0,0 @@ -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"; } - } -} diff --git a/src/org/ibex/js/JSPrimitive.java b/src/org/ibex/js/JSPrimitive.java deleted file mode 100644 index 904a587..0000000 --- a/src/org/ibex/js/JSPrimitive.java +++ /dev/null @@ -1,109 +0,0 @@ -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= 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); - } -} diff --git a/src/org/ibex/js/JSReflection.java b/src/org/ibex/js/JSReflection.java deleted file mode 100644 index 52f7f9c..0000000 --- a/src/org/ibex/js/JSReflection.java +++ /dev/null @@ -1,89 +0,0 @@ -// 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= 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 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= '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 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;iregardless of pushbacks */ - 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 lexed token */ - protected int line = 0; - - /** the line number of the most recently parsed 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); } - } -} diff --git a/src/org/ibex/js/Parser.java b/src/org/ibex/js/Parser.java deleted file mode 100644 index 6293107..0000000 --- a/src/org/ibex/js/Parser.java +++ /dev/null @@ -1,1049 +0,0 @@ -// 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 code */ - 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 minPrecedence and append the - * bytecodes for that expression to appendTo; 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, - * continueExprAfterAssignable 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, - * continueExpr will attempt to extend this expression by - * parsing additional tokens and appending additional bytecodes. - * - * No operators with precedence less than minPrecedence - * 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;ipublic static final int 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" - }; - -} - - diff --git a/src/org/ibex/js/Trap.java b/src/org/ibex/js/Trap.java deleted file mode 100644 index 580ed69..0000000 --- a/src/org/ibex/js/Trap.java +++ /dev/null @@ -1,28 +0,0 @@ -// 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(); } -} diff --git a/src/org/ibex/net/HTTP.java b/src/org/ibex/net/HTTP.java deleted file mode 100644 index da94713..0000000 --- a/src/org/ibex/net/HTTP.java +++ /dev/null @@ -1,1304 +0,0 @@ -// 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 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> 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= 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 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; - } - } - } - - } - } -} diff --git a/src/org/ibex/net/SOAP.java b/src/org/ibex/net/SOAP.java deleted file mode 100644 index d54ebce..0000000 --- a/src/org/ibex/net/SOAP.java +++ /dev/null @@ -1,285 +0,0 @@ -// 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: - *
  • Multi-ref data and circular references - *
  • 'Document Style' - *
  • WSDL support - *
- */ -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 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 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 o to sb */ - 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("\r\n"); - } else { - sb.append(" <" + name + " xsi:type=\"xsd:double\">"); - sb.append(o); - sb.append("\r\n"); - } - - } else if (o instanceof Boolean) { - sb.append(" <" + name + " xsi:type=\"xsd:boolean\">"); - sb.append(((Boolean)o).booleanValue() ? "true" : "false"); - sb.append("\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("\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("\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\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("\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("\r\n"); - content.append("\r\n"); - content.append("\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(" \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; - } - -} diff --git a/src/org/ibex/net/XMLRPC.java b/src/org/ibex/net/XMLRPC.java deleted file mode 100644 index 72a2c76..0000000 --- a/src/org/ibex/net/XMLRPC.java +++ /dev/null @@ -1,345 +0,0 @@ -// 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 The - * XML-RPC Spec, subject to these limitations: - *
    - *
  1. XMLRPC cannot invoke methods that require a argument - *
  2. if a return value contains a , it will be returned as a string - *
  3. The decision to pass a number as or 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 element. We - * hope that most xml-rpc servers will be able to automatically - * convert. - *
- */ -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 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\n"); - content.append(" \n"); - content.append(" "); - content.append(method); - content.append("\n"); - content.append(" \n"); - for(int i=0; i\n"); - appendObject(args[i], content); - content.append(" \n"); - } - content.append(" \n"); - content.append(" "); - return content.toString(); - } - - /** Appends the XML-RPC representation of o to sb */ - 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(" "); - sb.append(((Number)o).intValue()); - sb.append("\n"); - } else { - sb.append(" "); - sb.append(o); - sb.append("\n"); - } - - } else if (o instanceof Boolean) { - sb.append(" "); - sb.append(((Boolean)o).booleanValue() ? "1" : "0"); - sb.append("\n"); - - } else if (o instanceof Stream) { - try { - sb.append(" \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 \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(" "); - 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("\n"); - - } else if (o instanceof JSDate) { - sb.append(" "); - 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("\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(" \n"); - JSArray a = (JSArray)o; - for(int i=0; i\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(" \n"); - Enumeration e = j.keys(); - while(e.hasMoreElements()) { - Object key = e.nextElement(); - sb.append(" " + key + "\n"); - appendObject(j.get(key), sb); - sb.append(" \n"); - } - sb.append(" \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 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 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 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 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 ""; - } - } - - 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; - } - - -} - diff --git a/src/org/ibex/util/Cache.java b/src/org/ibex/util/Cache.java deleted file mode 100644 index af88c88..0000000 --- a/src/org/ibex/util/Cache.java +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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); - } - -} - - diff --git a/src/org/ibex/util/CachedInputStream.java b/src/org/ibex/util/CachedInputStream.java deleted file mode 100644 index a712f84..0000000 --- a/src/org/ibex/util/CachedInputStream.java +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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; - } - } - } -} diff --git a/src/org/ibex/util/Callback.java b/src/org/ibex/util/Callback.java deleted file mode 100644 index 471df9b..0000000 --- a/src/org/ibex/util/Callback.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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); - -} diff --git a/src/org/ibex/util/CounterEnumeration.java b/src/org/ibex/util/CounterEnumeration.java deleted file mode 100644 index 5a01f3e..0000000 --- a/src/org/ibex/util/CounterEnumeration.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2004 Adam Megacz 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++); } -} diff --git a/src/org/ibex/util/DirtyList.java b/src/org/ibex/util/DirtyList.java deleted file mode 100644 index 0a77a94..0000000 --- a/src/org/ibex/util/DirtyList.java +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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= 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 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; ib) 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; - } - -} diff --git a/src/org/ibex/util/EjAlbertBrowserLauncher.java b/src/org/ibex/util/EjAlbertBrowserLauncher.java deleted file mode 100644 index cf46138..0000000 --- a/src/org/ibex/util/EjAlbertBrowserLauncher.java +++ /dev/null @@ -1,589 +0,0 @@ -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. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * Credits: - *
Steven Spencer, JavaWorld magazine (Java Tip 66) - *
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 (ejalbert@cs.stanford.edu) - * @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. - *

- * Note that if this is false, openURL() 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 (int) method of com.apple.MacOS.AETarget */ - private static Constructor aeTargetConstructor; - - /** The (int, int, int) method of com.apple.MacOS.AppleEvent */ - private static Constructor appleEventConstructor; - - /** The (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 true if all intialization succeeded - * false 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 . - 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; } -} diff --git a/src/org/ibex/util/FileNameEncoder.java b/src/org/ibex/util/FileNameEncoder.java deleted file mode 100644 index e68bba2..0000000 --- a/src/org/ibex/util/FileNameEncoder.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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 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= 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); - } - }*/ -} diff --git a/src/org/ibex/util/Hash.java b/src/org/ibex/util/Hash.java deleted file mode 100644 index 11fe4d8..0000000 --- a/src/org/ibex/util/Hash.java +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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) 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; - } - } -} - - diff --git a/src/org/ibex/util/InputStreamToByteArray.java b/src/org/ibex/util/InputStreamToByteArray.java deleted file mode 100644 index 7e19644..0000000 --- a/src/org/ibex/util/InputStreamToByteArray.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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; - } - -} diff --git a/src/org/ibex/util/KnownLength.java b/src/org/ibex/util/KnownLength.java deleted file mode 100644 index 06118bb..0000000 --- a/src/org/ibex/util/KnownLength.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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; - } - } - -} diff --git a/src/org/ibex/util/LineReader.java b/src/org/ibex/util/LineReader.java deleted file mode 100644 index 429c218..0000000 --- a/src/org/ibex/util/LineReader.java +++ /dev/null @@ -1,46 +0,0 @@ -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 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 + ""); - - } else if (o instanceof JSArray) { - JS.log(indent + name + ""); - JSArray na = (JSArray)o; - for(int i=0; i"); - 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); - - } - }*/ - -} diff --git a/src/org/ibex/util/MSPack.c b/src/org/ibex/util/MSPack.c deleted file mode 100644 index f09cf35..0000000 --- a/src/org/ibex/util/MSPack.c +++ /dev/null @@ -1,202 +0,0 @@ -/* -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 -#include -#include -#include -#include - -#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;iwritable = 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")) - 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", 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' ... 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 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("")) return null; - if (sig.startsWith(" 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("")) return; - if (sig.startsWith("") && jc.getClassName().startsWith("java.lang.reflect.")) return; - - if (dest.contains(method)) return; - dest.add(method); - - if (method.getName().equals("") && jc.getSuperClass() != null) - loadMethod(jc.getSuperClass().getClassName() + "."); - - if (method.isStatic() || method.getName().equals("")) loadMethod(jc.getClassName() + "."); - if (method.getName().equals("")) { - // 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"); - } - 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() + "."); - 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"); - } - - 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")) 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")) return; - HashSet s = (HashSet)subclasses.get(c); - if (s == null) return; - Object[] subclasses = s.toArray(); - for(int i=0; i 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=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=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; - } -} - diff --git a/src/org/ibex/util/Preprocessor.java b/src/org/ibex/util/Preprocessor.java deleted file mode 100644 index 4698fdc..0000000 --- a/src/org/ibex/util/Preprocessor.java +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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= 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); - } - } - } -} - diff --git a/src/org/ibex/util/Queue.java b/src/org/ibex/util/Queue.java deleted file mode 100644 index 91b9b29..0000000 --- a/src/org/ibex/util/Queue.java +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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) 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 - block 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]; - } - -} diff --git a/src/org/ibex/util/Scheduler.java b/src/org/ibex/util/Scheduler.java deleted file mode 100644 index a2ce69c..0000000 --- a/src/org/ibex/util/Scheduler.java +++ /dev/null @@ -1,95 +0,0 @@ -// 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 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(); - } - -} diff --git a/src/org/ibex/util/Simplex.java b/src/org/ibex/util/Simplex.java deleted file mode 100644 index 2ae314a..0000000 --- a/src/org/ibex/util/Simplex.java +++ /dev/null @@ -1,1345 +0,0 @@ -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 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]= 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; } - } - -} - diff --git a/src/org/ibex/util/Task.java b/src/org/ibex/util/Task.java deleted file mode 100644 index e710724..0000000 --- a/src/org/ibex/util/Task.java +++ /dev/null @@ -1,8 +0,0 @@ -// 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; -} diff --git a/src/org/ibex/util/Vec.java b/src/org/ibex/util/Vec.java deleted file mode 100644 index ffe7cfd..0000000 --- a/src/org/ibex/util/Vec.java +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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= 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 < 0) throw new RuntimeException("tried to remove an element outside the vector's limits"); - for(int j=i; j= 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= 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 < 0) throw new RuntimeException("tried to remove an element outside the vector's limits"); - for(int j=i; j= 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; - } - } -} diff --git a/src/org/ibex/util/XML.java b/src/org/ibex/util/XML.java deleted file mode 100644 index d0775c7..0000000 --- a/src/org/ibex/util/XML.java +++ /dev/null @@ -1,1174 +0,0 @@ -// Copyright (C) 2003 Adam Megacz 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. - * - *

Implementation Notes

- *

As the parser traverses into an element, it adds it to the linked list - * called elements. However, elements 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.

- * - *

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.

- * - *
    - *
  • Each time the buffer offset off is moved, the length - * len must be decreased.
  • - *
  • Each time the buffer length is decreased, it must be checked to make - * sure it is >0.
  • - *
  • error is defined as a Validity Constraint Violation and - * is recoverable
  • - *
  • fatal error is defined as a Well-formedness Constraint - * Violation and is not recoverable
  • - *
- * - * @author David Crawshaw - * @see XML Specification - * @see XML Namespaces - */ -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 buf[off] == '<' */ - private final void readTag() throws IOException, Exn { - // Start Tag '<' Name (S Attribute)* S? '>' - boolean starttag = true; - - // End Tag '' - 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 ' - 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 '') '>' - 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 '') '>' - 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 '') '>' - 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 '') '>' - 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 '') '>' - 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*)) '?>' - 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*)) ']]>' - readChars(false, "]]>", false); - } else { - col += 7; off += 7; len -=7; - // CDATA '' Char*)) ']]>' - readChars(true, "]]>", false); - } - col += 3; off += 3; len -= 3; - } else { - if (s == '/') { - // End Tag '' - 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 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 ( 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 < 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. - * - *

DO NOT store a reference to the Element object, as - * they are reused by XML Parser.

- */ - public abstract void startElement(Element e) throws Exn; - - /** - * Represents up to a line of character data. - * - *

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.

- * - *

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.

- */ - 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 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'; - } -} -- 1.7.10.4