You are viewing a plain text version of this content. The canonical link for it is here.
Posted to sanselan-commits@incubator.apache.org by cm...@apache.org on 2007/11/29 02:27:15 UTC

svn commit: r599250 [3/15] - in /incubator/sanselan/trunk/src/main/java/org: apache/sanselan/ apache/sanselan/color/ apache/sanselan/common/ apache/sanselan/common/byteSources/ apache/sanselan/common/mylzw/ apache/sanselan/formats/bmp/ apache/sanselan/...

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileFunctions.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileFunctions.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileFunctions.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileFunctions.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,1034 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.RandomAccessFile;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.util.Debug;
+
+public class BinaryFileFunctions implements BinaryConstants
+{
+	protected boolean debug = false;
+
+	public final void setDebug(boolean b)
+	{
+		debug = b;
+	}
+
+	public final boolean getDebug()
+	{
+		return debug;
+	}
+
+	protected final void readRandomBytes(InputStream is)
+			throws ImageReadException, IOException
+	{
+
+		for (int counter = 0; counter < 100; counter++)
+		{
+			readByte("" + counter, is, "Random Data");
+		}
+	}
+
+	public final void debugNumber(String msg, int data)
+	{
+		debugNumber(msg, data, 1);
+	}
+
+	public final void debugNumber(String msg, int data, int bytes)
+	{
+		debugNumber(new PrintWriter(new OutputStreamWriter(System.out)), msg,
+				data, bytes);
+	}
+
+	public final void debugNumber(PrintWriter pw, String msg, int data)
+	{
+		debugNumber(pw, msg, data, 1);
+	}
+
+	public final void debugNumber(PrintWriter pw, String msg, int data,
+			int bytes)
+	{
+		pw.print(msg + ": " + data + " (");
+		int byteData = data;
+		for (int i = 0; i < bytes; i++)
+		{
+			if (i > 0)
+				System.out.print(",");
+			int singleByte = 0xff & byteData;
+			pw.print((char) singleByte + " [" + singleByte + "]");
+			byteData >>= 8;
+		}
+		pw.println(") [0x" + Integer.toHexString(data) + ", "
+				+ Integer.toBinaryString(data) + "]");
+		pw.flush();
+	}
+
+	public final boolean startsWith(byte haystack[], byte needle[])
+	{
+		if (needle == null)
+			return false;
+		if (haystack == null)
+			return false;
+		if (needle.length > haystack.length)
+			return false;
+
+		for (int i = 0; i < needle.length; i++)
+		{
+			if (needle[i] != haystack[i])
+				return false;
+		}
+
+		return true;
+	}
+
+	public final void readAndVerifyBytes(InputStream is, byte expected[],
+			String exception) throws ImageReadException, IOException
+	{
+		for (int i = 0; i < expected.length; i++)
+		{
+			int data = is.read();
+			byte b = (byte) (0xff & data);
+
+			if ((data < 0) || (b != expected[i]))
+			{
+				//				System.out.println("i" + ": " + i);
+
+				this.debugByteArray("expected", expected);
+				debugNumber("data[" + i + "]", b);
+				//				debugNumber("expected[" + i + "]", expected[i]);
+
+				throw new ImageReadException(exception);
+			}
+		}
+	}
+
+	protected final void readAndVerifyBytes(String name, InputStream is,
+			byte expected[], String exception) throws ImageReadException,
+			IOException
+	{
+		byte bytes[] = readByteArray(name, expected.length, is, exception);
+
+		for (int i = 0; i < expected.length; i++)
+		{
+			if (bytes[i] != expected[i])
+			{
+				System.out.println("i" + ": " + i);
+				debugNumber("bytes[" + i + "]", bytes[i]);
+				debugNumber("expected[" + i + "]", expected[i]);
+
+				throw new ImageReadException(exception);
+			}
+		}
+	}
+
+	public final void skipBytes(InputStream is, int length, String exception)
+			throws IOException
+	{
+		long total = 0;
+		while (length != total)
+		{
+			long skipped = is.skip(length - total);
+			if (skipped < 1)
+				throw new IOException(exception + " (" + skipped + ")");
+			total += skipped;
+		}
+	}
+
+	protected final void scanForByte(InputStream is, byte value)
+			throws IOException
+	{
+		int count = 0;
+		for (int i = 0; count < 3; i++)
+		//		while(count<3)
+		{
+			int b = is.read();
+			if (b < 0)
+				return;
+			if ((0xff & b) == value)
+			{
+				System.out.println("\t" + i + ": match.");
+				count++;
+			}
+		}
+	}
+
+	public final byte readByte(String name, InputStream is, String exception)
+			throws ImageReadException, IOException
+	{
+		int result = is.read();
+
+		if ((result < 0))
+		{
+			System.out.println(name + ": " + result);
+			throw new IOException(exception);
+		}
+
+		if (debug)
+			debugNumber(name, result);
+
+		return (byte) (0xff & result);
+	}
+
+	protected final RationalNumber[] convertByteArrayToRationalArray(
+			String name, byte bytes[], int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 8;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		RationalNumber result[] = new RationalNumber[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToRational(name, bytes, start + i * 8,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final RationalNumber convertByteArrayToRational(String name,
+			byte bytes[], int byteOrder)
+	{
+		return convertByteArrayToRational(name, bytes, 0, byteOrder);
+	}
+
+	protected final RationalNumber convertByteArrayToRational(String name,
+			byte bytes[], int start, int byteOrder)
+	{
+		int numerator = convertByteArrayToInt(name, bytes, start + 0, byteOrder);
+		int divisor = convertByteArrayToInt(name, bytes, start + 4, byteOrder);
+
+		return new RationalNumber(numerator, divisor);
+	}
+
+	protected final int convertByteArrayToInt(String name, byte bytes[],
+			int byteOrder)
+	{
+		return convertByteArrayToInt(name, bytes, 0, byteOrder);
+	}
+
+	protected final int convertByteArrayToInt(String name, byte bytes[],
+			int start, int byteOrder)
+	{
+		byte byte0 = bytes[start + 0];
+		byte byte1 = bytes[start + 1];
+		byte byte2 = bytes[start + 2];
+		byte byte3 = bytes[start + 3];
+
+		int result;
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		{
+			result = ((0xff & byte0) << 24) | ((0xff & byte1) << 16)
+					| ((0xff & byte2) << 8) | ((0xff & byte3) << 0);
+		}
+		else
+		{
+			// intel, little endian
+			result = ((0xff & byte3) << 24) | ((0xff & byte2) << 16)
+					| ((0xff & byte1) << 8) | ((0xff & byte0) << 0);
+		}
+
+		if (debug)
+			debugNumber(name, result, 4);
+
+		return result;
+	}
+
+	protected final int[] convertByteArrayToIntArray(String name, byte bytes[],
+			int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 4;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		int result[] = new int[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToInt(name, bytes, start + i * 4,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final void writeIntInToByteArray(int value, byte bytes[],
+			int start, int byteOrder)
+	{
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		{
+			bytes[start + 0] = (byte) (value >> 24);
+			bytes[start + 1] = (byte) (value >> 16);
+			bytes[start + 2] = (byte) (value >> 8);
+			bytes[start + 3] = (byte) (value >> 0);
+		}
+		else
+		{
+			bytes[start + 3] = (byte) (value >> 24);
+			bytes[start + 2] = (byte) (value >> 16);
+			bytes[start + 1] = (byte) (value >> 8);
+			bytes[start + 0] = (byte) (value >> 0);
+		}
+	}
+
+	protected final byte[] convertIntArrayToByteArray(int values[],
+			int byteOrder)
+	{
+		byte result[] = new byte[values.length * 4];
+
+		for (int i = 0; i < values.length; i++)
+		{
+			writeIntInToByteArray(values[i], result, i * 4, byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertShortArrayToByteArray(int values[],
+			int byteOrder)
+	{
+		byte result[] = new byte[values.length * 2];
+
+		for (int i = 0; i < values.length; i++)
+		{
+			int value = values[i];
+
+			if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+			{
+				result[i * 2 + 0] = (byte) (value >> 8);
+				result[i * 2 + 1] = (byte) (value >> 0);
+			}
+			else
+			{
+				result[i * 2 + 1] = (byte) (value >> 8);
+				result[i * 2 + 0] = (byte) (value >> 0);
+			}
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertShortToByteArray(int value, int byteOrder)
+	{
+		byte result[] = new byte[2];
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		{
+			result[0] = (byte) (value >> 8);
+			result[1] = (byte) (value >> 0);
+		}
+		else
+		{
+			result[1] = (byte) (value >> 8);
+			result[0] = (byte) (value >> 0);
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertIntArrayToRationalArray(int numerators[],
+			int denominators[], int byteOrder) throws ImageWriteException
+	{
+		if (numerators.length != denominators.length)
+			throw new ImageWriteException("numerators.length ("
+					+ numerators.length + " != denominators.length ("
+					+ denominators.length + ")");
+
+		byte result[] = new byte[numerators.length * 8];
+
+		for (int i = 0; i < numerators.length; i++)
+		{
+			writeIntInToByteArray(numerators[i], result, i * 8, byteOrder);
+			writeIntInToByteArray(denominators[i], result, i * 8 + 4, byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertRationalArrayToByteArray(
+			RationalNumber numbers[], int byteOrder) throws ImageWriteException
+	{
+		//		Debug.debug("convertRationalArrayToByteArray 2");
+		byte result[] = new byte[numbers.length * 8];
+
+		for (int i = 0; i < numbers.length; i++)
+		{
+			writeIntInToByteArray(numbers[i].numerator, result, i * 8,
+					byteOrder);
+			writeIntInToByteArray(numbers[i].divisor, result, i * 8 + 4,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertRationalToByteArray(RationalNumber number,
+			int byteOrder) throws ImageWriteException
+	{
+		byte result[] = new byte[8];
+
+		writeIntInToByteArray(number.numerator, result, 0, byteOrder);
+		writeIntInToByteArray(number.divisor, result, 4, byteOrder);
+
+		return result;
+	}
+
+	protected final int convertByteArrayToShort(String name, byte bytes[],
+			int byteOrder)
+	{
+		return convertByteArrayToShort(name, 0, bytes, byteOrder);
+	}
+
+	protected final int convertByteArrayToShort(String name, int start,
+			byte bytes[], int byteOrder)
+	{
+		byte byte0 = bytes[start + 0];
+		byte byte1 = bytes[start + 1];
+
+		//		return convert2BytesToShort(name, byte0, byte1, byteOrder);
+
+		int result;
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+			result = ((0xff & byte0) << 8) + ((0xff & byte1) << 0);
+		else
+			// intel, little endian
+			result = ((0xff & byte1) << 8) + ((0xff & byte0) << 0);
+
+		if (debug)
+			debugNumber(name, result, 2);
+
+		return result;
+	}
+
+	protected final int[] convertByteArrayToShortArray(String name,
+			byte bytes[], int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 2;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		int result[] = new int[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToShort(name, start + i * 2, bytes,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	public final byte[] readByteArray(String name, int length, InputStream is,
+			String exception) throws IOException
+	{
+		byte result[] = new byte[length];
+
+		int read = 0;
+		while (read < length)
+		{
+			int count = is.read(result, read, length - read);
+//			Debug.debug("count", count);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		if (debug)
+		{
+			for (int i = 0; ((i < length) && (i < 50)); i++)
+			{
+				debugNumber(name + " (" + i + ")", 0xff & result[i]);
+			}
+		}
+		return result;
+	}
+
+	public final void debugByteArray(String name, byte bytes[])
+	{
+		System.out.println(name + ": " + bytes.length);
+
+		for (int i = 0; ((i < bytes.length) && (i < 50)); i++)
+		{
+			debugNumber("\t" + " (" + i + ")", 0xff & bytes[i]);
+		}
+	}
+
+	protected final void debugNumberArray(String name, int numbers[], int length)
+	{
+		System.out.println(name + ": " + numbers.length);
+
+		for (int i = 0; ((i < numbers.length) && (i < 50)); i++)
+		{
+			debugNumber(name + " (" + i + ")", numbers[i], length);
+		}
+	}
+
+	public final byte[] readBytearray(String name, byte bytes[], int start,
+			int count)
+	{
+		if (bytes.length < (start + count))
+			return null;
+
+		byte result[] = new byte[count];
+		System.arraycopy(bytes, start, result, 0, count);
+
+		if (debug)
+			debugByteArray(name, result);
+
+		return result;
+	}
+
+	protected final byte[] getBytearrayTail(String name, byte bytes[], int count)
+	{
+		return readBytearray(name, bytes, count, bytes.length - count);
+	}
+
+	protected final byte[] getBytearrayHead(String name, byte bytes[], int count)
+	{
+		return readBytearray(name, bytes, 0, bytes.length - count);
+	}
+
+	public final boolean compareByteArrays(byte a[], byte b[])
+	{
+		if (a.length != b.length)
+		{
+			System.out.println("length mismatch: " + a.length + " != "
+					+ b.length);
+			return false;
+		}
+
+		return compareByteArrays(a, 0, b, 0, a.length);
+	}
+
+	public final boolean compareByteArrays(byte a[], int aStart, byte b[],
+			int bStart, int length)
+	{
+		if (a.length < (aStart + length))
+		{
+			return false;
+		}
+		if (b.length < (bStart + length))
+			return false;
+
+		for (int i = 0; i < length; i++)
+		{
+			if (a[aStart + i] != b[bStart + i])
+			{
+				debugNumber("\t" + "a[" + (aStart + i) + "]", a[aStart + i]);
+				debugNumber("\t" + "b[" + (bStart + i) + "]", b[bStart + i]);
+
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	protected final int read4Bytes(String name, InputStream is,
+			String exception, int byteOrder) throws ImageReadException,
+			IOException
+	{
+		int size = 4;
+		byte bytes[] = new byte[size];
+
+		int read = 0;
+		while (read < size)
+		{
+			int count = is.read(bytes, read, size - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		return convertByteArrayToInt(name, bytes, byteOrder);
+	}
+
+	protected final int read3Bytes(String name, InputStream is,
+			String exception, int byteOrder) throws ImageReadException,
+			IOException
+	{
+		byte byte0 = (byte) is.read();
+		byte byte1 = (byte) is.read();
+		byte byte2 = (byte) is.read();
+
+		int result;
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+			result = ((0xff & byte0) << 16) | ((0xff & byte1) << 8)
+					| ((0xff & byte2) << 0);
+		else
+			// intel, little endian
+			result = ((0xff & byte2) << 16) | ((0xff & byte1) << 8)
+					| ((0xff & byte0) << 0);
+
+		if (debug)
+			debugNumber(name, result, 3);
+
+		return result;
+		//		
+		//		
+		//		int size = 3;
+		//		byte bytes[] = new byte[size];
+		//
+		//		int read = 0;
+		//		while (read < size)
+		//		{
+		//			int count = is.read(bytes, read, size - read);
+		//			if (count < 1)
+		//				throw new IOException(exception);
+		//
+		//			read += count;
+		//		}
+		//
+		//		return convertByteArrayToInt(name, bytes, 0, 3, byteOrder);
+	}
+
+	protected final int read2Bytes(String name, InputStream is,
+			String exception, int byteOrder) throws ImageReadException,
+			IOException
+	{
+		int size = 2;
+		byte bytes[] = new byte[size];
+
+		int read = 0;
+		while (read < size)
+		{
+			int count = is.read(bytes, read, size - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		return convertByteArrayToShort(name, bytes, byteOrder);
+	}
+
+	protected final void printCharQuad(String msg, int i)
+	{
+		System.out.println(msg + ": '" + (char) (0xff & (i >> 24))
+				+ (char) (0xff & (i >> 16)) + (char) (0xff & (i >> 8))
+				+ (char) (0xff & (i >> 0)) + "'");
+
+	}
+
+	protected final void printCharQuad(PrintWriter pw, String msg, int i)
+	{
+		pw.println(msg + ": '" + (char) (0xff & (i >> 24))
+				+ (char) (0xff & (i >> 16)) + (char) (0xff & (i >> 8))
+				+ (char) (0xff & (i >> 0)) + "'");
+
+	}
+
+	protected final void printByteBits(String msg, byte i)
+	{
+		System.out.println(msg + ": '" + Integer.toBinaryString(0xff & i));
+	}
+
+	public final static int CharsToQuad(char c1, char c2, char c3, char c4)
+	{
+		return (((0xff & c1) << 24) | ((0xff & c2) << 16) | ((0xff & c3) << 8) | ((0xff & c4) << 0));
+	}
+
+	public final int findNull(byte src[])
+	{
+		return findNull(src, 0);
+	}
+
+	public final int findNull(byte src[], int start)
+	{
+		for (int i = start; i < src.length; i++)
+		{
+			if (src[i] == 0)
+				return i;
+
+		}
+		return -1;
+	}
+
+	protected final byte[] getRAFBytes(RandomAccessFile raf, long pos,
+			int length, String exception) throws IOException
+	{
+		if (debug)
+		{
+			System.out.println("getRAFBytes pos" + ": " + pos);
+			System.out.println("getRAFBytes length" + ": " + length);
+		}
+
+		byte result[] = new byte[length];
+
+		raf.seek(pos);
+
+		int read = 0;
+		while (read < length)
+		{
+			int count = raf.read(result, read, length - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		return result;
+
+	}
+
+	protected final float convertByteArrayToFloat(String name, byte bytes[],
+			int byteOrder)
+	{
+		return convertByteArrayToFloat(name, bytes, 0, byteOrder);
+	}
+
+	protected final float convertByteArrayToFloat(String name, byte bytes[],
+			int start, int byteOrder)
+	{
+		// TODO: not tested; probably wrong.
+
+		byte byte0 = bytes[start + 0];
+		byte byte1 = bytes[start + 1];
+		byte byte2 = bytes[start + 2];
+		byte byte3 = bytes[start + 3];
+
+		int bits;
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		{
+			bits = ((0xff & byte0) << 24) | ((0xff & byte1) << 16)
+					| ((0xff & byte2) << 8) | ((0xff & byte3) << 0);
+		}
+		else
+		{
+			// intel, little endian
+			bits = ((0xff & byte3) << 24) | ((0xff & byte2) << 16)
+					| ((0xff & byte1) << 8) | ((0xff & byte0) << 0);
+		}
+
+		float result = Float.intBitsToFloat(bits);
+
+		//		if (debug)
+		//			debugNumber(name, result, 4);
+
+		return result;
+	}
+
+	protected final float[] convertByteArrayToFloatArray(String name,
+			byte bytes[], int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 4;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		float result[] = new float[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToFloat(name, bytes, start + i * 4,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertFloatToByteArray(float value, int byteOrder)
+	{
+		// TODO: not tested; probably wrong.
+		byte result[] = new byte[4];
+
+		int bits = Float.floatToRawIntBits(value);
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		{
+			result[0] = (byte) (0xff & (bits >> 0));
+			result[1] = (byte) (0xff & (bits >> 8));
+			result[2] = (byte) (0xff & (bits >> 16));
+			result[3] = (byte) (0xff & (bits >> 24));
+		}
+		else
+		{
+			result[3] = (byte) (0xff & (bits >> 0));
+			result[2] = (byte) (0xff & (bits >> 8));
+			result[1] = (byte) (0xff & (bits >> 16));
+			result[0] = (byte) (0xff & (bits >> 24));
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertFloatArrayToByteArray(float values[],
+			int byteOrder)
+	{
+		// TODO: not tested; probably wrong.
+		byte result[] = new byte[values.length * 4];
+		for (int i = 0; i < values.length; i++)
+		{
+			float value = values[i];
+			int bits = Float.floatToRawIntBits(value);
+
+			int start = i * 4;
+			if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+			{
+				result[start + 0] = (byte) (0xff & (bits >> 0));
+				result[start + 1] = (byte) (0xff & (bits >> 8));
+				result[start + 2] = (byte) (0xff & (bits >> 16));
+				result[start + 3] = (byte) (0xff & (bits >> 24));
+			}
+			else
+			{
+				result[start + 3] = (byte) (0xff & (bits >> 0));
+				result[start + 2] = (byte) (0xff & (bits >> 8));
+				result[start + 1] = (byte) (0xff & (bits >> 16));
+				result[start + 0] = (byte) (0xff & (bits >> 24));
+			}
+		}
+		return result;
+	}
+
+	protected final byte[] convertDoubleToByteArray(double value, int byteOrder)
+	{
+		// TODO: not tested; probably wrong.
+		byte result[] = new byte[8];
+
+		long bits = Double.doubleToRawLongBits(value);
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		{
+			result[0] = (byte) (0xff & (bits >> 0));
+			result[1] = (byte) (0xff & (bits >> 8));
+			result[2] = (byte) (0xff & (bits >> 16));
+			result[3] = (byte) (0xff & (bits >> 24));
+			result[4] = (byte) (0xff & (bits >> 32));
+			result[5] = (byte) (0xff & (bits >> 40));
+			result[6] = (byte) (0xff & (bits >> 48));
+			result[7] = (byte) (0xff & (bits >> 56));
+		}
+		else
+		{
+			result[7] = (byte) (0xff & (bits >> 0));
+			result[6] = (byte) (0xff & (bits >> 8));
+			result[5] = (byte) (0xff & (bits >> 16));
+			result[4] = (byte) (0xff & (bits >> 24));
+			result[3] = (byte) (0xff & (bits >> 32));
+			result[2] = (byte) (0xff & (bits >> 40));
+			result[1] = (byte) (0xff & (bits >> 48));
+			result[0] = (byte) (0xff & (bits >> 56));
+		}
+
+		return result;
+	}
+
+	protected final byte[] convertDoubleArrayToByteArray(double values[],
+			int byteOrder)
+	{
+		// TODO: not tested; probably wrong.
+		byte result[] = new byte[values.length * 8];
+		for (int i = 0; i < values.length; i++)
+		{
+			double value = values[i];
+			long bits = Double.doubleToRawLongBits(value);
+
+			int start = i * 8;
+			if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+			{
+				result[start + 0] = (byte) (0xff & (bits >> 0));
+				result[start + 1] = (byte) (0xff & (bits >> 8));
+				result[start + 2] = (byte) (0xff & (bits >> 16));
+				result[start + 3] = (byte) (0xff & (bits >> 24));
+				result[start + 4] = (byte) (0xff & (bits >> 32));
+				result[start + 5] = (byte) (0xff & (bits >> 40));
+				result[start + 6] = (byte) (0xff & (bits >> 48));
+				result[start + 7] = (byte) (0xff & (bits >> 56));
+			}
+			else
+			{
+				result[start + 7] = (byte) (0xff & (bits >> 0));
+				result[start + 6] = (byte) (0xff & (bits >> 8));
+				result[start + 5] = (byte) (0xff & (bits >> 16));
+				result[start + 4] = (byte) (0xff & (bits >> 24));
+				result[start + 3] = (byte) (0xff & (bits >> 32));
+				result[start + 2] = (byte) (0xff & (bits >> 40));
+				result[start + 1] = (byte) (0xff & (bits >> 48));
+				result[start + 0] = (byte) (0xff & (bits >> 56));
+			}
+		}
+		return result;
+	}
+
+	protected final double convertByteArrayToDouble(String name, byte bytes[],
+			int byteOrder)
+	{
+		return convertByteArrayToDouble(name, bytes, 0, byteOrder);
+	}
+
+	protected final double convertByteArrayToDouble(String name, byte bytes[],
+			int start, int byteOrder)
+	{
+		// TODO: not tested; probably wrong.
+
+		byte byte0 = bytes[start + 0];
+		byte byte1 = bytes[start + 1];
+		byte byte2 = bytes[start + 2];
+		byte byte3 = bytes[start + 3];
+		byte byte4 = bytes[start + 4];
+		byte byte5 = bytes[start + 5];
+		byte byte6 = bytes[start + 6];
+		byte byte7 = bytes[start + 7];
+
+		long bits;
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		{
+			bits = ((0xff & byte0) << 56) | ((0xff & byte1) << 48)
+					| ((0xff & byte2) << 40) | ((0xff & byte3) << 32)
+					| ((0xff & byte4) << 24) | ((0xff & byte5) << 16)
+					| ((0xff & byte6) << 8) | ((0xff & byte7) << 0);
+
+		}
+		else
+		{
+			// intel, little endian
+			bits = ((0xff & byte7) << 56) | ((0xff & byte6) << 48)
+					| ((0xff & byte5) << 40) | ((0xff & byte4) << 32)
+					| ((0xff & byte3) << 24) | ((0xff & byte2) << 16)
+					| ((0xff & byte1) << 8) | ((0xff & byte0) << 0);
+		}
+
+		double result = Double.longBitsToDouble(bits);
+
+		//		if (debug)
+		//			debugNumber(name, result, 4);
+
+		return result;
+
+		//		byte array[];
+		//		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+		//			//			 ?? dunno byte order very likely wrong here.
+		//			array = new byte[]{
+		//					bytes[start + 0], bytes[start + 1], bytes[start + 2],
+		//					bytes[start + 3], bytes[start + 4], bytes[start + 5],
+		//					bytes[start + 6], bytes[start + 7],
+		//
+		//			};
+		//		else
+		//			// ?? dunno byte order very likely wrong here.
+		//			array = new byte[]{
+		//					bytes[start + 3], bytes[start + 2], bytes[start + 1],
+		//					bytes[start + 0], bytes[start + 7], bytes[start + 6],
+		//					bytes[start + 5], bytes[start + 4],
+		//			};
+		//
+		//		double result = Double.NaN;
+		//
+		//		try
+		//		{
+		//			ByteArrayInputStream bais = new ByteArrayInputStream(array);
+		//			if (start > 0)
+		//			{
+		//				skipBytes(bais, start);
+		//				//				bais.skip(start);
+		//			}
+		//			DataInputStream dis = new DataInputStream(bais);
+		//			result = dis.readDouble();
+		//
+		//			dis.close();
+		//		}
+		//		catch (Exception e)
+		//		{
+		//			Debug.debug(e);
+		//		}
+		//
+		//		return result;
+	}
+
+	protected final double[] convertByteArrayToDoubleArray(String name,
+			byte bytes[], int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 8;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		double result[] = new double[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToDouble(name, bytes, start + i * 8,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	protected void skipBytes(InputStream is, int length) throws IOException
+	{
+		this.skipBytes(is, length, "Couldn't skip bytes");
+	}
+
+	public final void copyStreamToStream(InputStream is, OutputStream os)
+			throws IOException
+	{
+		byte buffer[] = new byte[1024];
+		int read;
+		while ((read = is.read(buffer)) > 0)
+		{
+			os.write(buffer, 0, read);
+		}
+	}
+
+	public final byte[] getStreamBytes(InputStream is) throws IOException
+	{
+		ByteArrayOutputStream os = new ByteArrayOutputStream();
+		copyStreamToStream(is, os);
+		return os.toByteArray();
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileFunctions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileParser.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileParser.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+
+public class BinaryFileParser extends BinaryFileFunctions
+{
+	public BinaryFileParser(int byteOrder)
+	{
+		this.byteOrder = byteOrder;
+	}
+
+	public BinaryFileParser()
+	{
+
+	}
+
+	// default byte order for Java, many file formats.
+	private int byteOrder = BYTE_ORDER_NETWORK;
+
+	//	protected boolean BYTE_ORDER_reversed = true;
+
+	protected void setByteOrder(int a, int b) throws ImageReadException,
+			IOException
+	{
+		if (a != b)
+			throw new ImageReadException("Byte Order bytes don't match (" + a
+					+ ", " + b + ").");
+
+		if (a == BYTE_ORDER_MOTOROLA)
+			byteOrder = a;
+		else if (a == BYTE_ORDER_INTEL)
+			byteOrder = a;
+		else
+			throw new ImageReadException("Unknown Byte Order hint: " + a);
+	}
+
+	protected void setByteOrder(int byteOrder)
+	{
+		this.byteOrder = byteOrder;
+	}
+
+	protected int getByteOrder()
+	{
+		return byteOrder;
+	}
+
+	protected final int convertByteArrayToInt(String name, byte bytes[])
+	{
+		return convertByteArrayToInt(name, bytes, byteOrder);
+	}
+
+	public final int convertByteArrayToShort(String name, byte bytes[])
+	{
+		return convertByteArrayToShort(name, bytes, byteOrder);
+	}
+
+	public final int convertByteArrayToShort(String name, int start,
+			byte bytes[])
+	{
+		return convertByteArrayToShort(name, start, bytes, byteOrder);
+	}
+
+	public final int read4Bytes(String name, InputStream is, String exception)
+			throws ImageReadException, IOException
+	{
+		return read4Bytes(name, is, exception, byteOrder);
+	}
+
+	public final int read3Bytes(String name, InputStream is, String exception)
+			throws ImageReadException, IOException
+	{
+		return read3Bytes(name, is, exception, byteOrder);
+	}
+
+	public final int read2Bytes(String name, InputStream is, String exception)
+			throws ImageReadException, IOException
+	{
+		return read2Bytes(name, is, exception, byteOrder);
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryFileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryInputStream.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryInputStream.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryInputStream.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryInputStream.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,608 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+
+import org.apache.sanselan.ImageReadException;
+
+public class BinaryInputStream extends InputStream implements BinaryConstants
+{
+	protected boolean debug = false;
+
+	public final void setDebug(boolean b)
+	{
+		debug = b;
+	}
+
+	public final boolean getDebug()
+	{
+		return debug;
+	}
+
+	private final InputStream is;
+
+	public BinaryInputStream(InputStream is, int byteOrder)
+	{
+		this.byteOrder = byteOrder;
+		this.is = is;
+	}
+
+	public BinaryInputStream(InputStream is)
+	{
+		this.is = is;
+	}
+
+	// default byte order for Java, many file formats.
+	private int byteOrder = BYTE_ORDER_NETWORK;
+
+	protected void setByteOrder(int a, int b) throws ImageReadException,
+			IOException
+	{
+		if (a != b)
+			throw new ImageReadException("Byte Order bytes don't match (" + a
+					+ ", " + b + ").");
+
+		if (a == BYTE_ORDER_MOTOROLA)
+			byteOrder = a;
+		else if (a == BYTE_ORDER_INTEL)
+			byteOrder = a;
+		else
+			throw new ImageReadException("Unknown Byte Order hint: " + a);
+	}
+
+	protected void setByteOrder(int byteOrder)
+	{
+		this.byteOrder = byteOrder;
+	}
+
+	protected int getByteOrder()
+	{
+		return byteOrder;
+	}
+
+	public int read() throws IOException
+	{
+		return is.read();
+	}
+
+	protected final int convertByteArrayToInt(String name, byte bytes[])
+	{
+		return convertByteArrayToInt(name, bytes, byteOrder);
+	}
+
+	public final int convertByteArrayToShort(String name, byte bytes[])
+	{
+		return convertByteArrayToShort(name, bytes, byteOrder);
+	}
+
+	public final int convertByteArrayToShort(String name, int start,
+			byte bytes[])
+	{
+		return convertByteArrayToShort(name, start, bytes, byteOrder);
+	}
+
+	public final int read4Bytes(String name, String exception)
+			throws ImageReadException, IOException
+	{
+		return read4Bytes(name, exception, byteOrder);
+	}
+
+	public final int read3Bytes(String name, String exception)
+			throws ImageReadException, IOException
+	{
+		return read3Bytes(name, exception, byteOrder);
+	}
+
+	public final int read2Bytes(String name, String exception)
+			throws ImageReadException, IOException
+	{
+		return read2Bytes(name, exception, byteOrder);
+	}
+
+	protected final void readRandomBytes() throws ImageReadException,
+			IOException
+	{
+
+		for (int counter = 0; counter < 100; counter++)
+		{
+			readByte("" + counter, "Random Data");
+		}
+	}
+
+	public final void debugNumber(String msg, int data)
+	{
+		debugNumber(msg, data, 1);
+	}
+
+	public final void debugNumber(String msg, int data, int bytes)
+	{
+		System.out.print(msg + ": " + data + " (");
+		int byteData = data;
+		for (int i = 0; i < bytes; i++)
+		{
+			if (i > 0)
+				System.out.print(",");
+			int singleByte = 0xff & byteData;
+			System.out.print((char) singleByte + " [" + singleByte + "]");
+			byteData >>= 8;
+		}
+		System.out.println(") [0x" + Integer.toHexString(data) + ", "
+				+ Integer.toBinaryString(data) + "]");
+	}
+
+	public final void readAndVerifyBytes(byte expected[], String exception)
+			throws ImageReadException, IOException
+	{
+		for (int i = 0; i < expected.length; i++)
+		{
+			int data = is.read();
+			byte b = (byte) (0xff & data);
+
+			if ((data < 0) || (b != expected[i]))
+			{
+				System.out.println("i" + ": " + i);
+
+				this.debugByteArray("expected", expected);
+				debugNumber("data[" + i + "]", b);
+				//				debugNumber("expected[" + i + "]", expected[i]);
+
+				throw new ImageReadException(exception);
+			}
+		}
+	}
+
+	protected final void readAndVerifyBytes(String name, byte expected[],
+			String exception) throws ImageReadException, IOException
+	{
+		byte bytes[] = readByteArray(name, expected.length, exception);
+
+		for (int i = 0; i < expected.length; i++)
+		{
+			if (bytes[i] != expected[i])
+			{
+				System.out.println("i" + ": " + i);
+				debugNumber("bytes[" + i + "]", bytes[i]);
+				debugNumber("expected[" + i + "]", expected[i]);
+
+				throw new ImageReadException(exception);
+			}
+		}
+	}
+
+	public final void skipBytes(int length, String exception)
+			throws IOException
+	{
+		long total = 0;
+		while (length != total)
+		{
+			long skipped = is.skip(length - total);
+			if (skipped < 1)
+				throw new IOException(exception + " (" + skipped + ")");
+			total += skipped;
+		}
+	}
+
+	protected final void scanForByte(byte value) throws IOException
+	{
+		int count = 0;
+		for (int i = 0; count < 3; i++)
+		//		while(count<3)
+		{
+			int b = is.read();
+			if (b < 0)
+				return;
+			if ((0xff & b) == value)
+			{
+				System.out.println("\t" + i + ": match.");
+				count++;
+			}
+		}
+	}
+
+	public final byte readByte(String name, String exception)
+			throws IOException
+	{
+		int result = is.read();
+
+		if ((result < 0))
+		{
+			System.out.println(name + ": " + result);
+			throw new IOException(exception);
+		}
+
+		if (debug)
+			debugNumber(name, result);
+
+		return (byte) (0xff & result);
+	}
+
+	protected final RationalNumber[] convertByteArrayToRationalArray(
+			String name, byte bytes[], int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 8;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		RationalNumber result[] = new RationalNumber[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToRational(name, bytes, start + i * 8,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final RationalNumber convertByteArrayToRational(String name,
+			byte bytes[], int byteOrder)
+	{
+		return convertByteArrayToRational(name, bytes, 0, byteOrder);
+	}
+
+	protected final RationalNumber convertByteArrayToRational(String name,
+			byte bytes[], int start, int byteOrder)
+	{
+		int numerator = convertByteArrayToInt(name, bytes, start + 0, 4,
+				byteOrder);
+		int divisor = convertByteArrayToInt(name, bytes, start + 4, 4,
+				byteOrder);
+
+		return new RationalNumber(numerator, divisor);
+	}
+
+	protected final int convertByteArrayToInt(String name, byte bytes[],
+			int byteOrder)
+	{
+		return convertByteArrayToInt(name, bytes, 0, 4, byteOrder);
+	}
+
+	protected final int convertByteArrayToInt(String name, byte bytes[],
+			int start, int length, int byteOrder)
+	{
+		byte byte0 = bytes[start + 0];
+		byte byte1 = bytes[start + 1];
+		byte byte2 = bytes[start + 2];
+		byte byte3 = 0;
+		if (length == 4)
+			byte3 = bytes[start + 3];
+
+		//		return convert4BytesToInt(name, byte0, byte1, byte2, byte3, byteOrder);
+
+		int result;
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+			result = ((0xff & byte0) << 24) + ((0xff & byte1) << 16)
+					+ ((0xff & byte2) << 8) + ((0xff & byte3) << 0);
+		//		result = (( byte0) << 24) + ((byte1) << 16)
+		//		+ (( byte2) << 8) + (( byte3) << 0);
+		else
+			// intel, little endian
+			result = ((0xff & byte3) << 24) + ((0xff & byte2) << 16)
+					+ ((0xff & byte1) << 8) + ((0xff & byte0) << 0);
+		//		result = (( byte3) << 24) + (( byte2) << 16)
+		//		+ (( byte1) << 8) + (( byte0) << 0);
+
+		if (debug)
+			debugNumber(name, result, 4);
+
+		return result;
+	}
+
+	protected final int[] convertByteArrayToIntArray(String name, byte bytes[],
+			int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 4;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		int result[] = new int[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToInt(name, bytes, start + i * 4, 4,
+					byteOrder);
+		}
+
+		return result;
+	}
+
+	protected final int convertByteArrayToShort(String name, byte bytes[],
+			int byteOrder)
+	{
+		return convertByteArrayToShort(name, 0, bytes, byteOrder);
+	}
+
+	protected final int convertByteArrayToShort(String name, int start,
+			byte bytes[], int byteOrder)
+	{
+		byte byte0 = bytes[start + 0];
+		byte byte1 = bytes[start + 1];
+
+		//		return convert2BytesToShort(name, byte0, byte1, byteOrder);
+
+		int result;
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian
+			result = ((0xff & byte0) << 8) + ((0xff & byte1) << 0);
+		else
+			// intel, little endian
+			result = ((0xff & byte1) << 8) + ((0xff & byte0) << 0);
+
+		if (debug)
+			debugNumber(name, result, 2);
+
+		return result;
+	}
+
+	protected final int[] convertByteArrayToShortArray(String name,
+			byte bytes[], int start, int length, int byteOrder)
+	{
+		int expectedLength = start + length * 2;
+
+		if (bytes.length < expectedLength)
+		{
+			System.out.println(name + ": expected length: " + expectedLength
+					+ ", actual length: " + bytes.length);
+			return null;
+		}
+
+		int result[] = new int[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			result[i] = convertByteArrayToShort(name, start + i * 2, bytes,
+					byteOrder);
+
+			//			byte byte0 = bytes[start + i * 2];
+			//			byte byte1 = bytes[start + i * 2 + 1];
+			//			result[i] = convertBytesToShort(name, byte0, byte1, byteOrder);
+		}
+
+		return result;
+	}
+
+	public final byte[] readByteArray(String name, int length, String exception)
+			throws ImageReadException, IOException
+	{
+		byte result[] = new byte[length];
+
+		int read = 0;
+		while (read < length)
+		{
+			int count = is.read(result, read, length - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		if (debug)
+		{
+			for (int i = 0; ((i < length) && (i < 150)); i++)
+			{
+				debugNumber(name + " (" + i + ")", 0xff & result[i]);
+			}
+		}
+		return result;
+	}
+
+	protected final void debugByteArray(String name, byte bytes[])
+	{
+		System.out.println(name + ": " + bytes.length);
+
+		for (int i = 0; ((i < bytes.length) && (i < 50)); i++)
+		{
+			debugNumber(name + " (" + i + ")", bytes[i]);
+		}
+	}
+
+	protected final void debugNumberArray(String name, int numbers[], int length)
+	{
+		System.out.println(name + ": " + numbers.length);
+
+		for (int i = 0; ((i < numbers.length) && (i < 50)); i++)
+		{
+			debugNumber(name + " (" + i + ")", numbers[i], length);
+		}
+	}
+
+	public final byte[] readBytearray(String name, byte bytes[], int start,
+			int count)
+	{
+		if (bytes.length < (start + count))
+			return null;
+
+		byte result[] = new byte[count];
+		System.arraycopy(bytes, start, result, 0, count);
+
+		if (debug)
+			debugByteArray(name, result);
+
+		return result;
+	}
+
+	protected final byte[] getBytearrayTail(String name, byte bytes[], int count)
+	{
+		return readBytearray(name, bytes, count, bytes.length - count);
+	}
+
+	protected final byte[] getBytearrayHead(String name, byte bytes[], int count)
+	{
+		return readBytearray(name, bytes, 0, bytes.length - count);
+	}
+
+	public final boolean compareByteArrays(byte a[], int aStart, byte b[],
+			int bStart, int length)
+	{
+		if (a.length < (aStart + length))
+			return false;
+		if (b.length < (bStart + length))
+			return false;
+
+		for (int i = 0; i < length; i++)
+		{
+			if (a[aStart + i] != b[bStart + i])
+			{
+				debugNumber("a[" + (aStart + i) + "]", a[aStart + i]);
+				debugNumber("b[" + (bStart + i) + "]", b[bStart + i]);
+
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	protected final int read4Bytes(String name, String exception, int byteOrder)
+			throws ImageReadException, IOException
+	{
+		int size = 4;
+		byte bytes[] = new byte[size];
+
+		int read = 0;
+		while (read < size)
+		{
+			int count = is.read(bytes, read, size - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		return convertByteArrayToInt(name, bytes, byteOrder);
+	}
+
+	protected final int read3Bytes(String name, String exception, int byteOrder)
+			throws ImageReadException, IOException
+	{
+		int size = 3;
+		byte bytes[] = new byte[size];
+
+		int read = 0;
+		while (read < size)
+		{
+			int count = is.read(bytes, read, size - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		return convertByteArrayToInt(name, bytes, 0, 3, byteOrder);
+
+	}
+
+	protected final int read2Bytes(String name, String exception, int byteOrder)
+			throws ImageReadException, IOException
+	{
+		int size = 2;
+		byte bytes[] = new byte[size];
+
+		int read = 0;
+		while (read < size)
+		{
+			int count = is.read(bytes, read, size - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		return convertByteArrayToShort(name, bytes, byteOrder);
+	}
+
+	protected final void printCharQuad(String msg, int i)
+	{
+		System.out.println(msg + ": '" + (char) (0xff & (i >> 24))
+				+ (char) (0xff & (i >> 16)) + (char) (0xff & (i >> 8))
+				+ (char) (0xff & (i >> 0)) + "'");
+
+	}
+
+	protected final void printByteBits(String msg, byte i)
+	{
+		System.out.println(msg + ": '" + Integer.toBinaryString(0xff & i));
+	}
+
+	protected final static int CharsToQuad(char c1, char c2, char c3, char c4)
+	{
+		return (((0xff & c1) << 24) | ((0xff & c2) << 16) | ((0xff & c3) << 8) | ((0xff & c4) << 0));
+	}
+
+	public final int findNull(byte src[])
+	{
+		return findNull(src, 0);
+	}
+
+	public final int findNull(byte src[], int start)
+	{
+		for (int i = start; i < src.length; i++)
+		{
+			if (src[i] == 0)
+				return i;
+
+		}
+		return -1;
+	}
+
+	protected final byte[] getRAFBytes(RandomAccessFile raf, long pos,
+			int length, String exception) throws IOException
+	{
+		byte result[] = new byte[length];
+
+		if (debug)
+		{
+			System.out.println("getRAFBytes pos" + ": " + pos);
+			System.out.println("getRAFBytes length" + ": " + length);
+		}
+
+		raf.seek(pos);
+
+		int read = 0;
+		while (read < length)
+		{
+			int count = raf.read(result, read, length - read);
+			if (count < 1)
+				throw new IOException(exception);
+
+			read += count;
+		}
+
+		return result;
+
+	}
+
+	protected void skipBytes(int length) throws IOException
+	{
+		skipBytes(length, "Couldn't skip bytes");
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryOutputStream.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryOutputStream.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryOutputStream.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryOutputStream.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.sanselan.ImageWriteException;
+
+public class BinaryOutputStream extends OutputStream implements BinaryConstants
+{
+	protected boolean debug = false;
+
+	public final void setDebug(boolean b)
+	{
+		debug = b;
+	}
+
+	public final boolean getDebug()
+	{
+		return debug;
+	}
+
+	private final OutputStream os;
+
+	public BinaryOutputStream(OutputStream os, int byteOrder)
+	{
+		this.byteOrder = byteOrder;
+		this.os = os;
+	}
+
+	public BinaryOutputStream(OutputStream os)
+	{
+		this.os = os;
+	}
+
+	// default byte order for Java, many file formats.
+	private int byteOrder = BYTE_ORDER_NETWORK;
+
+	protected void setByteOrder(int a, int b) throws ImageWriteException,
+			IOException
+	{
+		if (a != b)
+			throw new ImageWriteException("Byte Order bytes don't match (" + a
+					+ ", " + b + ").");
+
+		if (a == BYTE_ORDER_MOTOROLA)
+			byteOrder = a;
+		else if (a == BYTE_ORDER_INTEL)
+			byteOrder = a;
+		else
+			throw new ImageWriteException("Unknown Byte Order hint: " + a);
+	}
+
+	protected void setByteOrder(int byteOrder)
+	{
+		this.byteOrder = byteOrder;
+	}
+
+	protected int getByteOrder()
+	{
+		return byteOrder;
+	}
+
+	public void write(int i) throws IOException
+	{
+		//		os.write(0xff & i); // unnecessary
+		os.write(i);
+	}
+
+	public final void write4Bytes(int value) throws ImageWriteException,
+			IOException
+	{
+		writeNBytes(value, 4);
+	}
+
+	public final void write3Bytes(int value) throws ImageWriteException,
+			IOException
+	{
+		writeNBytes(value, 3);
+	}
+
+	public final void write2Bytes(int value) throws ImageWriteException,
+			IOException
+	{
+		writeNBytes(value, 2);
+	}
+
+	public final void writeByteArray(byte bytes[]) throws IOException
+	{
+		os.write(bytes, 0, bytes.length);
+	}
+
+	private byte[] convertValueToByteArray(int value, int n)
+	{
+		byte result[] = new byte[n];
+
+		if (byteOrder == BYTE_ORDER_MOTOROLA)
+		{
+			for (int i = 0; i < n; i++)
+			{
+				int b = 0xff & (value >> (8 * (n - i - 1)));
+				result[i] = (byte) b;
+			}
+		}
+		else
+		{
+			for (int i = 0; i < n; i++)
+			{
+				int b = 0xff & (value >> (8 * i));
+				result[i] = (byte) b;
+			}
+		}
+
+		return result;
+	}
+
+	private final void writeNBytes(int value, int n)
+			throws ImageWriteException, IOException
+	{
+		write(convertValueToByteArray(value, n));
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BinaryOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStream.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStream.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStream.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStream.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class BitInputStream extends InputStream implements BinaryConstants
+{
+	// TODO should be byte order conscious, ie TIFF for reading 
+	// samples size<8 - shuoldn't that effect their order within byte?
+	private final InputStream is;
+
+	public BitInputStream(InputStream is)
+	{
+		this.is = is;
+		//			super(is);
+	}
+
+	public int read() throws IOException
+	{
+		if (cacheBitsRemaining > 0)
+			throw new IOException("BitInputStream: incomplete bit read");
+		return is.read();
+	}
+
+	private int cache;
+	private int cacheBitsRemaining = 0;
+	private long bytes_read = 0;
+
+	public final int readBits(int count) throws IOException
+	{
+		if (count < 8)
+		{
+			if (cacheBitsRemaining == 0)
+			{
+				// fill cache
+				cache = is.read();
+				cacheBitsRemaining = 8;
+				bytes_read++;
+			}
+			if (count > cacheBitsRemaining)
+				throw new IOException(
+						"BitInputStream: can't read bit fields across bytes");
+
+			//				int bits_to_shift = cache_bits_remaining - count;
+			cacheBitsRemaining -= count;
+			int bits = cache >> cacheBitsRemaining;
+
+			switch (count)
+			{
+				case 1 :
+					return bits & 1;
+				case 2 :
+					return bits & 3;
+				case 3 :
+					return bits & 7;
+				case 4 :
+					return bits & 15;
+				case 5 :
+					return bits & 31;
+				case 6 :
+					return bits & 63;
+				case 7 :
+					return bits & 127;
+			}
+
+		}
+		if (cacheBitsRemaining > 0)
+			throw new IOException("BitInputStream: incomplete bit read");
+
+		if (count == 8)
+		{
+			bytes_read++;
+			return is.read();
+		}
+
+		if (count == 16)
+		{
+			bytes_read += 2;
+			return (is.read() << 8) | (is.read() << 0);
+		}
+
+		if (count == 24)
+		{
+			bytes_read += 3;
+			return (is.read() << 16) | (is.read() << 8) | (is.read() << 0);
+		}
+
+		if (count == 32)
+		{
+			bytes_read += 4;
+			return (is.read() << 24) | (is.read() << 16) | (is.read() << 8)
+					| (is.read() << 0);
+		}
+
+		throw new IOException("BitInputStream: unknown error");
+	}
+
+	public void flushCache()
+	{
+		cacheBitsRemaining = 0;
+	}
+
+	public long getBytesRead()
+	{
+		return bytes_read;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class BitInputStreamFlexible extends InputStream
+		implements
+			BinaryConstants
+{
+	// TODO should be byte order conscious, ie TIFF for reading 
+	// samples size<8 - shuoldn't that effect their order within byte?
+	private final InputStream is;
+
+	public BitInputStreamFlexible(InputStream is)
+	{
+		this.is = is;
+		//			super(is);
+	}
+
+	public int read() throws IOException
+	{
+		if (cacheBitsRemaining > 0)
+			throw new IOException("BitInputStream: incomplete bit read");
+		return is.read();
+	}
+
+	private int cache;
+	private int cacheBitsRemaining = 0;
+	private long bytesRead = 0;
+
+	public final int readBits(int count) throws IOException
+	{
+
+		if (count <= 32) // catch-all
+		{
+			int result = 0;
+			//			int done = 0;
+
+			if (cacheBitsRemaining > 0)
+			{
+				if (count >= cacheBitsRemaining)
+				{
+					result = ((1 << cacheBitsRemaining) - 1) & cache;
+					count -= cacheBitsRemaining;
+					cacheBitsRemaining = 0;
+				}
+				else
+				{
+					//					cache >>= count;
+					cacheBitsRemaining -= count;
+					result = ((1 << count) - 1)
+							& (cache >> cacheBitsRemaining);
+					count = 0;
+				}
+			}
+			while (count >= 8)
+			{
+				cache = is.read();
+				if (cache < 0)
+					throw new IOException("couldn't read bits");
+				System.out.println("cache 1: " + cache + " ("
+						+ Integer.toHexString(cache) + ", "
+						+ Integer.toBinaryString(cache) + ")");
+				bytesRead++;
+				result = (result << 8) | (0xff & cache);
+				count -= 8;
+			}
+			if (count > 0)
+			{
+				cache = is.read();
+				if (cache < 0)
+					throw new IOException("couldn't read bits");
+				System.out.println("cache 2: " + cache + " ("
+						+ Integer.toHexString(cache) + ", "
+						+ Integer.toBinaryString(cache) + ")");
+				bytesRead++;
+				cacheBitsRemaining = 8 - count;
+				result = (result << count)
+						| (((1 << count) - 1) & (cache >> cacheBitsRemaining));
+				count = 0;
+			}
+
+			return result;
+		}
+
+		throw new IOException("BitInputStream: unknown error");
+
+	}
+
+	public void flushCache()
+	{
+		cacheBitsRemaining = 0;
+	}
+
+	public long getBytesRead()
+	{
+		return bytesRead;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/BitInputStreamFlexible.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/Compression.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/Compression.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/Compression.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/Compression.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.common.mylzw.MyLZWCompressor;
+import org.apache.sanselan.common.mylzw.MyLZWDecompressor;
+
+public class Compression
+{
+
+	public byte[] decompressLZW(byte compressed[], int LZWMinimumCodeSize,
+			int expectedSize, int byteOrder) throws IOException
+	{
+		InputStream is = new ByteArrayInputStream(compressed);
+
+		MyLZWDecompressor decompressor = new MyLZWDecompressor(
+				LZWMinimumCodeSize, byteOrder);
+		byte[] result = decompressor.decompress(is, expectedSize);
+
+		return result;
+	}
+
+	public byte[] decompressPackBits(byte compressed[], int expectedSize,
+			int byteOrder) throws ImageReadException, IOException
+	{
+		byte unpacked[] = new PackBits().decompress(compressed, expectedSize);
+		return unpacked;
+	}
+
+	public byte[] compressLZW(byte src[], int LZWMinimumCodeSize,
+			int byteOrder, boolean earlyLimit) throws IOException
+
+	{
+		MyLZWCompressor compressor = new MyLZWCompressor(LZWMinimumCodeSize,
+				byteOrder, earlyLimit);
+
+		byte compressed[] = compressor.compress(src);
+
+		return compressed;
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/Compression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IBufferedImageFactory.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IBufferedImageFactory.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IBufferedImageFactory.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IBufferedImageFactory.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,10 @@
+package org.apache.sanselan.common;
+
+import java.awt.image.BufferedImage;
+
+public interface IBufferedImageFactory
+{
+	public BufferedImage getColorBufferedImage(int width, int height, boolean hasAlpha);
+
+	public BufferedImage getGrayscaleBufferedImage(int width, int height, boolean hasAlpha);
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IBufferedImageFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IImageMetadata.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IImageMetadata.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IImageMetadata.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IImageMetadata.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.util.Vector;
+
+public interface IImageMetadata
+{
+	public String toString(String prefix);
+
+	public Vector getItems();
+
+	public interface IImageMetadataItem
+	{
+		public String toString(String prefix);
+
+		public String toString();
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/IImageMetadata.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ImageMetadata.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ImageMetadata.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ImageMetadata.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ImageMetadata.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.util.Vector;
+
+public class ImageMetadata implements IImageMetadata
+{
+
+	private final Vector items = new Vector();
+
+	public void add(String keyword, String text)
+	{
+		add(new Item(keyword, text));
+	}
+
+	public void add(IImageMetadataItem item)
+	{
+		items.add(item);
+	}
+
+	public Vector getItems()
+	{
+		return new Vector(items);
+	}
+
+	protected static final String newline = System
+			.getProperty("line.separator");
+
+	public String toString()
+	{
+		return toString(null);
+	}
+
+	public String toString(String prefix)
+	{
+		if (null == prefix)
+			prefix = "";
+
+		StringBuffer result = new StringBuffer();
+		for (int i = 0; i < items.size(); i++)
+		{
+			if (i > 0)
+				result.append(newline);
+			//			if (null != prefix)
+			//				result.append(prefix);
+
+			ImageMetadata.IImageMetadataItem item = (ImageMetadata.IImageMetadataItem) items
+					.get(i);
+			result.append(item.toString(prefix + "\t"));
+
+			//			Debug.debug("prefix", prefix);
+			//			Debug.debug("item", items.get(i));
+			//			Debug.debug();
+		}
+		return result.toString();
+	}
+
+	public static class Item implements IImageMetadataItem
+	{
+		private final String keyword, text;
+
+		public Item(String keyword, String text)
+		{
+			this.keyword = keyword;
+			this.text = text;
+		}
+
+		public String getKeyword()
+		{
+			return keyword;
+		}
+
+		public String getText()
+		{
+			return text;
+		}
+
+		public String toString()
+		{
+			return toString(null);
+		}
+
+		public String toString(String prefix)
+		{
+			String result = keyword + ": " + text;
+			if (null != prefix)
+				result = prefix + result;
+			return result;
+		}
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ImageMetadata.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/MyByteArrayOutputStream.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/MyByteArrayOutputStream.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/MyByteArrayOutputStream.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/MyByteArrayOutputStream.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class MyByteArrayOutputStream extends OutputStream
+// some performace benefit, because not thread safe.
+{
+	private final byte bytes[];
+
+	public MyByteArrayOutputStream(int length)
+	{
+		bytes = new byte[length];
+	}
+
+	private int count = 0;
+
+	public void write(int value) throws IOException
+	{
+		if (count >= bytes.length)
+			throw new IOException("Write exceeded expected length (" + count
+					+ ", " + bytes.length + ")");
+
+		bytes[count] = (byte) value;
+		count++;
+	}
+
+	public byte[] toByteArray()
+	{
+		if (count < bytes.length)
+		{
+			byte result[] = new byte[count];
+			System.arraycopy(bytes, 0, result, 0, count);
+			return result;
+		}
+		return bytes;
+	}
+
+	public int getBytesWritten()
+	{
+		return count;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/MyByteArrayOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/PackBits.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/PackBits.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/PackBits.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/PackBits.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.apache.sanselan.ImageReadException;
+
+public class PackBits
+{
+
+	public byte[] decompress(byte bytes[], int expected)
+			throws ImageReadException, IOException
+	{
+		int total = 0;
+
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+		//	Loop until you get the number of unpacked bytes you are expecting:
+		int i = 0;
+		while (total < expected)
+
+		{
+			//		Read the next source byte into n.
+			if (i >= bytes.length)
+				throw new ImageReadException(
+						"Tiff: Unpack bits source exhausted: " + i
+								+ ", done + " + total + ", expected + "
+								+ expected);
+
+			int n = bytes[i++];
+			//				If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+			if ((n >= 0) && (n <= 127))
+			{
+
+				int count = n + 1;
+
+				total += count;
+				for (int j = 0; j < count; j++)
+					baos.write(bytes[i++]);
+			}
+			//				Else if n is between -127 and -1 inclusive, copy the next byte -n+1
+			//				times.
+			else if ((n >= -127) && (n <= -1))
+			{
+				int b = bytes[i++];
+				int count = -n + 1;
+
+				total += count;
+				for (int j = 0; j < count; j++)
+					baos.write(b);
+			}
+			else if (n == -128)
+				throw new ImageReadException("Packbits: " + n);
+			//				Else if n is between -127 and -1 inclusive, copy the next byte -n+1
+			//				times.
+			//		else 
+			//				Else if n is -128, noop.
+		}
+		byte result[] = baos.toByteArray();
+
+		return result;
+
+	}
+
+	private int findNextDuplicate(byte bytes[], int start)
+	{
+		//		int last = -1;
+		if (start >= bytes.length)
+			return -1;
+
+		byte prev = bytes[start];
+
+		for (int i = start + 1; i < bytes.length; i++)
+		{
+			byte b = bytes[i];
+
+			if (b == prev)
+				return i - 1;
+
+			prev = b;
+		}
+
+		return -1;
+	}
+
+	private int findRunLength(byte bytes[], int start)
+	{
+		byte b = bytes[start];
+
+		int i;
+
+		for (i = start + 1; (i < bytes.length) && (bytes[i] == b); i++)
+			;
+
+		return i - start;
+	}
+
+	public byte[] compress(byte bytes[]) throws IOException
+	{
+		MyByteArrayOutputStream baos = new MyByteArrayOutputStream(
+				bytes.length * 2); // max length 1 extra byte for every 128
+
+		int ptr = 0;
+		int count = 0;
+		while (ptr < bytes.length)
+		{
+			count++;
+			int dup = findNextDuplicate(bytes, ptr);
+
+			if (dup == ptr) // write run length
+			{
+				int len = findRunLength(bytes, dup);
+				int actual_len = Math.min(len, 128);
+				baos.write(-(actual_len - 1));
+				baos.write(bytes[ptr]);
+				ptr += actual_len;
+			}
+			else
+			{ // write literals
+				int len = dup - ptr;
+
+				if (dup > 0)
+				{
+					int runlen = findRunLength(bytes, dup);
+					if (runlen < 3) // may want to discard next run.
+					{
+						int nextptr = ptr + len + runlen;
+						int nextdup = findNextDuplicate(bytes, nextptr);
+						if (nextdup != nextptr) // discard 2-byte run
+						{
+							dup = nextdup;
+							len = dup - ptr;
+						}
+					}
+				}
+
+				if (dup < 0)
+					len = bytes.length - ptr;
+				int actual_len = Math.min(len, 128);
+
+				baos.write(actual_len - 1);
+				for (int i = 0; i < actual_len; i++)
+				{
+					baos.write(bytes[ptr]);
+					ptr++;
+				}
+			}
+		}
+		byte result[] = baos.toByteArray();
+
+		return result;
+
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/PackBits.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/RationalNumber.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/RationalNumber.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/RationalNumber.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/RationalNumber.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.text.NumberFormat;
+
+public class RationalNumber extends Number
+
+{
+	public final int numerator;
+	public final int divisor;
+
+	public RationalNumber(int numerator, int divisor)
+	{
+		this.numerator = numerator;
+		this.divisor = divisor;
+	}
+
+	public double doubleValue()
+	{
+		return (double) numerator / (double) divisor;
+	}
+
+	public float floatValue()
+	{
+		return (float) numerator / (float) divisor;
+	}
+
+	public int intValue()
+	{
+		return (int) numerator / (int) divisor;
+	}
+
+	public long longValue()
+	{
+		return (long) numerator / (long) divisor;
+	}
+
+	public String toString()
+	{
+		if (divisor == 0)
+			return "Invalid rational number; Numerator: " + numerator
+					+ ", Divisor: " + divisor;
+		if ((numerator % divisor) == 0)
+			return "" + (numerator / divisor);
+		return numerator + "/" + divisor;
+	}
+
+	public String toDisplayString()
+	{
+		if ((numerator % divisor) == 0)
+			return "" + (numerator / divisor);
+		NumberFormat nf = NumberFormat.getNumberInstance();
+		nf.setMaximumFractionDigits(3);
+		return nf.format((double) numerator / (double) divisor);
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/RationalNumber.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/SimpleBufferedImageFactory.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/SimpleBufferedImageFactory.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/SimpleBufferedImageFactory.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/SimpleBufferedImageFactory.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,24 @@
+package org.apache.sanselan.common;
+
+import java.awt.image.BufferedImage;
+
+import org.apache.sanselan.util.Debug;
+
+public class SimpleBufferedImageFactory implements IBufferedImageFactory
+{
+	public BufferedImage getColorBufferedImage(int width, int height,
+			boolean hasAlpha)
+	{
+		if (hasAlpha)
+			return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+		return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+	}
+
+	public BufferedImage getGrayscaleBufferedImage(int width, int height,
+			boolean hasAlpha)
+	{
+		if (hasAlpha)
+			return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+		return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
+	}
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/SimpleBufferedImageFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.zip.InflaterInputStream;
+
+import org.apache.sanselan.ImageReadException;
+
+public class ZLibInflater extends BinaryFileFunctions
+{
+	public final byte[] zlibInflate(byte bytes[]) throws ImageReadException,
+			IOException
+	// slow, probably.
+	{
+		ByteArrayInputStream in = new ByteArrayInputStream(bytes);
+		InflaterInputStream zIn = new InflaterInputStream(in);
+		return getStreamBytes(zIn);
+	}
+
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/ZLibInflater.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSource.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSource.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSource.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSource.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common.byteSources;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.common.BinaryFileFunctions;
+
+public abstract class ByteSource extends BinaryFileFunctions
+{
+	protected final String filename;
+
+	public ByteSource(final String filename)
+	{
+		this.filename = filename;
+	}
+
+	public final InputStream getInputStream(int start) throws IOException
+	{
+		InputStream is = getInputStream();
+
+		skipBytes(is, start);
+
+		return is;
+	}
+
+	public abstract InputStream getInputStream() throws IOException;
+
+	public abstract byte[] getBlock(int start, int length) throws IOException;
+
+	public abstract byte[] getAll() throws IOException;
+
+//	public abstract long getLength();
+//
+//	public byte[] getAll() throws IOException
+//	{
+//		return getBlock(0, (int) getLength());
+//	}
+
+	public abstract String getDescription();
+
+	public final String getFilename()
+	{
+		return filename;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSourceArray.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSourceArray.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSourceArray.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSourceArray.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sanselan.common.byteSources;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ByteSourceArray extends ByteSource
+{
+	private final byte bytes[];
+
+	public ByteSourceArray(String filename, byte bytes[])
+	{
+		super(filename);
+		this.bytes = bytes;
+	}
+
+	public ByteSourceArray(byte bytes[])
+	{
+		super(null);
+		this.bytes = bytes;
+	}
+
+	public InputStream getInputStream() //throws IOException
+	{
+		return new ByteArrayInputStream(bytes);
+	}
+
+	public byte[] getBlock(int start, int length) throws IOException
+	{
+		if (start + length > bytes.length)
+			throw new IOException("Could not read block.");
+
+		byte result[] = new byte[length];
+		System.arraycopy(bytes, start, result, 0, length);
+		return result;
+	}
+
+//	public long getLength()
+//	{
+//		return bytes.length;
+//	}
+	
+	public byte[] getAll() throws IOException
+	{
+		return bytes;
+	}
+	
+
+	public String getDescription()
+	{
+		return bytes.length + " byte array";
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/common/byteSources/ByteSourceArray.java
------------------------------------------------------------------------------
    svn:eol-style = native