You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by kr...@apache.org on 2014/12/18 21:51:57 UTC
svn commit: r1646531 - in /commons/proper/compress/trunk: ./
src/main/java/org/apache/commons/compress/archivers/zip/
src/test/java/org/apache/commons/compress/
src/test/java/org/apache/commons/compress/archivers/
Author: krosenvold
Date: Thu Dec 18 20:51:57 2014
New Revision: 1646531
URL: http://svn.apache.org/r1646531
Log:
COMPRESS-295 Add support for transferring a zip entry from one zip file to another
Added:
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java
Modified:
commons/proper/compress/trunk/.gitignore
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/AbstractTestCase.java
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java
Modified: commons/proper/compress/trunk/.gitignore
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/.gitignore?rev=1646531&r1=1646530&r2=1646531&view=diff
==============================================================================
--- commons/proper/compress/trunk/.gitignore (original)
+++ commons/proper/compress/trunk/.gitignore Thu Dec 18 20:51:57 2014
@@ -2,4 +2,6 @@ target
.project
.classpath
.settings
+.idea
+*.iml
*~
Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java?rev=1646531&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java Thu Dec 18 20:51:57 2014
@@ -0,0 +1,32 @@
+/*
+ * 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.zip;
+
+/**
+ * A predicate to test if a #ZipArchiveEntry matches a criteria.
+ * Some day this can extend java.util.function.Predicate
+ */
+public interface ZipArchiveEntryPredicate {
+ /**
+ * Indicate if the given entry should be included in the operation
+ * @param zipArchiveEntry the entry to test
+ * @return true if the entry should be included
+ */
+ boolean test(ZipArchiveEntry zipArchiveEntry);
+}
Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java?rev=1646531&r1=1646530&r2=1646531&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java Thu Dec 18 20:51:57 2014
@@ -20,9 +20,11 @@ package org.apache.commons.compress.arch
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -432,27 +434,36 @@ public class ZipArchiveOutputStream exte
*/
@Override
public void closeArchiveEntry() throws IOException {
- if (finished) {
- throw new IOException("Stream has already been finished");
- }
-
- if (entry == null) {
- throw new IOException("No current entry to close");
- }
-
- if (!entry.hasWritten) {
- write(EMPTY, 0, 0);
- }
+ preClose();
flushDeflater();
- final Zip64Mode effectiveMode = getEffectiveZip64Mode(entry.entry);
long bytesWritten = written - entry.dataStart;
long realCrc = crc.getValue();
crc.reset();
+ doCloseEntry(realCrc, bytesWritten);
+ }
+
+ /**
+ * Writes all necessary data for this entry.
+ *
+ * @throws IOException on error
+ * @throws Zip64RequiredException if the entry's uncompressed or
+ * compressed size exceeds 4 GByte and {@link #setUseZip64}
+ * is {@link Zip64Mode#Never}.
+ */
+ private void closeCopiedEntry() throws IOException {
+ preClose();
+ long realCrc = entry.entry.getCrc();
+ entry.bytesRead = entry.entry.getSize();
+ doCloseEntry(realCrc, entry.entry.getCompressedSize());
+ }
+
+ private void doCloseEntry(long realCrc, long bytesWritten) throws IOException {
+ final Zip64Mode effectiveMode = getEffectiveZip64Mode(entry.entry);
final boolean actuallyNeedsZip64 =
- handleSizesAndCrc(bytesWritten, realCrc, effectiveMode);
+ handleSizesAndCrc(bytesWritten, realCrc, effectiveMode);
if (raf != null) {
rewriteSizesAndCrc(actuallyNeedsZip64);
@@ -462,6 +473,37 @@ public class ZipArchiveOutputStream exte
entry = null;
}
+ private void preClose() throws IOException {
+ if (finished) {
+ throw new IOException("Stream has already been finished");
+ }
+
+ if (entry == null) {
+ throw new IOException("No current entry to close");
+ }
+
+ if (!entry.hasWritten) {
+ write(EMPTY, 0, 0);
+ }
+ }
+
+ /**
+ * Adds an archive entry with a raw input stream.
+ *
+ * The entry is put and closed immediately.
+ *
+ * @param entry The archive entry to add
+ * @param rawStream The raw input stream of a different entry. May be compressed/encrypted.
+ * @throws IOException If copying fails
+ */
+ public void addRawArchiveEntry(ZipArchiveEntry entry, InputStream rawStream)
+ throws IOException {
+ ZipArchiveEntry ae = new ZipArchiveEntry((java.util.zip.ZipEntry)entry);
+ putArchiveEntry(ae);
+ copyFromZipInputStream(rawStream);
+ closeCopiedEntry();
+ }
+
/**
* Ensures all bytes sent to the deflater are written to the stream.
*/
@@ -768,6 +810,25 @@ public class ZipArchiveOutputStream exte
count(length);
}
+ private void copyFromZipInputStream(InputStream src) throws IOException {
+ if (entry == null) {
+ throw new IllegalStateException("No current entry");
+ }
+ ZipUtil.checkRequestedFeatures(entry.entry);
+ entry.hasWritten = true;
+ byte[] tmpBuf = new byte[4096];
+ int length = src.read( tmpBuf );
+ while ( length >= 0 )
+ {
+ writeOut( tmpBuf, 0, length );
+ written += length;
+ crc.update( tmpBuf, 0, length );
+
+ count( length );
+ length = src.read( tmpBuf );
+ }
+ }
+
/**
* write implementation for DEFLATED entries.
*/
Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java?rev=1646531&r1=1646530&r2=1646531&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java Thu Dec 18 20:51:57 2014
@@ -346,6 +346,44 @@ public class ZipFile implements Closeabl
}
/**
+ * Expose the raw stream of the archive entry (compressed form)
+ * <p/>
+ * This method does not relate to how/if we understand the payload in the
+ * stream, since we really only intend to move it on to somewhere else.
+ *
+ * @param ze The entry to get the stream for
+ * @return The raw input stream containing (possibly) compressed data.
+ */
+ private InputStream getRawInputStream(ZipArchiveEntry ze) {
+ if (!(ze instanceof Entry)) {
+ return null;
+ }
+ OffsetEntry offsetEntry = ((Entry) ze).getOffsetEntry();
+ long start = offsetEntry.dataOffset;
+ return new BoundedInputStream(start, ze.getCompressedSize());
+ }
+
+
+ /**
+ * Transfer selected entries from this zipfile to a given #ZipArchiveOutputStream.
+ * Compression and all other attributes will be as in this file.
+ * This method transfers entries based on the central directory of the zip file.
+ *
+ * @param target The zipArchiveOutputStream to write the entries to
+ * @param predicate A predicate that selects which entries to write
+ */
+ public void copyRawEntries(ZipArchiveOutputStream target, ZipArchiveEntryPredicate predicate)
+ throws IOException {
+ Enumeration<ZipArchiveEntry> src = getEntriesInPhysicalOrder();
+ while (src.hasMoreElements()) {
+ ZipArchiveEntry entry = src.nextElement();
+ if (predicate.test( entry)) {
+ target.addRawArchiveEntry(entry, getRawInputStream(entry));
+ }
+ }
+ }
+
+ /**
* Returns an InputStream for reading the contents of the given entry.
*
* @param ze the entry to get the stream for.
Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/AbstractTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/AbstractTestCase.java?rev=1646531&r1=1646530&r2=1646531&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/AbstractTestCase.java (original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/AbstractTestCase.java Thu Dec 18 20:51:57 2014
@@ -392,8 +392,7 @@ public abstract class AbstractTestCase e
* element of the two element array).
*/
protected File[] createTempDirAndFile() throws IOException {
- File tmpDir = mkdir("testdir");
- tmpDir.deleteOnExit();
+ File tmpDir = createTempDir();
File tmpFile = File.createTempFile("testfile", "", tmpDir);
tmpFile.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tmpFile);
@@ -405,6 +404,12 @@ public abstract class AbstractTestCase e
}
}
+ protected File createTempDir() throws IOException {
+ File tmpDir = mkdir("testdir");
+ tmpDir.deleteOnExit();
+ return tmpDir;
+ }
+
protected void closeQuietly(Closeable closeable){
if (closeable != null) {
try {
Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java?rev=1646531&r1=1646530&r2=1646531&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java (original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java Thu Dec 18 20:51:57 2014
@@ -18,22 +18,14 @@
*/
package org.apache.commons.compress.archivers;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.*;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.compress.AbstractTestCase;
-import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
-import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
-import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-import org.apache.commons.compress.archivers.zip.ZipFile;
-import org.apache.commons.compress.archivers.zip.ZipMethod;
+import org.apache.commons.compress.archivers.zip.*;
import org.apache.commons.compress.utils.IOUtils;
+import org.junit.Assert;
public final class ZipTestCase extends AbstractTestCase {
/**
@@ -293,6 +285,82 @@ public final class ZipTestCase extends A
rmdir(tmp[0]);
}
}
+ String first_payload = "ABBA";
+ String second_payload = "AAAAAAAAAAAA";
+ ZipArchiveEntryPredicate allFilesPredicate = new ZipArchiveEntryPredicate() {
+ public boolean test(ZipArchiveEntry zipArchiveEntry) {
+ return true;
+ }
+ };
+
+
+ public void testCopyRawEntriesFromFile
+ ()
+ throws IOException {
+
+ File[] tmp = createTempDirAndFile();
+ File reference = createReferenceFile(tmp[0]);
+
+ File a1 = File.createTempFile("src1.", ".zip", tmp[0]);
+ createFirstEntry(new ZipArchiveOutputStream(a1)).close();
+
+ File a2 = File.createTempFile("src2.", ".zip", tmp[0]);
+ createSecondEntry(new ZipArchiveOutputStream(a2)).close();
+
+ ZipFile zf1 = new ZipFile(a1);
+ ZipFile zf2 = new ZipFile(a2);
+ File fileResult = File.createTempFile("file-actual.", ".zip", tmp[0]);
+ ZipArchiveOutputStream zos2 = new ZipArchiveOutputStream(fileResult);
+ zf1.copyRawEntries(zos2, allFilesPredicate);
+ zf2.copyRawEntries(zos2, allFilesPredicate);
+ zos2.close();
+ assertSameFileContents(reference, fileResult);
+ zf1.close();
+ zf2.close();
+ }
+
+ private File createReferenceFile(File directory) throws IOException {
+ File reference = File.createTempFile("expected.", ".zip", directory);
+ ZipArchiveOutputStream zos = new ZipArchiveOutputStream(reference);
+ createFirstEntry(zos);
+ createSecondEntry(zos);
+ zos.close();
+ return reference;
+ }
+
+ private ZipArchiveOutputStream createFirstEntry(ZipArchiveOutputStream zos) throws IOException {
+ createArchiveEntry(first_payload, zos, "file1.txt");
+ return zos;
+ }
+
+ private ZipArchiveOutputStream createSecondEntry(ZipArchiveOutputStream zos) throws IOException {
+ createArchiveEntry(second_payload, zos, "file2.txt");
+ return zos;
+ }
+
+
+ private void assertSameFileContents(File expectedFile, File actualFile) throws IOException {
+ int size = (int) Math.max(expectedFile.length(), actualFile.length());
+ byte[] expected = new byte[size];
+ byte[] actual = new byte[size];
+ final FileInputStream expectedIs = new FileInputStream(expectedFile);
+ final FileInputStream actualIs = new FileInputStream(actualFile);
+ IOUtils.readFully(expectedIs, expected);
+ IOUtils.readFully(actualIs, actual);
+ expectedIs.close();
+ actualIs.close();
+ Assert.assertArrayEquals(expected, actual);
+ }
+
+
+ private void createArchiveEntry(String payload, ZipArchiveOutputStream zos, String name)
+ throws IOException {
+ ZipArchiveEntry in = new ZipArchiveEntry(name);
+ zos.putArchiveEntry(in);
+
+ zos.write(payload.getBytes());
+ zos.closeArchiveEntry();
+ }
public void testFileEntryFromFile() throws Exception {
File[] tmp = createTempDirAndFile();
Re: svn commit: r1646531 - in /commons/proper/compress/trunk: ./
src/main/java/org/apache/commons/compress/archivers/zip/ src/test/java/org/apache/commons/compress/
src/test/java/org/apache/commons/compress/archivers/
Posted by Kristian Rosenvold <kr...@gmail.com>.
I'll put taking a look at addRawArchiveEntry with ZipEntry on my todo
list. I have quite a few threads converging into the last class
already; but everything should be done in a few days now.
copyRawEntries could definitely be somewhere else. Originally I
implemented it on ZipArchiveOutputStream, but it's really not that
much better :)
Kristian
2014-12-23 18:43 GMT+01:00 Stefan Bodewig <bo...@apache.org>:
> On 2014-12-18, <kr...@apache.org> wrote:
>
>>> public void addRawArchiveEntry(ZipArchiveEntry entry, InputStream rawStream)
>
> Technically entry could be a java.util.zip.ZipEntry, I'm not sure this
> would open up new opportunities, though.
>
>>> /**
>>> * Transfer selected entries from this zipfile to a given #ZipArchiveOutputStream.
>>> * Compression and all other attributes will be as in this file.
>>> * This method transfers entries based on the central directory of the zip file.
>>> *
>>> * @param target The zipArchiveOutputStream to write the entries to
>>> * @param predicate A predicate that selects which entries to write
>>> */
>>> public void copyRawEntries(ZipArchiveOutputStream target, ZipArchiveEntryPredicate predicate)
>>> throws IOException {
>
> I'm not entirely sure this should be an instance method of ZipFile, it
> looks more like a utility method that could live outside of the class as
> it doesn't need any of the non-public parts of it.
>
> Then again ZipUtil is a bag of pretty unrelated methods so it doesn't
> sound like a happy place for it either.
>
> Stefan
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org
Re: svn commit: r1646531 - in /commons/proper/compress/trunk: ./ src/main/java/org/apache/commons/compress/archivers/zip/ src/test/java/org/apache/commons/compress/ src/test/java/org/apache/commons/compress/archivers/
Posted by Stefan Bodewig <bo...@apache.org>.
On 2014-12-18, <kr...@apache.org> wrote:
>> public void addRawArchiveEntry(ZipArchiveEntry entry, InputStream rawStream)
Technically entry could be a java.util.zip.ZipEntry, I'm not sure this
would open up new opportunities, though.
>> /**
>> * Transfer selected entries from this zipfile to a given #ZipArchiveOutputStream.
>> * Compression and all other attributes will be as in this file.
>> * This method transfers entries based on the central directory of the zip file.
>> *
>> * @param target The zipArchiveOutputStream to write the entries to
>> * @param predicate A predicate that selects which entries to write
>> */
>> public void copyRawEntries(ZipArchiveOutputStream target, ZipArchiveEntryPredicate predicate)
>> throws IOException {
I'm not entirely sure this should be an instance method of ZipFile, it
looks more like a utility method that could live outside of the class as
it doesn't need any of the non-public parts of it.
Then again ZipUtil is a bag of pretty unrelated methods so it doesn't
sound like a happy place for it either.
Stefan
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org