You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tc...@apache.org on 2008/07/07 02:28:49 UTC

svn commit: r674372 [3/6] - in /commons/sandbox/compress/branches/redesign: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/commons/ src/main/java/org/apache/commons/compress/ src/main/java/org/apa...

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,409 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.util.zip.CRC32;
+import java.util.zip.ZipException;
+
+/**
+ * Adds Unix file permission and UID/GID fields as well as symbolic link
+ * handling. <p>
+ *
+ * This class uses the ASi extra field in the format: <pre>
+ *         Value         Size            Description
+ *         -----         ----            -----------
+ * (Unix3) 0x756e        Short           tag for this extra block type
+ *         TSize         Short           total data size for this block
+ *         CRC           Long            CRC-32 of the remaining data
+ *         Mode          Short           file permissions
+ *         SizDev        Long            symlink'd size OR major/minor dev num
+ *         UID           Short           user ID
+ *         GID           Short           group ID
+ *         (var.)        variable        symbolic link filename
+ * </pre> taken from appnote.iz (Info-ZIP note, 981119) found at <a
+ * href="ftp://ftp.uu.net/pub/archiving/zip/doc/">
+ * ftp://ftp.uu.net/pub/archiving/zip/doc/</a> </p> <p>
+ *
+ * Short is two bytes and Long is four bytes in big endian byte and word order,
+ * device numbers are currently not supported.</p>
+ *
+ * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
+ * @version $Revision: 155439 $
+ */
+public class AsiExtraField
+    implements ZipExtraField, UnixStat, Cloneable
+{
+    private static final ZipShort HEADER_ID = new ZipShort( 0x756E );
+
+    /**
+     * Standard Unix stat(2) file mode.
+     *
+     * @since 1.1
+     */
+    private int m_mode;
+
+    /**
+     * User ID.
+     *
+     * @since 1.1
+     */
+    private int m_uid;
+
+    /**
+     * Group ID.
+     *
+     * @since 1.1
+     */
+    private int m_gid;
+
+    /**
+     * File this entry points to, if it is a symbolic link. <p>
+     *
+     * empty string - if entry is not a symbolic link.</p>
+     *
+     * @since 1.1
+     */
+    private String m_link = "";
+
+    /**
+     * Is this an entry for a directory?
+     *
+     * @since 1.1
+     */
+    private boolean m_dirFlag;
+
+    /**
+     * Instance used to calculate checksums.
+     *
+     * @since 1.1
+     */
+    private CRC32 m_crc = new CRC32();
+
+    /**
+     * Indicate whether this entry is a directory.
+     *
+     * @param dirFlag The new Directory value
+     * @since 1.1
+     */
+    public void setDirectory( final boolean dirFlag )
+    {
+        m_dirFlag = dirFlag;
+        m_mode = getMode( m_mode );
+    }
+
+    /**
+     * Set the group id.
+     *
+     * @param gid The new GroupId value
+     * @since 1.1
+     */
+    public void setGroupId( int gid )
+    {
+        m_gid = gid;
+    }
+
+    /**
+     * Indicate that this entry is a symbolic link to the given filename.
+     *
+     * @param name Name of the file this entry links to, empty String if it is
+     *      not a symbolic link.
+     * @since 1.1
+     */
+    public void setLinkedFile( final String name )
+    {
+        m_link = name;
+        m_mode = getMode( m_mode );
+    }
+
+    /**
+     * File mode of this file.
+     *
+     * @param mode The new Mode value
+     * @since 1.1
+     */
+    public void setMode( final int mode )
+    {
+        m_mode = getMode( mode );
+    }
+
+    /**
+     * Set the user id.
+     *
+     * @param uid The new UserId value
+     * @since 1.1
+     * @deprecated Use setUserID(int)
+     * @see #setUserID(int)
+     */
+    public void setUserId( final int uid )
+    {
+        m_uid = uid;
+    }
+
+    /**
+     * Set the user id.
+     *
+     * @param uid The new UserId value
+     */
+    public void setUserID( final int uid )
+    {
+        m_uid = uid;
+    }
+
+    /**
+     * Delegate to local file data.
+     *
+     * @return The CentralDirectoryData value
+     * @since 1.1
+     */
+    public byte[] getCentralDirectoryData()
+    {
+        return getLocalFileDataData();
+    }
+
+    /**
+     * Delegate to local file data.
+     *
+     * @return The CentralDirectoryLength value
+     * @since 1.1
+     */
+    public ZipShort getCentralDirectoryLength()
+    {
+        return getLocalFileDataLength();
+    }
+
+    /**
+     * Get the group id.
+     *
+     * @return The GroupId value
+     * @since 1.1
+     */
+    public int getGroupID()
+    {
+        return m_gid;
+    }
+
+    /**
+     * Get the group id.
+     *
+     * @return The GroupId value
+     * @since 1.1
+     * @deprecated Use getGroupID() instead
+     * @see #getGroupID()
+     */
+    public int getGroupId()
+    {
+        return m_gid;
+    }
+
+    /**
+     * The Header-ID.
+     *
+     * @return The HeaderId value
+     * @since 1.1
+     */
+    public ZipShort getHeaderID()
+    {
+        return HEADER_ID;
+    }
+
+    /**
+     * Name of linked file
+     *
+     * @return name of the file this entry links to if it is a symbolic link,
+     *      the empty string otherwise.
+     * @since 1.1
+     */
+    public String getLinkedFile()
+    {
+        return m_link;
+    }
+
+    /**
+     * The actual data to put into local file data - without Header-ID or length
+     * specifier.
+     *
+     * @return The LocalFileDataData value
+     * @since 1.1
+     */
+    public byte[] getLocalFileDataData()
+    {
+        // CRC will be added later
+        byte[] data = new byte[ getLocalFileDataLength().getValue() - 4 ];
+        System.arraycopy( ( new ZipShort( getMode() ) ).getBytes(), 0, data, 0, 2 );
+
+        byte[] linkArray = getLinkedFile().getBytes();
+        System.arraycopy( ( new ZipLong( linkArray.length ) ).getBytes(),
+                          0, data, 2, 4 );
+
+        System.arraycopy( ( new ZipShort( getUserID() ) ).getBytes(),
+                          0, data, 6, 2 );
+        System.arraycopy( ( new ZipShort( getGroupID() ) ).getBytes(),
+                          0, data, 8, 2 );
+
+        System.arraycopy( linkArray, 0, data, 10, linkArray.length );
+
+        m_crc.reset();
+        m_crc.update( data );
+        long checksum = m_crc.getValue();
+
+        byte[] result = new byte[ data.length + 4 ];
+        System.arraycopy( ( new ZipLong( checksum ) ).getBytes(), 0, result, 0, 4 );
+        System.arraycopy( data, 0, result, 4, data.length );
+        return result;
+    }
+
+    /**
+     * Length of the extra field in the local file data - without Header-ID or
+     * length specifier.
+     *
+     * @return The LocalFileDataLength value
+     * @since 1.1
+     */
+    public ZipShort getLocalFileDataLength()
+    {
+        return new ZipShort( 4 + // CRC
+                             2 + // Mode
+                             4 + // SizDev
+                             2 + // UID
+                             2 + // GID
+                             getLinkedFile().getBytes().length );
+    }
+
+    /**
+     * File mode of this file.
+     *
+     * @return The Mode value
+     * @since 1.1
+     */
+    public int getMode()
+    {
+        return m_mode;
+    }
+
+    /**
+     * Get the user id.
+     *
+     * @return The UserId value
+     * @since 1.1
+     * @deprecated Use getUserID()
+     * @see #getUserID()
+     */
+    public int getUserId()
+    {
+        return m_uid;
+    }
+
+    /**
+     * Get the user id.
+     *
+     * @return The UserID value
+     */
+    public int getUserID()
+    {
+        return m_uid;
+    }
+
+    /**
+     * Is this entry a directory?
+     *
+     * @return The Directory value
+     * @since 1.1
+     */
+    public boolean isDirectory()
+    {
+        return m_dirFlag && !isLink();
+    }
+
+    /**
+     * Is this entry a symbolic link?
+     *
+     * @return The Link value
+     * @since 1.1
+     */
+    public boolean isLink()
+    {
+        return getLinkedFile().length() != 0;
+    }
+
+    /**
+     * Populate data from this array as if it was in local file data.
+     *
+     * @param buffer the buffer
+     * @param offset the offset into buffer
+     * @param length the length of data in buffer
+     * @throws ZipException on error
+     * @since 1.1
+     */
+    public void parseFromLocalFileData( final byte[] buffer,
+                                        final int offset,
+                                        final int length )
+        throws ZipException
+    {
+
+        long givenChecksum = ( new ZipLong( buffer, offset ) ).getValue();
+        byte[] tmp = new byte[ length - 4 ];
+        System.arraycopy( buffer, offset + 4, tmp, 0, length - 4 );
+        m_crc.reset();
+        m_crc.update( tmp );
+        long realChecksum = m_crc.getValue();
+        if( givenChecksum != realChecksum )
+        {
+            throw new ZipException( "bad CRC checksum " + Long.toHexString( givenChecksum ) +
+                                    " instead of " + Long.toHexString( realChecksum ) );
+        }
+
+        int newMode = ( new ZipShort( tmp, 0 ) ).getValue();
+        byte[] linkArray = new byte[ (int)( new ZipLong( tmp, 2 ) ).getValue() ];
+        m_uid = ( new ZipShort( tmp, 6 ) ).getValue();
+        m_gid = ( new ZipShort( tmp, 8 ) ).getValue();
+
+        if( linkArray.length == 0 )
+        {
+            m_link = "";
+        }
+        else
+        {
+            System.arraycopy( tmp, 10, linkArray, 0, linkArray.length );
+            m_link = new String( linkArray );
+        }
+        setDirectory( ( newMode & DIR_FLAG ) != 0 );
+        setMode( newMode );
+    }
+
+    /**
+     * Get the file mode for given permissions with the correct file type.
+     *
+     * @param mode Description of Parameter
+     * @return The Mode value
+     * @since 1.1
+     */
+    protected int getMode( final int mode )
+    {
+        int type = FILE_FLAG;
+        if( isLink() )
+        {
+            type = LINK_FLAG;
+        }
+        else if( isDirectory() )
+        {
+            type = DIR_FLAG;
+        }
+        return type | ( mode & PERM_MASK );
+    }
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.zip.ZipException;
+
+/**
+ * ZipExtraField related methods
+ *
+ * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
+ * @version $Revision: 155439 $
+ */
+public class ExtraFieldUtils
+{
+    /**
+     * Static registry of known extra fields.
+     *
+     * @since 1.1
+     */
+    private static final Hashtable c_implementations;
+
+    static
+    {
+        c_implementations = new Hashtable();
+        register( AsiExtraField.class );
+    }
+
+    /**
+     * Create an instance of the approriate ExtraField, falls back to {@link
+     * UnrecognizedExtraField UnrecognizedExtraField}.
+     *
+     * Throws java.lang.IllegalAccessException if cant create implementation.
+     *
+     * @param headerID the header ID
+     * @return the extra field implementation
+     * @throws InstantiationException if cant create implementation
+     * @throws IllegalAccessException if cant create implementation
+     * @since 1.1
+     */
+    public static ZipExtraField createExtraField( final ZipShort headerID )
+        throws InstantiationException, IllegalAccessException
+    {
+        final Class clazz =
+            (Class)c_implementations.get( headerID );
+        if( clazz != null )
+        {
+            return (ZipExtraField)clazz.newInstance();
+        }
+        final UnrecognizedExtraField unrecognized = new UnrecognizedExtraField();
+        unrecognized.setHeaderID( headerID );
+        return unrecognized;
+    }
+
+    /**
+     * Merges the central directory fields of the given ZipExtraFields.
+     *
+     * @param data the central directory data
+     * @return the merged data
+     * @since 1.1
+     */
+    public static byte[] mergeCentralDirectoryData( final ZipExtraField[] data )
+    {
+        int sum = 4 * data.length;
+        for( int i = 0; i < data.length; i++ )
+        {
+            sum += data[ i ].getCentralDirectoryLength().getValue();
+        }
+        byte[] result = new byte[ sum ];
+        int start = 0;
+        for( int i = 0; i < data.length; i++ )
+        {
+            System.arraycopy( data[ i ].getHeaderID().getBytes(),
+                              0, result, start, 2 );
+            System.arraycopy( data[ i ].getCentralDirectoryLength().getBytes(),
+                              0, result, start + 2, 2 );
+            byte[] local = data[ i ].getCentralDirectoryData();
+            System.arraycopy( local, 0, result, start + 4, local.length );
+            start += ( local.length + 4 );
+        }
+        return result;
+    }
+
+    /**
+     * Merges the local file data fields of the given ZipExtraFields.
+     *
+     * @param data the data
+     * @return the merged data
+     * @since 1.1
+     */
+    public static byte[] mergeLocalFileDataData( final ZipExtraField[] data )
+    {
+        int sum = 4 * data.length;
+        for( int i = 0; i < data.length; i++ )
+        {
+            sum += data[ i ].getLocalFileDataLength().getValue();
+        }
+        byte[] result = new byte[ sum ];
+        int start = 0;
+        for( int i = 0; i < data.length; i++ )
+        {
+            System.arraycopy( data[ i ].getHeaderID().getBytes(),
+                              0, result, start, 2 );
+            System.arraycopy( data[ i ].getLocalFileDataLength().getBytes(),
+                              0, result, start + 2, 2 );
+            byte[] local = data[ i ].getLocalFileDataData();
+            System.arraycopy( local, 0, result, start + 4, local.length );
+            start += ( local.length + 4 );
+        }
+        return result;
+    }
+
+    /**
+     * Split the array into ExtraFields and populate them with the give data.
+     *
+     * @param data the data to parse
+     * @return the parsed fields
+     * @exception ZipException on error
+     * @since 1.1
+     */
+    public static ZipExtraField[] parse( final byte[] data )
+        throws ZipException
+    {
+        ArrayList v = new ArrayList();
+        int start = 0;
+        while( start <= data.length - 4 )
+        {
+            final ZipShort headerID = new ZipShort( data, start );
+            int length = ( new ZipShort( data, start + 2 ) ).getValue();
+            if( start + 4 + length > data.length )
+            {
+                throw new ZipException( "data starting at " + start + " is in unknown format" );
+            }
+            try
+            {
+                ZipExtraField ze = createExtraField( headerID );
+                ze.parseFromLocalFileData( data, start + 4, length );
+                v.add( ze );
+            }
+            catch( InstantiationException ie )
+            {
+                throw new ZipException( ie.getMessage() );
+            }
+            catch( IllegalAccessException iae )
+            {
+                throw new ZipException( iae.getMessage() );
+            }
+            start += ( length + 4 );
+        }
+        if( start != data.length )
+        {// array not exhausted
+            throw new ZipException( "data starting at " + start + " is in unknown format" );
+        }
+
+        final ZipExtraField[] result = new ZipExtraField[ v.size() ];
+        return (ZipExtraField[])v.toArray( result );
+    }
+
+    /**
+     * Register a ZipExtraField implementation. <p>
+     *
+     * The given class must have a no-arg constructor and implement the {@link
+     * ZipExtraField ZipExtraField interface}.</p>
+     *
+     * @param clazz The Class for particular implementation
+     * @since 1.1
+     */
+    public static void register( final Class clazz )
+    {
+        try
+        {
+            ZipExtraField ze = (ZipExtraField)clazz.newInstance();
+            c_implementations.put( ze.getHeaderID(), clazz );
+        }
+        catch( ClassCastException cc )
+        {
+            throw new RuntimeException( clazz +
+                                        " doesn\'t implement ZipExtraField" );
+        }
+        catch( InstantiationException ie )
+        {
+            throw new RuntimeException( clazz + " is not a concrete class" );
+        }
+        catch( IllegalAccessException ie )
+        {
+            throw new RuntimeException( clazz +
+                                        "\'s no-arg constructor is not public" );
+        }
+    }
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnixStat.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnixStat.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnixStat.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnixStat.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+/**
+ * Constants from stat.h on Unix systems.
+ *
+ * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
+ * @version $Revision: 155439 $
+ */
+public interface UnixStat
+{
+    /**
+     * Bits used for permissions (and sticky bit)
+     *
+     * @since 1.1
+     */
+    int PERM_MASK = 07777;
+    /**
+     * Indicates symbolic links.
+     *
+     * @since 1.1
+     */
+    int LINK_FLAG = 0120000;
+    /**
+     * Indicates plain files.
+     *
+     * @since 1.1
+     */
+    int FILE_FLAG = 0100000;
+    /**
+     * Indicates directories.
+     *
+     * @since 1.1
+     */
+    int DIR_FLAG = 040000;
+
+    // ----------------------------------------------------------
+    // somewhat arbitrary choices that are quite common for shared
+    // installations
+    // -----------------------------------------------------------
+
+    /**
+     * Default permissions for symbolic links.
+     *
+     * @since 1.1
+     */
+    int DEFAULT_LINK_PERM = 0777;
+
+    /**
+     * Default permissions for directories.
+     *
+     * @since 1.1
+     */
+    int DEFAULT_DIR_PERM = 0755;
+
+    /**
+     * Default permissions for plain files.
+     *
+     * @since 1.1
+     */
+    int DEFAULT_FILE_PERM = 0644;
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+/**
+ * Simple placeholder for all those extra fields we don't want to deal with. <p>
+ *
+ * Assumes local file data and central directory entries are identical - unless
+ * told the opposite.</p>
+ *
+ * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
+ * @version $Revision: 155439 $
+ */
+public class UnrecognizedExtraField
+    implements ZipExtraField
+{
+    /**
+     * Extra field data in central directory - without Header-ID or length
+     * specifier.
+     *
+     * @since 1.1
+     */
+    private byte[] m_centralData;
+
+    /**
+     * The Header-ID.
+     *
+     * @since 1.1
+     */
+    private ZipShort m_headerID;
+
+    /**
+     * Extra field data in local file data - without Header-ID or length
+     * specifier.
+     *
+     * @since 1.1
+     */
+    private byte[] m_localData;
+
+    /**
+     * Set the central directory data
+     *
+     * @param centralData the central directory data
+     */
+    public void setCentralDirectoryData( final byte[] centralData )
+    {
+        m_centralData = centralData;
+    }
+
+       /**
+     * Set the header ID.
+     *
+     * @param headerID the header ID
+     */
+    public void setHeaderID( final ZipShort headerID )
+    {
+        m_headerID = headerID;
+    }
+
+    /**
+     * Set the local file data.
+     *
+     * @param localData the local file data
+     */
+    public void setLocalFileDataData( final byte[] localData )
+    {
+        m_localData = localData;
+    }
+
+    /**
+     * Get the central directory data.
+     *
+     * @return the central directory data.
+     */
+    public byte[] getCentralDirectoryData()
+    {
+        if( m_centralData != null )
+        {
+            return m_centralData;
+        }
+        return getLocalFileDataData();
+    }
+
+    /**
+     * Get the length of the central directory in bytes.
+     *
+     * @return the length of the central directory in bytes.
+     */
+    public ZipShort getCentralDirectoryLength()
+    {
+        if( m_centralData != null )
+        {
+            return new ZipShort( m_centralData.length );
+        }
+        return getLocalFileDataLength();
+    }
+
+    /**
+     * Get the HeaderID.
+     *
+     * @return the HeaderID
+     */
+    public ZipShort getHeaderID()
+    {
+        return m_headerID;
+    }
+
+    /**
+     * Get the local file data.
+     *
+     * @return the local file data
+     */
+    public byte[] getLocalFileDataData()
+    {
+        return m_localData;
+    }
+
+    /**
+     * Get the length of local file data in bytes.
+     *
+     * @return the length of local file data in bytes
+     */
+    public ZipShort getLocalFileDataLength()
+    {
+        return new ZipShort( m_localData.length );
+    }
+
+    /**
+     * Parse LocalFiledata out of supplied buffer.
+     *
+     * @param buffer the buffer to use
+     * @param offset the offset into buffer
+     * @param length then length of data
+     */
+    public void parseFromLocalFileData( final byte[] buffer,
+                                        final int offset,
+                                        final int length )
+    {
+        final byte[] fileData = new byte[ length ];
+        System.arraycopy( buffer, offset, fileData, 0, length );
+        setLocalFileDataData( fileData );
+    }
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,457 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.zip.ZipException;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+
+/**
+ * Extension that adds better handling of extra fields and provides access to
+ * the internal and external file attributes.
+ *
+ * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
+ * @version $Revision: 155439 $
+ */
+public class ZipArchiveEntry
+    extends java.util.zip.ZipEntry
+    implements ArchiveEntry
+{
+    /**
+     * Helper for JDK 1.1
+     *
+     * @since 1.2
+     */
+    private static Method c_setCompressedSizeMethod;
+
+    /**
+     * Helper for JDK 1.1
+     *
+     * @since 1.2
+     */
+    private static final Object c_lockReflection = new Object();
+
+    /**
+     * Helper for JDK 1.1
+     *
+     * @since 1.2
+     */
+    private static boolean c_triedToGetMethod;
+
+    private final ArrayList m_extraFields = new ArrayList();
+
+    private int m_internalAttributes;
+    private long m_externalAttributes;
+
+    /**
+     * Helper for JDK 1.1 <-> 1.2 incompatibility.
+     *
+     * @since 1.2
+     */
+    private Long m_compressedSize;
+
+    /**
+     * Creates a new zip entry with the specified name.
+     *
+     * @param name the name of entry
+     * @since 1.1
+     */
+    public ZipArchiveEntry( final String name )
+    {
+        super( name );
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified zip entry.
+     *
+     * @param entry the JDK ZipEntry to adapt
+     * @exception ZipException if can not create entry
+     * @since 1.1
+     */
+    public ZipArchiveEntry( java.util.zip.ZipEntry entry )
+        throws ZipException
+    {
+        /*
+         * REVISIT: call super(entry) instead of this stuff in Ant2,
+         * "copy constructor" has not been available in JDK 1.1
+         */
+        super( entry.getName() );
+
+        setComment( entry.getComment() );
+        setMethod( entry.getMethod() );
+        setTime( entry.getTime() );
+
+        final long size = entry.getSize();
+        if( size > 0 )
+        {
+            setSize( size );
+        }
+
+        final long cSize = entry.getCompressedSize();
+        if( cSize > 0 )
+        {
+            setComprSize( cSize );
+        }
+
+        final long crc = entry.getCrc();
+        if( crc > 0 )
+        {
+            setCrc( crc );
+        }
+
+        final byte[] extra = entry.getExtra();
+        if( extra != null )
+        {
+            setExtraFields( ExtraFieldUtils.parse( extra ) );
+        }
+        else
+        {
+            // initializes extra data to an empty byte array
+            setExtra();
+        }
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified zip entry.
+     *
+     * @param entry the entry to adapt
+     * @exception ZipException if can not create entry
+     * @since 1.1
+     */
+    public ZipArchiveEntry( final ZipArchiveEntry entry )
+        throws ZipException
+    {
+        this( (java.util.zip.ZipEntry)entry );
+        setInternalAttributes( entry.getInternalAttributes() );
+        setExternalAttributes( entry.getExternalAttributes() );
+        setExtraFields( entry.getExtraFields() );
+    }
+
+    /**
+     * Try to get a handle to the setCompressedSize method.
+     *
+     * @since 1.2
+     */
+    private static void checkSCS()
+    {
+        if( !c_triedToGetMethod )
+        {
+            synchronized( c_lockReflection )
+            {
+                c_triedToGetMethod = true;
+                try
+                {
+                    c_setCompressedSizeMethod =
+                        java.util.zip.ZipEntry.class.getMethod( "setCompressedSize",
+                                                                new Class[]{Long.TYPE} );
+                }
+                catch( NoSuchMethodException nse )
+                {
+                }
+            }
+        }
+    }
+
+    /**
+     * Are we running JDK 1.2 or higher?
+     *
+     * @return Description of the Returned Value
+     * @since 1.2
+     */
+    private static boolean haveSetCompressedSize()
+    {
+        checkSCS();
+        return c_setCompressedSizeMethod != null;
+    }
+
+    /**
+     * Invoke setCompressedSize via reflection.
+     *
+     * @param entry Description of Parameter
+     * @param size Description of Parameter
+     * @since 1.2
+     */
+    private static void performSetCompressedSize( final ZipArchiveEntry entry,
+                                                  final long size )
+    {
+        final Long[] s = {new Long( size )};
+        try
+        {
+            c_setCompressedSizeMethod.invoke( entry, s );
+        }
+        catch( final InvocationTargetException ite )
+        {
+            final Throwable nested = ite.getTargetException();
+            final String message = "Exception setting the compressed size " +
+                "of " + entry + ": " + nested.getMessage();
+            throw new RuntimeException( message );
+        }
+        catch( final Throwable t )
+        {
+            final String message = "Exception setting the compressed size " +
+                "of " + entry + ": " + t.getMessage();
+            throw new RuntimeException( message );
+        }
+    }
+
+    /**
+     * Make this class work in JDK 1.1 like a 1.2 class. <p>
+     *
+     * This either stores the size for later usage or invokes setCompressedSize
+     * via reflection.</p>
+     *
+     * @param size The new ComprSize value
+     * @since 1.2
+     */
+    public void setComprSize( final long size )
+    {
+        if( haveSetCompressedSize() )
+        {
+            performSetCompressedSize( this, size );
+        }
+        else
+        {
+            m_compressedSize = new Long( size );
+        }
+    }
+
+    /**
+     * Sets the external file attributes.
+     *
+     * @param externalAttributes The new ExternalAttributes value
+     * @since 1.1
+     */
+    public void setExternalAttributes( final long externalAttributes )
+    {
+        m_externalAttributes = externalAttributes;
+    }
+
+    /**
+     * Throws an Exception if extra data cannot be parsed into extra fields.
+     *
+     * @param extra The new Extra value
+     * @throws RuntimeException if fail to set extra data
+     * @since 1.1
+     */
+    public void setExtra( final byte[] extra )
+        throws RuntimeException
+    {
+        try
+        {
+            setExtraFields( ExtraFieldUtils.parse( extra ) );
+        }
+        catch( final Exception e )
+        {
+            throw new RuntimeException( e.getMessage() );
+        }
+    }
+
+    /**
+     * Replaces all currently attached extra fields with the new array.
+     *
+     * @param fields The new ExtraFields value
+     * @since 1.1
+     */
+    public void setExtraFields( final ZipExtraField[] fields )
+    {
+        m_extraFields.clear();
+        for( int i = 0; i < fields.length; i++ )
+        {
+            m_extraFields.add( fields[ i ] );
+        }
+        setExtra();
+    }
+
+    /**
+     * Sets the internal file attributes.
+     *
+     * @param value The new InternalAttributes value
+     * @since 1.1
+     */
+    public void setInternalAttributes( final int value )
+    {
+        m_internalAttributes = value;
+    }
+
+    /**
+     * Retrieves the extra data for the central directory.
+     *
+     * @return The CentralDirectoryExtra value
+     * @since 1.1
+     */
+    public byte[] getCentralDirectoryExtra()
+    {
+        return ExtraFieldUtils.mergeCentralDirectoryData( getExtraFields() );
+    }
+
+    /**
+     * Override to make this class work in JDK 1.1 like a 1.2 class.
+     *
+     * @return The CompressedSize value
+     * @since 1.2
+     */
+    public long getCompressedSize()
+    {
+        if( m_compressedSize != null )
+        {
+            // has been set explicitly and we are running in a 1.1 VM
+            return m_compressedSize.longValue();
+        }
+        return super.getCompressedSize();
+    }
+
+    /**
+     * Retrieves the external file attributes.
+     *
+     * @return The ExternalAttributes value
+     * @since 1.1
+     */
+    public long getExternalAttributes()
+    {
+        return m_externalAttributes;
+    }
+
+    /**
+     * Retrieves extra fields.
+     *
+     * @return The ExtraFields value
+     * @since 1.1
+     */
+    public ZipExtraField[] getExtraFields()
+    {
+        final ZipExtraField[] result = new ZipExtraField[ m_extraFields.size() ];
+        return (ZipExtraField[])m_extraFields.toArray( result );
+    }
+
+    /**
+     * Retrieves the internal file attributes.
+     *
+     * @return The InternalAttributes value
+     * @since 1.1
+     */
+    public int getInternalAttributes()
+    {
+        return m_internalAttributes;
+    }
+
+    /**
+     * Retrieves the extra data for the local file data.
+     *
+     * @return The LocalFileDataExtra value
+     * @since 1.1
+     */
+    public byte[] getLocalFileDataExtra()
+    {
+        byte[] extra = getExtra();
+        return extra != null ? extra : new byte[ 0 ];
+    }
+
+    /**
+     * Adds an extra fields - replacing an already present extra field of the
+     * same type.
+     *
+     * @param extraField The feature to be added to the ExtraField attribute
+     * @since 1.1
+     */
+    public void addExtraField( final ZipExtraField extraField )
+    {
+        final ZipShort type = extraField.getHeaderID();
+        boolean done = false;
+        for( int i = 0; !done && i < m_extraFields.size(); i++ )
+        {
+            final ZipExtraField other = (ZipExtraField)m_extraFields.get( i );
+            if( other.getHeaderID().equals( type ) )
+            {
+                m_extraFields.set( i, extraField );
+                done = true;
+            }
+        }
+        if( !done )
+        {
+            m_extraFields.add( extraField );
+        }
+        setExtra();
+    }
+
+    /**
+     * Overwrite clone
+     *
+     * @return Description of the Returned Value
+     * @since 1.1
+     */
+    public Object clone()
+    {
+        ZipArchiveEntry entry = null;
+        try
+        {
+            entry = new ZipArchiveEntry( (java.util.zip.ZipEntry)super.clone() );
+        }
+        catch( final Exception e )
+        {
+            // impossible as extra data is in correct format
+            e.printStackTrace();
+            return null;
+        }
+
+        entry.setInternalAttributes( getInternalAttributes() );
+        entry.setExternalAttributes( getExternalAttributes() );
+        entry.setExtraFields( getExtraFields() );
+        return entry;
+    }
+
+    /**
+     * Remove an extra fields.
+     *
+     * @param type Description of Parameter
+     * @since 1.1
+     */
+    public void removeExtraField( final ZipShort type )
+    {
+        boolean done = false;
+        for( int i = 0; !done && i < m_extraFields.size(); i++ )
+        {
+            if( ( (ZipExtraField)m_extraFields.get( i ) ).getHeaderID().equals( type ) )
+            {
+                m_extraFields.remove( i );
+                done = true;
+            }
+        }
+        if( !done )
+        {
+            throw new java.util.NoSuchElementException();
+        }
+        setExtra();
+    }
+
+    /**
+     * Unfortunately {@link java.util.zip.ZipOutputStream
+     * java.util.zip.ZipOutputStream} seems to access the extra data directly,
+     * so overriding getExtra doesn't help - we need to modify super's data
+     * directly.
+     *
+     * @since 1.1
+     */
+    protected void setExtra()
+    {
+        super.setExtra( ExtraFieldUtils.mergeLocalFileDataData( getExtraFields() ) );
+    }
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipInputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+
+public class ZipArchiveInputStream extends ArchiveInputStream {
+
+	private final ZipInputStream input;
+
+	public ZipArchiveInputStream(InputStream inputStream) {
+		input = new ZipInputStream(inputStream);
+	}
+
+    public ArchiveEntry getNextEntry() throws IOException {
+    	java.util.zip.ZipEntry entry = input.getNextEntry();
+    	if(entry == null) {
+    		return null;
+    	}
+        return (ArchiveEntry)new ZipArchiveEntry(entry);
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException {
+        return input.read(b, off, len);
+    }
+    
+    public int read() throws IOException {
+        return input.read();
+    }
+
+    
+    public static boolean matches( byte[] signature ) {
+    	// 4b50 0403 0014 0000
+
+    	if (signature[0] != 0x50) {
+    		return false;
+    	}
+    	if (signature[1] != 0x4b) {
+    		return false;
+    	}
+    	if (signature[2] != 0x03) {
+    		return false;
+    	}
+    	if (signature[3] != 0x04) {
+    		return false;
+    	}
+    	if (signature[4] != 0x14) {
+    		return false;
+    	}
+    	if (signature[5] != 0x00) {
+    		return false;
+    	}
+    	if (signature[6] != 0x00) {
+    		return false;
+    	}
+    	if (signature[7] != 0x00) {
+    		return false;
+    	}
+    	
+    	return true;
+    }
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveOutputStream;
+
+public class ZipArchiveOutputStream extends ArchiveOutputStream {
+
+    private ZipOutputStream zipOut = null;
+
+    
+    public ZipArchiveOutputStream(OutputStream out) {
+        this.zipOut = new ZipOutputStream(out);
+    }
+    
+    public void putArchiveEntry(ArchiveEntry entry) throws IOException {
+        zipOut.putNextEntry((ZipArchiveEntry) entry);
+    }
+
+    public String getDefaultFileExtension() {
+        return "zip";
+    }
+
+    public byte[] getHeader() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getName() {
+        return "zip";
+    }
+
+    public void close() throws IOException {
+        zipOut.close();
+    }
+
+    public void write(byte[] buffer, int offset, int length) throws IOException {
+        zipOut.write(buffer, offset, length);
+    }
+
+    public void closeArchiveEntry() {
+        // do nothing
+    }
+
+	public void write(int arg0) throws IOException {
+		this.zipOut.write(arg0);
+	}
+ 
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipEntry.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipEntry.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipEntry.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipEntry.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,458 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.zip.ZipException;
+
+/**
+ * Extension that adds better handling of extra fields and provides access to
+ * the internal and external file attributes.
+ *
+ * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
+<<<<<<< HEAD:src/main/java/org/apache/commons/compress/archivers/zip/ZipEntry.java
+ * @version $Revision: 437550 $
+=======
+ * @version $Revision: 155439 $
+>>>>>>> 75cb63ff7005344589b57d17338b64783f8f430c:src/main/java/org/apache/commons/compress/archivers/zip/ZipEntry.java
+ */
+public class ZipEntry
+    extends java.util.zip.ZipEntry
+{
+    /**
+     * Helper for JDK 1.1
+     *
+     * @since 1.2
+     */
+    private static Method c_setCompressedSizeMethod;
+
+    /**
+     * Helper for JDK 1.1
+     *
+     * @since 1.2
+     */
+    private static final Object c_lockReflection = new Object();
+
+    /**
+     * Helper for JDK 1.1
+     *
+     * @since 1.2
+     */
+    private static boolean c_triedToGetMethod;
+
+    private final ArrayList m_extraFields = new ArrayList();
+
+    private int m_internalAttributes;
+    private long m_externalAttributes;
+
+    /**
+     * Helper for JDK 1.1 <-> 1.2 incompatibility.
+     *
+     * @since 1.2
+     */
+    private Long m_compressedSize;
+
+    /**
+     * Creates a new zip entry with the specified name.
+     *
+     * @param name the name of entry
+     * @since 1.1
+     */
+    public ZipEntry( final String name )
+    {
+        super( name );
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified zip entry.
+     *
+     * @param entry the JDK ZipEntry to adapt
+     * @exception ZipException if can not create entry
+     * @since 1.1
+     */
+    public ZipEntry( java.util.zip.ZipEntry entry )
+        throws ZipException
+    {
+        /*
+         * REVISIT: call super(entry) instead of this stuff in Ant2,
+         * "copy constructor" has not been available in JDK 1.1
+         */
+        super( entry.getName() );
+
+        setComment( entry.getComment() );
+        setMethod( entry.getMethod() );
+        setTime( entry.getTime() );
+
+        final long size = entry.getSize();
+        if( size > 0 )
+        {
+            setSize( size );
+        }
+
+        final long cSize = entry.getCompressedSize();
+        if( cSize > 0 )
+        {
+            setComprSize( cSize );
+        }
+
+        final long crc = entry.getCrc();
+        if( crc > 0 )
+        {
+            setCrc( crc );
+        }
+
+        final byte[] extra = entry.getExtra();
+        if( extra != null )
+        {
+            setExtraFields( ExtraFieldUtils.parse( extra ) );
+        }
+        else
+        {
+            // initializes extra data to an empty byte array
+            setExtra();
+        }
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified zip entry.
+     *
+     * @param entry the entry to adapt
+     * @exception ZipException if can not create entry
+     * @since 1.1
+     */
+    public ZipEntry( final ZipEntry entry )
+        throws ZipException
+    {
+        this( (java.util.zip.ZipEntry)entry );
+        setInternalAttributes( entry.getInternalAttributes() );
+        setExternalAttributes( entry.getExternalAttributes() );
+        setExtraFields( entry.getExtraFields() );
+    }
+
+    /**
+     * Try to get a handle to the setCompressedSize method.
+     *
+     * @since 1.2
+     */
+    private static void checkSCS()
+    {
+        if( !c_triedToGetMethod )
+        {
+            synchronized( c_lockReflection )
+            {
+                c_triedToGetMethod = true;
+                try
+                {
+                    c_setCompressedSizeMethod =
+                        java.util.zip.ZipEntry.class.getMethod( "setCompressedSize",
+                                                                new Class[]{Long.TYPE} );
+                }
+                catch( NoSuchMethodException nse )
+                {
+                }
+            }
+        }
+    }
+
+    /**
+     * Are we running JDK 1.2 or higher?
+     *
+     * @return Description of the Returned Value
+     * @since 1.2
+     */
+    private static boolean haveSetCompressedSize()
+    {
+        checkSCS();
+        return c_setCompressedSizeMethod != null;
+    }
+
+    /**
+     * Invoke setCompressedSize via reflection.
+     *
+     * @param entry Description of Parameter
+     * @param size Description of Parameter
+     * @since 1.2
+     */
+    private static void performSetCompressedSize( final ZipEntry entry,
+                                                  final long size )
+    {
+        final Long[] s = {new Long( size )};
+        try
+        {
+            c_setCompressedSizeMethod.invoke( entry, s );
+        }
+        catch( final InvocationTargetException ite )
+        {
+            final Throwable nested = ite.getTargetException();
+            final String message = "Exception setting the compressed size " +
+                "of " + entry + ": " + nested.getMessage();
+            throw new RuntimeException( message );
+        }
+        catch( final Throwable t )
+        {
+            final String message = "Exception setting the compressed size " +
+                "of " + entry + ": " + t.getMessage();
+            throw new RuntimeException( message );
+        }
+    }
+
+    /**
+     * Make this class work in JDK 1.1 like a 1.2 class. <p>
+     *
+     * This either stores the size for later usage or invokes setCompressedSize
+     * via reflection.</p>
+     *
+     * @param size The new ComprSize value
+     * @since 1.2
+     */
+    public void setComprSize( final long size )
+    {
+        if( haveSetCompressedSize() )
+        {
+            performSetCompressedSize( this, size );
+        }
+        else
+        {
+            m_compressedSize = new Long( size );
+        }
+    }
+
+    /**
+     * Sets the external file attributes.
+     *
+     * @param externalAttributes The new ExternalAttributes value
+     * @since 1.1
+     */
+    public void setExternalAttributes( final long externalAttributes )
+    {
+        m_externalAttributes = externalAttributes;
+    }
+
+    /**
+     * Throws an Exception if extra data cannot be parsed into extra fields.
+     *
+     * @param extra The new Extra value
+     * @throws RuntimeException if fail to set extra data
+     * @since 1.1
+     */
+    public void setExtra( final byte[] extra )
+        throws RuntimeException
+    {
+        try
+        {
+            setExtraFields( ExtraFieldUtils.parse( extra ) );
+        }
+        catch( final Exception e )
+        {
+            throw new RuntimeException( e.getMessage() );
+        }
+    }
+
+    /**
+     * Replaces all currently attached extra fields with the new array.
+     *
+     * @param fields The new ExtraFields value
+     * @since 1.1
+     */
+    public void setExtraFields( final ZipExtraField[] fields )
+    {
+        m_extraFields.clear();
+        for( int i = 0; i < fields.length; i++ )
+        {
+            m_extraFields.add( fields[ i ] );
+        }
+        setExtra();
+    }
+
+    /**
+     * Sets the internal file attributes.
+     *
+     * @param value The new InternalAttributes value
+     * @since 1.1
+     */
+    public void setInternalAttributes( final int value )
+    {
+        m_internalAttributes = value;
+    }
+
+    /**
+     * Retrieves the extra data for the central directory.
+     *
+     * @return The CentralDirectoryExtra value
+     * @since 1.1
+     */
+    public byte[] getCentralDirectoryExtra()
+    {
+        return ExtraFieldUtils.mergeCentralDirectoryData( getExtraFields() );
+    }
+
+    /**
+     * Override to make this class work in JDK 1.1 like a 1.2 class.
+     *
+     * @return The CompressedSize value
+     * @since 1.2
+     */
+    public long getCompressedSize()
+    {
+        if( m_compressedSize != null )
+        {
+            // has been set explicitly and we are running in a 1.1 VM
+            return m_compressedSize.longValue();
+        }
+        return super.getCompressedSize();
+    }
+
+    /**
+     * Retrieves the external file attributes.
+     *
+     * @return The ExternalAttributes value
+     * @since 1.1
+     */
+    public long getExternalAttributes()
+    {
+        return m_externalAttributes;
+    }
+
+    /**
+     * Retrieves extra fields.
+     *
+     * @return The ExtraFields value
+     * @since 1.1
+     */
+    public ZipExtraField[] getExtraFields()
+    {
+        final ZipExtraField[] result = new ZipExtraField[ m_extraFields.size() ];
+        return (ZipExtraField[])m_extraFields.toArray( result );
+    }
+
+    /**
+     * Retrieves the internal file attributes.
+     *
+     * @return The InternalAttributes value
+     * @since 1.1
+     */
+    public int getInternalAttributes()
+    {
+        return m_internalAttributes;
+    }
+
+    /**
+     * Retrieves the extra data for the local file data.
+     *
+     * @return The LocalFileDataExtra value
+     * @since 1.1
+     */
+    public byte[] getLocalFileDataExtra()
+    {
+        byte[] extra = getExtra();
+        return extra != null ? extra : new byte[ 0 ];
+    }
+
+    /**
+     * Adds an extra fields - replacing an already present extra field of the
+     * same type.
+     *
+     * @param extraField The feature to be added to the ExtraField attribute
+     * @since 1.1
+     */
+    public void addExtraField( final ZipExtraField extraField )
+    {
+        final ZipShort type = extraField.getHeaderID();
+        boolean done = false;
+        for( int i = 0; !done && i < m_extraFields.size(); i++ )
+        {
+            final ZipExtraField other = (ZipExtraField)m_extraFields.get( i );
+            if( other.getHeaderID().equals( type ) )
+            {
+                m_extraFields.set( i, extraField );
+                done = true;
+            }
+        }
+        if( !done )
+        {
+            m_extraFields.add( extraField );
+        }
+        setExtra();
+    }
+
+    /**
+     * Overwrite clone
+     *
+     * @return Description of the Returned Value
+     * @since 1.1
+     */
+    public Object clone()
+    {
+        ZipEntry entry = null;
+        try
+        {
+            entry = new ZipEntry( (java.util.zip.ZipEntry)super.clone() );
+        }
+        catch( final Exception e )
+        {
+            // impossible as extra data is in correct format
+            e.printStackTrace();
+            return null;
+        }
+
+        entry.setInternalAttributes( getInternalAttributes() );
+        entry.setExternalAttributes( getExternalAttributes() );
+        entry.setExtraFields( getExtraFields() );
+        return entry;
+    }
+
+    /**
+     * Remove an extra fields.
+     *
+     * @param type Description of Parameter
+     * @since 1.1
+     */
+    public void removeExtraField( final ZipShort type )
+    {
+        boolean done = false;
+        for( int i = 0; !done && i < m_extraFields.size(); i++ )
+        {
+            if( ( (ZipExtraField)m_extraFields.get( i ) ).getHeaderID().equals( type ) )
+            {
+                m_extraFields.remove( i );
+                done = true;
+            }
+        }
+        if( !done )
+        {
+            throw new java.util.NoSuchElementException();
+        }
+        setExtra();
+    }
+
+    /**
+     * Unfortunately {@link java.util.zip.ZipOutputStream
+     * java.util.zip.ZipOutputStream} seems to access the extra data directly,
+     * so overriding getExtra doesn't help - we need to modify super's data
+     * directly.
+     *
+     * @since 1.1
+     */
+    protected void setExtra()
+    {
+        super.setExtra( ExtraFieldUtils.mergeLocalFileDataData( getExtraFields() ) );
+    }
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.util.zip.ZipException;
+
+/**
+ * General format of extra field data. <p>
+ *
+ * Extra fields usually appear twice per file, once in the local file data and
+ * once in the central directory. Usually they are the same, but they don't have
+ * to be. {@link java.util.zip.ZipOutputStream java.util.zip.ZipOutputStream}
+ * will only use the local file data in both places.</p>
+ *
+ * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
+ * @version $Revision: 155439 $
+ */
+public interface ZipExtraField
+{
+    /**
+     * The Header-ID.
+     *
+     * @return The HeaderId value
+     * @since 1.1
+     */
+    ZipShort getHeaderID();
+
+    /**
+     * Length of the extra field in the local file data - without Header-ID or
+     * length specifier.
+     *
+     * @return The LocalFileDataLength value
+     * @since 1.1
+     */
+    ZipShort getLocalFileDataLength();
+
+    /**
+     * Length of the extra field in the central directory - without Header-ID or
+     * length specifier.
+     *
+     * @return The CentralDirectoryLength value
+     * @since 1.1
+     */
+    ZipShort getCentralDirectoryLength();
+
+    /**
+     * The actual data to put into local file data - without Header-ID or length
+     * specifier.
+     *
+     * @return The LocalFileDataData value
+     * @since 1.1
+     */
+    byte[] getLocalFileDataData();
+
+    /**
+     * The actual data to put central directory - without Header-ID or length
+     * specifier.
+     *
+     * @return The CentralDirectoryData value
+     * @since 1.1
+     */
+    byte[] getCentralDirectoryData();
+
+    /**
+     * Populate data from this array as if it was in local file data.
+     *
+     * @param buffer the buffer to read data from
+     * @param offset offset into buffer to read data
+     * @param length the length of data
+     * @exception ZipException on error
+     * @since 1.1
+     */
+    void parseFromLocalFileData( byte[] buffer, int offset, int length )
+        throws ZipException;
+}

Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java?rev=674372&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java Sun Jul  6 17:28:46 2008
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+/**
+ * Utility class that represents a four byte integer with conversion rules for
+ * the big endian byte order of ZIP files.
+ *
+ * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
+ * @version $Revision: 155439 $
+ */
+public final class ZipLong implements Cloneable
+{
+    private long m_value;
+
+    /**
+     * Create instance from a number.
+     *
+     * @param value the value
+     * @since 1.1
+     */
+    public ZipLong( final long value )
+    {
+        m_value = value;
+    }
+
+    /**
+     * Create instance from bytes.
+     *
+     * @param buffer the buffer to read data from
+     * @since 1.1
+     */
+    public ZipLong( final byte[] buffer )
+    {
+        this( buffer, 0 );
+    }
+
+    /**
+     * Create instance from the four bytes starting at offset.
+     *
+     * @param buffer buffer to read data from
+     * @param offset offset into buffer
+     * @since 1.1
+     */
+    public ZipLong( final byte[] buffer, final int offset )
+    {
+        m_value = ( buffer[ offset + 3 ] << 24 ) & 0xFF000000l;
+        m_value += ( buffer[ offset + 2 ] << 16 ) & 0xFF0000;
+        m_value += ( buffer[ offset + 1 ] << 8 ) & 0xFF00;
+        m_value += ( buffer[ offset ] & 0xFF );
+    }
+
+    /**
+     * Get value as two bytes in big endian byte order.
+     *
+     * @return The value as bytes
+     * @since 1.1
+     */
+    public byte[] getBytes()
+    {
+        byte[] result = new byte[ 4 ];
+        result[ 0 ] = (byte)( ( m_value & 0xFF ) );
+        result[ 1 ] = (byte)( ( m_value & 0xFF00 ) >> 8 );
+        result[ 2 ] = (byte)( ( m_value & 0xFF0000 ) >> 16 );
+        result[ 3 ] = (byte)( ( m_value & 0xFF000000l ) >> 24 );
+        return result;
+    }
+
+    /**
+     * Get value as Java int.
+     *
+     * @return The value
+     * @since 1.1
+     */
+    public long getValue()
+    {
+        return m_value;
+    }
+
+    /**
+     * Override to make two instances with same value equal.
+     *
+     * @param o the object to compare against
+     * @return true if equyal, false otherwise
+     * @since 1.1
+     */
+    public boolean equals( final Object o )
+    {
+        if( o == null || !( o instanceof ZipLong ) )
+        {
+            return false;
+        }
+        return m_value == ( (ZipLong)o ).getValue();
+    }
+
+    /**
+     * Override to make two instances with same value equal.
+     *
+     * @return the hashcode
+     * @since 1.1
+     */
+    public int hashCode()
+    {
+        return (int)m_value;
+    }
+}