[jsword-svn] r1358 - trunk/common/src/main/java/org/crosswire/common/compress
dmsmith at www.crosswire.org
dmsmith at www.crosswire.org
Wed May 30 13:04:20 MST 2007
Author: dmsmith
Date: 2007-05-30 13:04:20 -0700 (Wed, 30 May 2007)
New Revision: 1358
Added:
trunk/common/src/main/java/org/crosswire/common/compress/AbstractCompressor.java
trunk/common/src/main/java/org/crosswire/common/compress/Compressor.java
trunk/common/src/main/java/org/crosswire/common/compress/CompressorType.java
trunk/common/src/main/java/org/crosswire/common/compress/Zip.java
Modified:
trunk/common/src/main/java/org/crosswire/common/compress/LZSS.java
Log:
Completed the LZSS code. Still needs to be tested.
Added: trunk/common/src/main/java/org/crosswire/common/compress/AbstractCompressor.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/compress/AbstractCompressor.java (rev 0)
+++ trunk/common/src/main/java/org/crosswire/common/compress/AbstractCompressor.java 2007-05-30 20:04:20 UTC (rev 1358)
@@ -0,0 +1,40 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2007
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id$
+ */
+
+package org.crosswire.common.compress;
+
+/**
+ * A compressor provides the ability to compress and uncompress text.
+ *
+ * @see gnu.lgpl.License for license details.<br>
+ * The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public abstract class AbstractCompressor implements Compressor
+{
+ public AbstractCompressor(byte[] input)
+ {
+ this.input = input;
+ }
+
+ protected byte[] input;
+}
Property changes on: trunk/common/src/main/java/org/crosswire/common/compress/AbstractCompressor.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Added: trunk/common/src/main/java/org/crosswire/common/compress/Compressor.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/compress/Compressor.java (rev 0)
+++ trunk/common/src/main/java/org/crosswire/common/compress/Compressor.java 2007-05-30 20:04:20 UTC (rev 1358)
@@ -0,0 +1,58 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2007
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id$
+ */
+
+package org.crosswire.common.compress;
+
+import java.io.IOException;
+
+/**
+ * A compressor provides the ability to compress and uncompress block text.
+ * Implementing classes are expected to provide a way to supply the input.
+ *
+ * @see gnu.lgpl.License for license details.<br>
+ * The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public interface Compressor
+{
+ /**
+ * Compresses the input and provides the result.
+ *
+ * @return the compressed result
+ */
+ byte[] compress() throws IOException;
+
+ /**
+ * Uncompresses the input and provides the result.
+ *
+ * @return the uncompressed result
+ */
+ byte[] uncompress() throws IOException;
+
+ /**
+ * Uncompresses the input and provides the result.
+ *
+ * @param expectedSize the size of the result buffer
+ * @return the uncompressed result
+ */
+ byte[] uncompress(int expectedLength) throws IOException;
+}
Property changes on: trunk/common/src/main/java/org/crosswire/common/compress/Compressor.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Added: trunk/common/src/main/java/org/crosswire/common/compress/CompressorType.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/compress/CompressorType.java (rev 0)
+++ trunk/common/src/main/java/org/crosswire/common/compress/CompressorType.java 2007-05-30 20:04:20 UTC (rev 1358)
@@ -0,0 +1,144 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2007
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id$
+ */
+package org.crosswire.common.compress;
+
+import java.io.Serializable;
+
+/**
+ * An Enumeration of the possible Edits.
+ *
+ * @see gnu.lgpl.License for license details.
+ * The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public abstract class CompressorType implements Serializable
+{
+ /**
+ * Delete a sequence.
+ */
+ public static final CompressorType ZIP = new CompressorType("ZIP") //$NON-NLS-1$
+ {
+ /* (non-Javadoc)
+ * @see org.crosswire.common.compress.CompressorType#getCompressor(byte[])
+ */
+ public Compressor getCompressor(byte[] input)
+ {
+ return new Zip(input);
+ }
+
+ /**
+ * Serialization ID
+ */
+ private static final long serialVersionUID = 7380833510438155782L;
+ };
+
+ /**
+ * Insert a sequence
+ */
+ public static final CompressorType LZSS = new CompressorType("LZSS") //$NON-NLS-1$
+ {
+ /* (non-Javadoc)
+ * @see org.crosswire.common.compress.CompressorType#getCompressor(byte[])
+ */
+ public Compressor getCompressor(byte[] input)
+ {
+ return new LZSS(input);
+ }
+
+ /**
+ * Serialization ID
+ */
+ private static final long serialVersionUID = -5794644645111043930L;
+ };
+
+ /**
+ * @param name The name of the CompressorType
+ */
+ protected CompressorType(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Get a compressor.
+ */
+ public abstract Compressor getCompressor(byte[] input);
+
+ /**
+ * Lookup method to convert from a String
+ */
+ public static CompressorType fromString(String name)
+ {
+ for (int i = 0; i < VALUES.length; i++)
+ {
+ CompressorType o = VALUES[i];
+ if (o.name.equalsIgnoreCase(name))
+ {
+ return o;
+ }
+ }
+ // cannot get here
+ assert false;
+ return null;
+ }
+
+ /**
+ * Lookup method to convert from an integer
+ */
+ public static CompressorType fromInteger(int i)
+ {
+ return VALUES[i];
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * The name of the EditType
+ */
+ private String name;
+
+ // Support for serialization
+ private static int nextObj;
+ private final int obj = nextObj++;
+
+ Object readResolve()
+ {
+ return VALUES[obj];
+ }
+
+ private static final CompressorType[] VALUES =
+ {
+ ZIP,
+ LZSS,
+ };
+
+ /**
+ * Serialization ID
+ */
+ private static final long serialVersionUID = 3256727260177708345L;
+}
Property changes on: trunk/common/src/main/java/org/crosswire/common/compress/CompressorType.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Modified: trunk/common/src/main/java/org/crosswire/common/compress/LZSS.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/compress/LZSS.java 2007-05-30 20:00:06 UTC (rev 1357)
+++ trunk/common/src/main/java/org/crosswire/common/compress/LZSS.java 2007-05-30 20:04:20 UTC (rev 1358)
@@ -82,7 +82,7 @@
* The copyright to this program is held by it's authors.
* @author DM Smith [dmsmith555 at yahoo dot com]
*/
-public class LZSS
+public class LZSS extends AbstractCompressor
{
/**
* Create an LZSS that is capable of transforming the input.
@@ -91,360 +91,369 @@
*/
public LZSS(byte[] input)
{
- readBuffer = input;
+ super(input);
}
- /**
- * Encodes the input stream into the output stream.
- *
- * @return the encoded result
+ /*
+ * (non-Javadoc)
+ * @see org.crosswire.common.compress.Compressor#compress()
*/
- public byte[] encode()
- {
- short i; // an iterator
- int r; // node number in the binary tree
- short s; // position in the ring buffer
- int len; // len of initial string
- int lastMatchLength; // length of last match
- int codeBufPos; // position in the output buffer
- byte[] codeBuff = new byte[17]; // the output buffer
- byte mask; // bit mask for byte 0 of out readBuffer
- byte c; // character read from string
+ public byte[] compress()
+ {
+ short i; // an iterator
+ int r; // node number in the binary tree
+ short s; // position in the ring buffer
+ int len; // len of initial string
+ int lastMatchLength; // length of last match
+ int codeBufPos; // position in the output buffer
+ byte[] codeBuff = new byte[17]; // the output buffer
+ byte mask; // bit mask for byte 0 of out readBuffer
+ byte c; // character read from string
- // Start with a clean tree.
- initTree();
+ // Start with a clean tree.
+ initTree();
- // code_buf[0] works as eight flags. A "1" represents that the
- // unit is an unencoded letter (1 byte), and a "0" represents
- // that the next unit is a <position,length> pair (2 bytes).
- //
- // code_buf[1..16] stores eight units of code. Since the best
- // we can do is store eight <position,length> pairs, at most 16
- // bytes are needed to store this.
- //
- // This is why the maximum size of the code buffer is 17 bytes.
- codeBuff[0] = 0;
- codeBufPos = 1;
+ // code_buf[0] works as eight flags. A "1" represents that the
+ // unit is an unencoded letter (1 byte), and a "0" represents
+ // that the next unit is a <position,length> pair (2 bytes).
+ //
+ // code_buf[1..16] stores eight units of code. Since the best
+ // we can do is store eight <position,length> pairs, at most 16
+ // bytes are needed to store this.
+ //
+ // This is why the maximum size of the code buffer is 17 bytes.
+ codeBuff[0] = 0;
+ codeBufPos = 1;
- // Mask iterates over the 8 bits in the code buffer. The first
- // character ends up being stored in the low bit.
- //
- // bit 8 7 6 5 4 3 2 1
- // | |
- // | first sequence in code buffer
- // |
- // last sequence in code buffer
- mask = 1;
+ // Mask iterates over the 8 bits in the code buffer. The first
+ // character ends up being stored in the low bit.
+ //
+ // bit 8 7 6 5 4 3 2 1
+ // | |
+ // | first sequence in code buffer
+ // |
+ // last sequence in code buffer
+ mask = 1;
- s = 0;
- r = RING_SIZE - MAX_STORE_LENGTH;
+ s = 0;
+ r = RING_SIZE - MAX_STORE_LENGTH;
- // Initialize the ring buffer with spaces...
+ // Initialize the ring buffer with spaces...
- // Note that the last MAX_STORE_LENGTH bytes of the ring buffer are not filled.
- // This is because those MAX_STORE_LENGTH bytes will be filled in immediately
- // with bytes from the input stream.
- for (i = 0; i < r; i++)
- {
- ringBuffer[i] = ' ';
- }
-
- // Read MAX_STORE_LENGTH bytes into the last MAX_STORE_LENGTH bytes of the ring buffer.
- //
- // This function loads the buffer with X characters and returns
- // the actual amount loaded.
- len = getBytes(ringBuffer, r, MAX_STORE_LENGTH);
+ // Note that the last MAX_STORE_LENGTH bytes of the ring buffer are not filled.
+ // This is because those MAX_STORE_LENGTH bytes will be filled in immediately
+ // with bytes from the input stream.
+ for (i = 0; i < r; i++)
+ {
+ ringBuffer[i] = ' ';
+ }
- // Make sure there is something to be compressed.
- if (len == 0)
- {
- return new byte[0];
- }
+ // Read MAX_STORE_LENGTH bytes into the last MAX_STORE_LENGTH bytes of the ring buffer.
+ //
+ // This function loads the buffer with X characters and returns
+ // the actual amount loaded.
+ len = getBytes(ringBuffer, r, MAX_STORE_LENGTH);
- // Insert the MAX_STORE_LENGTH strings, each of which begins with one or more
- // 'space' characters. Note the order in which these strings
- // are inserted. This way, degenerate trees will be less likely
- // to occur.
- for (i = 1; i <= MAX_STORE_LENGTH; i++)
- {
- insertNode((short) (r - i));
- }
+ // Make sure there is something to be compressed.
+ if (len == 0)
+ {
+ return new byte[0];
+ }
- // Finally, insert the whole string just read. The
- // member variables match_length and match_position are set.
- insertNode((short) r);
+ // Insert the MAX_STORE_LENGTH strings, each of which begins with one or more
+ // 'space' characters. Note the order in which these strings
+ // are inserted. This way, degenerate trees will be less likely
+ // to occur.
+ for (i = 1; i <= MAX_STORE_LENGTH; i++)
+ {
+ insertNode((short) (r - i));
+ }
- // Now that we're preloaded, continue till done.
- do
- {
+ // Finally, insert the whole string just read. The
+ // member variables match_length and match_position are set.
+ insertNode((short) r);
- // matchLength may be spuriously long near the end of text.
- if (matchLength > len)
- {
- matchLength = len;
- }
+ // Now that we're preloaded, continue till done.
+ do
+ {
- // Is it cheaper to store this as a single character? If so, make it so.
- if (matchLength < THRESHOLD)
- {
- // Send one character. Remember that code_buf[0] is the
- // set of flags for the next eight items.
- matchLength = 1;
- codeBuff[0] |= mask;
- codeBuff[codeBufPos++] = ringBuffer[r];
- }
- else
- {
- // Otherwise, we do indeed have a string that can be stored
- // compressed to save space.
+ // matchLength may be spuriously long near the end of text.
+ if (matchLength > len)
+ {
+ matchLength = len;
+ }
- // The next 16 bits need to contain the position (12 bits)
- // and the length (4 bits).
- codeBuff[codeBufPos++] = (byte) matchPosition;
- codeBuff[codeBufPos++] = (byte) (((matchPosition >> 4) & 0xf0) | (matchLength - THRESHOLD));
- }
+ // Is it cheaper to store this as a single character? If so, make it so.
+ if (matchLength < THRESHOLD)
+ {
+ // Send one character. Remember that code_buf[0] is the
+ // set of flags for the next eight items.
+ matchLength = 1;
+ codeBuff[0] |= mask;
+ codeBuff[codeBufPos++] = ringBuffer[r];
+ }
+ else
+ {
+ // Otherwise, we do indeed have a string that can be stored
+ // compressed to save space.
- // Shift the mask one bit to the left so that it will be ready
- // to store the new bit.
- mask = (byte) (mask << 1);
+ // The next 16 bits need to contain the position (12 bits)
+ // and the length (4 bits).
+ codeBuff[codeBufPos++] = (byte) matchPosition;
+ codeBuff[codeBufPos++] = (byte) (((matchPosition >> 4) & 0xf0) | (matchLength - THRESHOLD));
+ }
- // If the mask is now 0, then we know that we have a full set
- // of flags and items in the code buffer. These need to be
- // output.
- if (mask == 0)
- {
- // code_buf is the buffer of characters to be output.
- // code_buf_pos is the number of characters it contains.
- sendBytes(codeBuff, codeBufPos);
+ // Shift the mask one bit to the left so that it will be ready
+ // to store the new bit.
+ mask = (byte) (mask << 1);
- // Reset for next buffer...
- codeBuff[0] = 0;
- codeBufPos = 1;
- mask = 1;
- }
+ // If the mask is now 0, then we know that we have a full set
+ // of flags and items in the code buffer. These need to be
+ // output.
+ if (mask == 0)
+ {
+ // code_buf is the buffer of characters to be output.
+ // code_buf_pos is the number of characters it contains.
+ sendBytes(codeBuff, codeBufPos);
- lastMatchLength = matchLength;
+ // Reset for next buffer...
+ codeBuff[0] = 0;
+ codeBufPos = 1;
+ mask = 1;
+ }
- // Delete old strings and read new bytes...
- for (i = 0; i < lastMatchLength; i++)
- {
+ lastMatchLength = matchLength;
- // Get next character...
- try
- {
- c = getByte();
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- break;
- }
+ // Delete old strings and read new bytes...
+ for (i = 0; i < lastMatchLength; i++)
+ {
- // Delete "old strings"
- deleteNode(s);
+ // Get next character...
+ try
+ {
+ c = getByte();
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ break;
+ }
- // Put this character into the ring buffer.
- //
- // The original comment here says "If the position is near
- // the end of the buffer, extend the buffer to make
- // string comparison easier."
- //
- // That's a little misleading, because the "end" of the
- // buffer is really what we consider to be the "beginning"
- // of the buffer, that is, positions 0 through MAX_STORE_LENGTH.
- //
- // The idea is that the front end of the buffer is duplicated
- // into the back end so that when you're looking at characters
- // at the back end of the buffer, you can index ahead (beyond
- // the normal end of the buffer) and see the characters
- // that are at the front end of the buffer wihtout having
- // to adjust the index.
- //
- // That is...
- //
- // 1234xxxxxxxxxxxxxxxxxxxxxxxxxxxxx1234
- // | | |
- // position 0 end of buffer |
- // |
- // duplicate of front of buffer
- ringBuffer[s] = c;
+ // Delete "old strings"
+ deleteNode(s);
- if (s < MAX_STORE_LENGTH - 1)
- {
- ringBuffer[s + RING_SIZE] = c;
- }
+ // Put this character into the ring buffer.
+ //
+ // The original comment here says "If the position is near
+ // the end of the buffer, extend the buffer to make
+ // string comparison easier."
+ //
+ // That's a little misleading, because the "end" of the
+ // buffer is really what we consider to be the "beginning"
+ // of the buffer, that is, positions 0 through MAX_STORE_LENGTH.
+ //
+ // The idea is that the front end of the buffer is duplicated
+ // into the back end so that when you're looking at characters
+ // at the back end of the buffer, you can index ahead (beyond
+ // the normal end of the buffer) and see the characters
+ // that are at the front end of the buffer wihtout having
+ // to adjust the index.
+ //
+ // That is...
+ //
+ // 1234xxxxxxxxxxxxxxxxxxxxxxxxxxxxx1234
+ // | | |
+ // position 0 end of buffer |
+ // |
+ // duplicate of front of buffer
+ ringBuffer[s] = c;
- // Increment the position, and wrap around when we're at
- // the end. Note that this relies on RING_SIZE being a power of 2.
- s = (short) ((s + 1) & (RING_SIZE - 1));
- r = (short) ((r + 1) & (RING_SIZE - 1));
+ if (s < MAX_STORE_LENGTH - 1)
+ {
+ ringBuffer[s + RING_SIZE] = c;
+ }
- // Register the string that is found in
- // ringBuffer[r..r + MAX_STORE_LENGTH - 1].
- insertNode((short) r);
- }
+ // Increment the position, and wrap around when we're at
+ // the end. Note that this relies on RING_SIZE being a power of 2.
+ s = (short) ((s + 1) & (RING_SIZE - 1));
+ r = (short) ((r + 1) & (RING_SIZE - 1));
- // If we didn't quit because we hit the last_match_length,
- // then we must have quit because we ran out of characters
- // to process.
- while (i++ < lastMatchLength)
- {
- deleteNode(s);
+ // Register the string that is found in
+ // ringBuffer[r..r + MAX_STORE_LENGTH - 1].
+ insertNode((short) r);
+ }
- s = (short) ((s + 1) & (RING_SIZE - 1));
- r = (short) ((r + 1) & (RING_SIZE - 1));
+ // If we didn't quit because we hit the last_match_length,
+ // then we must have quit because we ran out of characters
+ // to process.
+ while (i++ < lastMatchLength)
+ {
+ deleteNode(s);
- // Note that len hitting 0 is the key that causes the
- // do...while() to terminate. This is the only place
- // within the loop that len is modified.
- //
- // Its original value is MAX_STORE_LENGTH (or a number less than MAX_STORE_LENGTH for
- // short strings).
- if (--len != 0)
- {
- insertNode((short) r); /* buffer may not be empty. */
- }
- }
+ s = (short) ((s + 1) & (RING_SIZE - 1));
+ r = (short) ((r + 1) & (RING_SIZE - 1));
- // End of do...while() loop. Continue processing until there
- // are no more characters to be compressed. The variable
- // "len" is used to signal this condition.
- }
- while (len > 0);
+ // Note that len hitting 0 is the key that causes the
+ // do...while() to terminate. This is the only place
+ // within the loop that len is modified.
+ //
+ // Its original value is MAX_STORE_LENGTH (or a number less than MAX_STORE_LENGTH for
+ // short strings).
+ if (--len != 0)
+ {
+ insertNode((short) r); /* buffer may not be empty. */
+ }
+ }
- // There could still be something in the output buffer. Send it now.
- if (codeBufPos > 1)
- {
- // code_buf is the encoded string to send.
- // code_buf_ptr is the number of characters.
- sendBytes(codeBuff, codeBufPos);
- }
+ // End of do...while() loop. Continue processing until there
+ // are no more characters to be compressed. The variable
+ // "len" is used to signal this condition.
+ }
+ while (len > 0);
- return writeBuffer;
- }
+ // There could still be something in the output buffer. Send it now.
+ if (codeBufPos > 1)
+ {
+ // code_buf is the encoded string to send.
+ // code_buf_ptr is the number of characters.
+ sendBytes(codeBuff, codeBufPos);
+ }
- /**
- * Decode the input stream into the output stream.
- *
- * @return the decoded result
- */
- public byte[] decode()
- {
- byte[] c = new byte[MAX_STORE_LENGTH]; // an array of chars
- byte flags; // 8 bits of flags
+ return writeBuffer;
+ }
- // Initialize the ring buffer with a common string.
- //
- // Note that the last MAX_STORE_LENGTH bytes of the ring buffer are not filled.
- // r is a nodeNumber
- int r = RING_SIZE - MAX_STORE_LENGTH;
- for (int i = 0; i < r; i++)
- {
- ringBuffer[i] = ' ';
- }
+ /*
+ * (non-Javadoc)
+ * @see org.crosswire.common.compress.Compressor#uncompress(int)
+ */
+ public byte[] uncompress(int expectedSize)
+ {
+ writeBufferSizeIncrement = expectedSize;
+ writeBuffer = new byte[expectedSize];
+ return uncompress();
+ }
- flags = 0;
- int flagCount = 0; // which flag we're on
+ /*
+ * (non-Javadoc)
+ * @see org.crosswire.common.compress.Compressor#uncompress()
+ */
+ public byte[] uncompress()
+ {
+ byte[] c = new byte[MAX_STORE_LENGTH]; // an array of chars
+ byte flags; // 8 bits of flags
- while (true)
- {
+ // Initialize the ring buffer with a common string.
+ //
+ // Note that the last MAX_STORE_LENGTH bytes of the ring buffer are not filled.
+ // r is a nodeNumber
+ int r = RING_SIZE - MAX_STORE_LENGTH;
+ for (int i = 0; i < r; i++)
+ {
+ ringBuffer[i] = ' ';
+ }
- // If there are more bits of interest in this flag, then
- // shift that next interesting bit into the 1's position.
- //
- // If this flag has been exhausted, the next byte must be a flag.
- if (flagCount > 0)
- {
- flags = (byte) (flags >> 1);
- flagCount--;
- }
- else
- {
- // Next byte must be a flag.
- if (!hasMoreToRead())
- {
- break;
- }
+ flags = 0;
+ int flagCount = 0; // which flag we're on
- flags = getByte();
+ while (true)
+ {
- // Set the flag counter. While at first it might appear
- // that this should be an 8 since there are 8 bits in the
- // flag, it should really be a 7 because the shift must
- // be performed 7 times in order to see all 8 bits.
- flagCount = 7;
- }
+ // If there are more bits of interest in this flag, then
+ // shift that next interesting bit into the 1's position.
+ //
+ // If this flag has been exhausted, the next byte must be a flag.
+ if (flagCount > 0)
+ {
+ flags = (byte) (flags >> 1);
+ flagCount--;
+ }
+ else
+ {
+ // Next byte must be a flag.
+ if (!hasMoreToRead())
+ {
+ break;
+ }
- // If the low order bit of the flag is now set, then we know
- // that the next byte is a single, unencoded character.
- if ((flags & 1) != 0)
- {
- if (getBytes(c, 1) != 1)
- {
- break;
- }
+ flags = getByte();
- if (sendBytes(c, 1) != 1)
- {
- break;
- }
+ // Set the flag counter. While at first it might appear
+ // that this should be an 8 since there are 8 bits in the
+ // flag, it should really be a 7 because the shift must
+ // be performed 7 times in order to see all 8 bits.
+ flagCount = 7;
+ }
- // Add to buffer, and increment to next spot. Wrap at end.
- ringBuffer[r] = c[0];
- r = (short) ((r + 1) & (RING_SIZE - 1));
- }
- else
- {
- // Otherwise, we know that the next two bytes are a
- // <position,length> pair. The position is in 12 bits and
- // the length is in 4 bits.
+ // If the low order bit of the flag is now set, then we know
+ // that the next byte is a single, unencoded character.
+ if ((flags & 1) != 0)
+ {
+ if (getBytes(c, 1) != 1)
+ {
+ break;
+ }
- // Original code:
- // if ((i = getc(infile)) == EOF)
- // break;
- // if ((j = getc(infile)) == EOF)
- // break;
- // i |= ((j & 0xf0) << 4);
- // j = (j & 0x0f) + THRESHOLD;
- //
- // I've modified this to only make one input call, and
- // have changed the variable names to something more
- // obvious.
+ if (sendBytes(c, 1) != 1)
+ {
+ break;
+ }
- if (getBytes(c, 2) != 2)
- {
- break;
- }
+ // Add to buffer, and increment to next spot. Wrap at end.
+ ringBuffer[r] = c[0];
+ r = (short) ((r + 1) & (RING_SIZE - 1));
+ }
+ else
+ {
+ // Otherwise, we know that the next two bytes are a
+ // <position,length> pair. The position is in 12 bits and
+ // the length is in 4 bits.
- // Convert these two characters into the position and
- // length in the ringBuffer. Note that the length is always at least
- // THRESHOLD, which is why we're able to get a length
- // of 18 out of only 4 bits.
- int pos = (short) (c[0] | ((c[1] & 0xF0) << 4));
- int len = (short) ((c[1] & 0x0F) + THRESHOLD);
+ // Original code:
+ // if ((i = getc(infile)) == EOF)
+ // break;
+ // if ((j = getc(infile)) == EOF)
+ // break;
+ // i |= ((j & 0xf0) << 4);
+ // j = (j & 0x0f) + THRESHOLD;
+ //
+ // I've modified this to only make one input call, and
+ // have changed the variable names to something more
+ // obvious.
- // There are now "len" characters at position "pos" in
- // the ring buffer that can be pulled out. Note that
- // len is never more than MAX_STORE_LENGTH.
- for (int k = 0; k < len; k++)
- {
- c[k] = ringBuffer[(pos + k) & (RING_SIZE - 1)];
+ if (getBytes(c, 2) != 2)
+ {
+ break;
+ }
- // Add to buffer, and increment to next spot. Wrap at end.
- ringBuffer[r] = c[k];
- r = (short) ((r + 1) & (RING_SIZE - 1));
- }
+ // Convert these two characters into the position and
+ // length in the ringBuffer. Note that the length is always at least
+ // THRESHOLD, which is why we're able to get a length
+ // of 18 out of only 4 bits.
+ int pos = (short) (c[0] | ((c[1] & 0xF0) << 4));
+ int len = (short) ((c[1] & 0x0F) + THRESHOLD);
- // Add the "len" characters to the output stream.
- if (sendBytes(c, len) != len)
- {
- break;
- }
- }
- }
- return writeBuffer;
- }
+ // There are now "len" characters at position "pos" in
+ // the ring buffer that can be pulled out. Note that
+ // len is never more than MAX_STORE_LENGTH.
+ for (int k = 0; k < len; k++)
+ {
+ c[k] = ringBuffer[(pos + k) & (RING_SIZE - 1)];
- /**
+ // Add to buffer, and increment to next spot. Wrap at end.
+ ringBuffer[r] = c[k];
+ r = (short) ((r + 1) & (RING_SIZE - 1));
+ }
+
+ // Add the "len" characters to the output stream.
+ if (sendBytes(c, len) != len)
+ {
+ break;
+ }
+ }
+ }
+ return writeBuffer;
+ }
+
+ /**
* Initializes the tree nodes to "empty" states.
*/
private void initTree()
@@ -690,7 +699,7 @@
return realLen;
}
-
+
/**
* Return whether there are more bytes to read.
*
@@ -723,27 +732,27 @@
return len;
}
- private byte[] ensureCapacity(byte[] input, int currentPosition, int length)
+ private byte[] ensureCapacity(byte[] inputBuf, int currentPosition, int length)
{
// Make sure the buffer is more than big enough
- if (input != null)
+ int biggerLength = currentPosition + length + writeBufferSizeIncrement;
+ if (inputBuf != null)
{
- int inputLength = readBuffer.length;
+ int inputLength = inputBuf.length;
if ((currentPosition + length) > inputLength)
{
- int biggerLength = currentPosition + length + 1024;
byte[] biggerBuf = new byte[biggerLength];
- System.arraycopy(readBuffer, 0, biggerBuf, 0, inputLength);
+ System.arraycopy(inputBuf, 0, biggerBuf, 0, inputLength);
for (int i = inputLength; i < biggerLength; i++)
{
biggerBuf[i] = '\0';
}
return biggerBuf;
}
- return input;
+ return inputBuf;
}
- return new byte[length + 1024];
+ return new byte[length + writeBufferSizeIncrement];
}
/**
@@ -837,6 +846,11 @@
private int readOffset;
/**
+ * The incremental size of the writeBuffer to use.
+ */
+ private int writeBufferSizeIncrement = 1024;
+
+ /**
* The buffer to get or send, when compressed.
*/
private byte[] writeBuffer;
Added: trunk/common/src/main/java/org/crosswire/common/compress/Zip.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/compress/Zip.java (rev 0)
+++ trunk/common/src/main/java/org/crosswire/common/compress/Zip.java 2007-05-30 20:04:20 UTC (rev 1358)
@@ -0,0 +1,110 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2007
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id$
+ */
+
+package org.crosswire.common.compress;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * A class can be Activatable if it needs a significant amount of memory on an
+ * irregular basis, and so would benefit from being told when to wake-up and
+ * when to conserver memory.
+ *
+ * @see gnu.lgpl.License for license details.<br>
+ * The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public class Zip extends AbstractCompressor
+{
+ /**
+ * Create a Zip that is capable of transforming the input.
+ *
+ * @param input to compress or uncompress.
+ */
+ public Zip(byte[] input)
+ {
+ super(input);
+ }
+
+ /* (non-Javadoc)
+ * @see org.crosswire.common.compress.Compressor#compress()
+ */
+ public byte[] compress() throws IOException
+ {
+ ByteArrayInputStream bis = new ByteArrayInputStream(input);
+ BufferedInputStream in = new BufferedInputStream(bis);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DeflaterOutputStream out = new DeflaterOutputStream(bos, new Deflater(), ZBUF_SIZE);
+ byte[] buf = new byte[ZBUF_SIZE];
+
+ for (int count = in.read(buf); count != -1; count = in.read(buf))
+ {
+ out.write(buf, 0, count);
+ }
+ in.close();
+ out.flush();
+ out.close();
+ return bos.toByteArray();
+ }
+
+ /* (non-Javadoc)
+ * @see org.crosswire.common.compress.Compressor#uncompress()
+ */
+ public byte[] uncompress() throws IOException
+ {
+ return uncompress(ZBUF_SIZE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.crosswire.common.compress.Compressor#uncompress(int)
+ */
+ public byte[] uncompress(int expectedLength) throws IOException
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ BufferedOutputStream out = new BufferedOutputStream(bos, expectedLength);
+ ByteArrayInputStream bis = new ByteArrayInputStream(input);
+ InflaterInputStream in = new InflaterInputStream(bis, new Inflater(), expectedLength);
+ byte[] buf = new byte[expectedLength];
+
+ for (int count = in.read(buf); count != -1; count = in.read(buf))
+ {
+ out.write(buf, 0, count);
+ }
+ in.close();
+ out.flush();
+ out.close();
+ return bos.toByteArray();
+ }
+
+ /**
+ * The size to read/write when unzipping a compressed byte array of unknown size.
+ */
+ private static final int ZBUF_SIZE = 2048;
+}
Property changes on: trunk/common/src/main/java/org/crosswire/common/compress/Zip.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
More information about the jsword-svn
mailing list