You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tc...@apache.org on 2008/07/10 12:17:49 UTC
svn commit: r675498 [2/6] - in /commons/sandbox/compress/branches/redesign:
./ src/ src/main/ src/main/java/ src/main/java/org/
src/main/java/org/apache/ src/main/java/org/apache/commons/
src/main/java/org/apache/commons/compress/ src/main/java/org/apa...
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.jar;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+
+public class JarArchiveOutputStream extends ZipArchiveOutputStream {
+
+ public JarArchiveOutputStream( final OutputStream out ) {
+ super(out);
+ }
+
+ public void putArchiveEntry(ArchiveEntry entry) throws IOException {
+ // TODO special jar stuff
+ super.putArchiveEntry((ZipArchiveEntry) entry);
+ }
+}
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,692 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.tar;
+
+import java.io.File;
+import java.util.Date;
+import java.util.Locale;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+
+/**
+ * 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$ $Date$
+ * @see TarInputStream
+ * @see TarArchiveOutputStream
+ */
+public class TarArchiveEntry implements ArchiveEntry {
+ /**
+ * 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 TarArchiveEntry( final String name )
+ {
+ this();
+
+ final boolean isDir = name.endsWith( "/" );
+
+ m_name = new StringBuffer( name );
+ m_mode = isDir ? 040755 : 0100644;
+ m_linkFlag = isDir ? TarConstants.LF_DIR : TarConstants.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 TarArchiveEntry( 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 TarArchiveEntry( 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 = TarConstants.LF_DIR;
+
+ if( m_name.charAt( m_name.length() - 1 ) != '/' )
+ {
+ m_name.append( "/" );
+ }
+ }
+ else
+ {
+ m_mode = 0100644;
+ m_linkFlag = TarConstants.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 TarArchiveEntry( final byte[] header )
+ {
+ this();
+ parseTarHeader( header );
+ }
+
+ /**
+ * Construct an empty entry and prepares the header values.
+ */
+ private TarArchiveEntry()
+ {
+ m_magic = new StringBuffer( TarConstants.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 TarArchiveEntry[] getDirectoryEntries()
+ {
+ if( null == m_file || !m_file.isDirectory() )
+ {
+ return new TarArchiveEntry[ 0 ];
+ }
+
+ final String[] list = m_file.list();
+ final TarArchiveEntry[] result = new TarArchiveEntry[ list.length ];
+
+ for( int i = 0; i < list.length; ++i )
+ {
+ result[ i ] = new TarArchiveEntry( 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 TarArchiveEntry 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 == TarConstants.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 == TarConstants.LF_GNUTYPE_LONGNAME &&
+ m_name.toString().equals( TarConstants.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 TarArchiveEntry 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, TarConstants.MODELEN );
+ offset += TarConstants.MODELEN;
+ m_userID = (int)TarUtils.parseOctal( header, offset, TarConstants.UIDLEN );
+ offset += TarConstants.UIDLEN;
+ m_groupID = (int)TarUtils.parseOctal( header, offset, TarConstants.GIDLEN );
+ offset += TarConstants.GIDLEN;
+ m_size = TarUtils.parseOctal( header, offset, TarConstants.SIZELEN );
+ offset += TarConstants.SIZELEN;
+ m_modTime = TarUtils.parseOctal( header, offset, TarConstants.MODTIMELEN );
+ offset += TarConstants.MODTIMELEN;
+ m_checkSum = (int)TarUtils.parseOctal( header, offset, TarConstants.CHKSUMLEN );
+ offset += TarConstants.CHKSUMLEN;
+ m_linkFlag = header[ offset++ ];
+ m_linkName = TarUtils.parseName( header, offset, NAMELEN );
+ offset += NAMELEN;
+ m_magic = TarUtils.parseName( header, offset, TarConstants.MAGICLEN );
+ offset += TarConstants.MAGICLEN;
+ m_userName = TarUtils.parseName( header, offset, TarConstants.UNAMELEN );
+ offset += TarConstants.UNAMELEN;
+ m_groupName = TarUtils.parseName( header, offset, TarConstants.GNAMELEN );
+ offset += TarConstants.GNAMELEN;
+ m_devMajor = (int)TarUtils.parseOctal( header, offset, TarConstants.DEVLEN );
+ offset += TarConstants.DEVLEN;
+ m_devMinor = (int)TarUtils.parseOctal( header, offset, TarConstants.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, TarConstants.MODELEN );
+ offset = TarUtils.getOctalBytes( m_userID, buffer, offset, TarConstants.UIDLEN );
+ offset = TarUtils.getOctalBytes( m_groupID, buffer, offset, TarConstants.GIDLEN );
+ offset = TarUtils.getLongOctalBytes( m_size, buffer, offset, TarConstants.SIZELEN );
+ offset = TarUtils.getLongOctalBytes( m_modTime, buffer, offset, TarConstants.MODTIMELEN );
+
+ final int checkSumOffset = offset;
+ for( int i = 0; i < TarConstants.CHKSUMLEN; ++i )
+ {
+ buffer[ offset++ ] = (byte)' ';
+ }
+
+ buffer[ offset++ ] = m_linkFlag;
+ offset = TarUtils.getNameBytes( m_linkName, buffer, offset, NAMELEN );
+ offset = TarUtils.getNameBytes( m_magic, buffer, offset, TarConstants.MAGICLEN );
+ offset = TarUtils.getNameBytes( m_userName, buffer, offset, TarConstants.UNAMELEN );
+ offset = TarUtils.getNameBytes( m_groupName, buffer, offset, TarConstants.GNAMELEN );
+ offset = TarUtils.getOctalBytes( m_devMajor, buffer, offset, TarConstants.DEVLEN );
+ offset = TarUtils.getOctalBytes( m_devMinor, buffer, offset, TarConstants.DEVLEN );
+
+ while( offset < buffer.length )
+ {
+ buffer[ offset++ ] = 0;
+ }
+
+ final long checkSum = TarUtils.computeCheckSum( buffer );
+ TarUtils.getCheckSumOctalBytes( checkSum, buffer, checkSumOffset, TarConstants.CHKSUMLEN );
+ }
+}
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.tar;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+
+public class TarArchiveInputStream extends ArchiveInputStream {
+ private final TarInputStream in;
+
+ public TarArchiveInputStream( InputStream inputStream ) {
+ in = new TarInputStream(inputStream);
+ }
+
+ public ArchiveEntry getNextEntry() throws IOException {
+ return (ArchiveEntry)in.getNextEntry();
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ return in.read(b, off, len);
+ }
+
+ public int read() throws IOException {
+ return in.read();
+ }
+
+ public static boolean matches( byte[] signature ) {
+ // 6574 7473 2e31 6d78
+
+ if (signature[0] != 0x74) {
+ return false;
+ }
+ if (signature[1] != 0x65) {
+ return false;
+ }
+ if (signature[2] != 0x73) {
+ return false;
+ }
+ if (signature[3] != 0x74) {
+ return false;
+ }
+ if (signature[4] != 0x31) {
+ return false;
+ }
+ if (signature[5] != 0x2e) {
+ return false;
+ }
+ if (signature[6] != 0x78) {
+ return false;
+ }
+ if (signature[7] != 0x6d) {
+ return false;
+ }
+
+ return true;
+ }
+
+}
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.tar;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveOutputStream;
+
+public class TarArchiveOutputStream extends ArchiveOutputStream {
+
+ private TarOutputStream out = null;
+
+ /**
+ * @param out
+ */
+ public TarArchiveOutputStream(OutputStream out) {
+ this.out = new TarOutputStream(out);
+ }
+
+ public void close() throws IOException {
+ this.out.close();
+ }
+
+ public void closeArchiveEntry() throws IOException {
+ this.out.closeEntry();
+ }
+
+ public void putArchiveEntry(ArchiveEntry entry) throws IOException {
+ this.out.putNextEntry((TarArchiveEntry)entry);
+ }
+
+ public void write(byte[] buffer, int offset, int length) throws IOException {
+ this.out.write(buffer, offset, length);
+ }
+
+ public String getDefaultFileExtension() {
+ return "tar";
+ }
+
+ public byte[] getHeader() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getName() {
+ return "tar";
+ }
+
+ public void write(int b) throws IOException {
+ this.out.write(b);
+ }
+}
+
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarBuffer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarBuffer.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarBuffer.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarBuffer.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,509 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.tar;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * The TarBuffer class implements the tar archive concept of a buffered input
+ * stream. This concept goes back to the days of blocked tape drives and special
+ * io devices. In the Java universe, the only real function that this class
+ * performs is to ensure that files have the correct "block" size, or other tars
+ * will complain. <p>
+ *
+ * You should never have a need to access this class directly. TarBuffers are
+ * created by Tar IO Streams.
+ *
+ * @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision$ $Date$
+ */
+class TarBuffer
+{
+ public static final int DEFAULT_RECORDSIZE = ( 512 );
+ public static final int DEFAULT_BLOCKSIZE = ( DEFAULT_RECORDSIZE * 20 );
+
+ private byte[] m_blockBuffer;
+ private int m_blockSize;
+ private int m_currBlkIdx;
+ private int m_currRecIdx;
+ private boolean m_debug;
+
+ private InputStream m_input;
+ private OutputStream m_output;
+ private int m_recordSize;
+ private int m_recsPerBlock;
+
+ public TarBuffer( final InputStream input )
+ {
+ this( input, TarBuffer.DEFAULT_BLOCKSIZE );
+ }
+
+ public TarBuffer( final InputStream input, final int blockSize )
+ {
+ this( input, blockSize, TarBuffer.DEFAULT_RECORDSIZE );
+ }
+
+ public TarBuffer( final InputStream input,
+ final int blockSize,
+ final int recordSize )
+ {
+ m_input = input;
+ initialize( blockSize, recordSize );
+ }
+
+ public TarBuffer( final OutputStream output )
+ {
+ this( output, TarBuffer.DEFAULT_BLOCKSIZE );
+ }
+
+ public TarBuffer( final OutputStream output, final int blockSize )
+ {
+ this( output, blockSize, TarBuffer.DEFAULT_RECORDSIZE );
+ }
+
+ public TarBuffer( final OutputStream output,
+ final int blockSize,
+ final int recordSize )
+ {
+ m_output = output;
+ initialize( blockSize, recordSize );
+ }
+
+ /**
+ * Set the debugging flag for the buffer.
+ *
+ * @param debug If true, print debugging output.
+ */
+ public void setDebug( final boolean debug )
+ {
+ m_debug = debug;
+ }
+
+ /**
+ * Get the TAR Buffer's block size. Blocks consist of multiple records.
+ *
+ * @return The BlockSize value
+ */
+ public int getBlockSize()
+ {
+ return m_blockSize;
+ }
+
+ /**
+ * Get the current block number, zero based.
+ *
+ * @return The current zero based block number.
+ */
+ public int getCurrentBlockNum()
+ {
+ return m_currBlkIdx;
+ }
+
+ /**
+ * Get the current record number, within the current block, zero based.
+ * Thus, current offset = (currentBlockNum * recsPerBlk) + currentRecNum.
+ *
+ * @return The current zero based record number.
+ */
+ public int getCurrentRecordNum()
+ {
+ return m_currRecIdx - 1;
+ }
+
+ /**
+ * Get the TAR Buffer's record size.
+ *
+ * @return The RecordSize value
+ */
+ public int getRecordSize()
+ {
+ return m_recordSize;
+ }
+
+ /**
+ * Determine if an archive record indicate End of Archive. End of archive is
+ * indicated by a record that consists entirely of null bytes.
+ *
+ * @param record The record data to check.
+ * @return The EOFRecord value
+ */
+ public boolean isEOFRecord( final byte[] record )
+ {
+ final int size = getRecordSize();
+ for( int i = 0; i < size; ++i )
+ {
+ if( record[ i ] != 0 )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Close the TarBuffer. If this is an output buffer, also flush the current
+ * block before closing.
+ */
+ public void close()
+ throws IOException
+ {
+ if( m_debug )
+ {
+ debug( "TarBuffer.closeBuffer()." );
+ }
+
+ if( null != m_output )
+ {
+ flushBlock();
+
+ if( m_output != System.out && m_output != System.err )
+ {
+ m_output.close();
+ m_output = null;
+ }
+ }
+ else if( m_input != null )
+ {
+ if( m_input != System.in )
+ {
+ m_input.close();
+ m_input = null;
+ }
+ }
+ }
+
+ /**
+ * Read a record from the input stream and return the data.
+ *
+ * @return The record data.
+ * @exception IOException Description of Exception
+ */
+ public byte[] readRecord()
+ throws IOException
+ {
+ if( m_debug )
+ {
+ final String message = "ReadRecord: recIdx = " + m_currRecIdx +
+ " blkIdx = " + m_currBlkIdx;
+ debug( message );
+ }
+
+ if( null == m_input )
+ {
+ final String message = "reading from an output buffer";
+ throw new IOException( message );
+ }
+
+ if( m_currRecIdx >= m_recsPerBlock )
+ {
+ if( !readBlock() )
+ {
+ return null;
+ }
+ }
+
+ final byte[] result = new byte[ m_recordSize ];
+ System.arraycopy( m_blockBuffer,
+ ( m_currRecIdx * m_recordSize ),
+ result,
+ 0,
+ m_recordSize );
+
+ m_currRecIdx++;
+
+ return result;
+ }
+
+ /**
+ * Skip over a record on the input stream.
+ */
+ public void skipRecord()
+ throws IOException
+ {
+ if( m_debug )
+ {
+ final String message = "SkipRecord: recIdx = " + m_currRecIdx +
+ " blkIdx = " + m_currBlkIdx;
+ debug( message );
+ }
+
+ if( null == m_input )
+ {
+ final String message = "reading (via skip) from an output buffer";
+ throw new IOException( message );
+ }
+
+ if( m_currRecIdx >= m_recsPerBlock )
+ {
+ if( !readBlock() )
+ {
+ return;// UNDONE
+ }
+ }
+
+ m_currRecIdx++;
+ }
+
+ /**
+ * Write an archive record to the archive.
+ *
+ * @param record The record data to write to the archive.
+ */
+ public void writeRecord( final byte[] record )
+ throws IOException
+ {
+ if( m_debug )
+ {
+ final String message = "WriteRecord: recIdx = " + m_currRecIdx +
+ " blkIdx = " + m_currBlkIdx;
+ debug( message );
+ }
+
+ if( null == m_output )
+ {
+ final String message = "writing to an input buffer";
+ throw new IOException( message );
+ }
+
+ if( record.length != m_recordSize )
+ {
+ final String message = "record to write has length '" +
+ record.length + "' which is not the record size of '" +
+ m_recordSize + "'";
+ throw new IOException( message );
+ }
+
+ if( m_currRecIdx >= m_recsPerBlock )
+ {
+ writeBlock();
+ }
+
+ System.arraycopy( record,
+ 0,
+ m_blockBuffer,
+ ( m_currRecIdx * m_recordSize ),
+ m_recordSize );
+
+ m_currRecIdx++;
+ }
+
+ /**
+ * Write an archive record to the archive, where the record may be inside of
+ * a larger array buffer. The buffer must be "offset plus record size" long.
+ *
+ * @param buffer The buffer containing the record data to write.
+ * @param offset The offset of the record data within buf.
+ */
+ public void writeRecord( final byte[] buffer, final int offset )
+ throws IOException
+ {
+ if( m_debug )
+ {
+ final String message = "WriteRecord: recIdx = " + m_currRecIdx +
+ " blkIdx = " + m_currBlkIdx;
+ debug( message );
+ }
+
+ if( null == m_output )
+ {
+ final String message = "writing to an input buffer";
+ throw new IOException( message );
+ }
+
+ if( ( offset + m_recordSize ) > buffer.length )
+ {
+ final String message = "record has length '" + buffer.length +
+ "' with offset '" + offset + "' which is less than the record size of '" +
+ m_recordSize + "'";
+ throw new IOException( message );
+ }
+
+ if( m_currRecIdx >= m_recsPerBlock )
+ {
+ writeBlock();
+ }
+
+ System.arraycopy( buffer,
+ offset,
+ m_blockBuffer,
+ ( m_currRecIdx * m_recordSize ),
+ m_recordSize );
+
+ m_currRecIdx++;
+ }
+
+ /**
+ * Flush the current data block if it has any data in it.
+ */
+ private void flushBlock()
+ throws IOException
+ {
+ if( m_debug )
+ {
+ final String message = "TarBuffer.flushBlock() called.";
+ debug( message );
+ }
+
+ if( m_output == null )
+ {
+ final String message = "writing to an input buffer";
+ throw new IOException( message );
+ }
+
+ if( m_currRecIdx > 0 )
+ {
+ writeBlock();
+ }
+ }
+
+ /**
+ * Initialization common to all constructors.
+ */
+ private void initialize( final int blockSize, final int recordSize )
+ {
+ m_debug = false;
+ m_blockSize = blockSize;
+ m_recordSize = recordSize;
+ m_recsPerBlock = ( m_blockSize / m_recordSize );
+ m_blockBuffer = new byte[ m_blockSize ];
+
+ if( null != m_input )
+ {
+ m_currBlkIdx = -1;
+ m_currRecIdx = m_recsPerBlock;
+ }
+ else
+ {
+ m_currBlkIdx = 0;
+ m_currRecIdx = 0;
+ }
+ }
+
+ /**
+ * @return false if End-Of-File, else true
+ */
+ private boolean readBlock()
+ throws IOException
+ {
+ if( m_debug )
+ {
+ final String message = "ReadBlock: blkIdx = " + m_currBlkIdx;
+ debug( message );
+ }
+
+ if( null == m_input )
+ {
+ final String message = "reading from an output buffer";
+ throw new IOException( message );
+ }
+
+ m_currRecIdx = 0;
+
+ int offset = 0;
+ int bytesNeeded = m_blockSize;
+
+ while( bytesNeeded > 0 )
+ {
+ final long numBytes = m_input.read( m_blockBuffer, offset, bytesNeeded );
+
+ //
+ // NOTE
+ // We have fit EOF, and the block is not full!
+ //
+ // This is a broken archive. It does not follow the standard
+ // blocking algorithm. However, because we are generous, and
+ // it requires little effort, we will simply ignore the error
+ // and continue as if the entire block were read. This does
+ // not appear to break anything upstream. We used to return
+ // false in this case.
+ //
+ // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
+ //
+ if( numBytes == -1 )
+ {
+ // However, just leaving the unread portion of the buffer dirty does
+ // cause problems in some cases. This problem is described in
+ // http://issues.apache.org/bugzilla/show_bug.cgi?id=29877
+ //
+ // The solution is to fill the unused portion of the buffer with zeros.
+
+ Arrays.fill(m_blockBuffer, offset, offset + bytesNeeded, (byte) 0);
+
+ break;
+ }
+
+ offset += numBytes;
+ bytesNeeded -= numBytes;
+
+ if( numBytes != m_blockSize )
+ {
+ if( m_debug )
+ {
+ System.err.println( "ReadBlock: INCOMPLETE READ "
+ + numBytes + " of " + m_blockSize
+ + " bytes read." );
+ }
+ }
+ }
+
+ m_currBlkIdx++;
+
+ return true;
+ }
+
+ /**
+ * Write a TarBuffer block to the archive.
+ *
+ * @exception IOException Description of Exception
+ */
+ private void writeBlock()
+ throws IOException
+ {
+ if( m_debug )
+ {
+ final String message = "WriteBlock: blkIdx = " + m_currBlkIdx;
+ debug( message );
+ }
+
+ if( null == m_output )
+ {
+ final String message = "writing to an input buffer";
+ throw new IOException( message );
+ }
+
+ m_output.write( m_blockBuffer, 0, m_blockSize );
+ m_output.flush();
+
+ m_currRecIdx = 0;
+ m_currBlkIdx++;
+ }
+
+ protected void debug( final String message )
+ {
+ if( m_debug )
+ {
+ System.err.println( message );
+ }
+ }
+}
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarBuffer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarBuffer.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarBuffer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.tar;
+
+/**
+ * This interface contains all the definitions used in the package.
+ *
+ * @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
+ * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
+ * @version $Revision$ $Date$
+ */
+interface TarConstants
+{
+ /**
+ * The length of the mode field in a header buffer.
+ */
+ int MODELEN = 8;
+
+ /**
+ * The length of the user id field in a header buffer.
+ */
+ int UIDLEN = 8;
+
+ /**
+ * The length of the group id field in a header buffer.
+ */
+ int GIDLEN = 8;
+
+ /**
+ * The length of the checksum field in a header buffer.
+ */
+ int CHKSUMLEN = 8;
+
+ /**
+ * The length of the size field in a header buffer.
+ */
+ int SIZELEN = 12;
+
+ /**
+ * The length of the magic field in a header buffer.
+ */
+ int MAGICLEN = 8;
+
+ /**
+ * The length of the modification time field in a header buffer.
+ */
+ int MODTIMELEN = 12;
+
+ /**
+ * The length of the user name field in a header buffer.
+ */
+ int UNAMELEN = 32;
+
+ /**
+ * The length of the group name field in a header buffer.
+ */
+ int GNAMELEN = 32;
+
+ /**
+ * The length of the devices field in a header buffer.
+ */
+ 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.
+ */
+ byte LF_OLDNORM = 0;
+
+ /**
+ * Normal file type.
+ */
+ byte LF_NORMAL = (byte)'0';
+
+ /**
+ * Link file type.
+ */
+ byte LF_LINK = (byte)'1';
+
+ /**
+ * Symbolic link file type.
+ */
+ byte LF_SYMLINK = (byte)'2';
+
+ /**
+ * Character device file type.
+ */
+ byte LF_CHR = (byte)'3';
+
+ /**
+ * Block device file type.
+ */
+ byte LF_BLK = (byte)'4';
+
+ /**
+ * Directory file type.
+ */
+ byte LF_DIR = (byte)'5';
+
+ /**
+ * FIFO (pipe) file type.
+ */
+ byte LF_FIFO = (byte)'6';
+
+ /**
+ * Contiguous file type.
+ */
+ byte LF_CONTIG = (byte)'7';
+
+ /**
+ * The magic tag representing a POSIX tar archive.
+ */
+ String TMAGIC = "ustar";
+
+ /**
+ * The magic tag representing a GNU tar archive.
+ */
+ String GNU_TMAGIC = "ustar ";
+
+ /**
+ * The namr of the GNU tar entry which contains a long name.
+ */
+ String GNU_LONGLINK = "././@LongLink";
+
+ /**
+ * Identifies the *next* file on the tape as having a long name.
+ */
+ byte LF_GNUTYPE_LONGNAME = (byte)'L';
+}
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,475 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.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$ $Date$
+ * @see TarInputStream
+ * @see TarArchiveEntry
+ */
+public class TarInputStream
+ extends FilterInputStream
+{
+ private TarBuffer m_buffer;
+ private TarArchiveEntry 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 TarArchiveEntry 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 TarArchiveEntry( 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: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java?rev=675498&view=auto
==============================================================================
--- commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java (added)
+++ commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java Thu Jul 10 03:17:44 2008
@@ -0,0 +1,427 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.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$ $Date$
+ * @see TarInputStream
+ * @see TarArchiveEntry
+ */
+public 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 TarArchiveEntry to be written to the archive.
+ * @exception IOException when an IO error causes operation to fail
+ */
+ public void putNextEntry( final TarArchiveEntry entry )
+ throws IOException
+ {
+ if( entry.getName().length() >= TarArchiveEntry.NAMELEN )
+ {
+ if( m_longFileMode == LONGFILE_GNU )
+ {
+ // create a TarArchiveEntry for the LongLink, the contents
+ // of which are the entry's name
+ final TarArchiveEntry longLinkEntry =
+ new TarArchiveEntry( TarConstants.GNU_LONGLINK,
+ TarConstants.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 ( > " + TarArchiveEntry.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
+ */
+ public 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: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: commons/sandbox/compress/branches/redesign/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
------------------------------------------------------------------------------
svn:mime-type = text/plain