You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by da...@apache.org on 2013/05/19 11:36:18 UTC

svn commit: r1484246 - in /commons/proper/compress/trunk: ./ src/main/java/org/apache/commons/compress/archivers/ src/main/java/org/apache/commons/compress/archivers/arj/ src/main/java/org/apache/commons/compress/archivers/sevenz/ src/main/java/org/apa...

Author: damjan
Date: Sun May 19 09:36:17 2013
New Revision: 1484246

URL: http://svn.apache.org/r1484246
Log:
Add initial support for ARJ archives.
Document it.

We only support reading at the moment,
and only support the STORED (absense of) compression
with no encryption or multi-volume support.

Jira issue key: COMPRESS-226


Added:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/LocalFileHeader.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/MainHeader.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/package.html   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java   (with props)
Modified:
    commons/proper/compress/trunk/pom.xml
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
    commons/proper/compress/trunk/src/site/xdoc/examples.xml
    commons/proper/compress/trunk/src/site/xdoc/index.xml

Modified: commons/proper/compress/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/pom.xml?rev=1484246&r1=1484245&r2=1484246&view=diff
==============================================================================
--- commons/proper/compress/trunk/pom.xml (original)
+++ commons/proper/compress/trunk/pom.xml Sun May 19 09:36:17 2013
@@ -31,7 +31,7 @@
   <!-- The description is not indented to make it look better in the release notes -->
   <description>
 Apache Commons Compress software defines an API for working with compression and archive formats.
-These include: bzip2, gzip, pack200, xz and ar, cpio, jar, tar, zip, dump, 7z.
+These include: bzip2, gzip, pack200, xz and ar, cpio, jar, tar, zip, dump, 7z, arj.
   </description>
 
   <properties>

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java?rev=1484246&r1=1484245&r2=1484246&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java Sun May 19 09:36:17 2013
@@ -25,6 +25,7 @@ import java.io.OutputStream;
 
 import org.apache.commons.compress.archivers.ar.ArArchiveInputStream;
 import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream;
+import org.apache.commons.compress.archivers.arj.ArjArchiveInputStream;
 import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
 import org.apache.commons.compress.archivers.cpio.CpioArchiveOutputStream;
 import org.apache.commons.compress.archivers.dump.DumpArchiveInputStream;
@@ -79,6 +80,11 @@ public class ArchiveStreamFactory {
      */
     public static final String AR = "ar";
     /**
+     * Constant used to identify the ARJ archive format.
+     * @since 1.6
+     */
+    public static final String ARJ = "arj";
+    /**
      * Constant used to identify the CPIO archive format.
      * @since 1.1
      */
@@ -110,8 +116,8 @@ public class ArchiveStreamFactory {
     private String entryEncoding = null;
 
     /**
-     * Returns the encoding to use for zip and tar files, or null for
-     * the default.
+     * Returns the encoding to use for arj, zip and tar files,
+     * or null for the default.
      *
      * @return entry encoding, or null
      * @since 1.5
@@ -121,8 +127,8 @@ public class ArchiveStreamFactory {
     }
 
     /**
-     * Sets the encoding to use for zip and tar files. Use null for
-     * the default.
+     * Sets the encoding to use for arj, zip and tar files.
+     * Use null for the default.
      *
      * @since 1.5
      */
@@ -133,7 +139,7 @@ public class ArchiveStreamFactory {
     /**
      * Create an archive input stream from an archiver name and an input stream.
      * 
-     * @param archiverName the archive name, i.e. "ar", "zip", "tar", "jar", "dump" or "cpio"
+     * @param archiverName the archive name, i.e. "ar", "arj", "zip", "tar", "jar", "dump" or "cpio"
      * @param in the input stream
      * @return the archive input stream
      * @throws ArchiveException if the archiver name is not known
@@ -154,6 +160,13 @@ public class ArchiveStreamFactory {
         if (AR.equalsIgnoreCase(archiverName)) {
             return new ArArchiveInputStream(in);
         }
+        if (ARJ.equalsIgnoreCase(archiverName)) {
+            if (entryEncoding != null) {
+                return new ArjArchiveInputStream(in, entryEncoding);
+            } else {
+                return new ArjArchiveInputStream(in);
+            }
+        }
         if (ZIP.equalsIgnoreCase(archiverName)) {
             if (entryEncoding != null) {
                 return new ZipArchiveInputStream(in, entryEncoding);
@@ -263,6 +276,8 @@ public class ArchiveStreamFactory {
                 return new ArArchiveInputStream(in);
             } else if (CpioArchiveInputStream.matches(signature, signatureLength)) {
                 return new CpioArchiveInputStream(in);
+            } else if (ArjArchiveInputStream.matches(signature, signatureLength)) {
+                return new ArjArchiveInputStream(in);
             }
 
             // Dump needs a bigger buffer to check the signature;

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java?rev=1484246&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java Sun May 19 09:36:17 2013
@@ -0,0 +1,64 @@
+/*
+ *  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.arj;
+
+import java.io.File;
+import java.util.Date;
+import java.util.regex.Matcher;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipUtil;
+
+/**
+ * An entry in an ARJ archive.
+ * 
+ * @NotThreadSafe
+ */
+public class ArjArchiveEntry implements ArchiveEntry {
+    private final LocalFileHeader localFileHeader;
+    
+    public ArjArchiveEntry() {
+        localFileHeader = new LocalFileHeader();
+    }
+    
+    ArjArchiveEntry(final LocalFileHeader localFileHeader) {
+        this.localFileHeader = localFileHeader;
+    }
+
+    public String getName() {
+        if ((localFileHeader.arjFlags & LocalFileHeader.Flags.PATHSYM) != 0) {
+            return localFileHeader.name.replaceAll("/",
+                    Matcher.quoteReplacement(File.separator));
+        } else {
+            return localFileHeader.name;
+        }
+    }
+
+    public long getSize() {
+        return localFileHeader.originalSize;
+    }
+
+    public boolean isDirectory() {
+        return localFileHeader.fileType == LocalFileHeader.FileTypes.DIRECTORY;
+    }
+
+    public Date getLastModifiedDate() {
+        return new Date(ZipUtil.dosToJavaTime(
+                0xffffFFFFL & localFileHeader.dateTimeModified));
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java?rev=1484246&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java Sun May 19 09:36:17 2013
@@ -0,0 +1,321 @@
+/*
+ *  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.arj;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.zip.CRC32;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.utils.BoundedInputStream;
+import org.apache.commons.compress.utils.CRC32VerifyingInputStream;
+
+/**
+ * Implements the "arj" archive format as an InputStream.
+ * <p>
+ * <a href="http://farmanager.com/svn/trunk/plugins/multiarc/arc.doc/arj.txt">Reference</a>
+ * @NotThreadSafe
+ */
+public class ArjArchiveInputStream extends ArchiveInputStream {
+    private static final boolean DEBUG = false;
+    private static final int ARJ_MAGIC_1 = 0x60;
+    private static final int ARJ_MAGIC_2 = 0xEA;
+    private final DataInputStream in;
+    private final String charset;
+    private final MainHeader mainHeader;
+    private LocalFileHeader currentLocalFileHeader = null;
+    private InputStream currentInputStream = null;
+    
+    /**
+     * Constructs the ArjInputStream, taking ownership of the inputStream that is passed in.
+     * @param inputStream the underlying stream, whose ownership is taken
+     * @param charset the charset used for file names and comments
+     *   in the archive
+     * @throws IOException
+     */
+    public ArjArchiveInputStream(final InputStream inputStream,
+            final String charset) throws ArchiveException {
+        in = new DataInputStream(inputStream);
+        this.charset = charset;
+        try {
+            mainHeader = readMainHeader();
+            if ((mainHeader.arjFlags & MainHeader.Flags.GARBLED) != 0) {
+                throw new ArchiveException("Encrypted ARJ files are unsupported");
+            }
+            if ((mainHeader.arjFlags & MainHeader.Flags.VOLUME) != 0) {
+                throw new ArchiveException("Multi-volume ARJ files are unsupported");
+            }
+        } catch (IOException ioException) {
+            throw new ArchiveException(ioException.getMessage(), ioException);
+        }
+    }
+
+    /**
+     * Constructs the ArjInputStream, taking ownership of the inputStream that is passed in,
+     * and using the CP437 character encoding.
+     * @param inputStream the underlying stream, whose ownership is taken
+     * @throws IOException
+     */
+    public ArjArchiveInputStream(final InputStream inputStream)
+            throws ArchiveException {
+        this(inputStream, "CP437");
+    }
+    
+    @Override
+    public void close() {
+        try {
+            in.close();
+        } catch (IOException ignored) {
+        }
+    }
+    
+    private static final void debug(final String message) {
+        if (DEBUG) {
+            System.out.println(message);
+        }
+    }
+    
+    private static final int read16(final DataInputStream in) throws IOException {
+        final int value = in.readUnsignedShort();
+        return Integer.reverseBytes(value) >>> 16;
+    }
+    
+    private final String readString(final DataInputStream in) throws IOException {
+        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        int nextByte;
+        while ((nextByte = in.readUnsignedByte()) != 0) {
+            buffer.write(nextByte);
+        }
+        return new String(buffer.toByteArray(), charset);
+    }
+    
+    private byte[] readHeader() throws IOException {
+        boolean found = false;
+        byte[] basicHeaderBytes = null;
+        do {
+            int first = 0;
+            int second = in.readUnsignedByte();
+            do {
+                first = second;
+                second = in.readUnsignedByte();
+            } while (first != ARJ_MAGIC_1 && second != ARJ_MAGIC_2);
+            final int basicHeaderSize = read16(in);
+            if (basicHeaderSize == 0) {
+                // end of archive
+                return null;
+            }
+            if (basicHeaderSize <= 2600) {
+                basicHeaderBytes = new byte[basicHeaderSize];
+                in.readFully(basicHeaderBytes);
+                final int basicHeaderCrc32 = Integer.reverseBytes(in.readInt());
+                final CRC32 crc32 = new CRC32();
+                crc32.update(basicHeaderBytes);
+                if (basicHeaderCrc32 == (int)crc32.getValue()) {
+                    found = true;
+                }
+            }
+        } while (!found);
+        return basicHeaderBytes;
+    }
+    
+    private MainHeader readMainHeader() throws IOException {
+        final byte[] basicHeaderBytes = readHeader();
+        if (basicHeaderBytes == null) {
+            throw new IOException("Archive ends without any headers");
+        }
+        final DataInputStream basicHeader = new DataInputStream(
+                new ByteArrayInputStream(basicHeaderBytes));
+        
+        final int firstHeaderSize = basicHeader.readUnsignedByte();
+        final byte[] firstHeaderBytes = new byte[firstHeaderSize - 1];
+        basicHeader.readFully(firstHeaderBytes);
+        final DataInputStream firstHeader = new DataInputStream(
+                new ByteArrayInputStream(firstHeaderBytes));
+        
+        final MainHeader mainHeader = new MainHeader();
+        mainHeader.archiverVersionNumber = firstHeader.readUnsignedByte();
+        mainHeader.minVersionToExtract = firstHeader.readUnsignedByte();
+        mainHeader.hostOS = firstHeader.readUnsignedByte();
+        mainHeader.arjFlags = firstHeader.readUnsignedByte();
+        mainHeader.securityVersion = firstHeader.readUnsignedByte();
+        mainHeader.fileType = firstHeader.readUnsignedByte();
+        mainHeader.reserved = firstHeader.readUnsignedByte();
+        mainHeader.dateTimeCreated = Integer.reverseBytes(firstHeader.readInt());
+        mainHeader.dateTimeModified = Integer.reverseBytes(firstHeader.readInt());
+        mainHeader.archiveSize = 0xffffFFFFL & Integer.reverseBytes(firstHeader.readInt());
+        mainHeader.securityEnvelopeFilePosition = Integer.reverseBytes(firstHeader.readInt());
+        mainHeader.fileSpecPosition = read16(firstHeader);
+        mainHeader.securityEnvelopeLength = read16(firstHeader);
+        mainHeader.encryptionVersion = firstHeader.readUnsignedByte();
+        mainHeader.lastChapter = firstHeader.readUnsignedByte();
+        
+        try {
+            mainHeader.arjProtectionFactor = firstHeader.readUnsignedByte();
+            mainHeader.arjFlags2 = firstHeader.readUnsignedByte();
+            firstHeader.readUnsignedByte();
+            firstHeader.readUnsignedByte();
+        } catch (EOFException eof) {
+        }
+        
+        mainHeader.name = readString(basicHeader);
+        mainHeader.comment = readString(basicHeader);
+        
+        final  int extendedHeaderSize = read16(in);
+        if (extendedHeaderSize > 0) {
+            mainHeader.extendedHeaderBytes = new byte[extendedHeaderSize];
+            in.readFully(mainHeader.extendedHeaderBytes);
+            final int extendedHeaderCrc32 = Integer.reverseBytes(in.readInt());
+            final CRC32 crc32 = new CRC32();
+            crc32.update(mainHeader.extendedHeaderBytes);
+            if (extendedHeaderCrc32 != (int)crc32.getValue()) {
+                throw new IOException("Extended header CRC32 verification failure");
+            }
+        }
+        
+        debug(mainHeader.toString());
+        
+        return mainHeader;
+    }
+    
+    private LocalFileHeader readLocalFileHeader() throws IOException {
+        final byte[] basicHeaderBytes = readHeader();
+        if (basicHeaderBytes == null) {
+            return null;
+        }
+        final DataInputStream basicHeader = new DataInputStream(
+                new ByteArrayInputStream(basicHeaderBytes));
+        
+        final int firstHeaderSize = basicHeader.readUnsignedByte();
+        final byte[] firstHeaderBytes = new byte[firstHeaderSize - 1];
+        basicHeader.readFully(firstHeaderBytes);
+        final DataInputStream firstHeader = new DataInputStream(
+                new ByteArrayInputStream(firstHeaderBytes));
+
+        final LocalFileHeader localFileHeader = new LocalFileHeader();
+        localFileHeader.archiverVersionNumber = firstHeader.readUnsignedByte();
+        localFileHeader.minVersionToExtract = firstHeader.readUnsignedByte();
+        localFileHeader.hostOS = firstHeader.readUnsignedByte();
+        localFileHeader.arjFlags = firstHeader.readUnsignedByte();
+        localFileHeader.method = firstHeader.readUnsignedByte();
+        localFileHeader.fileType = firstHeader.readUnsignedByte();
+        localFileHeader.reserved = firstHeader.readUnsignedByte();
+        localFileHeader.dateTimeModified = Integer.reverseBytes(firstHeader.readInt());
+        localFileHeader.compressedSize = 0xffffFFFFL & Integer.reverseBytes(firstHeader.readInt());
+        localFileHeader.originalSize = 0xffffFFFFL & Integer.reverseBytes(firstHeader.readInt());
+        localFileHeader.originalCrc32 = Integer.reverseBytes(firstHeader.readInt());
+        localFileHeader.fileSpecPosition = read16(firstHeader);
+        localFileHeader.fileAccessMode = read16(firstHeader);
+        localFileHeader.firstChapter = firstHeader.readUnsignedByte();
+        localFileHeader.lastChapter = firstHeader.readUnsignedByte();
+        
+        try {
+            localFileHeader.extendedFilePosition = Integer.reverseBytes(firstHeader.readInt());
+            localFileHeader.dateTimeAccessed = Integer.reverseBytes(firstHeader.readInt());
+            localFileHeader.dateTimeCreated = Integer.reverseBytes(firstHeader.readInt());
+            localFileHeader.originalSizeEvenForVolumes = Integer.reverseBytes(firstHeader.readInt());
+        } catch (EOFException eof) {
+        }
+        
+        localFileHeader.name = readString(basicHeader);
+        localFileHeader.comment = readString(basicHeader);
+
+        ArrayList<byte[]> extendedHeaders = new ArrayList<byte[]>();
+        int extendedHeaderSize;
+        while ((extendedHeaderSize = read16(in)) > 0) {
+            final byte[] extendedHeaderBytes = new byte[extendedHeaderSize];
+            in.readFully(extendedHeaderBytes);
+            final int extendedHeaderCrc32 = Integer.reverseBytes(in.readInt());
+            final CRC32 crc32 = new CRC32();
+            crc32.update(extendedHeaderBytes);
+            if (extendedHeaderCrc32 != (int)crc32.getValue()) {
+                throw new IOException("Extended header CRC32 verification failure");
+            }
+            extendedHeaders.add(extendedHeaderBytes);
+        }
+        localFileHeader.extendedHeaders = extendedHeaders.toArray(new byte[extendedHeaders.size()][]);
+        
+        debug(localFileHeader.toString());
+        
+        return localFileHeader;
+    }
+    
+    public static boolean matches(final byte[] signature, final int length) {
+        return length >= 2 &&
+                (0xff & signature[0]) == ARJ_MAGIC_1 &&
+                (0xff & signature[1]) == ARJ_MAGIC_2;
+    }
+    
+    public String getArchiveName() {
+        return mainHeader.name;
+    }
+    
+    public String getArchiveComment() {
+        return mainHeader.comment;
+    }
+    
+    @Override
+    public ArjArchiveEntry getNextEntry() throws IOException {
+        if (currentInputStream != null) {
+            while (currentInputStream.read() >= 0) {
+            }
+            currentLocalFileHeader = null;
+            currentInputStream = null;
+        }
+        
+        currentLocalFileHeader = readLocalFileHeader();
+        if (currentLocalFileHeader != null) {
+            currentInputStream = new BoundedInputStream(in, currentLocalFileHeader.compressedSize);
+            if (currentLocalFileHeader.method == LocalFileHeader.Methods.STORED) {
+                currentInputStream = new CRC32VerifyingInputStream(currentInputStream,
+                        currentLocalFileHeader.originalSize, currentLocalFileHeader.originalCrc32);
+            }
+            return new ArjArchiveEntry(currentLocalFileHeader);
+        } else {
+            currentInputStream = null;
+            return null;
+        }
+    }
+    
+    @Override
+    public boolean canReadEntryData(ArchiveEntry ae) {
+        return currentLocalFileHeader.method == LocalFileHeader.Methods.STORED;
+    }
+    
+    @Override
+    public int read() throws IOException {
+        if (currentLocalFileHeader.method != LocalFileHeader.Methods.STORED) {
+            throw new IOException("Unsupported compression method " + currentLocalFileHeader.method);
+        }
+        return currentInputStream.read();
+    }
+    
+    @Override
+    public int read(final byte[] b, final int off, final int len) throws IOException {
+        if (currentLocalFileHeader.method != LocalFileHeader.Methods.STORED) {
+            throw new IOException("Unsupported compression method " + currentLocalFileHeader.method);
+        }
+        return currentInputStream.read(b, off, len);
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/LocalFileHeader.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/LocalFileHeader.java?rev=1484246&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/LocalFileHeader.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/LocalFileHeader.java Sun May 19 09:36:17 2013
@@ -0,0 +1,123 @@
+/*
+ *  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.arj;
+
+import java.util.Arrays;
+
+class LocalFileHeader {
+    int archiverVersionNumber;
+    int minVersionToExtract;
+    int hostOS;
+    int arjFlags;
+    int method;
+    int fileType;
+    int reserved;
+    int dateTimeModified;
+    long compressedSize;
+    long originalSize;
+    int originalCrc32;
+    int fileSpecPosition;
+    int fileAccessMode;
+    int firstChapter;
+    int lastChapter;
+    
+    int extendedFilePosition;
+    int dateTimeAccessed;
+    int dateTimeCreated;
+    int originalSizeEvenForVolumes;
+    
+    String name;
+    String comment;
+    
+    byte[][] extendedHeaders = null;
+    
+    static class Flags {
+        static final int GARBLED = 0x01;
+        static final int VOLUME = 0x04;
+        static final int EXTFILE = 0x08;
+        static final int PATHSYM = 0x10;
+        static final int BACKUP = 0x20;
+    }
+    
+    static class FileTypes {
+        static final int BINARY = 0;
+        static final int SEVEN_BIT_TEXT = 1;
+        static final int DIRECTORY = 3;
+        static final int VOLUME_LABEL = 4;
+        static final int CHAPTER_LABEL = 5;
+    }
+    
+    static class Methods {
+        static final int STORED = 0;
+        static final int COMPRESSED_MOST = 1;
+        static final int COMPRESSED_FASTEST = 4;
+        static final int NO_DATA_NO_CRC = 8;
+        static final int NO_DATA = 9;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("LocalFileHeader [archiverVersionNumber=");
+        builder.append(archiverVersionNumber);
+        builder.append(", minVersionToExtract=");
+        builder.append(minVersionToExtract);
+        builder.append(", hostOS=");
+        builder.append(hostOS);
+        builder.append(", arjFlags=");
+        builder.append(arjFlags);
+        builder.append(", method=");
+        builder.append(method);
+        builder.append(", fileType=");
+        builder.append(fileType);
+        builder.append(", reserved=");
+        builder.append(reserved);
+        builder.append(", dateTimeModified=");
+        builder.append(dateTimeModified);
+        builder.append(", compressedSize=");
+        builder.append(compressedSize);
+        builder.append(", originalSize=");
+        builder.append(originalSize);
+        builder.append(", originalCrc32=");
+        builder.append(originalCrc32);
+        builder.append(", fileSpecPosition=");
+        builder.append(fileSpecPosition);
+        builder.append(", fileAccessMode=");
+        builder.append(fileAccessMode);
+        builder.append(", firstChapter=");
+        builder.append(firstChapter);
+        builder.append(", lastChapter=");
+        builder.append(lastChapter);
+        builder.append(", extendedFilePosition=");
+        builder.append(extendedFilePosition);
+        builder.append(", dateTimeAccessed=");
+        builder.append(dateTimeAccessed);
+        builder.append(", dateTimeCreated=");
+        builder.append(dateTimeCreated);
+        builder.append(", originalSizeEvenForVolumes=");
+        builder.append(originalSizeEvenForVolumes);
+        builder.append(", name=");
+        builder.append(name);
+        builder.append(", comment=");
+        builder.append(comment);
+        builder.append(", extendedHeaders=");
+        builder.append(Arrays.toString(extendedHeaders));
+        builder.append("]");
+        return builder.toString();
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/LocalFileHeader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/MainHeader.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/MainHeader.java?rev=1484246&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/MainHeader.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/MainHeader.java Sun May 19 09:36:17 2013
@@ -0,0 +1,102 @@
+/*
+ *  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.arj;
+
+import java.util.Arrays;
+
+class MainHeader {
+    int archiverVersionNumber;
+    int minVersionToExtract;
+    int hostOS;
+    int arjFlags;
+    int securityVersion;
+    int fileType;
+    int reserved;
+    int dateTimeCreated;
+    int dateTimeModified;
+    long archiveSize;
+    int securityEnvelopeFilePosition;
+    int fileSpecPosition;
+    int securityEnvelopeLength;
+    int encryptionVersion;
+    int lastChapter;
+    int arjProtectionFactor;
+    int arjFlags2;
+    String name;
+    String comment;
+    byte[] extendedHeaderBytes = null;
+    
+    static class Flags {
+        static final int GARBLED = 0x01;
+        static final int OLD_SECURED_NEW_ANSI_PAGE = 0x02;
+        static final int VOLUME = 0x04;
+        static final int ARJPROT = 0x08;
+        static final int PATHSYM = 0x10;
+        static final int BACKUP = 0x20;
+        static final int SECURED = 0x40;
+        static final int ALTNAME = 0x80;
+    }
+
+    
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("MainHeader [archiverVersionNumber=");
+        builder.append(archiverVersionNumber);
+        builder.append(", minVersionToExtract=");
+        builder.append(minVersionToExtract);
+        builder.append(", hostOS=");
+        builder.append(hostOS);
+        builder.append(", arjFlags=");
+        builder.append(arjFlags);
+        builder.append(", securityVersion=");
+        builder.append(securityVersion);
+        builder.append(", fileType=");
+        builder.append(fileType);
+        builder.append(", reserved=");
+        builder.append(reserved);
+        builder.append(", dateTimeCreated=");
+        builder.append(dateTimeCreated);
+        builder.append(", dateTimeModified=");
+        builder.append(dateTimeModified);
+        builder.append(", archiveSize=");
+        builder.append(archiveSize);
+        builder.append(", securityEnvelopeFilePosition=");
+        builder.append(securityEnvelopeFilePosition);
+        builder.append(", fileSpecPosition=");
+        builder.append(fileSpecPosition);
+        builder.append(", securityEnvelopeLength=");
+        builder.append(securityEnvelopeLength);
+        builder.append(", encryptionVersion=");
+        builder.append(encryptionVersion);
+        builder.append(", lastChapter=");
+        builder.append(lastChapter);
+        builder.append(", arjProtectionFactor=");
+        builder.append(arjProtectionFactor);
+        builder.append(", arjFlags2=");
+        builder.append(arjFlags2);
+        builder.append(", name=");
+        builder.append(name);
+        builder.append(", comment=");
+        builder.append(comment);
+        builder.append(", extendedHeaderBytes=");
+        builder.append(Arrays.toString(extendedHeaderBytes));
+        builder.append("]");
+        return builder.toString();
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/MainHeader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/package.html
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/package.html?rev=1484246&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/package.html (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/package.html Sun May 19 09:36:17 2013
@@ -0,0 +1,24 @@
+<html>
+<!--
+
+   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.
+
+-->
+  <body>
+    <p>Provides stream classes for reading archives using
+      the ARJ format.</p>
+  </body>
+</html>

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/arj/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java?rev=1484246&r1=1484245&r2=1484246&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java Sun May 19 09:36:17 2013
@@ -28,6 +28,7 @@ import java.util.Arrays;
 import java.util.BitSet;
 import java.util.zip.CRC32;
 
+import org.apache.commons.compress.utils.BoundedInputStream;
 import org.apache.commons.compress.utils.CRC32VerifyingInputStream;
 
 /**
@@ -925,44 +926,4 @@ public class SevenZFile {
         }
         return value;
     }
-    
-    private static class BoundedInputStream extends InputStream {
-        private final InputStream in;
-        private long bytesRemaining;
-        
-        public BoundedInputStream(final InputStream in, final long size) {
-            this.in = in;
-            bytesRemaining = size;
-        }
-        
-        @Override
-        public int read() throws IOException {
-            if (bytesRemaining > 0) {
-                --bytesRemaining;
-                return in.read();
-            } else {
-                return -1;
-            }
-        }
-
-        @Override
-        public int read(byte[] b, int off, int len) throws IOException {
-            if (bytesRemaining == 0) {
-                return -1;
-            }
-            int bytesToRead = len;
-            if (bytesToRead > bytesRemaining) {
-                bytesToRead = (int) bytesRemaining;
-            }
-            final int bytesRead = in.read(b, off, bytesToRead);
-            if (bytesRead >= 0) {
-                bytesRemaining -= bytesRead;
-            }
-            return bytesRead;
-        }
-
-        @Override
-        public void close() {
-        }
-    }
 }

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java?rev=1484246&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java Sun May 19 09:36:17 2013
@@ -0,0 +1,61 @@
+/*
+ *  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.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class BoundedInputStream extends InputStream {
+    private final InputStream in;
+    private long bytesRemaining;
+    
+    public BoundedInputStream(final InputStream in, final long size) {
+        this.in = in;
+        bytesRemaining = size;
+    }
+    
+    @Override
+    public int read() throws IOException {
+        if (bytesRemaining > 0) {
+            --bytesRemaining;
+            return in.read();
+        } else {
+            return -1;
+        }
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        if (bytesRemaining == 0) {
+            return -1;
+        }
+        int bytesToRead = len;
+        if (bytesToRead > bytesRemaining) {
+            bytesToRead = (int) bytesRemaining;
+        }
+        final int bytesRead = in.read(b, off, bytesToRead);
+        if (bytesRead >= 0) {
+            bytesRemaining -= bytesRead;
+        }
+        return bytesRead;
+    }
+
+    @Override
+    public void close() {
+    }
+}
\ No newline at end of file

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/compress/trunk/src/site/xdoc/examples.xml
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/site/xdoc/examples.xml?rev=1484246&r1=1484245&r2=1484246&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/site/xdoc/examples.xml (original)
+++ commons/proper/compress/trunk/src/site/xdoc/examples.xml Sun May 19 09:36:17 2013
@@ -33,7 +33,7 @@
 
         <p>The compressor formats supported are gzip, bzip2, xz and
         Pack200, the archiver formats are ar, cpio, dump (read-only),
-        tar, zip and 7z.  Pack200 is a special case as it can only
+        tar, zip, 7z and arj.  Pack200 is a special case as it can only
         compress JAR files.</p>
       </subsection>
 
@@ -439,6 +439,20 @@ LOOP UNTIL entry.getSize() HAS BEEN READ
 ]]></source>
       </subsection>
 
+      <subsection name="arj">
+
+        <p>Uncompressing a given arj archive (you would
+          certainly add exception handling and make sure all streams
+          get closed properly):</p>
+<source><![CDATA[
+ArjArchiveEntry entry = arjInput.getNextEntry();
+byte[] content = new byte[entry.getSize()];
+LOOP UNTIL entry.getSize() HAS BEEN READ {
+    arjInput.read(content, offset, content.length - offset);
+}
+]]></source>
+      </subsection>
+
     </section>
   </body>
 </document>

Modified: commons/proper/compress/trunk/src/site/xdoc/index.xml
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/site/xdoc/index.xml?rev=1484246&r1=1484245&r2=1484246&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/site/xdoc/index.xml (original)
+++ commons/proper/compress/trunk/src/site/xdoc/index.xml Sun May 19 09:36:17 2013
@@ -27,7 +27,7 @@
             <p>
                 The Apache Commons Compress library defines an API for
                 working with ar, cpio, Unix dump, tar, zip, gzip, XZ, Pack200,
-                bzip2 and 7z files.
+                bzip2, 7z and arj files.
             </p>
             <p>
                 The code in this component has many origins:
@@ -72,11 +72,11 @@
             domain <a href="http://tukaani.org/xz/java.html">XZ for
             Java</a> library.</p>
 
-          <p>The ar, cpio, dump, tar, 7z and zip formats are supported as
+          <p>The ar, arj, cpio, dump, tar, 7z and zip formats are supported as
             archivers where the <a href="zip.html">zip</a>
             implementation provides capabilities that go beyond the
             features found in java.util.zip.  As of Commons Compress
-            1.3 support for the dump format is read-only.</p>
+            1.3 support for the dump, 7z and arj formats is read-only.</p>
 
           <p>The compress component provides abstract base classes for
             compressors and archivers together with factories that can