From d4b20f5d2bc0a9ac401fba811917bdfaaf54ce62 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 27 Feb 2006 10:38:56 +0100 Subject: [PATCH] checkpoint --- src/edu/berkeley/obits/AtmelSerial.java | 1 - src/edu/berkeley/obits/Bits.java | 68 ++++ src/edu/berkeley/obits/device/atmel/Wires.java | 24 ++ src/org/ibex/util/Basket.java | 359 ++++++++++++++++++ src/org/ibex/util/Encode.java | 469 ++++++++++++++++++++++++ src/org/ibex/util/Log.java | 244 ++++++++++++ 6 files changed, 1164 insertions(+), 1 deletion(-) create mode 100644 src/edu/berkeley/obits/Bits.java create mode 100644 src/edu/berkeley/obits/device/atmel/Wires.java create mode 100644 src/org/ibex/util/Basket.java create mode 100644 src/org/ibex/util/Encode.java create mode 100644 src/org/ibex/util/Log.java diff --git a/src/edu/berkeley/obits/AtmelSerial.java b/src/edu/berkeley/obits/AtmelSerial.java index 464f0c0..6c3ee4f 100644 --- a/src/edu/berkeley/obits/AtmelSerial.java +++ b/src/edu/berkeley/obits/AtmelSerial.java @@ -2,7 +2,6 @@ package edu.berkeley.obits; import edu.berkeley.obits.device.atmel.*; import org.ibex.util.*; -import org.ibex.graphics.Picture; import java.io.*; import java.util.*; import gnu.io.*; diff --git a/src/edu/berkeley/obits/Bits.java b/src/edu/berkeley/obits/Bits.java new file mode 100644 index 0000000..ee2c6b5 --- /dev/null +++ b/src/edu/berkeley/obits/Bits.java @@ -0,0 +1,68 @@ +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; 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; + } + } + + } + */ +} diff --git a/src/edu/berkeley/obits/device/atmel/Wires.java b/src/edu/berkeley/obits/device/atmel/Wires.java new file mode 100644 index 0000000..283d929 --- /dev/null +++ b/src/edu/berkeley/obits/device/atmel/Wires.java @@ -0,0 +1,24 @@ +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; + +} diff --git a/src/org/ibex/util/Basket.java b/src/org/ibex/util/Basket.java new file mode 100644 index 0000000..baee97c --- /dev/null +++ b/src/org/ibex/util/Basket.java @@ -0,0 +1,359 @@ +// 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 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. + * + *

See C. Radke, Communications of the ACM, 1970, 103-105

+ * + * @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 loadFactor * usedslots > num_slots, call + * rehash(). */ + 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. + * + *

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

+ * + * Default implementation uses indexmultiple == 1, and + * stores only the keys in entries. + */ + 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= 0; } + + /** Warning: This function is equivalent here to + * containsKey(). 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= 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; iuserKey is the key + * passed to the map, storedKey is from the map. + * + *

Default implementation provides standard Java equality + * testing, k1 == null ? k2 == null : k1.equals(k2).

+ */ + protected boolean equals(Object userKey, Object storedKey) { + return userKey == null ? storedKey == null : userKey.equals(storedKey); + } + + /** Returns the array position in entries, adjusted for + * indexmultiple, where k is/should be stored + * using Radke's quadratic residue linear probing. + * + *

entries[0] is a hard coded exception for the null + * key.

+ * + *

If the key is not found, this function returns + * (-1 * indexPosition) - 1, where indexPosition + * is the array position where the mapping should be stored.

+ * + *

Uses placeholder as a placeholder object, and + * compares keys using equals(Object, Object).

+ */ + 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 placeholder references) and if necessary + * by increasing the size of the entries 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 + +} diff --git a/src/org/ibex/util/Encode.java b/src/org/ibex/util/Encode.java new file mode 100644 index 0000000..9d38f73 --- /dev/null +++ b/src/org/ibex/util/Encode.java @@ -0,0 +1,469 @@ +// 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 String and byte[] 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 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; i0) 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>> 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 len 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=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 s.length() 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=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=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 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)); + } + +} -- 1.7.10.4