commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject svn commit: r743006 - in /commons/sandbox/compress/trunk/src: main/java/org/apache/commons/compress/archivers/ main/java/org/apache/commons/compress/archivers/tar/ test/java/org/apache/commons/compress/
Date Tue, 10 Feb 2009 16:11:21 GMT
Author: bodewig
Date: Tue Feb 10 16:10:45 2009
New Revision: 743006

URL: http://svn.apache.org/viewvc?rev=743006&view=rev
Log:
rename Tar*Stream

Added:
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
Removed:
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarInputStream.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarOutputStream.java
Modified:
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
    commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/DetectArchiverTestCase.java

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java?rev=743006&r1=743005&r2=743006&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
(original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
Tue Feb 10 16:10:45 2009
@@ -28,8 +28,8 @@
 import org.apache.commons.compress.archivers.cpio.CpioArchiveOutputStream;
 import org.apache.commons.compress.archivers.jar.JarArchiveInputStream;
 import org.apache.commons.compress.archivers.jar.JarArchiveOutputStream;
-import org.apache.commons.compress.archivers.tar.TarInputStream;
-import org.apache.commons.compress.archivers.tar.TarOutputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
 
@@ -52,7 +52,7 @@
         } else if("zip".equalsIgnoreCase(archiverName)) {
             return new ZipArchiveInputStream(in);
         } else if("tar".equalsIgnoreCase(archiverName)) {
-            return new TarInputStream(in);
+            return new TarArchiveInputStream(in);
         } else if("jar".equalsIgnoreCase(archiverName)) {
             return new JarArchiveInputStream(in);
         } else if("cpio".equalsIgnoreCase(archiverName)) {
@@ -67,7 +67,7 @@
         } else if("zip".equalsIgnoreCase(archiverName)) {
             return new ZipArchiveOutputStream(out);
         } else if("tar".equalsIgnoreCase(archiverName)) {
-            return new TarOutputStream(out);
+            return new TarArchiveOutputStream(out);
         } else if("jar".equalsIgnoreCase(archiverName)) {
             return new JarArchiveOutputStream(out);
         } else if("cpio".equalsIgnoreCase(archiverName)) {
@@ -88,8 +88,8 @@
             return new ZipArchiveInputStream(input);
         } else if(JarArchiveInputStream.matches(signature, signatureLength)) {
             return new JarArchiveInputStream(input);
-        } else if(TarInputStream.matches(signature, signatureLength)) {
-            return new TarInputStream(input);
+        } else if(TarArchiveInputStream.matches(signature, signatureLength)) {
+            return new TarArchiveInputStream(input);
         } else if(ArArchiveInputStream.matches(signature, signatureLength)) {
             return new ArArchiveInputStream(input);
         } else if(CpioArchiveInputStream.matches(signature, signatureLength)) {

Added: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java?rev=743006&view=auto
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
(added)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
Tue Feb 10 16:10:45 2009
@@ -0,0 +1,431 @@
+/*
+ *  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.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.commons.compress.archivers.tar;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+
+/**
+ * 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().
+ *
+ */
+public class TarArchiveInputStream extends ArchiveInputStream {
+    private static final int SMALL_BUFFER_SIZE = 256;
+    private static final int BUFFER_SIZE = 8 * 1024;
+    private static final int LARGE_BUFFER_SIZE = 32 * 1024;
+    private static final int BYTE_MASK = 0xFF;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean debug;
+    protected boolean hasHitEOF;
+    protected long entrySize;
+    protected long entryOffset;
+    protected byte[] readBuf;
+    protected TarBuffer buffer;
+    protected TarArchiveEntry currEntry;
+
+    /**
+     * This contents of this array is not used at all in this class,
+     * it is only here to avoid repreated object creation during calls
+     * to the no-arg read method.
+     */
+    protected byte[] oneBuf;
+
+    // CheckStyle:VisibilityModifier ON
+
+    private final InputStream in;
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     */
+    public TarArchiveInputStream(InputStream is) {
+        this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     * @param blockSize the block size to use
+     */
+    public TarArchiveInputStream(InputStream is, int blockSize) {
+        this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     * @param blockSize the block size to use
+     * @param recordSize the record size to use
+     */
+    public TarArchiveInputStream(InputStream is, int blockSize, int recordSize) {
+        this.in = is;
+
+        this.buffer = new TarBuffer(is, blockSize, recordSize);
+        this.readBuf = null;
+        this.oneBuf = new byte[1];
+        this.debug = false;
+        this.hasHitEOF = false;
+    }
+
+    /**
+     * Sets the debugging flag.
+     *
+     * @param debug True to turn on debugging.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+        buffer.setDebug(debug);
+    }
+
+    /**
+     * Closes this stream. Calls the TarBuffer's close() method.
+     * @throws IOException on error
+     */
+    public void close() throws IOException {
+        buffer.close();
+    }
+
+    /**
+     * Get the record size being used by this stream's TarBuffer.
+     *
+     * @return The TarBuffer record size.
+     */
+    public int getRecordSize() {
+        return 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.
+     * Integer.MAX_VALUE is returen in case more than Integer.MAX_VALUE
+     * bytes are left in the current entry in the archive.
+     *
+     * @return The number of available bytes for the current entry.
+     * @throws IOException for signature
+     */
+    public int available() throws IOException {
+        if (entrySize - entryOffset > Integer.MAX_VALUE) {
+            return Integer.MAX_VALUE;
+        }
+        return (int) (entrySize - entryOffset);
+    }
+
+    /**
+     * 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.
+     * @return the number actually skipped
+     * @throws IOException on error
+     */
+    public long skip(long numToSkip) throws IOException {
+        // REVIEW
+        // This is horribly inefficient, but it ensures that we
+        // properly skip over bytes via the TarBuffer...
+        //
+        byte[] skipBuf = new byte[BUFFER_SIZE];
+        long skip = numToSkip;
+        while (skip > 0) {
+            int realSkip = (int) (skip > skipBuf.length ? skipBuf.length : skip);
+            int numRead = read(skipBuf, 0, realSkip);
+            if (numRead == -1) {
+                break;
+            }
+            skip -= numRead;
+        }
+        return (numToSkip - skip);
+    }
+
+    /**
+     * Since we do not support marking just yet, we do nothing.
+     */
+    public void reset() {
+    }
+
+    /**
+     * 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.
+     * @throws IOException on error
+     */
+    public ArchiveEntry getNextEntry() throws IOException {
+        if (hasHitEOF) {
+            return null;
+        }
+
+        if (currEntry != null) {
+            long numToSkip = entrySize - entryOffset;
+
+            if (debug) {
+                System.err.println("TarInputStream: SKIP currENTRY '"
+                                   + currEntry.getName() + "' SZ "
+                                   + entrySize + " OFF "
+                                   + entryOffset + "  skipping "
+                                   + numToSkip + " bytes");
+            }
+
+            while (numToSkip > 0) {
+                long skipped = skip(numToSkip);
+                if (skipped <= 0) {
+                    throw new RuntimeException("failed to skip current tar"
+                                               + " entry");
+                }
+                numToSkip -= skipped;
+            }
+
+            readBuf = null;
+        }
+
+        byte[] headerBuf = buffer.readRecord();
+
+        if (headerBuf == null) {
+            if (debug) {
+                System.err.println("READ NULL RECORD");
+            }
+            hasHitEOF = true;
+        } else if (buffer.isEOFRecord(headerBuf)) {
+            if (debug) {
+                System.err.println("READ EOF RECORD");
+            }
+            hasHitEOF = true;
+        }
+
+        if (hasHitEOF) {
+            currEntry = null;
+        } else {
+            currEntry = new TarArchiveEntry(headerBuf);
+
+            if (debug) {
+                System.err.println("TarInputStream: SET CURRENTRY '"
+                                   + currEntry.getName()
+                                   + "' size = "
+                                   + currEntry.getSize());
+            }
+
+            entryOffset = 0;
+
+            entrySize = currEntry.getSize();
+        }
+
+        if (currEntry != null && currEntry.isGNULongNameEntry()) {
+            // read in the name
+            StringBuffer longName = new StringBuffer();
+            byte[] buf = new byte[SMALL_BUFFER_SIZE];
+            int length = 0;
+            while ((length = read(buf)) >= 0) {
+                longName.append(new String(buf, 0, length));
+            }
+            getNextEntry();
+            if (currEntry == null) {
+                // Bugzilla: 40334
+                // Malformed tar file - long entry name not followed by entry
+                return null;
+            }
+            // remove trailing null terminator
+            if (longName.length() > 0
+                && longName.charAt(longName.length() - 1) == 0) {
+                longName.deleteCharAt(longName.length() - 1);
+            }
+            currEntry.setName(longName.toString());
+        }
+
+        return currEntry;
+    }
+
+    /**
+     * 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.
+     * @throws IOException on error
+     */
+    public int read() throws IOException {
+        int num = read(oneBuf, 0, 1);
+        return num == -1 ? -1 : ((int) oneBuf[0]) & BYTE_MASK;
+    }
+
+    /**
+     * 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 buf The buffer into which to place bytes read.
+     * @param offset The offset at which to place bytes read.
+     * @param numToRead The number of bytes to read.
+     * @return The number of bytes read, or -1 at EOF.
+     * @throws IOException on error
+     */
+    public int read(byte[] buf, int offset, int numToRead) throws IOException {
+        int totalRead = 0;
+
+        if (entryOffset >= entrySize) {
+            return -1;
+        }
+
+        if ((numToRead + entryOffset) > entrySize) {
+            numToRead = (int) (entrySize - entryOffset);
+        }
+
+        if (readBuf != null) {
+            int sz = (numToRead > readBuf.length) ? readBuf.length
+                : numToRead;
+
+            System.arraycopy(readBuf, 0, buf, offset, sz);
+
+            if (sz >= readBuf.length) {
+                readBuf = null;
+            } else {
+                int newLen = readBuf.length - sz;
+                byte[] newBuf = new byte[newLen];
+
+                System.arraycopy(readBuf, sz, newBuf, 0, newLen);
+
+                readBuf = newBuf;
+            }
+
+            totalRead += sz;
+            numToRead -= sz;
+            offset += sz;
+        }
+
+        while (numToRead > 0) {
+            byte[] rec = buffer.readRecord();
+
+            if (rec == null) {
+                // Unexpected EOF!
+                throw new IOException("unexpected EOF with " + numToRead
+                                      + " bytes unread");
+            }
+
+            int sz = numToRead;
+            int recLen = rec.length;
+
+            if (recLen > sz) {
+                System.arraycopy(rec, 0, buf, offset, sz);
+
+                readBuf = new byte[recLen - sz];
+
+                System.arraycopy(rec, sz, readBuf, 0, recLen - sz);
+            } else {
+                sz = recLen;
+
+                System.arraycopy(rec, 0, buf, offset, recLen);
+            }
+
+            totalRead += sz;
+            numToRead -= sz;
+            offset += sz;
+        }
+
+        entryOffset += totalRead;
+
+        return totalRead;
+    }
+
+    /**
+     * Copies the contents of the current tar archive entry directly into
+     * an output stream.
+     *
+     * @param out The OutputStream into which to write the entry's data.
+     * @throws IOException on error
+     */
+    public void copyEntryContents(OutputStream out) throws IOException {
+        byte[] buf = new byte[LARGE_BUFFER_SIZE];
+
+        while (true) {
+            int numRead = read(buf, 0, buf.length);
+
+            if (numRead == -1) {
+                break;
+            }
+
+            out.write(buf, 0, numRead);
+        }
+    }
+
+    // used to be implemented via FilterInputStream
+    public int read(byte[] b) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    // ArchiveInputStream
+
+    public static boolean matches(byte[] signature, int length) {
+        // 6574 7473 2e31 6d78
+
+        if (length < 8) {
+            return false;
+        }
+
+        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;
+    }
+
+}

Added: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java?rev=743006&view=auto
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
(added)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
Tue Feb 10 16:10:45 2009
@@ -0,0 +1,380 @@
+/*
+ * 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;
+
+/**
+ * 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().
+ *
+ */
+public class TarArchiveOutputStream extends ArchiveOutputStream {
+    /** Fail if a long file name is required in the archive. */
+    public static final int LONGFILE_ERROR = 0;
+
+    /** Long paths will be truncated in the archive. */
+    public static final int LONGFILE_TRUNCATE = 1;
+
+    /** GNU tar extensions are used to store long file names in the archive. */
+    public static final int LONGFILE_GNU = 2;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean   debug;
+    protected long      currSize;
+    protected String    currName;
+    protected long      currBytes;
+    protected byte[]    oneBuf;
+    protected byte[]    recordBuf;
+    protected int       assemLen;
+    protected byte[]    assemBuf;
+    protected TarBuffer buffer;
+    protected int       longFileMode = LONGFILE_ERROR;
+    // CheckStyle:VisibilityModifier ON
+
+    private boolean closed = false;
+
+    private final OutputStream out;
+
+    /**
+     * Constructor for TarInputStream.
+     * @param os the output stream to use
+     */
+    public TarArchiveOutputStream(OutputStream os) {
+        this(os, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param os the output stream to use
+     * @param blockSize the block size to use
+     */
+    public TarArchiveOutputStream(OutputStream os, int blockSize) {
+        this(os, blockSize, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param os the output stream to use
+     * @param blockSize the block size to use
+     * @param recordSize the record size to use
+     */
+    public TarArchiveOutputStream(OutputStream os, int blockSize, int recordSize) {
+        out = os;
+
+        this.buffer = new TarBuffer(os, blockSize, recordSize);
+        this.debug = false;
+        this.assemLen = 0;
+        this.assemBuf = new byte[recordSize];
+        this.recordBuf = new byte[recordSize];
+        this.oneBuf = new byte[1];
+    }
+
+    /**
+     * Set the long file mode.
+     * This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1) or LONGFILE_GNU(2).
+     * This specifies the treatment of long file names (names >= TarConstants.NAMELEN).
+     * Default is LONGFILE_ERROR.
+     * @param longFileMode the mode to use
+     */
+    public void setLongFileMode(int longFileMode) {
+        this.longFileMode = longFileMode;
+    }
+
+
+    /**
+     * Sets the debugging flag.
+     *
+     * @param debugF True to turn on debugging.
+     */
+    public void setDebug(boolean debugF) {
+        this.debug = debugF;
+    }
+
+    /**
+     * Sets the debugging flag in this stream's TarBuffer.
+     *
+     * @param debug True to turn on debugging.
+     */
+    public void setBufferDebug(boolean debug) {
+        buffer.setDebug(debug);
+    }
+
+    /**
+     * Ends the TAR archive without closing the underlying OutputStream.
+     * The result is that the two EOF records of nulls are written.
+     * @throws IOException on error
+     */
+    public void finish() throws IOException {
+        // See Bugzilla 28776 for a discussion on this
+        // http://issues.apache.org/bugzilla/show_bug.cgi?id=28776
+        writeEOFRecord();
+        writeEOFRecord();
+    }
+
+    /**
+     * Ends the TAR archive and closes the underlying OutputStream.
+     * This means that finish() is called followed by calling the
+     * TarBuffer's close().
+     * @throws IOException on error
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            finish();
+            buffer.close();
+            out.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Get the record size being used by this stream's TarBuffer.
+     *
+     * @return The TarBuffer record size.
+     */
+    public int getRecordSize() {
+        return buffer.getRecordSize();
+    }
+
+    /**
+     * 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.
+     * @throws IOException on error
+     */
+    public void putNextEntry(TarArchiveEntry entry) throws IOException {
+        if (entry.getName().length() >= TarConstants.NAMELEN) {
+
+            if (longFileMode == LONGFILE_GNU) {
+                // create a TarEntry for the LongLink, the contents
+                // of which are the entry's name
+                TarArchiveEntry longLinkEntry = new TarArchiveEntry(TarConstants.GNU_LONGLINK,
+                                                                    TarConstants.LF_GNUTYPE_LONGNAME);
+
+                longLinkEntry.setSize(entry.getName().length() + 1);
+                putNextEntry(longLinkEntry);
+                write(entry.getName().getBytes());
+                write(0);
+                closeEntry();
+            } else if (longFileMode != LONGFILE_TRUNCATE) {
+                throw new RuntimeException("file name '" + entry.getName()
+                                           + "' is too long ( > "
+                                           + TarConstants.NAMELEN + " bytes)");
+            }
+        }
+
+        entry.writeEntryHeader(recordBuf);
+        buffer.writeRecord(recordBuf);
+
+        currBytes = 0;
+
+        if (entry.isDirectory()) {
+            currSize = 0;
+        } else {
+            currSize = entry.getSize();
+        }
+        currName = entry.getName();
+    }
+
+    /**
+     * 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.
+     * @throws IOException on error
+     */
+    public void closeEntry() throws IOException {
+        if (assemLen > 0) {
+            for (int i = assemLen; i < assemBuf.length; ++i) {
+                assemBuf[i] = 0;
+            }
+
+            buffer.writeRecord(assemBuf);
+
+            currBytes += assemLen;
+            assemLen = 0;
+        }
+
+        if (currBytes < currSize) {
+            throw new IOException("entry '" + currName + "' closed at '"
+                                  + currBytes
+                                  + "' before the '" + currSize
+                                  + "' bytes specified in the header were written");
+        }
+    }
+
+    /**
+     * Writes a byte to the current tar archive entry.
+     *
+     * This method simply calls read( byte[], int, int ).
+     *
+     * @param b The byte written.
+     * @throws IOException on error
+     */
+    public void write(int b) throws IOException {
+        oneBuf[0] = (byte) b;
+
+        write(oneBuf, 0, 1);
+    }
+
+    /**
+     * Writes bytes to the current tar archive entry.
+     *
+     * This method simply calls write( byte[], int, int ).
+     *
+     * @param wBuf The buffer to write to the archive.
+     * @throws IOException on error
+     */
+    public void write(byte[] wBuf) throws IOException {
+        write(wBuf, 0, wBuf.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 wBuf The buffer to write to the archive.
+     * @param wOffset The offset in the buffer from which to get bytes.
+     * @param numToWrite The number of bytes to write.
+     * @throws IOException on error
+     */
+    public void write(byte[] wBuf, int wOffset, int numToWrite) throws IOException {
+        if ((currBytes + numToWrite) > currSize) {
+            throw new IOException("request to write '" + numToWrite
+                                  + "' bytes exceeds size in header of '"
+                                  + currSize + "' bytes for entry '"
+                                  + currName + "'");
+
+            //
+            // 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 (assemLen > 0) {
+            if ((assemLen + numToWrite) >= recordBuf.length) {
+                int aLen = recordBuf.length - assemLen;
+
+                System.arraycopy(assemBuf, 0, recordBuf, 0,
+                                 assemLen);
+                System.arraycopy(wBuf, wOffset, recordBuf,
+                                 assemLen, aLen);
+                buffer.writeRecord(recordBuf);
+
+                currBytes += recordBuf.length;
+                wOffset += aLen;
+                numToWrite -= aLen;
+                assemLen = 0;
+            } else {
+                System.arraycopy(wBuf, wOffset, assemBuf, assemLen,
+                                 numToWrite);
+
+                wOffset += numToWrite;
+                assemLen += numToWrite;
+                numToWrite = 0;
+            }
+        }
+
+        //
+        // When we get here we have EITHER:
+        // o An empty "assemble" buffer.
+        // o No bytes to write (numToWrite == 0)
+        //
+        while (numToWrite > 0) {
+            if (numToWrite < recordBuf.length) {
+                System.arraycopy(wBuf, wOffset, assemBuf, assemLen,
+                                 numToWrite);
+
+                assemLen += numToWrite;
+
+                break;
+            }
+
+            buffer.writeRecord(wBuf, wOffset);
+
+            int num = recordBuf.length;
+
+            currBytes += num;
+            numToWrite -= num;
+            wOffset += num;
+        }
+    }
+
+    /**
+     * Write an EOF (end of archive) record to the tar archive.
+     * An EOF record consists of a record of all zeros.
+     */
+    private void writeEOFRecord() throws IOException {
+        for (int i = 0; i < recordBuf.length; ++i) {
+            recordBuf[i] = 0;
+        }
+
+        buffer.writeRecord(recordBuf);
+    }
+
+    // used to be implemented via FilterOutputStream
+    public void flush() throws IOException {
+        out.flush();
+    }
+
+    // ArchiveOutputStream
+
+    public void closeArchiveEntry() throws IOException {
+        closeEntry();
+    }
+
+    public void putArchiveEntry(ArchiveEntry entry) throws IOException {
+        putNextEntry((TarArchiveEntry) entry);
+    }
+
+    public String getDefaultFileExtension() {
+        return "tar";
+    }
+
+    public byte[] getHeader() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getName() {
+        return "tar";
+    }
+
+}

Modified: commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/DetectArchiverTestCase.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/DetectArchiverTestCase.java?rev=743006&r1=743005&r2=743006&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/DetectArchiverTestCase.java
(original)
+++ commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/DetectArchiverTestCase.java
Tue Feb 10 16:10:45 2009
@@ -29,7 +29,7 @@
 import org.apache.commons.compress.archivers.ar.ArArchiveInputStream;
 import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
 import org.apache.commons.compress.archivers.jar.JarArchiveInputStream;
-import org.apache.commons.compress.archivers.tar.TarInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
 
 public final class DetectArchiverTestCase extends TestCase {
@@ -46,7 +46,7 @@
 				new BufferedInputStream(new FileInputStream(
 						new File(getClass().getClassLoader().getResource("bla.tar").getFile()))));
 		assertNotNull(tar);
-		assertTrue(tar instanceof TarInputStream);
+		assertTrue(tar instanceof TarArchiveInputStream);
 
 		final ArchiveInputStream zip = factory.createArchiveInputStream(
 				new BufferedInputStream(new FileInputStream(



Mime
View raw message