Modified: 
commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipOutputStream.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipOutputStream.java?rev=733688&r1=733687&r2=733688&view=diff
==============================================================================
--- 
commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipOutputStream.java
 (original)
+++ 
commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipOutputStream.java
 Mon Jan 12 03:15:34 2009
@@ -1,728 +1,943 @@
 /*
- * 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
+ *  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
+ *      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.
  *
- * 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.commons.compress.archivers.zip;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.RandomAccessFile;
 import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Date;
 import java.util.Hashtable;
+import java.util.Vector;
 import java.util.zip.CRC32;
 import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
 import java.util.zip.ZipException;
 
 /**
  * Reimplementation of {...@link java.util.zip.ZipOutputStream
- * java.util.zip.ZipOutputStream} that does handle the extended functionality 
of
- * this package, especially internal/external file attributes and extra fields
- * with different layouts for local file data and central directory entries. 
<p>
+ * java.util.zip.ZipOutputStream} that does handle the extended
+ * functionality of this package, especially internal/external file
+ * attributes and extra fields with different layouts for local file
+ * data and central directory entries.
+ *
+ * <p>This class will try to use {...@link java.io.RandomAccessFile
+ * RandomAccessFile} when you know that the output is going to go to a
+ * file.</p>
+ *
+ * <p>If RandomAccessFile cannot be used, this implementation will use
+ * a Data Descriptor to store size and CRC information for {...@link
+ * #DEFLATED DEFLATED} entries, this means, you don't need to
+ * calculate them yourself.  Unfortunately this is not possible for
+ * the {...@link #STORED STORED} method, here setting the CRC and
+ * uncompressed size information is required before {...@link
+ * #putNextEntry putNextEntry} can be called.</p>
  *
- * This implementation will use a Data Descriptor to store size and CRC
- * information for DEFLATED entries, this means, you don't need to calculate
- * them yourself. Unfortunately this is not possible for the STORED method, 
here
- * setting the CRC and uncompressed size information is required before 
{...@link
- * #putNextEntry putNextEntry} will be called.</p>
  */
-public class ZipOutputStream
-    extends DeflaterOutputStream
-{
-    /**
-     * Helper, a 0 as ZipShort.
+public class ZipOutputStream extends FilterOutputStream {
+
+    private static final int BYTE_MASK = 0xFF;
+    private static final int SHORT = 2;
+    private static final int WORD = 4;
+    private static final int BUFFER_SIZE = 512;
+    /* 
+     * Apparently Deflater.setInput gets slowed down a lot on Sun JVMs
+     * when it gets handed a really big buffer.  See
+     * https://issues.apache.org/bugzilla/show_bug.cgi?id=45396
      *
-     * @since 1.1
+     * Using a buffer size of 8 kB proved to be a good compromise
      */
-    private static final byte[] ZERO = {0, 0};
+    private static final int DEFLATER_BLOCK_SIZE = 8192;
 
     /**
-     * Helper, a 0 as ZipLong.
+     * Compression method for deflated entries.
      *
      * @since 1.1
      */
-    private static final byte[] LZERO = {0, 0, 0, 0};
+    public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED;
 
     /**
-     * Compression method for deflated entries.
+     * Default compression level for deflated entries.
      *
-     * @since 1.1
+     * @since Ant 1.7
      */
-    public static final int DEFLATED = ZipEntry.DEFLATED;
+    public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION;
 
     /**
-     * Compression method for deflated entries.
+     * Compression method for stored entries.
      *
      * @since 1.1
      */
-    public static final int STORED = ZipEntry.STORED;
+    public static final int STORED = java.util.zip.ZipEntry.STORED;
 
-    /*
-     * Various ZIP constants
-     */
     /**
-     * local file header signature
+     * Current entry.
      *
      * @since 1.1
      */
-    protected static final ZipLong LFH_SIG = new ZipLong( 0X04034B50L );
+    private ZipEntry entry;
+
     /**
-     * data descriptor signature
+     * The file comment.
      *
      * @since 1.1
      */
-    protected static final ZipLong DD_SIG = new ZipLong( 0X08074B50L );
+    private String comment = "";
+
     /**
-     * central file header signature
+     * Compression level for next entry.
      *
      * @since 1.1
      */
-    protected static final ZipLong CFH_SIG = new ZipLong( 0X02014B50L );
+    private int level = DEFAULT_COMPRESSION;
+
     /**
-     * end of central dir signature
+     * Has the compression level changed when compared to the last
+     * entry?
      *
-     * @since 1.1
+     * @since 1.5
      */
-    protected static final ZipLong EOCD_SIG = new ZipLong( 0X06054B50L );
+    private boolean hasCompressionLevelChanged = false;
 
     /**
-     * Smallest date/time ZIP can handle.
+     * Default compression method for next entry.
      *
      * @since 1.1
      */
-    private static final ZipLong DOS_TIME_MIN = new ZipLong( 0x00002100L );
+    private int method = java.util.zip.ZipEntry.DEFLATED;
 
     /**
-     * The file comment.
+     * List of ZipEntries written so far.
      *
      * @since 1.1
      */
-    private String m_comment = "";
+    private Vector entries = new Vector();
 
     /**
-     * Compression level for next entry.
+     * CRC instance to avoid parsing DEFLATED data twice.
      *
      * @since 1.1
      */
-    private int m_level = Deflater.DEFAULT_COMPRESSION;
+    private CRC32 crc = new CRC32();
 
     /**
-     * Default compression method for next entry.
+     * Count the bytes written to out.
      *
      * @since 1.1
      */
-    private int m_method = DEFLATED;
+    private long written = 0;
 
     /**
-     * List of ZipEntries written so far.
+     * Data for local header data
      *
      * @since 1.1
      */
-    private final ArrayList m_entries = new ArrayList();
+    private long dataStart = 0;
 
     /**
-     * CRC instance to avoid parsing DEFLATED data twice.
+     * Offset for CRC entry in the local file header data for the
+     * current entry starts here.
      *
-     * @since 1.1
+     * @since 1.15
      */
-    private final CRC32 m_crc = new CRC32();
+    private long localDataStart = 0;
 
     /**
-     * Count the bytes written to out.
+     * Start of central directory.
      *
      * @since 1.1
      */
-    private long m_written;
+    private long cdOffset = 0;
 
     /**
-     * Data for current entry started here.
+     * Length of central directory.
      *
      * @since 1.1
      */
-    private long m_dataStart;
+    private long cdLength = 0;
 
     /**
-     * Start of central directory.
+     * Helper, a 0 as ZipShort.
      *
      * @since 1.1
      */
-    private ZipLong m_cdOffset = new ZipLong( 0 );
+    private static final byte[] ZERO = {0, 0};
 
     /**
-     * Length of central directory.
+     * Helper, a 0 as ZipLong.
      *
      * @since 1.1
      */
-    private ZipLong m_cdLength = new ZipLong( 0 );
+    private static final byte[] LZERO = {0, 0, 0, 0};
 
     /**
-     * Holds the offsets of the LFH starts for each entry
+     * Holds the offsets of the LFH starts for each entry.
      *
      * @since 1.1
      */
-    private final Hashtable m_offsets = new Hashtable();
+    private Hashtable offsets = new Hashtable();
 
     /**
-     * The encoding to use for filenames and the file comment. <p>
+     * The encoding to use for filenames and the file comment.
      *
-     * For a list of possible values see <a
-     * 
href="http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html";>
-     * 
http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html
-     * </a>. Defaults to the platform's default character encoding.</p>
+     * <p>For a list of possible values see <a
+     * 
href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html";>http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
+     * Defaults to the platform's default character encoding.</p>
      *
      * @since 1.3
      */
-    private String m_encoding;
+    private String encoding = null;
+
+    // CheckStyle:VisibilityModifier OFF - bc
 
     /**
-     * Current entry.
+     * This Deflater object is used for output.
      *
-     * @since 1.1
+     * <p>This attribute is only protected to provide a level of API
+     * backwards compatibility.  This class used to extend {...@link
+     * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
+     * Revision 1.13.</p>
+     *
+     * @since 1.14
      */
-    private ZipArchiveEntry m_entry;
+    protected Deflater def = new Deflater(level, true);
 
     /**
-     * Creates a new ZIP OutputStream filtering the underlying stream.
+     * This buffer servers as a Deflater.
      *
-     * @param output the output stream to write to
-     * @since 1.1
+     * <p>This attribute is only protected to provide a level of API
+     * backwards compatibility.  This class used to extend {...@link
+     * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
+     * Revision 1.13.</p>
+     *
+     * @since 1.14
      */
-    public ZipOutputStream( final OutputStream output )
-    {
-        super( output, new Deflater( Deflater.DEFAULT_COMPRESSION, true ) );
-    }
+    protected byte[] buf = new byte[BUFFER_SIZE];
+
+    // CheckStyle:VisibilityModifier ON
 
     /**
-     * Convert a Date object to a DOS date/time field. <p>
-     *
-     * Stolen from InfoZip's <code>fileio.c</code></p>
+     * Optional random access output.
      *
-     * @param time Description of Parameter
-     * @return Description of the Returned Value
-     * @since 1.1
+     * @since 1.14
      */
-    protected static ZipLong toDosTime( Date time )
-    {
-        Calendar cal = Calendar.getInstance();
-        cal.setTime( time );
-        int year = cal.get(Calendar.YEAR);
-        int month = cal.get(Calendar.MONTH) + 1;
-        if( year < 1980 )
-        {
-            return DOS_TIME_MIN;
-        }
-        long value = ( ( year - 1980 ) << 25 )
-            | ( month << 21 )
-            | ( cal.get(Calendar.DAY_OF_MONTH) << 16 )
-            | ( cal.get(Calendar.HOUR_OF_DAY) << 11 )
-            | ( cal.get(Calendar.MINUTE) << 5 )
-            | ( cal.get(Calendar.SECOND) >> 1 );
-
-        byte[] result = new byte[ 4 ];
-        result[ 0 ] = (byte)( ( value & 0xFF ) );
-        result[ 1 ] = (byte)( ( value & 0xFF00 ) >> 8 );
-        result[ 2 ] = (byte)( ( value & 0xFF0000 ) >> 16 );
-        result[ 3 ] = (byte)( ( value & 0xFF000000l ) >> 24 );
-        return new ZipLong( result );
-    }
+    private RandomAccessFile raf = null;
 
     /**
-     * Set the file comment.
-     *
-     * @param comment The new Comment value
+     * Creates a new ZIP OutputStream filtering the underlying stream.
+     * @param out the outputstream to zip
      * @since 1.1
      */
-    public void setComment( String comment )
-    {
-        m_comment = comment;
+    public ZipOutputStream(OutputStream out) {
+        super(out);
     }
 
     /**
-     * The encoding to use for filenames and the file comment. <p>
-     *
-     * For a list of possible values see <a
-     * 
href="http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html";>
-     * 
http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html
-     * </a>. Defaults to the platform's default character encoding.</p>
-     *
-     * @param encoding The new Encoding value
-     * @since 1.3
-     */
-    public void setEncoding( String encoding )
-    {
-        m_encoding = encoding;
+     * Creates a new ZIP OutputStream writing to a File.  Will use
+     * random access if possible.
+     * @param file the file to zip to
+     * @since 1.14
+     * @throws IOException on error
+     */
+    public ZipOutputStream(File file) throws IOException {
+        super(null);
+
+        try {
+            raf = new RandomAccessFile(file, "rw");
+            raf.setLength(0);
+        } catch (IOException e) {
+            if (raf != null) {
+                try {
+                    raf.close();
+                } catch (IOException inner) {
+                    // ignore
+                }
+                raf = null;
+            }
+            out = new FileOutputStream(file);
+        }
     }
 
     /**
-     * Sets the compression level for subsequent entries. <p>
-     *
-     * Default is Deflater.DEFAULT_COMPRESSION.</p>
+     * This method indicates whether this archive is writing to a seekable 
stream (i.e., to a random
+     * access file).
      *
-     * @param level The new Level value
-     * @since 1.1
+     * <p>For seekable streams, you don't need to calculate the CRC or
+     * uncompressed size for {...@link #STORED} entries before
+     * invoking {...@link #putNextEntry}.
+     * @return true if seekable
+     * @since 1.17
      */
-    public void setLevel( int level )
-    {
-        m_level = level;
+    public boolean isSeekable() {
+        return raf != null;
     }
 
     /**
-     * Sets the default compression method for subsequent entries. <p>
-     *
-     * Default is DEFLATED.</p>
+     * The encoding to use for filenames and the file comment.
      *
-     * @param method The new Method value
-     * @since 1.1
+     * <p>For a list of possible values see <a
+     * 
href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html";>http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
+     * Defaults to the platform's default character encoding.</p>
+     * @param encoding the encoding value
+     * @since 1.3
      */
-    public void setMethod( final int method )
-    {
-        m_method = method;
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
     }
 
     /**
      * The encoding to use for filenames and the file comment.
      *
      * @return null if using the platform's default character encoding.
+     *
      * @since 1.3
      */
-    public String getEncoding()
-    {
-        return m_encoding;
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Finishs writing the contents and closes this as well as the
+     * underlying stream.
+     *
+     * @since 1.1
+     * @throws IOException on error
+     */
+    public void finish() throws IOException {
+        closeEntry();
+        cdOffset = written;
+        for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) {
+            writeCentralFileHeader((ZipEntry) entries.elementAt(i));
+        }
+        cdLength = written - cdOffset;
+        writeCentralDirectoryEnd();
+        offsets.clear();
+        entries.removeAllElements();
     }
 
     /**
      * Writes all necessary data for this entry.
      *
-     * @throws IOException if an IO failure causes operation to fail
      * @since 1.1
+     * @throws IOException on error
      */
-    public void closeEntry()
-        throws IOException
-    {
-        if( m_entry == null )
-        {
+    public void closeEntry() throws IOException {
+        if (entry == null) {
             return;
         }
 
-        long realCrc = m_crc.getValue();
-        m_crc.reset();
+        long realCrc = crc.getValue();
+        crc.reset();
 
-        if( m_entry.getMethod() == DEFLATED )
-        {
+        if (entry.getMethod() == DEFLATED) {
             def.finish();
-            while( !def.finished() )
-            {
+            while (!def.finished()) {
                 deflate();
             }
 
-            m_entry.setSize( def.getTotalIn() );
-            m_entry.setComprSize( def.getTotalOut() );
-            m_entry.setCrc( realCrc );
+            entry.setSize(adjustToLong(def.getTotalIn()));
+            entry.setCompressedSize(adjustToLong(def.getTotalOut()));
+            entry.setCrc(realCrc);
 
             def.reset();
 
-            m_written += m_entry.getCompressedSize();
-        }
-        else
-        {
-            if( m_entry.getCrc() != realCrc )
-            {
-                throw new ZipException( "bad CRC checksum for entry "
-                                        + m_entry.getName() + ": "
-                                        + Long.toHexString( m_entry.getCrc() )
-                                        + " instead of "
-                                        + Long.toHexString( realCrc ) );
+            written += entry.getCompressedSize();
+        } else if (raf == null) {
+            if (entry.getCrc() != realCrc) {
+                throw new ZipException("bad CRC checksum for entry "
+                                       + entry.getName() + ": "
+                                       + Long.toHexString(entry.getCrc())
+                                       + " instead of "
+                                       + Long.toHexString(realCrc));
             }
 
-            if( m_entry.getSize() != m_written - m_dataStart )
-            {
-                throw new ZipException( "bad size for entry "
-                                        + m_entry.getName() + ": "
-                                        + m_entry.getSize()
-                                        + " instead of "
-                                        + ( m_written - m_dataStart ) );
+            if (entry.getSize() != written - dataStart) {
+                throw new ZipException("bad size for entry "
+                                       + entry.getName() + ": "
+                                       + entry.getSize()
+                                       + " instead of "
+                                       + (written - dataStart));
             }
+        } else { /* method is STORED and we used RandomAccessFile */
+            long size = written - dataStart;
 
+            entry.setSize(size);
+            entry.setCompressedSize(size);
+            entry.setCrc(realCrc);
         }
 
-        writeDataDescriptor( m_entry );
-        m_entry = null;
-    }
+        // If random access output, write the local file header containing
+        // the correct CRC and compressed/uncompressed sizes
+        if (raf != null) {
+            long save = raf.getFilePointer();
 
-    /*
-     * Found out by experiment, that DeflaterOutputStream.close()
-     * will call finish() - so we don't need to override close
-     * ourselves.
-     */
-    /**
-     * Finishs writing the contents and closes this as well as the underlying
-     * stream.
-     *
-     * @throws IOException if an IO failure causes operation to fail
-     * @since 1.1
-     */
-    public void finish()
-        throws IOException
-    {
-        closeEntry();
-        m_cdOffset = new ZipLong( m_written );
-        final int size = m_entries.size();
-        for( int i = 0; i < size; i++ )
-        {
-            final ZipArchiveEntry entry = (ZipArchiveEntry)m_entries.get( i );
-            writeCentralFileHeader( entry );
+            raf.seek(localDataStart);
+            writeOut(ZipLong.getBytes(entry.getCrc()));
+            writeOut(ZipLong.getBytes(entry.getCompressedSize()));
+            writeOut(ZipLong.getBytes(entry.getSize()));
+            raf.seek(save);
         }
-        m_cdLength = new ZipLong( m_written - m_cdOffset.getValue() );
-        writeCentralDirectoryEnd();
-        m_offsets.clear();
-        m_entries.clear();
+
+        writeDataDescriptor(entry);
+        entry = null;
     }
 
     /**
      * Begin writing next entry.
-     *
-     * @param entry the entry
-     * @throws IOException if an IO failure causes operation to fail
+     * @param ze the entry to write
      * @since 1.1
+     * @throws IOException on error
      */
-    public void putNextEntry( final ZipArchiveEntry entry )
-        throws IOException
-    {
+    public void putNextEntry(ZipEntry ze) throws IOException {
         closeEntry();
 
-        m_entry = entry;
-        m_entries.add( m_entry );
+        entry = ze;
+        entries.addElement(entry);
 
-        if( m_entry.getMethod() == -1 )
-        {// not specified
-            m_entry.setMethod( m_method );
+        if (entry.getMethod() == -1) { // not specified
+            entry.setMethod(method);
         }
 
-        if( m_entry.getTime() == -1 )
-        {// not specified
-            m_entry.setTime( System.currentTimeMillis() );
+        if (entry.getTime() == -1) { // not specified
+            entry.setTime(System.currentTimeMillis());
         }
 
-        if( m_entry.getMethod() == STORED )
-        {
-            if( m_entry.getSize() == -1 )
-            {
-                throw new ZipException( "uncompressed size is required for 
STORED method" );
+        // Size/CRC not required if RandomAccessFile is used
+        if (entry.getMethod() == STORED && raf == null) {
+            if (entry.getSize() == -1) {
+                throw new ZipException("uncompressed size is required for"
+                                       + " STORED method when not writing to a"
+                                       + " file");
             }
-            if( m_entry.getCrc() == -1 )
-            {
-                throw new ZipException( "crc checksum is required for STORED 
method" );
+            if (entry.getCrc() == -1) {
+                throw new ZipException("crc checksum is required for STORED"
+                                       + " method when not writing to a file");
             }
-            m_entry.setComprSize( m_entry.getSize() );
+            entry.setCompressedSize(entry.getSize());
         }
-        else
-        {
-            def.setLevel( m_level );
+
+        if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {
+            def.setLevel(level);
+            hasCompressionLevelChanged = false;
         }
-        writeLocalFileHeader( m_entry );
+        writeLocalFileHeader(entry);
     }
 
     /**
-     * Writes bytes to ZIP entry. <p>
-     *
-     * Override is necessary to support STORED entries, as well as calculationg
-     * CRC automatically for DEFLATED entries.</p>
+     * Set the file comment.
+     * @param comment the comment
+     * @since 1.1
+     */
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    /**
+     * Sets the compression level for subsequent entries.
      *
-     * @param buffer the buffer to write to
-     * @param offset the offset to write to
-     * @param length the length of data to write
-     * @exception IOException if an IO error causes operation to fail
+     * <p>Default is Deflater.DEFAULT_COMPRESSION.</p>
+     * @param level the compression level.
+     * @throws IllegalArgumentException if an invalid compression level is 
specified.
+     * @since 1.1
      */
-    public void write( final byte[] buffer,
-                       final int offset,
-                       final int length )
-        throws IOException
-    {
-        if( m_entry.getMethod() == DEFLATED )
-        {
-            super.write( buffer, offset, length );
+    public void setLevel(int level) {
+        if (level < Deflater.DEFAULT_COMPRESSION
+            || level > Deflater.BEST_COMPRESSION) {
+            throw new IllegalArgumentException(
+                "Invalid compression level: " + level);
         }
-        else
-        {
-            out.write( buffer, offset, length );
-            m_written += length;
-        }
-        m_crc.update( buffer, offset, length );
+        hasCompressionLevelChanged = (this.level != level);
+        this.level = level;
     }
 
     /**
-     * Retrieve the bytes for the given String in the encoding set for this
-     * Stream.
+     * Sets the default compression method for subsequent entries.
      *
-     * @param name the name to decode
-     * @return the bytes for string
-     * @exception ZipException if fail to retrieve bytes for specified string
-     * @since 1.3
+     * <p>Default is DEFLATED.</p>
+     * @param method an <code>int</code> from java.util.zip.ZipEntry
+     * @since 1.1
      */
-    protected byte[] getBytes( String name )
-        throws ZipException
-    {
-        if( m_encoding == null )
-        {
-            return name.getBytes();
-        }
-        else
-        {
-            try
-            {
-                return name.getBytes( m_encoding );
-            }
-            catch( UnsupportedEncodingException uee )
-            {
-                throw new ZipException( uee.getMessage() );
+    public void setMethod(int method) {
+        this.method = method;
+    }
+
+    /**
+     * Writes bytes to ZIP entry.
+     * @param b the byte array to write
+     * @param offset the start position to write from
+     * @param length the number of bytes to write
+     * @throws IOException on error
+     */
+    public void write(byte[] b, int offset, int length) throws IOException {
+        if (entry.getMethod() == DEFLATED) {
+            if (length > 0) {
+                if (!def.finished()) {
+                    if (length <= DEFLATER_BLOCK_SIZE) {
+                        def.setInput(b, offset, length);
+                        deflateUntilInputIsNeeded();
+                    } else {
+                        final int fullblocks = length / DEFLATER_BLOCK_SIZE;
+                        for (int i = 0; i < fullblocks; i++) {
+                            def.setInput(b, offset + i * DEFLATER_BLOCK_SIZE,
+                                         DEFLATER_BLOCK_SIZE);
+                            deflateUntilInputIsNeeded();
+                        }
+                        final int done = fullblocks * DEFLATER_BLOCK_SIZE;
+                        if (done < length) {
+                            def.setInput(b, offset + done, length - done);
+                            deflateUntilInputIsNeeded();
+                        }
+                    }
+                }
             }
+        } else {
+            writeOut(b, offset, length);
+            written += length;
         }
+        crc.update(b, offset, length);
     }
 
     /**
-     * Writes the &quot;End of central dir record&quot;
+     * Writes a single byte to ZIP entry.
      *
-     * @exception IOException when an IO erro causes operation to fail
-     * @since 1.1
+     * <p>Delegates to the three arg method.</p>
+     * @param b the byte to write
+     * @since 1.14
+     * @throws IOException on error
      */
-    protected void writeCentralDirectoryEnd()
-        throws IOException
-    {
-        out.write( EOCD_SIG.getBytes() );
+    public void write(int b) throws IOException {
+        byte[] buff = new byte[1];
+        buff[0] = (byte) (b & BYTE_MASK);
+        write(buff, 0, 1);
+    }
 
-        // disk numbers
-        out.write( ZERO );
-        out.write( ZERO );
+    /**
+     * Closes this output stream and releases any system resources
+     * associated with the stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since 1.14
+     */
+    public void close() throws IOException {
+        finish();
 
-        // number of entries
-        byte[] num = ( new ZipShort( m_entries.size() ) ).getBytes();
-        out.write( num );
-        out.write( num );
+        if (raf != null) {
+            raf.close();
+        }
+        if (out != null) {
+            out.close();
+        }
+    }
 
-        // length and location of CD
-        out.write( m_cdLength.getBytes() );
-        out.write( m_cdOffset.getBytes() );
+    /**
+     * Flushes this output stream and forces any buffered output bytes
+     * to be written out to the stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since 1.14
+     */
+    public void flush() throws IOException {
+        if (out != null) {
+            out.flush();
+        }
+    }
 
-        // ZIP file comment
-        byte[] data = getBytes( m_comment );
-        out.write( ( new ZipShort( data.length ) ).getBytes() );
-        out.write( data );
+    /*
+     * Various ZIP constants
+     */
+    /**
+     * local file header signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] LFH_SIG = ZipLong.getBytes(0X04034B50L);
+    /**
+     * data descriptor signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] DD_SIG = ZipLong.getBytes(0X08074B50L);
+    /**
+     * central file header signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] CFH_SIG = ZipLong.getBytes(0X02014B50L);
+    /**
+     * end of central dir signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] EOCD_SIG = ZipLong.getBytes(0X06054B50L);
+
+    /**
+     * Writes next block of compressed data to the output stream.
+     * @throws IOException on error
+     *
+     * @since 1.14
+     */
+    protected final void deflate() throws IOException {
+        int len = def.deflate(buf, 0, buf.length);
+        if (len > 0) {
+            writeOut(buf, 0, len);
+        }
     }
 
     /**
-     * Writes the central file header entry
+     * Writes the local file header entry
+     * @param ze the entry to write
+     * @throws IOException on error
      *
-     * @param entry the zip entry
-     * @throws IOException when an IO error causes operation to fail
      * @since 1.1
      */
-    protected void writeCentralFileHeader( final ZipArchiveEntry entry )
-        throws IOException
-    {
-        out.write( CFH_SIG.getBytes() );
-        m_written += 4;
+    protected void writeLocalFileHeader(ZipEntry ze) throws IOException {
+        offsets.put(ze, ZipLong.getBytes(written));
 
-        // version made by
-        out.write( ( new ZipShort( 20 ) ).getBytes() );
-        m_written += 2;
+        writeOut(LFH_SIG);
+        written += WORD;
+
+        //store method in local variable to prevent multiple method calls
+        final int zipMethod = ze.getMethod();
 
         // version needed to extract
         // general purpose bit flag
-        if( entry.getMethod() == DEFLATED )
-        {
+        // CheckStyle:MagicNumber OFF
+        if (zipMethod == DEFLATED && raf == null) {
             // requires version 2 as we are going to store length info
             // in the data descriptor
-            out.write( ( new ZipShort( 20 ) ).getBytes() );
+            writeOut(ZipShort.getBytes(20));
 
             // bit3 set to signal, we use a data descriptor
-            out.write( ( new ZipShort( 8 ) ).getBytes() );
-        }
-        else
-        {
-            out.write( ( new ZipShort( 10 ) ).getBytes() );
-            out.write( ZERO );
+            writeOut(ZipShort.getBytes(8));
+        } else {
+            writeOut(ZipShort.getBytes(10));
+            writeOut(ZERO);
         }
-        m_written += 4;
+        // CheckStyle:MagicNumber ON
+        written += WORD;
 
         // compression method
-        out.write( ( new ZipShort( entry.getMethod() ) ).getBytes() );
-        m_written += 2;
+        writeOut(ZipShort.getBytes(zipMethod));
+        written += SHORT;
 
         // last mod. time and date
-        out.write( toDosTime( new Date( entry.getTime() ) ).getBytes() );
-        m_written += 4;
+        writeOut(toDosTime(ze.getTime()));
+        written += WORD;
 
         // CRC
         // compressed length
         // uncompressed length
-        out.write( ( new ZipLong( entry.getCrc() ) ).getBytes() );
-        out.write( ( new ZipLong( entry.getCompressedSize() ) ).getBytes() );
-        out.write( ( new ZipLong( entry.getSize() ) ).getBytes() );
-        m_written += 12;
+        localDataStart = written;
+        if (zipMethod == DEFLATED || raf != null) {
+            writeOut(LZERO);
+            writeOut(LZERO);
+            writeOut(LZERO);
+        } else {
+            writeOut(ZipLong.getBytes(ze.getCrc()));
+            writeOut(ZipLong.getBytes(ze.getSize()));
+            writeOut(ZipLong.getBytes(ze.getSize()));
+        }
+        // CheckStyle:MagicNumber OFF
+        written += 12;
+        // CheckStyle:MagicNumber ON
 
         // file name length
-        byte[] name = getBytes( entry.getName() );
-        out.write( ( new ZipShort( name.length ) ).getBytes() );
-        m_written += 2;
+        byte[] name = getBytes(ze.getName());
+        writeOut(ZipShort.getBytes(name.length));
+        written += SHORT;
 
         // extra field length
-        byte[] extra = entry.getCentralDirectoryExtra();
-        out.write( ( new ZipShort( extra.length ) ).getBytes() );
-        m_written += 2;
-
-        // file comment length
-        String comm = entry.getComment();
-        if( comm == null )
-        {
-            comm = "";
-        }
-        byte[] comment = getBytes( comm );
-        out.write( ( new ZipShort( comment.length ) ).getBytes() );
-        m_written += 2;
-
-        // disk number start
-        out.write( ZERO );
-        m_written += 2;
-
-        // internal file attributes
-        out.write( ( new ZipShort( entry.getInternalAttributes() ) 
).getBytes() );
-        m_written += 2;
-
-        // external file attributes
-        out.write( ( new ZipLong( entry.getExternalAttributes() ) ).getBytes() 
);
-        m_written += 4;
-
-        // relative offset of LFH
-        out.write( ( (ZipLong)m_offsets.get( entry ) ).getBytes() );
-        m_written += 4;
+        byte[] extra = ze.getLocalFileDataExtra();
+        writeOut(ZipShort.getBytes(extra.length));
+        written += SHORT;
 
         // file name
-        out.write( name );
-        m_written += name.length;
+        writeOut(name);
+        written += name.length;
 
         // extra field
-        out.write( extra );
-        m_written += extra.length;
+        writeOut(extra);
+        written += extra.length;
 
-        // file comment
-        out.write( comment );
-        m_written += comment.length;
+        dataStart = written;
     }
 
     /**
-     * Writes the data descriptor entry
+     * Writes the data descriptor entry.
+     * @param ze the entry to write
+     * @throws IOException on error
      *
-     * @param ze Description of Parameter
-     * @throws IOException if an IO failure causes operation to fail
      * @since 1.1
      */
-    protected void writeDataDescriptor( ZipArchiveEntry ze )
-        throws IOException
-    {
-        if( ze.getMethod() != DEFLATED )
-        {
+    protected void writeDataDescriptor(ZipEntry ze) throws IOException {
+        if (ze.getMethod() != DEFLATED || raf != null) {
             return;
         }
-        out.write( DD_SIG.getBytes() );
-        out.write( ( new ZipLong( m_entry.getCrc() ) ).getBytes() );
-        out.write( ( new ZipLong( m_entry.getCompressedSize() ) ).getBytes() );
-        out.write( ( new ZipLong( m_entry.getSize() ) ).getBytes() );
-        m_written += 16;
+        writeOut(DD_SIG);
+        writeOut(ZipLong.getBytes(entry.getCrc()));
+        writeOut(ZipLong.getBytes(entry.getCompressedSize()));
+        writeOut(ZipLong.getBytes(entry.getSize()));
+        // CheckStyle:MagicNumber OFF
+        written += 16;
+        // CheckStyle:MagicNumber ON
     }
 
     /**
-     * Writes the local file header entry
+     * Writes the central file header entry.
+     * @param ze the entry to write
+     * @throws IOException on error
      *
-     * @param entry the zip entry
-     * @exception IOException when an IO error causes operation to fail
      * @since 1.1
      */
-    protected void writeLocalFileHeader( final ZipArchiveEntry entry )
-        throws IOException
-    {
-        m_offsets.put( entry, new ZipLong( m_written ) );
+    protected void writeCentralFileHeader(ZipEntry ze) throws IOException {
+        writeOut(CFH_SIG);
+        written += WORD;
 
-        out.write( LFH_SIG.getBytes() );
-        m_written += 4;
+        // version made by
+        // CheckStyle:MagicNumber OFF
+        writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20));
+        written += SHORT;
 
         // version needed to extract
         // general purpose bit flag
-        if( entry.getMethod() == DEFLATED )
-        {
+        if (ze.getMethod() == DEFLATED && raf == null) {
             // requires version 2 as we are going to store length info
             // in the data descriptor
-            out.write( ( new ZipShort( 20 ) ).getBytes() );
+            writeOut(ZipShort.getBytes(20));
 
             // bit3 set to signal, we use a data descriptor
-            out.write( ( new ZipShort( 8 ) ).getBytes() );
-        }
-        else
-        {
-            out.write( ( new ZipShort( 10 ) ).getBytes() );
-            out.write( ZERO );
+            writeOut(ZipShort.getBytes(8));
+        } else {
+            writeOut(ZipShort.getBytes(10));
+            writeOut(ZERO);
         }
-        m_written += 4;
+        // CheckStyle:MagicNumber ON
+        written += WORD;
 
         // compression method
-        out.write( ( new ZipShort( entry.getMethod() ) ).getBytes() );
-        m_written += 2;
+        writeOut(ZipShort.getBytes(ze.getMethod()));
+        written += SHORT;
 
         // last mod. time and date
-        out.write( toDosTime( new Date( entry.getTime() ) ).getBytes() );
-        m_written += 4;
+        writeOut(toDosTime(ze.getTime()));
+        written += WORD;
 
         // CRC
         // compressed length
         // uncompressed length
-        if( entry.getMethod() == DEFLATED )
-        {
-            out.write( LZERO );
-            out.write( LZERO );
-            out.write( LZERO );
-        }
-        else
-        {
-            out.write( ( new ZipLong( entry.getCrc() ) ).getBytes() );
-            out.write( ( new ZipLong( entry.getSize() ) ).getBytes() );
-            out.write( ( new ZipLong( entry.getSize() ) ).getBytes() );
-        }
-        m_written += 12;
+        writeOut(ZipLong.getBytes(ze.getCrc()));
+        writeOut(ZipLong.getBytes(ze.getCompressedSize()));
+        writeOut(ZipLong.getBytes(ze.getSize()));
+        // CheckStyle:MagicNumber OFF
+        written += 12;
+        // CheckStyle:MagicNumber ON
 
         // file name length
-        byte[] name = getBytes( entry.getName() );
-        out.write( ( new ZipShort( name.length ) ).getBytes() );
-        m_written += 2;
+        byte[] name = getBytes(ze.getName());
+        writeOut(ZipShort.getBytes(name.length));
+        written += SHORT;
 
         // extra field length
-        byte[] extra = entry.getLocalFileDataExtra();
-        out.write( ( new ZipShort( extra.length ) ).getBytes() );
-        m_written += 2;
+        byte[] extra = ze.getCentralDirectoryExtra();
+        writeOut(ZipShort.getBytes(extra.length));
+        written += SHORT;
+
+        // file comment length
+        String comm = ze.getComment();
+        if (comm == null) {
+            comm = "";
+        }
+        byte[] commentB = getBytes(comm);
+        writeOut(ZipShort.getBytes(commentB.length));
+        written += SHORT;
+
+        // disk number start
+        writeOut(ZERO);
+        written += SHORT;
+
+        // internal file attributes
+        writeOut(ZipShort.getBytes(ze.getInternalAttributes()));
+        written += SHORT;
+
+        // external file attributes
+        writeOut(ZipLong.getBytes(ze.getExternalAttributes()));
+        written += WORD;
+
+        // relative offset of LFH
+        writeOut((byte[]) offsets.get(ze));
+        written += WORD;
 
         // file name
-        out.write( name );
-        m_written += name.length;
+        writeOut(name);
+        written += name.length;
 
         // extra field
-        out.write( extra );
-        m_written += extra.length;
+        writeOut(extra);
+        written += extra.length;
+
+        // file comment
+        writeOut(commentB);
+        written += commentB.length;
+    }
+
+    /**
+     * Writes the &quot;End of central dir record&quot;.
+     * @throws IOException on error
+     *
+     * @since 1.1
+     */
+    protected void writeCentralDirectoryEnd() throws IOException {
+        writeOut(EOCD_SIG);
+
+        // disk numbers
+        writeOut(ZERO);
+        writeOut(ZERO);
+
+        // number of entries
+        byte[] num = ZipShort.getBytes(entries.size());
+        writeOut(num);
+        writeOut(num);
+
+        // length and location of CD
+        writeOut(ZipLong.getBytes(cdLength));
+        writeOut(ZipLong.getBytes(cdOffset));
+
+        // ZIP file comment
+        byte[] data = getBytes(comment);
+        writeOut(ZipShort.getBytes(data.length));
+        writeOut(data);
+    }
+
+    /**
+     * Smallest date/time ZIP can handle.
+     *
+     * @since 1.1
+     */
+    private static final byte[] DOS_TIME_MIN = ZipLong.getBytes(0x00002100L);
+
+    /**
+     * Convert a Date object to a DOS date/time field.
+     * @param time the <code>Date</code> to convert
+     * @return the date as a <code>ZipLong</code>
+     * @since 1.1
+     */
+    protected static ZipLong toDosTime(Date time) {
+        return new ZipLong(toDosTime(time.getTime()));
+    }
+
+    /**
+     * Convert a Date object to a DOS date/time field.
+     *
+     * <p>Stolen from InfoZip's <code>fileio.c</code></p>
+     * @param t number of milliseconds since the epoch
+     * @return the date as a byte array
+     * @since 1.26
+     */
+    protected static byte[] toDosTime(long t) {
+        Date time = new Date(t);
+        // CheckStyle:MagicNumberCheck OFF - I do not think that using 
constants
+        //                                   here will improve the readablity
+        int year = time.getYear() + 1900;
+        if (year < 1980) {
+            return DOS_TIME_MIN;
+        }
+        int month = time.getMonth() + 1;
+        long value =  ((year - 1980) << 25)
+            |         (month << 21)
+            |         (time.getDate() << 16)
+            |         (time.getHours() << 11)
+            |         (time.getMinutes() << 5)
+            |         (time.getSeconds() >> 1);
+        return ZipLong.getBytes(value);
+        // CheckStyle:MagicNumberCheck ON
+    }
+
+    /**
+     * Retrieve the bytes for the given String in the encoding set for
+     * this Stream.
+     * @param name the string to get bytes from
+     * @return the bytes as a byte array
+     * @throws ZipException on error
+     *
+     * @since 1.3
+     */
+    protected byte[] getBytes(String name) throws ZipException {
+        if (encoding == null) {
+            return name.getBytes();
+        } else {
+            try {
+                return name.getBytes(encoding);
+            } catch (UnsupportedEncodingException uee) {
+                throw new ZipException(uee.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Write bytes to output or random access file.
+     * @param data the byte array to write
+     * @throws IOException on error
+     *
+     * @since 1.14
+     */
+    protected final void writeOut(byte[] data) throws IOException {
+        writeOut(data, 0, data.length);
+    }
+
+    /**
+     * Write bytes to output or random access file.
+     * @param data the byte array to write
+     * @param offset the start position to write from
+     * @param length the number of bytes to write
+     * @throws IOException on error
+     *
+     * @since 1.14
+     */
+    protected final void writeOut(byte[] data, int offset, int length)
+        throws IOException {
+        if (raf != null) {
+            raf.write(data, offset, length);
+        } else {
+            out.write(data, offset, length);
+        }
+    }
+
+    /**
+     * Assumes a negative integer really is a positive integer that
+     * has wrapped around and re-creates the original value.
+     * @param i the value to treat as unsigned int.
+     * @return the unsigned int as a long.
+     * @since 1.34
+     */
+    protected static long adjustToLong(int i) {
+        if (i < 0) {
+            return 2 * ((long) Integer.MAX_VALUE) + 2 + i;
+        } else {
+            return i;
+        }
+    }
 
-        m_dataStart = m_written;
+    private void deflateUntilInputIsNeeded() throws IOException {
+        while (!def.needsInput()) {
+            deflate();
+        }
     }
 
 }

Modified: 
commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipShort.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipShort.java?rev=733688&r1=733687&r2=733688&view=diff
==============================================================================
--- 
commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipShort.java
 (original)
+++ 
commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipShort.java
 Mon Jan 12 03:15:34 2009
@@ -1,115 +1,135 @@
 /*
- * 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
+ *  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
+ *      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.
  *
- * 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.commons.compress.archivers.zip;
 
 /**
- * Utility class that represents a two byte integer with conversion rules for
- * the big endian byte order of ZIP files.
+ * Utility class that represents a two byte integer with conversion
+ * rules for the big endian byte order of ZIP files.
+ *
  */
-public final class ZipShort implements Cloneable
-{
-    private int m_value;
+public final class ZipShort implements Cloneable {
+    private static final int BYTE_MASK = 0xFF;
+    private static final int BYTE_1_MASK = 0xFF00;
+    private static final int BYTE_1_SHIFT = 8;
+
+    private int value;
 
     /**
      * Create instance from a number.
-     *
-     * @param value Description of Parameter
+     * @param value the int to store as a ZipShort
      * @since 1.1
      */
-    public ZipShort( int value )
-    {
-        this.m_value = value;
+    public ZipShort (int value) {
+        this.value = value;
     }
 
     /**
      * Create instance from bytes.
-     *
-     * @param bytes Description of Parameter
+     * @param bytes the bytes to store as a ZipShort
      * @since 1.1
      */
-    public ZipShort( byte[] bytes )
-    {
-        this( bytes, 0 );
+    public ZipShort (byte[] bytes) {
+        this(bytes, 0);
     }
 
     /**
      * Create instance from the two bytes starting at offset.
-     *
-     * @param bytes Description of Parameter
-     * @param offset Description of Parameter
+     * @param bytes the bytes to store as a ZipShort
+     * @param offset the offset to start
      * @since 1.1
      */
-    public ZipShort( byte[] bytes, int offset )
-    {
-        m_value = ( bytes[ offset + 1 ] << 8 ) & 0xFF00;
-        m_value += ( bytes[ offset ] & 0xFF );
+    public ZipShort (byte[] bytes, int offset) {
+        value = ZipShort.getValue(bytes, offset);
     }
 
     /**
      * Get value as two bytes in big endian byte order.
-     *
-     * @return The Bytes value
+     * @return the value as a a two byte array in big endian byte order
      * @since 1.1
      */
-    public byte[] getBytes()
-    {
-        byte[] result = new byte[ 2 ];
-        result[ 0 ] = (byte)( m_value & 0xFF );
-        result[ 1 ] = (byte)( ( m_value & 0xFF00 ) >> 8 );
+    public byte[] getBytes() {
+        byte[] result = new byte[2];
+        result[0] = (byte) (value & BYTE_MASK);
+        result[1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
         return result;
     }
 
     /**
      * Get value as Java int.
-     *
-     * @return The Value value
+     * @return value as a Java int
      * @since 1.1
      */
-    public int getValue()
-    {
-        return m_value;
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Get value as two bytes in big endian byte order.
+     * @param value the Java int to convert to bytes
+     * @return the converted int as a byte array in big endian byte order
+     */
+    public static byte[] getBytes(int value) {
+        byte[] result = new byte[2];
+        result[0] = (byte) (value & BYTE_MASK);
+        result[1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
+        return result;
+    }
+
+    /**
+     * Helper method to get the value as a java int from two bytes starting at 
given array offset
+     * @param bytes the array of bytes
+     * @param offset the offset to start
+     * @return the correspondanding java int value
+     */
+    public static int getValue(byte[] bytes, int offset) {
+        int value = (bytes[offset + 1] << BYTE_1_SHIFT) & BYTE_1_MASK;
+        value += (bytes[offset] & BYTE_MASK);
+        return value;
+    }
+
+    /**
+     * Helper method to get the value as a java int from a two-byte array
+     * @param bytes the array of bytes
+     * @return the correspondanding java int value
+     */
+    public static int getValue(byte[] bytes) {
+        return getValue(bytes, 0);
     }
 
     /**
      * Override to make two instances with same value equal.
-     *
-     * @param o Description of Parameter
-     * @return Description of the Returned Value
+     * @param o an object to compare
+     * @return true if the objects are equal
      * @since 1.1
      */
-    public boolean equals( Object o )
-    {
-        if( o == null || !( o instanceof ZipShort ) )
-        {
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof ZipShort)) {
             return false;
         }
-        return m_value == ( (ZipShort)o ).getValue();
+        return value == ((ZipShort) o).getValue();
     }
 
     /**
      * Override to make two instances with same value equal.
-     *
-     * @return Description of the Returned Value
+     * @return the value stored in the ZipShort
      * @since 1.1
      */
-    public int hashCode()
-    {
-        return m_value;
+    public int hashCode() {
+        return value;
     }
 }


Reply via email to