commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nicola...@apache.org
Subject cvs commit: jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip AsiExtraField.java ExtraFieldUtils.java package.html UnixStat.java UnrecognizedExtraField.java ZipEntry.java ZipExtraField.java ZipLong.java ZipOutputStream.java ZipShort.java
Date Mon, 08 Jul 2002 22:16:38 GMT
nicolaken    2002/07/08 15:16:38

  Added:       io/src/java/org/apache/commons/io/compress/zip
                        AsiExtraField.java ExtraFieldUtils.java
                        package.html UnixStat.java
                        UnrecognizedExtraField.java ZipEntry.java
                        ZipExtraField.java ZipLong.java
                        ZipOutputStream.java ZipShort.java
  Log:
  New zip classes from Avalon excalibur.
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/AsiExtraField.java
  
  Index: AsiExtraField.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.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: 1.1 $
   */
  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 );
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/ExtraFieldUtils.java
  
  Index: ExtraFieldUtils.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.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: 1.1 $
   */
  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" );
          }
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/package.html
  
  Index: package.html
  ===================================================================
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  <html>
  <head>
    <title></title>
  </head>
         <body>
  <p>         Zip Utilities that extend JDK zip classes by adding better  
        handling of extra fields. The utility classes also provide        
  access to the internal and external file attributes. These utility
  classes originated in the Ant project.<br>
         </p>
   <br>
  </body>
  </html>
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/UnixStat.java
  
  Index: UnixStat.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.zip;
  
  /**
   * Constants from stat.h on Unix systems.
   *
   * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
   * @version $Revision: 1.1 $
   */
  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;
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/UnrecognizedExtraField.java
  
  Index: UnrecognizedExtraField.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.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: 1.1 $
   */
  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
       * @deprecated Use setHeaderID() instead
       * @see #setHeaderID(ZipShort)
       */
      public void setHeaderId( final ZipShort headerID )
      {
          setHeaderID( headerID );
      }
  
      /**
       * 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
       * @deprecated Use getHeaderID() instead
       * @see #getHeaderID()
       */
      public ZipShort getHeaderId()
      {
          return m_headerID;
      }
  
      /**
       * 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 );
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/ZipEntry.java
  
  Index: ZipEntry.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.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>
   * @version $Revision: 1.1 $
   */
  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() ) );
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/ZipExtraField.java
  
  Index: ZipExtraField.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.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: 1.1 $
   */
  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;
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/ZipLong.java
  
  Index: ZipLong.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.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: 1.1 $
   */
  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;
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/ZipOutputStream.java
  
  Index: ZipOutputStream.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.zip;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.UnsupportedEncodingException;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.Calendar;
  import java.util.Hashtable;
  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>
   *
   * 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>
   *
   * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
   * @version $Revision: 1.1 $
   */
  public class ZipOutputStream
      extends DeflaterOutputStream
  {
      /**
       * Helper, a 0 as ZipShort.
       *
       * @since 1.1
       */
      private static final byte[] ZERO = {0, 0};
  
      /**
       * Helper, a 0 as ZipLong.
       *
       * @since 1.1
       */
      private static final byte[] LZERO = {0, 0, 0, 0};
  
      /**
       * Compression method for deflated entries.
       *
       * @since 1.1
       */
      public static final int DEFLATED = ZipEntry.DEFLATED;
  
      /**
       * Compression method for deflated entries.
       *
       * @since 1.1
       */
      public static final int STORED = ZipEntry.STORED;
  
      /*
       * Various ZIP constants
       */
      /**
       * local file header signature
       *
       * @since 1.1
       */
      protected static final ZipLong LFH_SIG = new ZipLong( 0X04034B50L );
      /**
       * data descriptor signature
       *
       * @since 1.1
       */
      protected static final ZipLong DD_SIG = new ZipLong( 0X08074B50L );
      /**
       * central file header signature
       *
       * @since 1.1
       */
      protected static final ZipLong CFH_SIG = new ZipLong( 0X02014B50L );
      /**
       * end of central dir signature
       *
       * @since 1.1
       */
      protected static final ZipLong EOCD_SIG = new ZipLong( 0X06054B50L );
  
      /**
       * Smallest date/time ZIP can handle.
       *
       * @since 1.1
       */
      private static final ZipLong DOS_TIME_MIN = new ZipLong( 0x00002100L );
  
      /**
       * The file comment.
       *
       * @since 1.1
       */
      private String m_comment = "";
  
      /**
       * Compression level for next entry.
       *
       * @since 1.1
       */
      private int m_level = Deflater.DEFAULT_COMPRESSION;
  
      /**
       * Default compression method for next entry.
       *
       * @since 1.1
       */
      private int m_method = DEFLATED;
  
      /**
       * List of ZipEntries written so far.
       *
       * @since 1.1
       */
      private final ArrayList m_entries = new ArrayList();
  
      /**
       * CRC instance to avoid parsing DEFLATED data twice.
       *
       * @since 1.1
       */
      private final CRC32 m_crc = new CRC32();
  
      /**
       * Count the bytes written to out.
       *
       * @since 1.1
       */
      private long m_written;
  
      /**
       * Data for current entry started here.
       *
       * @since 1.1
       */
      private long m_dataStart;
  
      /**
       * Start of central directory.
       *
       * @since 1.1
       */
      private ZipLong m_cdOffset = new ZipLong( 0 );
  
      /**
       * Length of central directory.
       *
       * @since 1.1
       */
      private ZipLong m_cdLength = new ZipLong( 0 );
  
      /**
       * Holds the offsets of the LFH starts for each entry
       *
       * @since 1.1
       */
      private final Hashtable m_offsets = new Hashtable();
  
      /**
       * 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>
       *
       * @since 1.3
       */
      private String m_encoding;
  
      /**
       * Current entry.
       *
       * @since 1.1
       */
      private ZipEntry m_entry;
  
      /**
       * Creates a new ZIP OutputStream filtering the underlying stream.
       *
       * @param output the output stream to write to
       * @since 1.1
       */
      public ZipOutputStream( final OutputStream output )
      {
          super( output, new Deflater( Deflater.DEFAULT_COMPRESSION, true ) );
      }
  
      /**
       * Convert a Date object to a DOS date/time field. <p>
       *
       * Stolen from InfoZip's <code>fileio.c</code></p>
       *
       * @param time Description of Parameter
       * @return Description of the Returned Value
       * @since 1.1
       */
      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 );
      }
  
      /**
       * Set the file comment.
       *
       * @param comment The new Comment value
       * @since 1.1
       */
      public void setComment( String comment )
      {
          m_comment = comment;
      }
  
      /**
       * 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;
      }
  
      /**
       * Sets the compression level for subsequent entries. <p>
       *
       * Default is Deflater.DEFAULT_COMPRESSION.</p>
       *
       * @param level The new Level value
       * @since 1.1
       */
      public void setLevel( int level )
      {
          m_level = level;
      }
  
      /**
       * Sets the default compression method for subsequent entries. <p>
       *
       * Default is DEFLATED.</p>
       *
       * @param method The new Method value
       * @since 1.1
       */
      public void setMethod( final int method )
      {
          m_method = method;
      }
  
      /**
       * 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;
      }
  
      /**
       * Writes all necessary data for this entry.
       *
       * @throws IOException if an IO failure causes operation to fail
       * @since 1.1
       */
      public void closeEntry()
          throws IOException
      {
          if( m_entry == null )
          {
              return;
          }
  
          long realCrc = m_crc.getValue();
          m_crc.reset();
  
          if( m_entry.getMethod() == DEFLATED )
          {
              def.finish();
              while( !def.finished() )
              {
                  deflate();
              }
  
              m_entry.setSize( def.getTotalIn() );
              m_entry.setComprSize( def.getTotalOut() );
              m_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 ) );
              }
  
              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 ) );
              }
  
          }
  
          writeDataDescriptor( m_entry );
          m_entry = null;
      }
  
      /*
       * 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 ZipEntry entry = (ZipEntry)m_entries.get( i );
              writeCentralFileHeader( entry );
          }
          m_cdLength = new ZipLong( m_written - m_cdOffset.getValue() );
          writeCentralDirectoryEnd();
          m_offsets.clear();
          m_entries.clear();
      }
  
      /**
       * Begin writing next entry.
       *
       * @param entry the entry
       * @throws IOException if an IO failure causes operation to fail
       * @since 1.1
       */
      public void putNextEntry( final ZipEntry entry )
          throws IOException
      {
          closeEntry();
  
          m_entry = entry;
          m_entries.add( m_entry );
  
          if( m_entry.getMethod() == -1 )
          {// not specified
              m_entry.setMethod( m_method );
          }
  
          if( m_entry.getTime() == -1 )
          {// not specified
              m_entry.setTime( System.currentTimeMillis() );
          }
  
          if( m_entry.getMethod() == STORED )
          {
              if( m_entry.getSize() == -1 )
              {
                  throw new ZipException( "uncompressed size is required for STORED method" );
              }
              if( m_entry.getCrc() == -1 )
              {
                  throw new ZipException( "crc checksum is required for STORED method" );
              }
              m_entry.setComprSize( m_entry.getSize() );
          }
          else
          {
              def.setLevel( m_level );
          }
          writeLocalFileHeader( m_entry );
      }
  
      /**
       * Writes bytes to ZIP entry. <p>
       *
       * Override is necessary to support STORED entries, as well as calculationg
       * CRC automatically for DEFLATED entries.</p>
       *
       * @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
       */
      public void write( final byte[] buffer,
                         final int offset,
                         final int length )
          throws IOException
      {
          if( m_entry.getMethod() == DEFLATED )
          {
              super.write( buffer, offset, length );
          }
          else
          {
              out.write( buffer, offset, length );
              m_written += length;
          }
          m_crc.update( buffer, offset, length );
      }
  
      /**
       * Retrieve the bytes for the given String in the encoding set for this
       * Stream.
       *
       * @param name the name to decode
       * @return the bytes for string
       * @exception ZipException if fail to retrieve bytes for specified string
       * @since 1.3
       */
      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() );
              }
          }
      }
  
      /**
       * Writes the &quot;End of central dir record&quot;
       *
       * @exception IOException when an IO erro causes operation to fail
       * @since 1.1
       */
      protected void writeCentralDirectoryEnd()
          throws IOException
      {
          out.write( EOCD_SIG.getBytes() );
  
          // disk numbers
          out.write( ZERO );
          out.write( ZERO );
  
          // number of entries
          byte[] num = ( new ZipShort( m_entries.size() ) ).getBytes();
          out.write( num );
          out.write( num );
  
          // length and location of CD
          out.write( m_cdLength.getBytes() );
          out.write( m_cdOffset.getBytes() );
  
          // ZIP file comment
          byte[] data = getBytes( m_comment );
          out.write( ( new ZipShort( data.length ) ).getBytes() );
          out.write( data );
      }
  
      /**
       * Writes the central file header entry
       *
       * @param entry the zip entry
       * @throws IOException when an IO error causes operation to fail
       * @since 1.1
       */
      protected void writeCentralFileHeader( final ZipEntry entry )
          throws IOException
      {
          out.write( CFH_SIG.getBytes() );
          m_written += 4;
  
          // version made by
          out.write( ( new ZipShort( 20 ) ).getBytes() );
          m_written += 2;
  
          // version needed to extract
          // general purpose bit flag
          if( entry.getMethod() == DEFLATED )
          {
              // requires version 2 as we are going to store length info
              // in the data descriptor
              out.write( ( new ZipShort( 20 ) ).getBytes() );
  
              // 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 );
          }
          m_written += 4;
  
          // compression method
          out.write( ( new ZipShort( entry.getMethod() ) ).getBytes() );
          m_written += 2;
  
          // last mod. time and date
          out.write( toDosTime( new Date( entry.getTime() ) ).getBytes() );
          m_written += 4;
  
          // 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;
  
          // file name length
          byte[] name = getBytes( entry.getName() );
          out.write( ( new ZipShort( name.length ) ).getBytes() );
          m_written += 2;
  
          // 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;
  
          // file name
          out.write( name );
          m_written += name.length;
  
          // extra field
          out.write( extra );
          m_written += extra.length;
  
          // file comment
          out.write( comment );
          m_written += comment.length;
      }
  
      /**
       * Writes the data descriptor entry
       *
       * @param ze Description of Parameter
       * @throws IOException if an IO failure causes operation to fail
       * @since 1.1
       */
      protected void writeDataDescriptor( ZipEntry ze )
          throws IOException
      {
          if( ze.getMethod() != DEFLATED )
          {
              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;
      }
  
      /**
       * Writes the local file header entry
       *
       * @param entry the zip entry
       * @exception IOException when an IO error causes operation to fail
       * @since 1.1
       */
      protected void writeLocalFileHeader( final ZipEntry entry )
          throws IOException
      {
          m_offsets.put( entry, new ZipLong( m_written ) );
  
          out.write( LFH_SIG.getBytes() );
          m_written += 4;
  
          // version needed to extract
          // general purpose bit flag
          if( entry.getMethod() == DEFLATED )
          {
              // requires version 2 as we are going to store length info
              // in the data descriptor
              out.write( ( new ZipShort( 20 ) ).getBytes() );
  
              // 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 );
          }
          m_written += 4;
  
          // compression method
          out.write( ( new ZipShort( entry.getMethod() ) ).getBytes() );
          m_written += 2;
  
          // last mod. time and date
          out.write( toDosTime( new Date( entry.getTime() ) ).getBytes() );
          m_written += 4;
  
          // 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;
  
          // file name length
          byte[] name = getBytes( entry.getName() );
          out.write( ( new ZipShort( name.length ) ).getBytes() );
          m_written += 2;
  
          // extra field length
          byte[] extra = entry.getLocalFileDataExtra();
          out.write( ( new ZipShort( extra.length ) ).getBytes() );
          m_written += 2;
  
          // file name
          out.write( name );
          m_written += name.length;
  
          // extra field
          out.write( extra );
          m_written += extra.length;
  
          m_dataStart = m_written;
      }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/io/src/java/org/apache/commons/io/compress/zip/ZipShort.java
  
  Index: ZipShort.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.commons.io.compress.zip;
  
  /**
   * Utility class that represents a two 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: 1.1 $
   */
  public final class ZipShort
      implements Cloneable
  {
      private int m_value;
  
      /**
       * Create instance from a number.
       *
       * @param value Description of Parameter
       * @since 1.1
       */
      public ZipShort( int value )
      {
          this.m_value = value;
      }
  
      /**
       * Create instance from bytes.
       *
       * @param bytes Description of Parameter
       * @since 1.1
       */
      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
       * @since 1.1
       */
      public ZipShort( byte[] bytes, int offset )
      {
          m_value = ( bytes[ offset + 1 ] << 8 ) & 0xFF00;
          m_value += ( bytes[ offset ] & 0xFF );
      }
  
      /**
       * Get value as two bytes in big endian byte order.
       *
       * @return The Bytes value
       * @since 1.1
       */
      public byte[] getBytes()
      {
          byte[] result = new byte[ 2 ];
          result[ 0 ] = (byte)( m_value & 0xFF );
          result[ 1 ] = (byte)( ( m_value & 0xFF00 ) >> 8 );
          return result;
      }
  
      /**
       * Get value as Java int.
       *
       * @return The Value value
       * @since 1.1
       */
      public int getValue()
      {
          return m_value;
      }
  
      /**
       * Override to make two instances with same value equal.
       *
       * @param o Description of Parameter
       * @return Description of the Returned Value
       * @since 1.1
       */
      public boolean equals( Object o )
      {
          if( o == null || !( o instanceof ZipShort ) )
          {
              return false;
          }
          return m_value == ( (ZipShort)o ).getValue();
      }
  
      /**
       * Override to make two instances with same value equal.
       *
       * @return Description of the Returned Value
       * @since 1.1
       */
      public int hashCode()
      {
          return m_value;
      }
  }
  
  
  

--
To unsubscribe, e-mail:   <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>


Mime
View raw message