import edu.berkeley.obits.device.atmel.*;
import org.ibex.util.*;
-import org.ibex.graphics.Picture;
import java.io.*;
import java.util.*;
import gnu.io.*;
--- /dev/null
+package edu.berkeley.obits;
+
+public abstract class Bits {
+ /*
+ public abstract boolean get(long bit);
+ public abstract void set(long bit, boolean val);
+
+ public int get(long bit, int len) {
+ int ret = 0;
+ for(long i=bit; i<bit+len; i++) ret = (ret << 1) | get(i);
+ return ret;
+ }
+ public void set(long bit, int len, int val) {
+ for(long i=bit+len-1; i>=bit; i--) {
+ set(i, (val & 1) != 0);
+ val >>= 1;
+ }
+ }
+
+ public final boolean get(int offset, int bit) { return get(offset*8 + bit); }
+ public final int get(int offset, int bit, int len) { return get(offset*8 + bit, num); }
+ public final void set(int offset, int bit, boolean b) { set(offset*8 + bit, b); }
+ public final void set(int offset, int bit, int len, int val) { set(offset*8 + bit, num, val); }
+
+ public static class Offset extends Bits {
+ private final Bits bits;
+ private final long off;
+
+ public Offset(Bits bits, long offset) { this.off = offset; this.bits = bits; }
+ public Offset(Bits bits, int offset, int bit) { this(bits, offset*8+bit); }
+
+ public boolean get(long bit) { return bits.get(bit+off); }
+ public int get(long bit, int len) { return bits.get(bit+off, len); }
+ public void set(long bit, boolean val) { bits.set(bit+off, val); }
+ public void set(long bit, int len, int val) { bits.set(bit+off, len, val); }
+ }
+
+ public static class Arr extends Bits {
+ private byte[] bits;
+ public Bits(int capacity) { this.bits = new byte[(capacity / 8) + (capacity%8 == 0 ? 0 : 1)]; }
+
+ public boolean get(long bit) {
+ if (bit / 8 >= bits.length) return false;
+ int ret = bits[bit/8];
+ ret >> 8-(bit-((bit/8)*8));
+ return (ret & 1) != 0;
+ }
+
+ public void set(long bit, boolean b) {
+ if (bit / 8 >= bits.length) {
+ if (!b) return;
+ byte[] bits2 = new byte[Math.max((bit/8)+1, (bits.length * 2))];
+ System.arraycopy(bits, 0, bits2, 0, bits.length);
+ bits = bits2;
+ set(bit, b);
+ return;
+ }
+ byte mask = (byte)(1 << (8-(bit-((bit/8)*8))));
+ if (b) {
+ bits[bit/8] |= mask;
+ } else {
+ bits[bit/8] &= ~mask;
+ }
+ }
+
+ }
+ */
+}
--- /dev/null
+package edu.berkeley.obits.device.atmel;
+
+import edu.berkeley.obits.*;
+
+public enum Wires {
+
+ NW, SW, NE, SE,
+
+ N, S, E, W,
+
+ CM,
+
+ XL, YL,
+
+ C, R,
+
+ F,
+ BO,
+
+ XO, YO,
+
+ L0, L1, L2, L3, L4;
+
+}
--- /dev/null
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.ibex.util;
+
+import java.io.Serializable;
+
+public interface Basket extends Serializable {
+ public boolean containsValue(Object object);
+ public void clear();
+ public int size();
+ public void remove(Object object);
+
+ public interface List extends Basket {
+ public void add(Object object);
+ public void add(int index, Object object);
+ public Object set(int index, Object object);
+ public Object get(int index);
+ public Object remove(int index);
+ public int indexOf(Object object);
+ public void reverse();
+ public void sort(CompareFunc c);
+ }
+
+ public interface RandomAccess extends List { }
+
+ public interface Queue extends Basket {
+ public void enqueue(Object o);
+ public Object dequeue();
+ }
+
+ public interface Stack extends Basket {
+ public Object pop();
+ public Object peek();
+ public void push(Object object);
+ }
+
+ public interface Map extends Basket {
+ public boolean containsKey(Object key);
+ public Object get(Object key);
+ public Object put(Object key, Object value);
+ }
+
+ public interface CompareFunc {
+ public int compare(Object a, Object b);
+ }
+
+
+ // Implementations ////////////////////////////////////////////////////////
+
+ public class Array implements RandomAccess, Stack, Queue {
+ private static final long serialVersionUID = 1233428092L;
+
+ private Object[] o;
+ private int size = 0;
+
+ public Array() { this(10); }
+ public Array(int initialCapacity) { o = new Object[initialCapacity]; }
+ public Array(Object entry) { this(1); add(entry); }
+
+ public void enqueue(Object o) { add(o); }
+
+ // FEATURE: make this more efficient with general wraparound
+ public Object dequeue() {
+ if (size==0) return null;
+ Object ret = o[0];
+ for(int i=1; i<size; i++) o[i-1]=o[i];
+ return ret;
+ }
+
+ public void add(Object obj) { add(size, obj); }
+ public void add(int i, Object obj) {
+ size(size + 1);
+ if (size - 1 > i) System.arraycopy(o, i, o, size, size - i - 1);
+ o[i] = obj; size++;
+ }
+ public Object set(int i, Object obj) {
+ if (i >= o.length) throw new IndexOutOfBoundsException(
+ "index "+i+" is beyond list boundary "+size);
+ Object old = o[i]; o[i] = obj;
+ size = Math.max(i+1, size);
+ return old;
+ }
+ public Object get(int i) {
+ if (i >= size) throw new IndexOutOfBoundsException(
+ "index "+i+" is beyond list boundary "+size);
+ return o[i];
+ }
+ public Object remove(int i) {
+ if (i >= size || i < 0) throw new IndexOutOfBoundsException(
+ "index "+i+" is beyond list boundary "+size);
+ Object old = o[i]; o[i] = null;
+ if (size - 1 > i) System.arraycopy(o, i + 1, o, i, size - i - 1);
+ size--; return old;
+ }
+ public void remove(Object obj) { remove(indexOf(obj)); }
+
+ public int indexOf(Object obj) {
+ for (int i=0; i < size; i++)
+ if ((obj == null && o[i] == null) || obj.equals(o[i])) return i;
+ return -1;
+ }
+
+ public boolean containsValue(Object obj) {
+ for (int i=0; i < size; i++)
+ if ((obj == null && o[i] == null) || obj.equals(o[i])) return true;
+ return false;
+ }
+ public void clear() { for (int i=0; i < size; i++) o[i] = null; size = 0; }
+ public int size() { return size; }
+ public void size(int s) {
+ if (o.length >= s) return;
+ Object[] newo = new Object[s];
+ System.arraycopy(o, 0, newo, 0, size);
+ o = newo;
+ }
+
+ public void reverse() {
+ Object tmp; int max = (int)Math.floor((double)size / 2);
+ for (int i=0; i < size; i++) { tmp = o[i]; o[i] = o[size - i]; o[size - i] = tmp; }
+ }
+
+ public void sort(CompareFunc c) { sort(this, null, c, 0, size); }
+
+ public static void sort(Array a, Array 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.o[i];
+ if (b != null) tmpb = b.o[i];
+ int j;
+ for(j=i-1;j>=start;j--) {
+ if(c.compare(a.o[j],tmpa) <= 0) break;
+ a.o[j+1] = a.o[j];
+ if (b != null) b.o[j+1] = b.o[j];
+ }
+ a.o[j+1] = tmpa;
+ if (b != null) b.o[j+1] = tmpb;
+ }
+ return;
+ }
+ Object pivot = a.o[end];
+ int lo = start - 1;
+ int hi = end;
+ do {
+ while(c.compare(a.o[++lo],pivot) < 0) { }
+ while((hi > lo) && c.compare(a.o[--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(Array vec, int a, int b) {
+ if(a != b) {
+ Object tmp = vec.o[a];
+ vec.o[a] = vec.o[b];
+ vec.o[b] = tmp;
+ }
+ }
+
+ public Object peek() {
+ if (size < 1) throw new IndexOutOfBoundsException("array is empty");
+ return o[size - 1];
+ }
+ public Object pop() { return remove(size - 1); }
+ public void push(Object o) { add(o); }
+ }
+
+ /** Implementation of a hash table using Radke's quadratic residue
+ * linear probing. Uses a single array to store all entries.
+ *
+ * <p>See C. Radke, Communications of the ACM, 1970, 103-105</p>
+ *
+ * @author adam@ibex.org, crawshaw@ibex.org
+ */
+ public class Hash implements Basket, Map {
+ static final long serialVersionUID = 3948384093L;
+
+ /** Used internally to record used slots. */
+ final Object placeholder = new java.io.Serializable() { private static final long serialVersionUID = 1331L; };
+
+ /** When <tt>loadFactor * usedslots > num_slots</tt>, call
+ * <tt>rehash()</tt>. */
+ final float loadFactor;
+
+ /** Used to determine the number of array slots required by each
+ * mapping entry. */
+ final int indexmultiple;
+
+ /** Number of currently active entries. */
+ private int size = 0;
+
+ /** Number of placeholders in entries[]. */
+ private int placeholders = 0;
+
+ /** Array of mappings.
+ *
+ * <p>Each map requires multiple slots in the array, and subclasses
+ * can vary the number of required slots without reimplementing all
+ * the functions of this class by changing the value of
+ * <tt>indexmultiple</tt>.</p>
+ *
+ * Default implementation uses <tt>indexmultiple == 1</tt>, and
+ * stores only the keys in <tt>entries</tt>.
+ */
+ private Object[] entries = null;
+
+ public Hash() { this(16, 0.75F); }
+ public Hash(int cap, float load) { this(2, cap, load); }
+ public Hash(int indexmultiple, int initialCapacity, float loadFactor) {
+ // using a pseudoprime in the form 4x+3 ensures full coverage
+ initialCapacity = (initialCapacity / 4) * 4 + 3;
+ this.loadFactor = loadFactor;
+ this.indexmultiple = indexmultiple;
+ this.entries = new Object[initialCapacity * indexmultiple];
+ }
+
+ public int size() { return size; }
+ public void clear() { for (int i = 0; i<entries.length; i++) entries[i] = null; size = 0; }
+
+ public boolean containsKey(Object k) { return indexOf(k) >= 0; }
+
+ /** <b>Warning:</b> This function is equivalent here to
+ * <tt>containsKey()</tt>. For a value map, use Basket.HashMap. */
+ public boolean containsValue(Object k) { return containsKey(k); }
+
+
+ // UGLY
+ public Object[] dumpkeys() {
+ Object[] ret = new Object[size];
+ int pos = 0;
+ for(int i=0; i<entries.length; i+=indexmultiple)
+ if (placeholder!=entries[i] && entries[i]!=null) {
+ ret[pos++] = entries[i];
+ }
+ return ret;
+ }
+
+ public void remove(Object k) { remove(indexOf(k)); }
+ public void remove(int dest) {
+ if (dest < 0) return;
+ // instead of removing, insert a placeholder
+ entries[dest] = placeholder;
+ for (int inc=1; inc < indexmultiple; inc++) entries[dest + inc] = null;
+ size--;
+ placeholders++;
+ }
+
+ public Object get(Object key) { return get(key, 0); }
+ public Object get(Object key, int whichval) {
+ int i = indexOf(key);
+ return i >= 0 ? entries[i + 1 + whichval] : null;
+ }
+
+ public Object put(Object key, Object value) { return put(key, value, 0); }
+ public Object put(Object key, Object value, int whichval) {
+ if (loadFactor * (size + placeholders) > entries.length) rehash();
+ int dest = indexOf(key);
+ Object old = null;
+ if (dest < 0) {
+ dest = -1 * (dest + 1);
+ if (entries[dest] != placeholder) size++;
+ entries[dest] = key;
+ for(int i=1; i<indexmultiple; i++) entries[dest+i] = null;
+ } else {
+ old = entries[dest + 1 + whichval];
+ }
+ entries[dest + 1 + whichval] = value;
+ return old;
+ }
+
+ /*
+ public boolean containsKey(Object k) { return super.containsValue(k); }
+ public boolean containsValue(Object v) {
+ for (int i=0; i < entries.length/indexmultiple; i++)
+ if ((i == 0 || entries[i * indexmultiple] != null) && // exception for null key
+ !equals(placeholder, entries[i * indexmultiple]) &&
+ v == null ? entries[i + 1] == null : v.equals(entries[i + 1]))
+ return true;
+ return false;
+ }
+ */
+
+ /** Compares two keys for equality. <tt>userKey</tt> is the key
+ * passed to the map, <tt>storedKey</tt> is from the map.
+ *
+ * <p>Default implementation provides standard Java equality
+ * testing, <tt>k1 == null ? k2 == null : k1.equals(k2)</tt>.</p>
+ */
+ protected boolean equals(Object userKey, Object storedKey) {
+ return userKey == null ? storedKey == null : userKey.equals(storedKey);
+ }
+
+ /** Returns the array position in <tt>entries</tt>, adjusted for
+ * <tt>indexmultiple</tt>, where <tt>k</tt> is/should be stored
+ * using Radke's quadratic residue linear probing.
+ *
+ * <p><tt>entries[0]</tt> is a hard coded exception for the null
+ * key.</p>
+ *
+ * <p>If the key is not found, this function returns
+ * <tt>(-1 * indexPosition) - 1</tt>, where <tt>indexPosition</tt>
+ * is the array position where the mapping should be stored.</p>
+ *
+ * <p>Uses <tt>placeholder</tt> as a placeholder object, and
+ * compares keys using <tt>equals(Object, Object)</tt>.</p>
+ */
+ private int indexOf(Object k) {
+ // special case null key
+ if (k == null) return equals(placeholder, entries[0]) ? -1 : 0;
+
+ int hash = k == null ? 0 : k.hashCode();
+ final int orig = Math.abs(hash) % (entries.length / indexmultiple);
+ int dest = orig * indexmultiple;
+ int tries = 1;
+ boolean plus = true;
+
+ while (entries[dest] != null) {
+ if (equals(k, entries[dest])) return dest;
+ dest = Math.abs((orig + (plus ? 1 : -1) * tries * tries) % (entries.length / indexmultiple)) * indexmultiple;
+ if (plus) tries++;
+ plus = !plus;
+ }
+ return -1 * dest - 1;
+ }
+
+ /** Doubles the available entry space, first by packing the data
+ * set (removes <tt>placeholder</tt> references) and if necessary
+ * by increasing the size of the <tt>entries</tt> array.
+ */
+ private void rehash() {
+ Object[] oldentries = entries;
+ entries = new Object[oldentries.length * indexmultiple];
+
+ for (int i=0; i < (oldentries.length/indexmultiple); i++) {
+ int pos = i * indexmultiple;
+ if (pos > 0 && oldentries[pos] == null) continue;
+ if (oldentries[pos] == placeholder) continue;
+
+ // dont adjust any of the support entries
+ int dest = indexOf(oldentries[pos]);
+ dest = -1 * dest - 1; size++; // always new entry
+ for (int inc=0; inc < indexmultiple; inc++)
+ entries[dest + inc] = oldentries[pos + inc];
+ }
+ placeholders = 0;
+ }
+ }
+
+ // FIXME, BalancedTree goes here
+
+}
--- /dev/null
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.ibex.util;
+
+import java.io.*;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+/** General <tt>String</tt> and <tt>byte[]</tt> processing functions,
+ * including Base64 and a safe filename transform.
+ *
+ * @author adam@ibex.org
+ */
+public final class Encode {
+
+ public static class QuotedPrintable {
+ public static String decode(String s, boolean lax) {
+ //
+ // =XX -> hex representation, must be uppercase
+ // 9, 32, 33-60, 62-126 can be literal
+ // 9, 32 at end-of-line must get encoded
+ // trailing whitespace must be deleted when decoding
+ // =\n = soft line break
+ // lines cannot be more than 76 chars long
+ //
+
+ // lax is used for RFC2047 headers; removes restrictions on which chars you can encode
+ return s;
+ }
+ }
+
+
+ public static class RFC2047 {
+ public static String decode(String s) {
+ /*
+ try { while (s.indexOf("=?") != -1) {
+ String pre = s.substring(0, s.indexOf("=?"));
+ s = s.substring(s.indexOf("=?") + 2);
+
+ // MIME charset; FIXME use this
+ String charset = s.substring(0, s.indexOf('?')).toLowerCase();
+ s = s.substring(s.indexOf('?') + 1);
+
+ String encoding = s.substring(0, s.indexOf('?')).toLowerCase();
+ s = s.substring(s.indexOf('?') + 1);
+
+ String encodedText = s.substring(0, s.indexOf("?="));
+
+ if (encoding.equals("b")) encodedText = new String(Base64.decode(encodedText));
+
+ // except that ANY char can be endoed (unlike real qp)
+ else if (encoding.equals("q")) encodedText = MIME.QuotedPrintable.decode(encodedText, true);
+ else Log.warn(MIME.class, "unknown RFC2047 encoding \""+encoding+"\"");
+
+ String post = s.substring(s.indexOf("?=") + 2);
+ s = pre + encodedText + post;
+
+ // FIXME re-encode when transmitting
+
+ } } catch (Exception e) {
+ Log.warn(MIME.class, "error trying to decode RFC2047 encoded-word: \""+s+"\"");
+ Log.warn(MIME.class, e);
+ }
+ */
+ return s;
+ }
+ }
+
+
+ public static long twoFloatsToLong(float a, float b) {
+ return ((Float.floatToIntBits(a) & 0xffffffffL) << 32) | (Float.floatToIntBits(b) & 0xffffffffL); }
+ public static float longToFloat1(long l) { return Float.intBitsToFloat((int)((l >> 32) & 0xffffffff)); }
+ public static float longToFloat2(long l) { return Float.intBitsToFloat((int)(l & 0xffffffff)); }
+
+ private static final char[] fn =
+ new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ public static String toFilename(String s) {
+ StringBuffer sb = new StringBuffer();
+ try {
+ byte[] b = s.getBytes("UTF-8");
+ for(int i=0; i<b.length; i++) {
+ char c = (char)(b[i] & 0xff);
+ if (c == File.separatorChar || c < 32 || c > 126 || c == '%' || (i == 0 && c == '.'))
+ sb.append("%" + fn[(b[i] & 0xf0) >> 8] + fn[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 fromFilename(String s) {
+ StringBuffer sb = new StringBuffer();
+ byte[] b = new byte[s.length() * 2];
+ int bytes = 0;
+ for(int i=0; i<s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '%') b[bytes++] = (byte)Integer.parseInt(("" + s.charAt(++i) + s.charAt(++i)), 16);
+ else b[bytes++] = (byte)c;
+ }
+ try {
+ return new String(b, 0, bytes, "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ throw new Error("this should never happen; Java spec mandates UTF-8 support");
+ }
+ }
+
+ public static class Ascii {
+ public static class In extends InputStream {
+ public final int radix;
+ private final Reader reader;
+ private int blen = 0;
+ private byte[] bbuf = new byte[1024 * 16];
+ private int clen = 0;
+ private char[] cbuf = new char[1024 * 16];
+ public In(int radix, InputStream is) {
+ // FIXME: radix must be a power of 2
+ this.radix = radix;
+ this.reader = new InputStreamReader(is);
+ }
+ public int read() throws IOException {
+ byte[] buf = new byte[1];
+ while(true) {
+ int numread = read(buf, 0, 1);
+ if (numread<0) return -1;
+ if (numread>0) return (buf[0] & 0xff);
+ }
+ }
+ public long skip(long n) throws IOException {
+ while(blen<=0) if (!fillb()) return -1;
+ int numskip = Math.min((int)n, blen);
+ if (blen > numskip) System.arraycopy(bbuf, numskip, bbuf, 0, blen-numskip);
+ blen -= numskip;
+ return numskip;
+ }
+ public int read(byte[] b) throws IOException { return read(b, 0, b.length); }
+ public int available() { return blen; }
+ public boolean markSupported() { return false; }
+ public void close() throws IOException { reader.close(); }
+ public int read(byte[] buf, int off, int len) throws IOException {
+ while(blen<=0) if (!fillb()) return -1;
+ int numread = Math.min(len, blen);
+ System.arraycopy(bbuf, 0, buf, off, numread);
+ if (numread < blen) System.arraycopy(bbuf, numread, bbuf, 0, blen-numread);
+ blen -= numread;
+ return numread;
+ }
+ public boolean fillc() throws IOException {
+ int numread = reader.read(cbuf, clen, cbuf.length - clen);
+ if (numread == -1) return false;
+ int j = 0;
+ for(int i=0; i<numread; i++) {
+ if (!Character.isWhitespace(cbuf[clen+i]))
+ cbuf[clen+(j++)] = cbuf[clen+i];
+ }
+ clen += j;
+ return true;
+ }
+ public boolean fillb() throws IOException {
+ int minChars;
+ int bytesPerMinChars;
+ switch(radix) {
+ case 2: { minChars = 8; bytesPerMinChars = 1; break; }
+ case 16: { minChars = 2; bytesPerMinChars = 1; break; }
+ default: throw new Error("unsupported");
+ }
+ while(clen < minChars) if (!fillc()) return false;
+ int pos = 0;
+ while(pos <= clen - minChars) {
+ bbuf[blen++] = (byte)Integer.parseInt(new String(cbuf, pos, minChars), radix);
+ pos += minChars;
+ }
+ System.arraycopy(cbuf, pos, cbuf, 0, clen-pos);
+ clen -= pos;
+ return true;
+ }
+ }
+ }
+
+ private static final byte[] encB64 = {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1',
+ (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8',
+ (byte)'9', (byte)'+', (byte)'/'
+ };
+
+ // FIXME could be far more efficient
+ public static class Base64InputStream extends ByteArrayInputStream {
+ public Base64InputStream(String s) { super(fromBase64(s.getBytes())); }
+ }
+
+ public static byte[] toBase64(String data) { return toBase64(data.getBytes()); }
+
+ /** Encode the input data producong a base 64 encoded byte array.
+ * @return A byte array containing the base 64 encoded data. */
+ public static byte[] toBase64(byte[] data) {
+ byte[] bytes;
+
+ int modulus = data.length % 3;
+ if (modulus == 0) {
+ bytes = new byte[4 * data.length / 3];
+ } else {
+ bytes = new byte[4 * ((data.length / 3) + 1)];
+ }
+
+ int dataLength = (data.length - modulus);
+ int a1, a2, a3;
+ for (int i = 0, j = 0; i < dataLength; i += 3, j += 4) {
+ a1 = data[i] & 0xff;
+ a2 = data[i + 1] & 0xff;
+ a3 = data[i + 2] & 0xff;
+
+ bytes[j] = encB64[(a1 >>> 2) & 0x3f];
+ bytes[j + 1] = encB64[((a1 << 4) | (a2 >>> 4)) & 0x3f];
+ bytes[j + 2] = encB64[((a2 << 2) | (a3 >>> 6)) & 0x3f];
+ bytes[j + 3] = encB64[a3 & 0x3f];
+ }
+
+ int b1, b2, b3;
+ int d1, d2;
+ switch (modulus) {
+ case 0: /* nothing left to do */
+ break;
+ case 1:
+ d1 = data[data.length - 1] & 0xff;
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = (d1 << 4) & 0x3f;
+
+ bytes[bytes.length - 4] = encB64[b1];
+ bytes[bytes.length - 3] = encB64[b2];
+ bytes[bytes.length - 2] = (byte)'=';
+ bytes[bytes.length - 1] = (byte)'=';
+ break;
+ case 2:
+ d1 = data[data.length - 2] & 0xff;
+ d2 = data[data.length - 1] & 0xff;
+
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+ b3 = (d2 << 2) & 0x3f;
+
+ bytes[bytes.length - 4] = encB64[b1];
+ bytes[bytes.length - 3] = encB64[b2];
+ bytes[bytes.length - 2] = encB64[b3];
+ bytes[bytes.length - 1] = (byte)'=';
+ break;
+ }
+
+ return bytes;
+ }
+
+
+ private static final byte[] decB64 = new byte[128];
+ static {
+ for (int i = 'A'; i <= 'Z'; i++) decB64[i] = (byte)(i - 'A');
+ for (int i = 'a'; i <= 'z'; i++) decB64[i] = (byte)(i - 'a' + 26);
+ for (int i = '0'; i <= '9'; i++) decB64[i] = (byte)(i - '0' + 52);
+ decB64['+'] = 62;
+ decB64['/'] = 63;
+ }
+
+ /** Decode base 64 encoded input data.
+ * @return A byte array representing the decoded data. */
+ public static byte[] fromBase64(byte[] data) {
+ byte[] bytes;
+ byte b1, b2, b3, b4;
+
+ if (data[data.length - 2] == '=') bytes = new byte[(((data.length / 4) - 1) * 3) + 1];
+ else if (data[data.length - 1] == '=') bytes = new byte[(((data.length / 4) - 1) * 3) + 2];
+ else bytes = new byte[((data.length / 4) * 3)];
+
+ for (int i = 0, j = 0; i < data.length - 4; i += 4, j += 3) {
+ b1 = decB64[data[i]];
+ b2 = decB64[data[i + 1]];
+ b3 = decB64[data[i + 2]];
+ b4 = decB64[data[i + 3]];
+
+ bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[j + 2] = (byte)((b3 << 6) | b4);
+ }
+
+ if (data[data.length - 2] == '=') {
+ b1 = decB64[data[data.length - 4]];
+ b2 = decB64[data[data.length - 3]];
+ bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
+ } else if (data[data.length - 1] == '=') {
+ b1 = decB64[data[data.length - 4]];
+ b2 = decB64[data[data.length - 3]];
+ b3 = decB64[data[data.length - 2]];
+ bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
+ } else {
+ b1 = decB64[data[data.length - 4]];
+ b2 = decB64[data[data.length - 3]];
+ b3 = decB64[data[data.length - 2]];
+ b4 = decB64[data[data.length - 1]];
+ bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
+ }
+ return bytes;
+ }
+
+ /** Decode a base 64 encoded String.
+ * @return A byte array representing the decoded data. */
+ public static byte[] fromBase64(String data) {
+ byte[] bytes;
+ byte b1, b2, b3, b4;
+
+ if (data.charAt(data.length() - 2) == '=')
+ bytes = new byte[(((data.length() / 4) - 1) * 3) + 1];
+ else if (data.charAt(data.length() - 1) == '=')
+ bytes = new byte[(((data.length() / 4) - 1) * 3) + 2];
+ else
+ bytes = new byte[((data.length() / 4) * 3)];
+
+ for (int i = 0, j = 0; i < data.length() - 4; i += 4, j += 3) {
+ b1 = decB64[data.charAt(i)];
+ b2 = decB64[data.charAt(i + 1)];
+ b3 = decB64[data.charAt(i + 2)];
+ b4 = decB64[data.charAt(i + 3)];
+
+ bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[j + 2] = (byte)((b3 << 6) | b4);
+ }
+
+ if (data.charAt(data.length() - 2) == '=') {
+ b1 = decB64[data.charAt(data.length() - 4)];
+ b2 = decB64[data.charAt(data.length() - 3)];
+ bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
+ } else if (data.charAt(data.length() - 1) == '=') {
+ b1 = decB64[data.charAt(data.length() - 4)];
+ b2 = decB64[data.charAt(data.length() - 3)];
+ b3 = decB64[data.charAt(data.length() - 2)];
+ bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
+ } else {
+ b1 = decB64[data.charAt(data.length() - 4)];
+ b2 = decB64[data.charAt(data.length() - 3)];
+ b3 = decB64[data.charAt(data.length() - 2)];
+ b4 = decB64[data.charAt(data.length() - 1)];
+ bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
+ bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
+ }
+ return bytes;
+ }
+
+
+ /** Packs 8-bit bytes into a String of 7-bit chars.
+ * @throws IllegalArgumentException when <tt>len</tt> is not a multiple of 7.
+ * @return A String representing the processed bytes. */
+ public static String toStringFrom8bit(byte[] b, int off, int len) throws IllegalArgumentException {
+ if (len % 7 != 0) throw new IllegalArgumentException("len must be a multiple of 7");
+ StringBuffer ret = new StringBuffer();
+ for(int i=off; i<off+len; i += 7) {
+ long l = 0;
+ for(int j=6; j>=0; j--) {
+ l <<= 8;
+ l |= (b[i + j] & 0xff);
+ }
+ for(int j=0; j<8; j++) {
+ ret.append((char)(l & 0x7f));
+ l >>= 7;
+ }
+ }
+ return ret.toString();
+ }
+
+ /** Packs a String of 7-bit chars into 8-bit bytes.
+ * @throws IllegalArgumentException when <tt>s.length()</tt> is not a multiple of 8.
+ * @return A byte array representing the processed String. */
+ public static byte[] fromStringTo8bit(String s) throws IllegalArgumentException {
+ if (s.length() % 8 != 0) throw new IllegalArgumentException("string length must be a multiple of 8");
+ byte[] ret = new byte[(s.length() / 8) * 7];
+ for(int i=0; i<s.length(); i += 8) {
+ long l = 0;
+ for(int j=7; j>=0; j--) {
+ l <<= 7;
+ l |= (s.charAt(i + j) & 0x7fL);
+ }
+ for(int j=0; j<7; j++) {
+ ret[(i / 8) * 7 + j] = (byte)(l & 0xff);
+ l >>= 8;
+ }
+ }
+ return ret;
+ }
+
+ public static class JavaSourceCode {
+
+ public static final int LINE_LENGTH = 80 / 4;
+ public static void main(String[] s) throws Exception { System.out.println(encode(s[0], s[1], System.in)); }
+
+ public static InputStream decode(String s) throws IOException {
+ return new GZIPInputStream(new StringInputStream(s)); }
+
+ private static class StringInputStream extends InputStream {
+ private final String s;
+ private final int length;
+ private int pos = 0;
+ public StringInputStream(String s) { this.s = s; this.length = s.length(); }
+ public int read() {
+ byte[] b = new byte[1];
+ int numread = read(b, 0, 1);
+ if (numread == -1) return -1;
+ if (numread == 0) throw new Error();
+ return b[0] & 0xff;
+ }
+ public int read(byte[] b, int off, int len) {
+ for(int i=off; i<off+len; i++) {
+ if (pos>=length) return i-off;
+ //int out = s.charAt(pos++);
+ b[i] = (byte)s.charAt(pos++);//(byte)(out > 127 ? 127-out : out);
+ }
+ return len;
+ }
+ }
+
+ public static String encode(String packageName, String className, InputStream is) throws IOException {
+
+ // compress first, since the encoded form has more entropy
+ ByteArrayOutputStream baos;
+ OutputStream os = new GZIPOutputStream(baos = new ByteArrayOutputStream());
+
+ byte[] buf = new byte[1024];
+ while(true) {
+ int numread = is.read(buf, 0, buf.length);
+ if (numread == -1) break;
+ os.write(buf, 0, numread);
+ }
+ os.close();
+ buf = baos.toByteArray();
+
+ StringBuffer ret = new StringBuffer();
+ ret.append("// generated by " + Encode.class.getName() + "\n\n");
+ ret.append("package " + packageName + ";\n\n");
+ ret.append("public class " + className + " {\n");
+ ret.append(" public static final String data = \n");
+ for(int pos = 0; pos<buf.length;) {
+ ret.append(" \"");
+ for(int i=0; i<LINE_LENGTH && pos<buf.length; i++) {
+ String cs = Integer.toOctalString(buf[pos++] & 0xff);
+ while(cs.length() < 3) cs = "0" + cs;
+ ret.append("\\" + cs);
+ }
+ ret.append("\" +\n");
+ }
+ ret.append(" \"\";\n");
+ ret.append("}\n");
+ return ret.toString();
+ }
+
+ }
+
+}
+
--- /dev/null
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.ibex.util;
+
+import java.util.*;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.InetAddress;
+import java.text.SimpleDateFormat;
+
+// FEATURE: logging exceptions should automatically unwrap exceptions
+
+/** Easy to use logger.
+ *
+ * @author adam@ibex.org
+ */
+public class Log {
+ private static final SimpleDateFormat formatDate = new SimpleDateFormat("EEE dd MMM yyyy");
+ private static final SimpleDateFormat formatTime = new SimpleDateFormat("[EEE HH:mm:ss] ");
+ private static final Hashtable threadAnnotations = new Hashtable();
+
+ 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 boolean stackTraces = System.getProperty("ibex.log.stackTraces", "true").equals("true");
+ public static int maximumNoteLength = Integer.parseInt(System.getProperty("ibex.log.notes.maximumLength", (1024 * 32)+""));
+ public static boolean rpc = false;
+ public static int lastDay = -1;
+
+ 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());
+ }
+
+ 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 final Basket.Map notebufs = new Basket.Hash();
+ public 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) {
+ Calendar cal = Calendar.getInstance();
+ if (lastDay < 0 || lastDay != cal.get(Calendar.DAY_OF_YEAR)) {
+ lastDay = cal.get(Calendar.DAY_OF_YEAR);
+ String now = formatDate.format(cal.getTime());
+ logstream.println();
+ logstream.println(colorize(GREEN, false, "=== " + now + " =========================================================="));
+ }
+ classname = formatTime.format(cal.getTime()) + classname;
+ }
+
+ 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)));
+ try {
+ if (stackTraces) {
+ String s = null;
+ String m = "";
+ while((s = br.readLine()) != null) m += s + "\n";
+ if (m.length() > 0) log(o, m.substring(0, m.length() - 1), level);
+ } else {
+ String m = br.readLine();
+ int ok = 0;
+ do {
+ String s = br.readLine();
+ if (s == null) break;
+ if (s.indexOf('(') != -1) {
+ String shortened = s.substring(s.indexOf('(')+1);
+ shortened = shortened.substring(0, shortened.indexOf(')'));
+ m += " " + shortened;
+ if (ok > 1) m = m.substring(0, Math.min(m.length(), 78));
+ ok++;
+ }
+ } while (m.length() < 78);
+ log(o, m, level);
+ }
+ lastClassName = "";
+ } 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"));
+ }
+ 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));
+ }
+
+}