[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