You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2011/09/04 05:42:27 UTC

svn commit: r1164958 - in /commons/proper/compress/trunk/src: main/java/org/apache/commons/compress/compressors/ main/java/org/apache/commons/compress/compressors/pack200/ test/java/org/apache/commons/compress/compressors/ test/resources/

Author: bodewig
Date: Sun Sep  4 03:42:27 2011
New Revision: 1164958

URL: http://svn.apache.org/viewvc?rev=1164958&view=rev
Log:
Pack200 support.  COMPRESS-142

Added:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/InMemoryStreamSwitcher.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamMode.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamSwitcher.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/TempFileStreamSwitcher.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/package.html   (with props)
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/Pack200TestCase.java   (with props)
    commons/proper/compress/trunk/src/test/resources/bla.pack   (with props)
Modified:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java?rev=1164958&r1=1164957&r2=1164958&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java Sun Sep  4 03:42:27 2011
@@ -26,6 +26,8 @@ import org.apache.commons.compress.compr
 import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
 import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
 import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
+import org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream;
+import org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream;
 
 /**
  * <p>Factory to create Compressor[In|Out]putStreams from names. To add other
@@ -40,7 +42,7 @@ import org.apache.commons.compress.compr
  *      new CompressorStreamFactory().createCompressorOutputStream(CompressorStreamFactory.BZIP2, out);
  * IOUtils.copy(new FileInputStream(input), cos);
  * cos.close();
- * </pre>    
+ * </pre>
  * 
  * Example (Compressing a file):
  * <pre>
@@ -65,6 +67,11 @@ public class CompressorStreamFactory {
      * @since Commons Compress 1.1
      */
     public static final String GZIP = "gz";
+    /**
+     * Constant used to identify the PACK200 compression algorithm.
+     * @since Commons Compress 1.3
+     */
+    public static final String PACK200 = "pack200";
 
     /**
      * Create an compressor input stream from an input stream, autodetecting
@@ -92,26 +99,30 @@ public class CompressorStreamFactory {
         try {
             int signatureLength = in.read(signature);
             in.reset();
-            
+
             if (BZip2CompressorInputStream.matches(signature, signatureLength)) {
                 return new BZip2CompressorInputStream(in);
             }
-            
+
             if (GzipCompressorInputStream.matches(signature, signatureLength)) {
                 return new GzipCompressorInputStream(in);
             }
 
+            if (Pack200CompressorInputStream.matches(signature, signatureLength)) {
+                return new Pack200CompressorInputStream(in);
+            }
+
         } catch (IOException e) {
             throw new CompressorException("Failed to detect Compressor from InputStream.", e);
         }
 
         throw new CompressorException("No Compressor found for the stream signature.");
     }
-    
+
     /**
      * Create a compressor input stream from a compressor name and an input stream.
      * 
-     * @param name of the compressor, i.e. "gz" or "bzip2"
+     * @param name of the compressor, i.e. "gz", "bzip2" or "pack200"
      * @param in the input stream
      * @return compressor input stream
      * @throws CompressorException if the compressor name is not known
@@ -125,15 +136,19 @@ public class CompressorStreamFactory {
         }
 
         try {
-            
+
             if (GZIP.equalsIgnoreCase(name)) {
                 return new GzipCompressorInputStream(in);
             }
-            
+
             if (BZIP2.equalsIgnoreCase(name)) {
                 return new BZip2CompressorInputStream(in);
             }
-            
+
+            if (PACK200.equalsIgnoreCase(name)) {
+                return new Pack200CompressorInputStream(in);
+            }
+
         } catch (IOException e) {
             throw new CompressorException(
                     "Could not create CompressorInputStream.", e);
@@ -144,7 +159,7 @@ public class CompressorStreamFactory {
     /**
      * Create an compressor output stream from an compressor name and an input stream.
      * 
-     * @param name the compressor name, i.e. "gz" or "bzip2"
+     * @param name the compressor name, i.e. "gz", "bzip2" or "pack200"
      * @param out the output stream
      * @return the compressor output stream
      * @throws CompressorException if the archiver name is not known
@@ -163,11 +178,15 @@ public class CompressorStreamFactory {
             if (GZIP.equalsIgnoreCase(name)) {
                 return new GzipCompressorOutputStream(out);
             }
-            
+
             if (BZIP2.equalsIgnoreCase(name)) {
                 return new BZip2CompressorOutputStream(out);
             }
-        
+
+            if (PACK200.equalsIgnoreCase(name)) {
+                return new Pack200CompressorOutputStream(out);
+            }
+
         } catch (IOException e) {
             throw new CompressorException(
                     "Could not create CompressorOutputStream", e);

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/InMemoryStreamSwitcher.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/InMemoryStreamSwitcher.java?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/InMemoryStreamSwitcher.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/InMemoryStreamSwitcher.java Sun Sep  4 03:42:27 2011
@@ -0,0 +1,45 @@
+/*
+ * 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.compressors.pack200;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * StreamSwitcher that caches all data written to the output side in
+ * memory.
+ * @since Apache Commons Compress 1.3
+ */
+class InMemoryStreamSwitcher extends StreamSwitcher {
+    InMemoryStreamSwitcher() {
+        super(new ByteArrayOutputStream());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    InputStream getInputView() throws IOException {
+        return new ByteArrayInputStream(((ByteArrayOutputStream) out)
+                                        .toByteArray());
+    }
+}
\ No newline at end of file

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/InMemoryStreamSwitcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java Sun Sep  4 03:42:27 2011
@@ -0,0 +1,253 @@
+/*
+ * 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.compressors.pack200;
+
+import java.io.File;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Pack200;
+
+import org.apache.commons.compress.compressors.CompressorInputStream;
+
+/**
+ * An input stream that decompresses from the Pack200 format to be read
+ * as any other stream.
+ * 
+ * @NotThreadSafe
+ * @since Apache Commons Compress 1.3
+ */
+public class Pack200CompressorInputStream extends CompressorInputStream {
+    private final InputStream originalInput;
+    private final StreamSwitcher streamSwitcher;
+
+    /**
+     * Decompresses the given stream, caching the decompressed data in
+     * memory.
+     *
+     * <p>When reading from a file the File-arg constructor may
+     * provide better performance.</p>
+     */
+    public Pack200CompressorInputStream(final InputStream in)
+        throws IOException {
+        this(in, StreamMode.IN_MEMORY);
+    }
+
+    /**
+     * Decompresses the given stream using the given strategy to cache
+     * the results.
+     *
+     * <p>When reading from a file the File-arg constructor may
+     * provide better performance.</p>
+     */
+    public Pack200CompressorInputStream(final InputStream in,
+                                        final StreamMode mode)
+        throws IOException {
+        this(in, null, mode, null);
+    }
+
+    /**
+     * Decompresses the given stream, caching the decompressed data in
+     * memory and using the given properties.
+     *
+     * <p>When reading from a file the File-arg constructor may
+     * provide better performance.</p>
+     */
+    public Pack200CompressorInputStream(final InputStream in,
+                                        final Map<String, String> props)
+        throws IOException {
+        this(in, StreamMode.IN_MEMORY, props);
+    }
+
+    /**
+     * Decompresses the given stream using the given strategy to cache
+     * the results and the given properties.
+     *
+     * <p>When reading from a file the File-arg constructor may
+     * provide better performance.</p>
+     */
+    public Pack200CompressorInputStream(final InputStream in,
+                                        final StreamMode mode,
+                                        final Map<String, String> props)
+        throws IOException {
+        this(in, null, mode, props);
+    }
+
+    /**
+     * Decompresses the given file, caching the decompressed data in
+     * memory.
+     */
+    public Pack200CompressorInputStream(final File f) throws IOException {
+        this(f, StreamMode.IN_MEMORY);
+    }
+
+    /**
+     * Decompresses the given file using the given strategy to cache
+     * the results.
+     */
+    public Pack200CompressorInputStream(final File f, final StreamMode mode)
+        throws IOException {
+        this(null, f, mode, null);
+    }
+
+    /**
+     * Decompresses the given file, caching the decompressed data in
+     * memory and using the given properties.
+     */
+    public Pack200CompressorInputStream(final File f,
+                                        final Map<String, String> props)
+        throws IOException {
+        this(f, StreamMode.IN_MEMORY, props);
+    }
+
+    /**
+     * Decompresses the given file using the given strategy to cache
+     * the results and the given properties.
+     */
+    public Pack200CompressorInputStream(final File f, final StreamMode mode,
+                                        final Map<String, String> props)
+        throws IOException {
+        this(null, f, mode, props);
+    }
+
+    private Pack200CompressorInputStream(final InputStream in, final File f,
+                                         final StreamMode mode,
+                                         final Map<String, String> props)
+        throws IOException {
+        originalInput = in;
+        streamSwitcher = mode.newStreamSwitcher();
+        JarOutputStream jarOut = new JarOutputStream(streamSwitcher);
+        Pack200.Unpacker u = Pack200.newUnpacker();
+        if (props != null) {
+            u.properties().putAll(props);
+        }
+        if (f == null) {
+            u.unpack(new FilterInputStream(in) {
+                    @Override
+                        public void close() {
+                        // unpack would close this stream but we
+                        // want to give the user code more control
+                    }
+                },
+                jarOut);
+        } else {
+            u.unpack(f, jarOut);
+        }
+        jarOut.close();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int read() throws IOException {
+        return streamSwitcher.getInput().read();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int read(byte[] b) throws IOException {
+        return streamSwitcher.getInput().read(b);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int read(byte[] b, int off, int count) throws IOException {
+        return streamSwitcher.getInput().read(b, off, count);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int available() throws IOException {
+        return streamSwitcher.getInput().available();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean markSupported() {
+        try {
+            return streamSwitcher.getInput().markSupported();
+        } catch (IOException ex) {
+            return false;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void mark(int limit) {
+        try {
+            streamSwitcher.getInput().mark(limit);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void reset() throws IOException {
+        streamSwitcher.getInput().reset();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public long skip(long count) throws IOException {
+        return streamSwitcher.getInput().skip(count);
+    }
+
+    @Override
+    public void close() throws IOException {
+        try {
+            streamSwitcher.stop();
+        } finally {
+            if (originalInput != null) {
+                originalInput.close();
+            }
+        }
+    }
+
+    private static final byte[] CAFE_DOOD = new byte[] {
+        (byte) 0xCA, (byte) 0xFE, (byte) 0xD0, (byte) 0x0D
+    };
+
+    /**
+     * Checks if the signature matches what is expected for a pack200
+     * file (0xCAFED00D).
+     * 
+     * @param signature
+     *            the bytes to check
+     * @param length
+     *            the number of bytes to check
+     * @return true, if this stream is a pack200 compressed stream,
+     * false otherwise
+     */
+    public static boolean matches(byte[] signature, int length) {
+        if (length < 4) {
+            return false;
+        }
+
+        for (int i = 0; i < 4; i++) {
+            if (signature[i] != CAFE_DOOD[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java Sun Sep  4 03:42:27 2011
@@ -0,0 +1,127 @@
+/*
+ * 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.compressors.pack200;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.jar.JarInputStream;
+import java.util.jar.Pack200;
+
+import org.apache.commons.compress.compressors.CompressorOutputStream;
+
+/**
+ * An output stream that compresses using the Pack200 format.
+ * 
+ * @NotThreadSafe
+ * @since Apache Commons Compress 1.3
+ */
+public class Pack200CompressorOutputStream extends CompressorOutputStream {
+    private boolean finished = false;
+    private final OutputStream originalOutput;
+    private final StreamSwitcher streamSwitcher;
+    private final Map<String, String> properties;
+
+    /**
+     * Compresses the given stream, caching the compressed data in
+     * memory.
+     */
+    public Pack200CompressorOutputStream(final OutputStream out)
+        throws IOException {
+        this(out, StreamMode.IN_MEMORY);
+    }
+
+    /**
+     * Compresses the given stream using the given strategy to cache
+     * the results.
+     */
+    public Pack200CompressorOutputStream(final OutputStream out,
+                                         final StreamMode mode)
+        throws IOException {
+        this(out, mode, null);
+    }
+
+    /**
+     * Compresses the given stream, caching the compressed data in
+     * memory and using the given properties.
+     */
+    public Pack200CompressorOutputStream(final OutputStream out,
+                                         final Map<String, String> props)
+        throws IOException {
+        this(out, StreamMode.IN_MEMORY, props);
+    }
+
+    /**
+     * Compresses the given stream using the given strategy to cache
+     * the results and the given properties.
+     */
+    public Pack200CompressorOutputStream(final OutputStream out,
+                                         final StreamMode mode,
+                                         final Map<String, String> props)
+        throws IOException {
+        originalOutput = out;
+        streamSwitcher = mode.newStreamSwitcher();
+        properties = props;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void write(int b) throws IOException {
+        streamSwitcher.write(b);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void write(byte[] b) throws IOException {
+        streamSwitcher.write(b);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void write(byte[] b, int from, int length) throws IOException {
+        streamSwitcher.write(b, from, length);
+    }
+
+    @Override
+    public void close() throws IOException {
+        finish();
+        try {
+            streamSwitcher.stop();
+        } finally {
+            originalOutput.close();
+        }
+    }
+
+    public void finish() throws IOException {
+        if (!finished) {
+            finished = true;
+            Pack200.Packer p = Pack200.newPacker();
+            if (properties != null) {
+                p.properties().putAll(properties);
+            }
+            p.pack(new JarInputStream(streamSwitcher.getInput()),
+                   originalOutput);
+        }
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamMode.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamMode.java?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamMode.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamMode.java Sun Sep  4 03:42:27 2011
@@ -0,0 +1,44 @@
+/*
+ * 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.compressors.pack200;
+
+import java.io.IOException;
+
+/**
+ * The different modes the Pack200 streams can use to wrap input and
+ * output.
+ * @since Apache Commons Compress 1.3
+ */
+public enum StreamMode {
+    /** Cache output in memory */
+    IN_MEMORY() {
+        StreamSwitcher newStreamSwitcher() {
+            return new InMemoryStreamSwitcher();
+        }
+    },
+    /** Cache output in a temporary file */
+    TEMP_FILE() {
+        StreamSwitcher newStreamSwitcher() throws IOException {
+            return new TempFileStreamSwitcher();
+        }
+    };
+
+    abstract StreamSwitcher newStreamSwitcher() throws IOException;
+}
\ No newline at end of file

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamMode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamSwitcher.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamSwitcher.java?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamSwitcher.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamSwitcher.java Sun Sep  4 03:42:27 2011
@@ -0,0 +1,75 @@
+/*
+ * 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.compressors.pack200;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Provides an InputStream to read all data written to this
+ * OutputStream.
+ *
+ * @ThreadSafe
+ * @since Apache Commons Compress 1.3
+ */
+abstract class StreamSwitcher extends FilterOutputStream {
+    private InputStream input;
+    private final Object INPUT_LOCK = new Object();
+
+    protected StreamSwitcher(OutputStream out) {
+        super(out);
+    }
+
+    protected StreamSwitcher() {
+        this(null);
+    }
+
+    /**
+     * Provides the input view.
+     */
+    InputStream getInput() throws IOException {
+        synchronized (INPUT_LOCK) {
+            if (input == null) {
+                input = getInputView();
+            }
+        }
+        return input;
+    }
+
+    /**
+     * Creates the input view.
+     */
+    abstract InputStream getInputView() throws IOException;
+
+    /**
+     * Closes input and output and releases all associated resources.
+     */
+    void stop() throws IOException {
+        close();
+        synchronized (INPUT_LOCK) {
+            if (input != null) {
+                input.close();
+                input = null;
+            }
+        }
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/StreamSwitcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/TempFileStreamSwitcher.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/TempFileStreamSwitcher.java?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/TempFileStreamSwitcher.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/TempFileStreamSwitcher.java Sun Sep  4 03:42:27 2011
@@ -0,0 +1,56 @@
+/*
+ * 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.compressors.pack200;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * StreamSwitcher that caches all data written to the output side in
+ * a temporary file.
+ * @since Apache Commons Compress 1.3
+ */
+class TempFileStreamSwitcher extends StreamSwitcher {
+    private final File f;
+
+    TempFileStreamSwitcher() throws IOException {
+        f = File.createTempFile("commons-compress", "packtemp");
+        f.deleteOnExit();
+        out = new FileOutputStream(f);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    InputStream getInputView() throws IOException {
+        out.close();
+        return new FileInputStream(f) {
+            @Override
+            public void close() throws IOException {
+                super.close();
+                f.delete();
+            }
+        };
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/TempFileStreamSwitcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/package.html
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/package.html?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/package.html (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/pack200/package.html Sun Sep  4 03:42:27 2011
@@ -0,0 +1,65 @@
+<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 compressing and decompressing
+      streams using the Pack200 algorithm used to compress Java
+      archives.</p>
+
+    <p>The streams of this package only work on JAR archives, i.e. a
+      {@link
+      org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream
+      Pack200CompressorOutputStream} expects to be wrapped around a
+      stream that a valid JAR archive will be written to and a {@link
+      org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream
+      Pack200CompressorInputStream} provides a stream to read from a
+      JAR archive.</p>
+
+    <p>JAR archives compressed with Pack200 will in general be
+      different from the original archive when decompressed again.
+      For details see
+      the <a href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/jar/Pack200.html">API
+      documentation of Pack200</a>.</p>
+
+    <p>The streams of this package work on non-deflated streams,
+      i.e. archives like those created with the <code>--no-gzip</code>
+      option of the JDK's <code>pack200</code> command line tool.  If
+      you want to work on deflated streams you must use an additional
+      stream layer - for example by using Apache Commons Compress'
+      gzip package.</p>
+
+    <p>The Pack200 API provided by the Java class library doesn't lend
+      itself to real stream
+      processing.  <code>Pack200CompressorInputStream</code> will
+      uncompress its input immediately and then provide
+      an <code>InputStream</code> to a cached result.
+      Likewise <code>Pack200CompressorOutputStream</code> will not
+      write anything to the given OutputStream
+      until <code>finish</code> or <code>close</code> is called - at
+      which point the cached output written so far gets
+      compressed.</p>
+
+    <p>Two different caching modes are available - "in memory", which
+      is the default, and "temporary file".  By default data is cached
+      in memory but you should switch to the temporary file option if
+      your archives are really big.</p>
+
+    <p>
+  </body>
+</html>

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

Added: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/Pack200TestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/Pack200TestCase.java?rev=1164958&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/Pack200TestCase.java (added)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/Pack200TestCase.java Sun Sep  4 03:42:27 2011
@@ -0,0 +1,159 @@
+/*
+ * 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.compressors;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.compress.AbstractTestCase;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.ArchiveOutputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream;
+import org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream;
+import org.apache.commons.compress.compressors.pack200.StreamMode;
+import org.apache.commons.compress.utils.IOUtils;
+
+public final class Pack200TestCase extends AbstractTestCase {
+
+    public void testJarUnarchiveAllInMemory() throws Exception {
+        jarUnarchiveAll(false, StreamMode.IN_MEMORY);
+    }
+
+    public void testJarUnarchiveAllFileArgInMemory() throws Exception {
+        jarUnarchiveAll(true, StreamMode.IN_MEMORY);
+    }
+
+    public void testJarUnarchiveAllTempFile() throws Exception {
+        jarUnarchiveAll(false, StreamMode.TEMP_FILE);
+    }
+
+    public void testJarUnarchiveAllFileTempFile() throws Exception {
+        jarUnarchiveAll(true, StreamMode.TEMP_FILE);
+    }
+
+    private void jarUnarchiveAll(boolean useFile, StreamMode mode)
+        throws Exception {
+        final File input = getFile("bla.pack");
+        final InputStream is = useFile
+            ? new Pack200CompressorInputStream(input, mode)
+            : new Pack200CompressorInputStream(new FileInputStream(input),
+                                               mode);
+        try {
+            final ArchiveInputStream in = new ArchiveStreamFactory()
+                .createArchiveInputStream("jar", is);
+
+            ArchiveEntry entry = in.getNextEntry();
+            while (entry != null) {
+                File archiveEntry = new File(dir, entry.getName());
+                archiveEntry.getParentFile().mkdirs();
+                if (entry.isDirectory()) {
+                    archiveEntry.mkdir();
+                    entry = in.getNextEntry();
+                    continue;
+                }
+                OutputStream out = new FileOutputStream(archiveEntry);
+                IOUtils.copy(in, out);
+                out.close();
+                entry = in.getNextEntry();
+            }
+
+            in.close();
+        } finally {
+            is.close();
+        }
+    }
+
+    public void testJarArchiveCreationInMemory() throws Exception {
+        jarArchiveCreation(StreamMode.IN_MEMORY);
+    }
+
+    public void testJarArchiveCreationTempFile() throws Exception {
+        jarArchiveCreation(StreamMode.TEMP_FILE);
+    }
+
+    private void jarArchiveCreation(StreamMode mode) throws Exception {
+        final File output = new File(dir, "bla.pack");
+
+        final File file1 = getFile("test1.xml");
+        final File file2 = getFile("test2.xml");
+
+        final OutputStream out = 
+            new Pack200CompressorOutputStream(new FileOutputStream(output),
+                                              mode);
+        try {
+            final ArchiveOutputStream os = new ArchiveStreamFactory()
+                .createArchiveOutputStream("jar", out);
+
+            os.putArchiveEntry(new ZipArchiveEntry("testdata/test1.xml"));
+            IOUtils.copy(new FileInputStream(file1), os);
+            os.closeArchiveEntry();
+
+            os.putArchiveEntry(new ZipArchiveEntry("testdata/test2.xml"));
+            IOUtils.copy(new FileInputStream(file2), os);
+            os.closeArchiveEntry();
+
+            os.close();
+        } finally {
+            out.close();
+        }
+
+        final InputStream is = new Pack200CompressorInputStream(output);
+        try {
+            final ArchiveInputStream in = new ArchiveStreamFactory()
+                .createArchiveInputStream("jar", is);
+            List<String> files = new ArrayList<String>();
+            files.add("testdata/test1.xml");
+            files.add("testdata/test2.xml");
+            checkArchiveContent(in, files);
+            in.close();
+        } finally {
+            is.close();
+        }
+    }
+
+    public void testGoodSignature() throws Exception {
+        final InputStream is = new FileInputStream(getFile("bla.pack"));
+        try {
+            byte[] sig = new byte[4];
+            is.read(sig);
+            assertTrue(Pack200CompressorInputStream.matches(sig, 4));
+        } finally {
+            is.close();
+        }
+    }
+
+    public void testBadSignature() throws Exception {
+        final InputStream is = new FileInputStream(getFile("bla.jar"));
+        try {
+            byte[] sig = new byte[4];
+            is.read(sig);
+            assertFalse(Pack200CompressorInputStream.matches(sig, 4));
+        } finally {
+            is.close();
+        }
+    }
+}

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/Pack200TestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/compress/trunk/src/test/resources/bla.pack
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/resources/bla.pack?rev=1164958&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/compress/trunk/src/test/resources/bla.pack
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream