[prev in list] [next in list] [prev in thread] [next in thread]
List: jakarta-commons-dev
Subject: svn commit: r427072 [2/5] - in /jakarta/commons/sandbox/compress/trunk: ./
From: tcurdt () apache ! org
Date: 2006-07-31 10:55:13
Message-ID: 20060731105521.C5EDB1A981F () eris ! apache ! org
[Download RAW message or body]
Added: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarEntry.java
URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarEntry.java?rev=427072&view=auto
==============================================================================
--- jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarEntry.java \
(added)
+++ jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarEntry.java \
Mon Jul 31 03:55:10 2006 @@ -0,0 +1,811 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.tar;
+
+import java.io.File;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * This class represents an entry in a Tar archive. It consists of the entry's
+ * header, as well as the entry's File. Entries can be instantiated in one of
+ * three ways, depending on how they are to be used. <p>
+ *
+ * TarEntries that are created from the header bytes read from an archive are
+ * instantiated with the TarEntry( byte[] ) constructor. These entries will be
+ * used when extracting from or listing the contents of an archive. These
+ * entries have their header filled in using the header bytes. They also set the
+ * File to null, since they reference an archive entry not a file. <p>
+ *
+ * TarEntries that are created from Files that are to be written into an archive
+ * are instantiated with the TarEntry( File ) constructor. These entries have
+ * their header filled in using the File's information. They also keep a
+ * reference to the File for convenience when writing entries. <p>
+ *
+ * Finally, TarEntries can be constructed from nothing but a name. This allows
+ * the programmer to construct the entry by hand, for instance when only an
+ * InputStream is available for writing to the archive, and the header
+ * information is constructed from other information. In this case the header
+ * fields are set to defaults and the File is set to null. <p>
+ *
+ * The C structure for a Tar Entry's header is: <pre>
+ * struct header {
+ * char name[NAMSIZ];
+ * char mode[8];
+ * char uid[8];
+ * char gid[8];
+ * char size[12];
+ * char mtime[12];
+ * char chksum[8];
+ * char linkflag;
+ * char linkname[NAMSIZ];
+ * char magic[8];
+ * char uname[TUNMLEN];
+ * char gname[TGNMLEN];
+ * char devmajor[8];
+ * char devminor[8];
+ * } header;
+ * </pre>
+ *
+ * @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
+ * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision: 155439 $ $Date$
+ * @see TarInputStream
+ * @see TarOutputStream
+ */
+public class TarEntry
+{
+ /**
+ * The length of the mode field in a header buffer.
+ */
+ private final static int MODELEN = 8;
+
+ /**
+ * The length of the user id field in a header buffer.
+ */
+ private final static int UIDLEN = 8;
+
+ /**
+ * The length of the group id field in a header buffer.
+ */
+ private final static int GIDLEN = 8;
+
+ /**
+ * The length of the checksum field in a header buffer.
+ */
+ private final static int CHKSUMLEN = 8;
+
+ /**
+ * The length of the size field in a header buffer.
+ */
+ private final static int SIZELEN = 12;
+
+ /**
+ * The length of the magic field in a header buffer.
+ */
+ private final static int MAGICLEN = 8;
+
+ /**
+ * The length of the modification time field in a header buffer.
+ */
+ private final static int MODTIMELEN = 12;
+
+ /**
+ * The length of the user name field in a header buffer.
+ */
+ private final static int UNAMELEN = 32;
+
+ /**
+ * The length of the group name field in a header buffer.
+ */
+ private final static int GNAMELEN = 32;
+
+ /**
+ * The length of the devices field in a header buffer.
+ */
+ private final static int DEVLEN = 8;
+
+ /**
+ * LF_ constants represent the "link flag" of an entry, or more commonly,
+ * the "entry type". This is the "old way" of indicating a normal file.
+ */
+ private final static byte LF_OLDNORM = 0;
+
+ /**
+ * Normal file type.
+ */
+ private final static byte LF_NORMAL = (byte)'0';
+
+ /**
+ * Link file type.
+ */
+ private final static byte LF_LINK = (byte)'1';
+
+ /**
+ * Symbolic link file type.
+ */
+ private final static byte LF_SYMLINK = (byte)'2';
+
+ /**
+ * Character device file type.
+ */
+ private final static byte LF_CHR = (byte)'3';
+
+ /**
+ * Block device file type.
+ */
+ private final static byte LF_BLK = (byte)'4';
+
+ /**
+ * Directory file type.
+ */
+ private final static byte LF_DIR = (byte)'5';
+
+ /**
+ * FIFO (pipe) file type.
+ */
+ private final static byte LF_FIFO = (byte)'6';
+
+ /**
+ * Contiguous file type.
+ */
+ private final static byte LF_CONTIG = (byte)'7';
+
+ /**
+ * The magic tag representing a POSIX tar archive.
+ */
+ private final static String TMAGIC = "ustar";
+
+ /**
+ * The magic tag representing a GNU tar archive.
+ */
+ private final static String GNU_TMAGIC = "ustar ";
+
+ /**
+ * The name of the GNU tar entry which contains a long name.
+ */
+ static String GNU_LONGLINK = "././@LongLink";
+
+ /**
+ * Identifies the *next* file on the tape as having a long name.
+ */
+ static byte LF_GNUTYPE_LONGNAME = (byte)'L';
+
+
+
+
+
+
+
+
+ /**
+ * The length of the name field in a header buffer.
+ */
+ public static final int NAMELEN = 100;
+
+ /**
+ * The entry's modification time.
+ */
+ private int m_checkSum;
+
+ /**
+ * The entry's group name.
+ */
+ private int m_devMajor;
+
+ /**
+ * The entry's major device number.
+ */
+ private int m_devMinor;
+
+ /**
+ * The entry's minor device number.
+ */
+ private File m_file;
+
+ /**
+ * The entry's user id.
+ */
+ private int m_groupID;
+
+ /**
+ * The entry's user name.
+ */
+ private StringBuffer m_groupName;
+
+ /**
+ * The entry's checksum.
+ */
+ private byte m_linkFlag;
+
+ /**
+ * The entry's link flag.
+ */
+ private StringBuffer m_linkName;
+
+ /**
+ * The entry's link name.
+ */
+ private StringBuffer m_magic;
+
+ /**
+ * The entry's size.
+ */
+ private long m_modTime;
+
+ /**
+ * The entry's name.
+ */
+ private int m_mode;
+
+ private StringBuffer m_name;
+
+ /**
+ * The entry's group id.
+ */
+ private long m_size;
+
+ /**
+ * The entry's permission mode.
+ */
+ private int m_userID;
+
+ /**
+ * The entry's magic tag.
+ */
+ private StringBuffer m_userName;
+
+ /**
+ * Construct an entry with only a name. This allows the programmer to
+ * construct the entry's header "by hand". File is set to null.
+ *
+ * @param name the name of the entry
+ */
+ public TarEntry( final String name )
+ {
+ this();
+
+ final boolean isDir = name.endsWith( "/" );
+
+ m_name = new StringBuffer( name );
+ m_mode = isDir ? 040755 : 0100644;
+ m_linkFlag = isDir ? TarEntry.LF_DIR : TarEntry.LF_NORMAL;
+ m_modTime = ( new Date() ).getTime() / 1000;
+ m_linkName = new StringBuffer( "" );
+ m_userName = new StringBuffer( "" );
+ m_groupName = new StringBuffer( "" );
+ }
+
+ /**
+ * Construct an entry with a name an a link flag.
+ *
+ * @param name Description of Parameter
+ * @param linkFlag Description of Parameter
+ */
+ public TarEntry( final String name, final byte linkFlag )
+ {
+ this( name );
+ m_linkFlag = linkFlag;
+ }
+
+ /**
+ * Construct an entry for a file. File is set to file, and the header is
+ * constructed from information from the file.
+ *
+ * @param file The file that the entry represents.
+ */
+ public TarEntry( final File file )
+ {
+ this();
+
+ m_file = file;
+
+ String name = file.getPath();
+
+ // Strip off drive letters!
+ final String osName =
+ System.getProperty( "os.name" ).toLowerCase( Locale.US );
+ if( -1 != osName.indexOf( "netware" ) )
+ {
+ if( name.length() > 2 )
+ {
+ final char ch1 = name.charAt( 0 );
+ final char ch2 = name.charAt( 1 );
+
+ if( ch2 == ':' &&
+ ( ( ch1 >= 'a' && ch1 <= 'z' ) ||
+ ( ch1 >= 'A' && ch1 <= 'Z' ) ) )
+ {
+ name = name.substring( 2 );
+ }
+ }
+ }
+ else if( -1 != osName.indexOf( "netware" ) )
+ {
+ final int colon = name.indexOf( ':' );
+ if( colon != -1 )
+ {
+ name = name.substring( colon + 1 );
+ }
+ }
+
+ name = name.replace( File.separatorChar, '/' );
+
+ // No absolute pathnames
+ // Windows (and Posix?) paths can start with "\\NetworkDrive\",
+ // so we loop on starting /'s.
+ while( name.startsWith( "/" ) )
+ {
+ name = name.substring( 1 );
+ }
+
+ m_linkName = new StringBuffer( "" );
+ m_name = new StringBuffer( name );
+
+ if( file.isDirectory() )
+ {
+ m_mode = 040755;
+ m_linkFlag = TarEntry.LF_DIR;
+
+ if( m_name.charAt( m_name.length() - 1 ) != '/' )
+ {
+ m_name.append( "/" );
+ }
+ }
+ else
+ {
+ m_mode = 0100644;
+ m_linkFlag = TarEntry.LF_NORMAL;
+ }
+
+ m_size = file.length();
+ m_modTime = file.lastModified() / 1000;
+ m_checkSum = 0;
+ m_devMajor = 0;
+ m_devMinor = 0;
+ }
+
+ /**
+ * Construct an entry from an archive's header bytes. File is set to null.
+ *
+ * @param header The header bytes from a tar archive entry.
+ */
+ public TarEntry( final byte[] header )
+ {
+ this();
+ parseTarHeader( header );
+ }
+
+ /**
+ * Construct an empty entry and prepares the header values.
+ */
+ private TarEntry()
+ {
+ m_magic = new StringBuffer( TarEntry.TMAGIC );
+ m_name = new StringBuffer();
+ m_linkName = new StringBuffer();
+
+ String user = System.getProperty( "user.name", "" );
+ if( user.length() > 31 )
+ {
+ user = user.substring( 0, 31 );
+ }
+
+ m_userName = new StringBuffer( user );
+ m_groupName = new StringBuffer( "" );
+ }
+
+ /**
+ * Set this entry's group id.
+ *
+ * @param groupId This entry's new group id.
+ */
+ public void setGroupID( final int groupId )
+ {
+ m_groupID = groupId;
+ }
+
+ /**
+ * Set this entry's group id.
+ *
+ * @param groupId This entry's new group id.
+ * @deprecated Use setGroupID() instead
+ * @see #setGroupID(int)
+ */
+ public void setGroupId( final int groupId )
+ {
+ m_groupID = groupId;
+ }
+
+ /**
+ * Set this entry's group name.
+ *
+ * @param groupName This entry's new group name.
+ */
+ public void setGroupName( final String groupName )
+ {
+ m_groupName = new StringBuffer( groupName );
+ }
+
+ /**
+ * Set this entry's modification time. The parameter passed to this method
+ * is in "Java time".
+ *
+ * @param time This entry's new modification time.
+ */
+ public void setModTime( final long time )
+ {
+ m_modTime = time / 1000;
+ }
+
+ /**
+ * Set this entry's modification time.
+ *
+ * @param time This entry's new modification time.
+ */
+ public void setModTime( final Date time )
+ {
+ m_modTime = time.getTime() / 1000;
+ }
+
+ /**
+ * Set the mode for this entry
+ *
+ * @param mode The new Mode value
+ */
+ public void setMode( final int mode )
+ {
+ m_mode = mode;
+ }
+
+ /**
+ * Set this entry's name.
+ *
+ * @param name This entry's new name.
+ */
+ public void setName( final String name )
+ {
+ m_name = new StringBuffer( name );
+ }
+
+ /**
+ * Set this entry's file size.
+ *
+ * @param size This entry's new file size.
+ */
+ public void setSize( final long size )
+ {
+ m_size = size;
+ }
+
+ /**
+ * Set this entry's user id.
+ *
+ * @param userId This entry's new user id.
+ */
+ public void setUserID( final int userId )
+ {
+ m_userID = userId;
+ }
+
+ /**
+ * Set this entry's user id.
+ *
+ * @param userId This entry's new user id.
+ * @deprecated Use setUserID() instead
+ * @see #setUserID(int)
+ */
+ public void setUserId( final int userId )
+ {
+ m_userID = userId;
+ }
+
+ /**
+ * Set this entry's user name.
+ *
+ * @param userName This entry's new user name.
+ */
+ public void setUserName( final String userName )
+ {
+ m_userName = new StringBuffer( userName );
+ }
+
+ /**
+ * If this entry represents a file, and the file is a directory, return an
+ * array of TarEntries for this entry's children.
+ *
+ * @return An array of TarEntry's for this entry's children.
+ */
+ public TarEntry[] getDirectoryEntries()
+ {
+ if( null == m_file || !m_file.isDirectory() )
+ {
+ return new TarEntry[ 0 ];
+ }
+
+ final String[] list = m_file.list();
+ final TarEntry[] result = new TarEntry[ list.length ];
+
+ for( int i = 0; i < list.length; ++i )
+ {
+ result[ i ] = new TarEntry( new File( m_file, list[ i ] ) );
+ }
+
+ return result;
+ }
+
+ /**
+ * Get this entry's file.
+ *
+ * @return This entry's file.
+ */
+ public File getFile()
+ {
+ return m_file;
+ }
+
+ /**
+ * Get this entry's group id.
+ *
+ * @return This entry's group id.
+ * @deprecated Use getGroupID() instead
+ * @see #getGroupID()
+ */
+ public int getGroupId()
+ {
+ return m_groupID;
+ }
+
+ /**
+ * Get this entry's group id.
+ *
+ * @return This entry's group id.
+ */
+ public int getGroupID()
+ {
+ return m_groupID;
+ }
+
+ /**
+ * Get this entry's group name.
+ *
+ * @return This entry's group name.
+ */
+ public String getGroupName()
+ {
+ return m_groupName.toString();
+ }
+
+ /**
+ * Set this entry's modification time.
+ *
+ * @return The ModTime value
+ */
+ public Date getModTime()
+ {
+ return new Date( m_modTime * 1000 );
+ }
+
+ /**
+ * Get this entry's mode.
+ *
+ * @return This entry's mode.
+ */
+ public int getMode()
+ {
+ return m_mode;
+ }
+
+ /**
+ * Get this entry's name.
+ *
+ * @return This entry's name.
+ */
+ public String getName()
+ {
+ return m_name.toString();
+ }
+
+ /**
+ * Get this entry's file size.
+ *
+ * @return This entry's file size.
+ */
+ public long getSize()
+ {
+ return m_size;
+ }
+
+ /**
+ * Get this entry's checksum.
+ *
+ * @return This entry's checksum.
+ */
+ public int getCheckSum()
+ {
+ return m_checkSum;
+ }
+
+ /**
+ * Get this entry's user id.
+ *
+ * @return This entry's user id.
+ * @deprecated Use getUserID() instead
+ * @see #getUserID()
+ */
+ public int getUserId()
+ {
+ return m_userID;
+ }
+
+ /**
+ * Get this entry's user id.
+ *
+ * @return This entry's user id.
+ */
+ public int getUserID()
+ {
+ return m_userID;
+ }
+
+ /**
+ * Get this entry's user name.
+ *
+ * @return This entry's user name.
+ */
+ public String getUserName()
+ {
+ return m_userName.toString();
+ }
+
+ /**
+ * Determine if the given entry is a descendant of this entry. Descendancy
+ * is determined by the name of the descendant starting with this entry's
+ * name.
+ *
+ * @param desc Entry to be checked as a descendent of
+ * @return True if entry is a descendant of
+ */
+ public boolean isDescendent( final TarEntry desc )
+ {
+ return desc.getName().startsWith( getName() );
+ }
+
+ /**
+ * Return whether or not this entry represents a directory.
+ *
+ * @return True if this entry is a directory.
+ */
+ public boolean isDirectory()
+ {
+ if( m_file != null )
+ {
+ return m_file.isDirectory();
+ }
+
+ if( m_linkFlag == TarEntry.LF_DIR )
+ {
+ return true;
+ }
+
+ if( getName().endsWith( "/" ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Indicate if this entry is a GNU long name block
+ *
+ * @return true if this is a long name extension provided by GNU tar
+ */
+ public boolean isGNULongNameEntry()
+ {
+ return m_linkFlag == TarEntry.LF_GNUTYPE_LONGNAME &&
+ m_name.toString().equals( TarEntry.GNU_LONGLINK );
+ }
+
+ /**
+ * Determine if the two entries are equal. Equality is determined by the
+ * header names being equal.
+ *
+ * @param other Entry to be checked for equality.
+ * @return True if the entries are equal.
+ */
+ public boolean equals( final TarEntry other )
+ {
+ return getName().equals( other.getName() );
+ }
+
+ /**
+ * Parse an entry's header information from a header buffer.
+ *
+ * @param header The tar entry header buffer to get information from.
+ */
+ private void parseTarHeader( final byte[] header )
+ {
+ int offset = 0;
+
+ m_name = TarUtils.parseName( header, offset, NAMELEN );
+ offset += NAMELEN;
+ m_mode = (int)TarUtils.parseOctal( header, offset, TarEntry.MODELEN );
+ offset += TarEntry.MODELEN;
+ m_userID = (int)TarUtils.parseOctal( header, offset, TarEntry.UIDLEN );
+ offset += TarEntry.UIDLEN;
+ m_groupID = (int)TarUtils.parseOctal( header, offset, TarEntry.GIDLEN );
+ offset += TarEntry.GIDLEN;
+ m_size = TarUtils.parseOctal( header, offset, TarEntry.SIZELEN );
+ offset += TarEntry.SIZELEN;
+ m_modTime = TarUtils.parseOctal( header, offset, TarEntry.MODTIMELEN );
+ offset += TarEntry.MODTIMELEN;
+ m_checkSum = (int)TarUtils.parseOctal( header, offset, TarEntry.CHKSUMLEN );
+ offset += TarEntry.CHKSUMLEN;
+ m_linkFlag = header[ offset++ ];
+ m_linkName = TarUtils.parseName( header, offset, NAMELEN );
+ offset += NAMELEN;
+ m_magic = TarUtils.parseName( header, offset, TarEntry.MAGICLEN );
+ offset += TarEntry.MAGICLEN;
+ m_userName = TarUtils.parseName( header, offset, TarEntry.UNAMELEN );
+ offset += TarEntry.UNAMELEN;
+ m_groupName = TarUtils.parseName( header, offset, TarEntry.GNAMELEN );
+ offset += TarEntry.GNAMELEN;
+ m_devMajor = (int)TarUtils.parseOctal( header, offset, TarEntry.DEVLEN );
+ offset += TarEntry.DEVLEN;
+ m_devMinor = (int)TarUtils.parseOctal( header, offset, TarEntry.DEVLEN );
+ }
+
+ /**
+ * Write an entry's header information to a header buffer.
+ *
+ * @param buffer The tar entry header buffer to fill in.
+ */
+ public void writeEntryHeader( final byte[] buffer )
+ {
+ int offset = 0;
+
+ offset = TarUtils.getNameBytes( m_name, buffer, offset, NAMELEN );
+ offset = TarUtils.getOctalBytes( m_mode, buffer, offset, TarEntry.MODELEN );
+ offset = TarUtils.getOctalBytes( m_userID, buffer, offset, TarEntry.UIDLEN \
); + offset = TarUtils.getOctalBytes( m_groupID, buffer, offset, \
TarEntry.GIDLEN ); + offset = TarUtils.getLongOctalBytes( m_size, buffer, \
offset, TarEntry.SIZELEN ); + offset = TarUtils.getLongOctalBytes( m_modTime, \
buffer, offset, TarEntry.MODTIMELEN ); +
+ final int checkSumOffset = offset;
+ for( int i = 0; i < TarEntry.CHKSUMLEN; ++i )
+ {
+ buffer[ offset++ ] = (byte)' ';
+ }
+
+ buffer[ offset++ ] = m_linkFlag;
+ offset = TarUtils.getNameBytes( m_linkName, buffer, offset, NAMELEN );
+ offset = TarUtils.getNameBytes( m_magic, buffer, offset, TarEntry.MAGICLEN \
); + offset = TarUtils.getNameBytes( m_userName, buffer, offset, \
TarEntry.UNAMELEN ); + offset = TarUtils.getNameBytes( m_groupName, buffer, \
offset, TarEntry.GNAMELEN ); + offset = TarUtils.getOctalBytes( m_devMajor, \
buffer, offset, TarEntry.DEVLEN ); + offset = TarUtils.getOctalBytes( \
m_devMinor, buffer, offset, TarEntry.DEVLEN ); +
+ while( offset < buffer.length )
+ {
+ buffer[ offset++ ] = 0;
+ }
+
+ final long checkSum = TarUtils.computeCheckSum( buffer );
+ TarUtils.getCheckSumOctalBytes( checkSum, buffer, checkSumOffset, \
TarEntry.CHKSUMLEN ); + }
+}
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarEntry.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarEntry.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarEntry.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Added: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarInputStream.java?rev=427072&view=auto
==============================================================================
--- jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarInputStream.java \
(added)
+++ jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarInputStream.java \
Mon Jul 31 03:55:10 2006 @@ -0,0 +1,470 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.tar;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+/**
+ * The TarInputStream reads a UNIX tar archive as an InputStream. methods are
+ * provided to position at each successive entry in the archive, and the read
+ * each entry as a normal input stream using read().
+ *
+ * @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
+ * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision: 155439 $ $Date$
+ * @see TarInputStream
+ * @see TarEntry
+ */
+public final class TarInputStream extends FilterInputStream
+{
+ private TarBuffer m_buffer;
+ private TarEntry m_currEntry;
+ private boolean m_debug;
+ private int m_entryOffset;
+ private int m_entrySize;
+ private boolean m_hasHitEOF;
+ private byte[] m_oneBuf;
+ private byte[] m_readBuf;
+
+ /**
+ * Construct a TarInputStream using specified input
+ * stream and default block and record sizes.
+ *
+ * @param input stream to create TarInputStream from
+ * @see TarBuffer#DEFAULT_BLOCKSIZE
+ * @see TarBuffer#DEFAULT_RECORDSIZE
+ */
+ public TarInputStream( final InputStream input )
+ {
+ this( input, TarBuffer.DEFAULT_BLOCKSIZE, TarBuffer.DEFAULT_RECORDSIZE );
+ }
+
+ /**
+ * Construct a TarInputStream using specified input
+ * stream, block size and default record sizes.
+ *
+ * @param input stream to create TarInputStream from
+ * @param blockSize the block size to use
+ * @see TarBuffer#DEFAULT_RECORDSIZE
+ */
+ public TarInputStream( final InputStream input,
+ final int blockSize )
+ {
+ this( input, blockSize, TarBuffer.DEFAULT_RECORDSIZE );
+ }
+
+ /**
+ * Construct a TarInputStream using specified input
+ * stream, block size and record sizes.
+ *
+ * @param input stream to create TarInputStream from
+ * @param blockSize the block size to use
+ * @param recordSize the record size to use
+ */
+ public TarInputStream( final InputStream input,
+ final int blockSize,
+ final int recordSize )
+ {
+ super( input );
+
+ m_buffer = new TarBuffer( input, blockSize, recordSize );
+ m_oneBuf = new byte[ 1 ];
+ }
+
+ /**
+ * Sets the debugging flag.
+ *
+ * @param debug The new Debug value
+ */
+ public void setDebug( final boolean debug )
+ {
+ m_debug = debug;
+ m_buffer.setDebug( debug );
+ }
+
+ /**
+ * Get the next entry in this tar archive. This will skip over any remaining
+ * data in the current entry, if there is one, and place the input stream at
+ * the header of the next entry, and read the header and instantiate a new
+ * TarEntry from the header bytes and return that entry. If there are no
+ * more entries in the archive, null will be returned to indicate that the
+ * end of the archive has been reached.
+ *
+ * @return The next TarEntry in the archive, or null.
+ * @exception IOException Description of Exception
+ */
+ public TarEntry getNextEntry()
+ throws IOException
+ {
+ if( m_hasHitEOF )
+ {
+ return null;
+ }
+
+ if( m_currEntry != null )
+ {
+ final int numToSkip = m_entrySize - m_entryOffset;
+
+ if( m_debug )
+ {
+ final String message = "TarInputStream: SKIP currENTRY '" +
+ m_currEntry.getName() + "' SZ " + m_entrySize +
+ " OFF " + m_entryOffset + " skipping " + numToSkip + " bytes";
+ debug( message );
+ }
+
+ if( numToSkip > 0 )
+ {
+ skip( numToSkip );
+ }
+
+ m_readBuf = null;
+ }
+
+ final byte[] headerBuf = m_buffer.readRecord();
+ if( headerBuf == null )
+ {
+ if( m_debug )
+ {
+ debug( "READ NULL RECORD" );
+ }
+ m_hasHitEOF = true;
+ }
+ else if( m_buffer.isEOFRecord( headerBuf ) )
+ {
+ if( m_debug )
+ {
+ debug( "READ EOF RECORD" );
+ }
+ m_hasHitEOF = true;
+ }
+
+ if( m_hasHitEOF )
+ {
+ m_currEntry = null;
+ }
+ else
+ {
+ m_currEntry = new TarEntry( headerBuf );
+
+ if( !( headerBuf[ 257 ] == 'u' && headerBuf[ 258 ] == 's' &&
+ headerBuf[ 259 ] == 't' && headerBuf[ 260 ] == 'a' &&
+ headerBuf[ 261 ] == 'r' ) )
+ {
+ //Must be v7Format
+ }
+
+ if( m_debug )
+ {
+ final String message = "TarInputStream: SET CURRENTRY '" +
+ m_currEntry.getName() + "' size = " + m_currEntry.getSize();
+ debug( message );
+ }
+
+ m_entryOffset = 0;
+
+ // REVIEW How do we resolve this discrepancy?!
+ m_entrySize = (int)m_currEntry.getSize();
+ }
+
+ if( null != m_currEntry && m_currEntry.isGNULongNameEntry() )
+ {
+ // read in the name
+ final StringBuffer longName = new StringBuffer();
+ final byte[] buffer = new byte[ 256 ];
+ int length = 0;
+ while( ( length = read( buffer ) ) >= 0 )
+ {
+ final String str = new String( buffer, 0, length );
+ longName.append( str );
+ }
+ getNextEntry();
+
+ // remove trailing null terminator
+ if (longName.length() > 0
+ && longName.charAt(longName.length() - 1) == 0) {
+ longName.deleteCharAt(longName.length() - 1);
+ }
+
+ m_currEntry.setName( longName.toString() );
+ }
+
+ return m_currEntry;
+ }
+
+ /**
+ * Get the record size being used by this stream's TarBuffer.
+ *
+ * @return The TarBuffer record size.
+ */
+ public int getRecordSize()
+ {
+ return m_buffer.getRecordSize();
+ }
+
+ /**
+ * Get the available data that can be read from the current entry in the
+ * archive. This does not indicate how much data is left in the entire
+ * archive, only in the current entry. This value is determined from the
+ * entry's size header field and the amount of data already read from the
+ * current entry.
+ *
+ * @return The number of available bytes for the current entry.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public int available()
+ throws IOException
+ {
+ return m_entrySize - m_entryOffset;
+ }
+
+ /**
+ * Closes this stream. Calls the TarBuffer's close() method.
+ *
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void close()
+ throws IOException
+ {
+ m_buffer.close();
+ }
+
+ /**
+ * Copies the contents of the current tar archive entry directly into an
+ * output stream.
+ *
+ * @param output The OutputStream into which to write the entry's data.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void copyEntryContents( final OutputStream output )
+ throws IOException
+ {
+ final byte[] buffer = new byte[ 32 * 1024 ];
+ while( true )
+ {
+ final int numRead = read( buffer, 0, buffer.length );
+ if( numRead == -1 )
+ {
+ break;
+ }
+
+ output.write( buffer, 0, numRead );
+ }
+ }
+
+ /**
+ * Since we do not support marking just yet, we do nothing.
+ *
+ * @param markLimit The limit to mark.
+ */
+ public void mark( int markLimit )
+ {
+ }
+
+ /**
+ * Since we do not support marking just yet, we return false.
+ *
+ * @return False.
+ */
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ /**
+ * Reads a byte from the current tar archive entry. This method simply calls
+ * read( byte[], int, int ).
+ *
+ * @return The byte read, or -1 at EOF.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public int read()
+ throws IOException
+ {
+ final int num = read( m_oneBuf, 0, 1 );
+ if( num == -1 )
+ {
+ return num;
+ }
+ else
+ {
+ return (int)m_oneBuf[ 0 ];
+ }
+ }
+
+ /**
+ * Reads bytes from the current tar archive entry. This method simply calls
+ * read( byte[], int, int ).
+ *
+ * @param buffer The buffer into which to place bytes read.
+ * @return The number of bytes read, or -1 at EOF.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public int read( final byte[] buffer )
+ throws IOException
+ {
+ return read( buffer, 0, buffer.length );
+ }
+
+ /**
+ * Reads bytes from the current tar archive entry. This method is aware of
+ * the boundaries of the current entry in the archive and will deal with
+ * them as if they were this stream's start and EOF.
+ *
+ * @param buffer The buffer into which to place bytes read.
+ * @param offset The offset at which to place bytes read.
+ * @param count The number of bytes to read.
+ * @return The number of bytes read, or -1 at EOF.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public int read( final byte[] buffer,
+ final int offset,
+ final int count )
+ throws IOException
+ {
+ int position = offset;
+ int numToRead = count;
+ int totalRead = 0;
+
+ if( m_entryOffset >= m_entrySize )
+ {
+ return -1;
+ }
+
+ if( ( numToRead + m_entryOffset ) > m_entrySize )
+ {
+ numToRead = ( m_entrySize - m_entryOffset );
+ }
+
+ if( null != m_readBuf )
+ {
+ final int size =
+ ( numToRead > m_readBuf.length ) ? m_readBuf.length : numToRead;
+
+ System.arraycopy( m_readBuf, 0, buffer, position, size );
+
+ if( size >= m_readBuf.length )
+ {
+ m_readBuf = null;
+ }
+ else
+ {
+ final int newLength = m_readBuf.length - size;
+ final byte[] newBuffer = new byte[ newLength ];
+
+ System.arraycopy( m_readBuf, size, newBuffer, 0, newLength );
+
+ m_readBuf = newBuffer;
+ }
+
+ totalRead += size;
+ numToRead -= size;
+ position += size;
+ }
+
+ while( numToRead > 0 )
+ {
+ final byte[] rec = m_buffer.readRecord();
+ if( null == rec )
+ {
+ // Unexpected EOF!
+ final String message =
+ "unexpected EOF with " + numToRead + " bytes unread";
+ throw new IOException( message );
+ }
+
+ int size = numToRead;
+ final int recordLength = rec.length;
+
+ if( recordLength > size )
+ {
+ System.arraycopy( rec, 0, buffer, position, size );
+
+ m_readBuf = new byte[ recordLength - size ];
+
+ System.arraycopy( rec, size, m_readBuf, 0, recordLength - size );
+ }
+ else
+ {
+ size = recordLength;
+
+ System.arraycopy( rec, 0, buffer, position, recordLength );
+ }
+
+ totalRead += size;
+ numToRead -= size;
+ position += size;
+ }
+
+ m_entryOffset += totalRead;
+
+ return totalRead;
+ }
+
+ /**
+ * Since we do not support marking just yet, we do nothing.
+ */
+ public void reset()
+ {
+ }
+
+ /**
+ * Skip bytes in the input buffer. This skips bytes in the current entry's
+ * data, not the entire archive, and will stop at the end of the current
+ * entry's data if the number to skip extends beyond that point.
+ *
+ * @param numToSkip The number of bytes to skip.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void skip( final int numToSkip )
+ throws IOException
+ {
+ // REVIEW
+ // This is horribly inefficient, but it ensures that we
+ // properly skip over bytes via the TarBuffer...
+ //
+ final byte[] skipBuf = new byte[ 8 * 1024 ];
+ int num = numToSkip;
+ while( num > 0 )
+ {
+ final int count = ( num > skipBuf.length ) ? skipBuf.length : num;
+ final int numRead = read( skipBuf, 0, count );
+ if( numRead == -1 )
+ {
+ break;
+ }
+
+ num -= numRead;
+ }
+ }
+
+ /**
+ * Utility method to do debugging.
+ * Capable of being overidden in sub-classes.
+ *
+ * @param message the message to use in debugging
+ */
+ protected void debug( final String message )
+ {
+ if( m_debug )
+ {
+ System.err.println( message );
+ }
+ }
+}
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Added: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java?rev=427072&view=auto
==============================================================================
--- jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java \
(added)
+++ jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java \
Mon Jul 31 03:55:10 2006 @@ -0,0 +1,422 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.tar;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+/**
+ * The TarOutputStream writes a UNIX tar archive as an OutputStream. Methods are
+ * provided to put entries, and then write their contents by writing to this
+ * stream using write().
+ *
+ * @author Timothy Gerard Endres <a href="mailto:time@ice.com">time@ice.com</a>
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision: 155439 $ $Date$
+ * @see TarInputStream
+ * @see TarEntry
+ */
+public final class TarOutputStream extends FilterOutputStream
+{
+ /**
+ * Flag to indicate that an error should be generated if
+ * an attempt is made to write an entry that exceeds the 100 char
+ * POSIX limit.
+ */
+ public static final int LONGFILE_ERROR = 0;
+
+ /**
+ * Flag to indicate that entry name should be truncated if
+ * an attempt is made to write an entry that exceeds the 100 char
+ * POSIX limit.
+ */
+ public static final int LONGFILE_TRUNCATE = 1;
+
+ /**
+ * Flag to indicate that entry name should be formatted
+ * according to GNU tar extension if an attempt is made
+ * to write an entry that exceeds the 100 char POSIX
+ * limit. Note that this makes the jar unreadable by
+ * non-GNU tar commands.
+ */
+ public static final int LONGFILE_GNU = 2;
+
+ private int m_longFileMode = LONGFILE_ERROR;
+ private byte[] m_assemBuf;
+ private int m_assemLen;
+ private TarBuffer m_buffer;
+ private int m_currBytes;
+ private int m_currSize;
+
+ private byte[] m_oneBuf;
+ private byte[] m_recordBuf;
+
+ /**
+ * Construct a TarOutputStream using specified input
+ * stream and default block and record sizes.
+ *
+ * @param output stream to create TarOutputStream from
+ * @see TarBuffer#DEFAULT_BLOCKSIZE
+ * @see TarBuffer#DEFAULT_RECORDSIZE
+ */
+ public TarOutputStream( final OutputStream output )
+ {
+ this( output, TarBuffer.DEFAULT_BLOCKSIZE, TarBuffer.DEFAULT_RECORDSIZE );
+ }
+
+ /**
+ * Construct a TarOutputStream using specified input
+ * stream, block size and default record sizes.
+ *
+ * @param output stream to create TarOutputStream from
+ * @param blockSize the block size
+ * @see TarBuffer#DEFAULT_RECORDSIZE
+ */
+ public TarOutputStream( final OutputStream output,
+ final int blockSize )
+ {
+ this( output, blockSize, TarBuffer.DEFAULT_RECORDSIZE );
+ }
+
+ /**
+ * Construct a TarOutputStream using specified input
+ * stream, block size and record sizes.
+ *
+ * @param output stream to create TarOutputStream from
+ * @param blockSize the block size
+ * @param recordSize the record size
+ */
+ public TarOutputStream( final OutputStream output,
+ final int blockSize,
+ final int recordSize )
+ {
+ super( output );
+
+ m_buffer = new TarBuffer( output, blockSize, recordSize );
+ m_assemLen = 0;
+ m_assemBuf = new byte[ recordSize ];
+ m_recordBuf = new byte[ recordSize ];
+ m_oneBuf = new byte[ 1 ];
+ }
+
+ /**
+ * Sets the debugging flag in this stream's TarBuffer.
+ *
+ * @param debug The new BufferDebug value
+ */
+ public void setBufferDebug( boolean debug )
+ {
+ m_buffer.setDebug( debug );
+ }
+
+ /**
+ * Set the mode used to work with entrys exceeding
+ * 100 chars (and thus break the POSIX standard).
+ * Must be one of the LONGFILE_* constants.
+ *
+ * @param longFileMode the mode
+ */
+ public void setLongFileMode( final int longFileMode )
+ {
+ if( LONGFILE_ERROR != longFileMode &&
+ LONGFILE_GNU != longFileMode &&
+ LONGFILE_TRUNCATE != longFileMode )
+ {
+ throw new IllegalArgumentException( "longFileMode" );
+ }
+ m_longFileMode = longFileMode;
+ }
+
+ /**
+ * Get the record size being used by this stream's TarBuffer.
+ *
+ * @return The TarBuffer record size.
+ */
+ public int getRecordSize()
+ {
+ return m_buffer.getRecordSize();
+ }
+
+ /**
+ * Ends the TAR archive and closes the underlying OutputStream. This means
+ * that finish() is called followed by calling the TarBuffer's close().
+ *
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void close()
+ throws IOException
+ {
+ finish();
+ m_buffer.close();
+ }
+
+ /**
+ * Close an entry. This method MUST be called for all file entries that
+ * contain data. The reason is that we must buffer data written to the
+ * stream in order to satisfy the buffer's record based writes. Thus, there
+ * may be data fragments still being assembled that must be written to the
+ * output stream before this entry is closed and the next entry written.
+ *
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void closeEntry()
+ throws IOException
+ {
+ if( m_assemLen > 0 )
+ {
+ for( int i = m_assemLen; i < m_assemBuf.length; ++i )
+ {
+ m_assemBuf[ i ] = 0;
+ }
+
+ m_buffer.writeRecord( m_assemBuf );
+
+ m_currBytes += m_assemLen;
+ m_assemLen = 0;
+ }
+
+ if( m_currBytes < m_currSize )
+ {
+ final String message = "entry closed at '" + m_currBytes +
+ "' before the '" + m_currSize +
+ "' bytes specified in the header were written";
+ throw new IOException( message );
+ }
+ }
+
+ /**
+ * Ends the TAR archive without closing the underlying OutputStream. The
+ * result is that the EOF record of nulls is written.
+ *
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void finish()
+ throws IOException
+ {
+ writeEOFRecord();
+ }
+
+ /**
+ * Put an entry on the output stream. This writes the entry's header record
+ * and positions the output stream for writing the contents of the entry.
+ * Once this method is called, the stream is ready for calls to write() to
+ * write the entry's contents. Once the contents are written, closeEntry()
+ * <B>MUST</B> be called to ensure that all buffered data is completely
+ * written to the output stream.
+ *
+ * @param entry The TarEntry to be written to the archive.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void putNextEntry( final TarEntry entry )
+ throws IOException
+ {
+ if( entry.getName().length() >= TarEntry.NAMELEN )
+ {
+ if( m_longFileMode == LONGFILE_GNU )
+ {
+ // create a TarEntry for the LongLink, the contents
+ // of which are the entry's name
+ final TarEntry longLinkEntry =
+ new TarEntry( TarEntry.GNU_LONGLINK,
+ TarEntry.LF_GNUTYPE_LONGNAME );
+
+ longLinkEntry.setSize( entry.getName().length() );
+ putNextEntry( longLinkEntry );
+ write( entry.getName().getBytes() );
+ //write( 0 );
+ closeEntry();
+ }
+ else if( m_longFileMode != LONGFILE_TRUNCATE )
+ {
+ final String message = "file name '" + entry.getName() +
+ "' is too long ( > " + TarEntry.NAMELEN + " bytes)";
+ throw new IOException( message );
+ }
+ }
+
+ entry.writeEntryHeader( m_recordBuf );
+ m_buffer.writeRecord( m_recordBuf );
+
+ m_currBytes = 0;
+
+ if( entry.isDirectory() )
+ {
+ m_currSize = 0;
+ }
+ else
+ {
+ m_currSize = (int)entry.getSize();
+ }
+ }
+
+ /**
+ * Copies the contents of the specified stream into current tar
+ * archive entry.
+ *
+ * @param input The InputStream from which to read entrys data
+ * @exception IOException when an IO error causes operation to fail
+ */
+ void copyEntryContents( final InputStream input )
+ throws IOException
+ {
+ final byte[] buffer = new byte[ 32 * 1024 ];
+ while( true )
+ {
+ final int numRead = input.read( buffer, 0, buffer.length );
+ if( numRead == -1 )
+ {
+ break;
+ }
+
+ write( buffer, 0, numRead );
+ }
+ }
+
+ /**
+ * Writes a byte to the current tar archive entry. This method simply calls
+ * read( byte[], int, int ).
+ *
+ * @param data The byte written.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void write( final int data )
+ throws IOException
+ {
+ m_oneBuf[ 0 ] = (byte)data;
+
+ write( m_oneBuf, 0, 1 );
+ }
+
+ /**
+ * Writes bytes to the current tar archive entry. This method simply calls
+ * write( byte[], int, int ).
+ *
+ * @param buffer The buffer to write to the archive.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void write( final byte[] buffer )
+ throws IOException
+ {
+ write( buffer, 0, buffer.length );
+ }
+
+ /**
+ * Writes bytes to the current tar archive entry. This method is aware of
+ * the current entry and will throw an exception if you attempt to write
+ * bytes past the length specified for the current entry. The method is also
+ * (painfully) aware of the record buffering required by TarBuffer, and
+ * manages buffers that are not a multiple of recordsize in length,
+ * including assembling records from small buffers.
+ *
+ * @param buffer The buffer to write to the archive.
+ * @param offset The offset in the buffer from which to get bytes.
+ * @param count The number of bytes to write.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void write( final byte[] buffer,
+ final int offset,
+ final int count )
+ throws IOException
+ {
+ int position = offset;
+ int numToWrite = count;
+ if( ( m_currBytes + numToWrite ) > m_currSize )
+ {
+ final String message = "request to write '" + numToWrite +
+ "' bytes exceeds size in header of '" + m_currSize + "' bytes";
+ throw new IOException( message );
+ //
+ // We have to deal with assembly!!!
+ // The programmer can be writing little 32 byte chunks for all
+ // we know, and we must assemble complete records for writing.
+ // REVIEW Maybe this should be in TarBuffer? Could that help to
+ // eliminate some of the buffer copying.
+ //
+ }
+
+ if( m_assemLen > 0 )
+ {
+ if( ( m_assemLen + numToWrite ) >= m_recordBuf.length )
+ {
+ final int length = m_recordBuf.length - m_assemLen;
+
+ System.arraycopy( m_assemBuf, 0, m_recordBuf, 0,
+ m_assemLen );
+ System.arraycopy( buffer, position, m_recordBuf,
+ m_assemLen, length );
+ m_buffer.writeRecord( m_recordBuf );
+
+ m_currBytes += m_recordBuf.length;
+ position += length;
+ numToWrite -= length;
+ m_assemLen = 0;
+ }
+ else
+ {
+ System.arraycopy( buffer, position, m_assemBuf, m_assemLen,
+ numToWrite );
+
+ position += numToWrite;
+ m_assemLen += numToWrite;
+ numToWrite -= numToWrite;
+ }
+ }
+
+ //
+ // When we get here we have EITHER:
+ // o An empty "assemble" buffer.
+ // o No bytes to write (numToWrite == 0)
+ //
+ while( numToWrite > 0 )
+ {
+ if( numToWrite < m_recordBuf.length )
+ {
+ System.arraycopy( buffer, position, m_assemBuf, m_assemLen,
+ numToWrite );
+
+ m_assemLen += numToWrite;
+
+ break;
+ }
+
+ m_buffer.writeRecord( buffer, position );
+
+ int num = m_recordBuf.length;
+
+ m_currBytes += num;
+ numToWrite -= num;
+ position += num;
+ }
+ }
+
+ /**
+ * Write an EOF (end of archive) record to the tar archive. An EOF record
+ * consists of a record of all zeros.
+ *
+ * @exception IOException when an IO error causes operation to fail
+ */
+ private void writeEOFRecord()
+ throws IOException
+ {
+ for( int i = 0; i < m_recordBuf.length; ++i )
+ {
+ m_recordBuf[ i ] = 0;
+ }
+
+ m_buffer.writeRecord( m_recordBuf );
+ }
+}
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Added: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarUtils.java
URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarUtils.java?rev=427072&view=auto
==============================================================================
--- jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarUtils.java \
(added)
+++ jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarUtils.java \
Mon Jul 31 03:55:10 2006 @@ -0,0 +1,233 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.tar;
+
+/**
+ * This class provides static utility methods to work with byte streams.
+ *
+ * @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
+ * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
+ * @version $Revision: 155439 $ $Date$
+ */
+public class TarUtils
+{
+ /**
+ * Parse the checksum octal integer from a header buffer.
+ *
+ * @param offset The offset into the buffer from which to parse.
+ * @param length The number of header bytes to parse.
+ * @param value Description of Parameter
+ * @param buf Description of Parameter
+ * @return The integer value of the entry's checksum.
+ */
+ public static int getCheckSumOctalBytes( final long value,
+ final byte[] buf,
+ final int offset,
+ final int length )
+ {
+ getOctalBytes( value, buf, offset, length );
+
+ buf[ offset + length - 1 ] = (byte)' ';
+ buf[ offset + length - 2 ] = 0;
+
+ return offset + length;
+ }
+
+ /**
+ * Parse an octal long integer from a header buffer.
+ *
+ * @param offset The offset into the buffer from which to parse.
+ * @param length The number of header bytes to parse.
+ * @param value Description of Parameter
+ * @param buf Description of Parameter
+ * @return The long value of the octal bytes.
+ */
+ public static int getLongOctalBytes( final long value,
+ final byte[] buf,
+ final int offset,
+ final int length )
+ {
+ byte[] temp = new byte[ length + 1 ];
+
+ getOctalBytes( value, temp, 0, length + 1 );
+ System.arraycopy( temp, 0, buf, offset, length );
+
+ return offset + length;
+ }
+
+ /**
+ * Determine the number of bytes in an entry name.
+ *
+ * @param offset The offset into the buffer from which to parse.
+ * @param length The number of header bytes to parse.
+ * @param name Description of Parameter
+ * @param buffer Description of Parameter
+ * @return The number of bytes in a header's entry name.
+ */
+ public static int getNameBytes( final StringBuffer name,
+ final byte[] buffer,
+ final int offset,
+ final int length )
+ {
+ int i;
+
+ for( i = 0; i < length && i < name.length(); ++i )
+ {
+ buffer[ offset + i ] = (byte)name.charAt( i );
+ }
+
+ for( ; i < length; ++i )
+ {
+ buffer[ offset + i ] = 0;
+ }
+
+ return offset + length;
+ }
+
+ /**
+ * Parse an octal integer from a header buffer.
+ *
+ * @param offset The offset into the buffer from which to parse.
+ * @param length The number of header bytes to parse.
+ * @return The integer value of the octal bytes.
+ */
+ public static int getOctalBytes( final long value,
+ final byte[] buffer,
+ final int offset,
+ final int length )
+ {
+ int idx = length - 1;
+
+ buffer[ offset + idx ] = 0;
+ --idx;
+ buffer[ offset + idx ] = (byte)' ';
+ --idx;
+
+ if( value == 0 )
+ {
+ buffer[ offset + idx ] = (byte)'0';
+ --idx;
+ }
+ else
+ {
+ long val = value;
+ while( idx >= 0 && val > 0 )
+ {
+ buffer[ offset + idx ] = (byte)( (byte)'0' + (byte)( val & 7 ) );
+ val = val >> 3;
+ idx--;
+ }
+ }
+
+ while( idx >= 0 )
+ {
+ buffer[ offset + idx ] = (byte)' ';
+ idx--;
+ }
+
+ return offset + length;
+ }
+
+ /**
+ * Compute the checksum of a tar entry header.
+ *
+ * @param buffer The tar entry's header buffer.
+ * @return The computed checksum.
+ */
+ public static long computeCheckSum( final byte[] buffer )
+ {
+ long sum = 0;
+
+ for( int i = 0; i < buffer.length; ++i )
+ {
+ sum += 255 & buffer[ i ];
+ }
+
+ return sum;
+ }
+
+ /**
+ * Parse an entry name from a header buffer.
+ *
+ * @param header The header buffer from which to parse.
+ * @param offset The offset into the buffer from which to parse.
+ * @param length The number of header bytes to parse.
+ * @return The header's entry name.
+ */
+ public static StringBuffer parseName( final byte[] header,
+ final int offset,
+ final int length )
+ {
+ StringBuffer result = new StringBuffer( length );
+ int end = offset + length;
+
+ for( int i = offset; i < end; ++i )
+ {
+ if( header[ i ] == 0 )
+ {
+ break;
+ }
+
+ result.append( (char)header[ i ] );
+ }
+
+ return result;
+ }
+
+ /**
+ * Parse an octal string from a header buffer. This is used for the file
+ * permission mode value.
+ *
+ * @param header The header buffer from which to parse.
+ * @param offset The offset into the buffer from which to parse.
+ * @param length The number of header bytes to parse.
+ * @return The long value of the octal string.
+ */
+ public static long parseOctal( final byte[] header,
+ final int offset,
+ final int length )
+ {
+ long result = 0;
+ boolean stillPadding = true;
+ int end = offset + length;
+
+ for( int i = offset; i < end; ++i )
+ {
+ if( header[ i ] == 0 )
+ {
+ break;
+ }
+
+ if( header[ i ] == (byte)' ' || header[ i ] == '0' )
+ {
+ if( stillPadding )
+ {
+ continue;
+ }
+
+ if( header[ i ] == (byte)' ' )
+ {
+ break;
+ }
+ }
+
+ stillPadding = false;
+ result = ( result << 3 ) + ( header[ i ] - '0' );
+ }
+
+ return result;
+ }
+}
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarUtils.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/tar/TarUtils.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Added: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java?rev=427072&view=auto
==============================================================================
--- jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java \
(added)
+++ jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java \
Mon Jul 31 03:55:10 2006 @@ -0,0 +1,406 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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 );
+ }
+}
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Added: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java?rev=427072&view=auto
==============================================================================
--- jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java \
(added)
+++ jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java \
Mon Jul 31 03:55:10 2006 @@ -0,0 +1,204 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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" );
+ }
+ }
+}
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Added: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/UnixStat.java
URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/UnixStat.java?rev=427072&view=auto
==============================================================================
--- jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/UnixStat.java \
(added)
+++ jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/UnixStat.java \
Mon Jul 31 03:55:10 2006 @@ -0,0 +1,76 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+}
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/UnixStat.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/UnixStat.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: jakarta/commons/sandbox/compress/trunk/src/java/org/apache/commons/compress/archivers/zip/UnixStat.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic