provide access to the general purpose bit flag field of a zip entry and fail when a STORED entry requires a data descriptor. COMPRESS-100
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@922309 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 9d68e83..535cf12 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -23,6 +23,12 @@
</properties>
<body>
<release version="1.1" date="as in SVN" description="Release 1.1">
+ <action type="fix" date="2010-03-12" issue="COMPRESS-100">
+ ZipArchiveInputStream will throw an exception if it detects an
+ entry that uses a data descriptor for a STORED entry since it
+ cannot reliably find the end of data for this "compression"
+ method.
+ </action>
<action type="fix" date="2010-03-12" issue="COMPRESS-101">
ZipArchiveInputStream should now properly read archives that
use data descriptors but without the "unofficial" signature.
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java b/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java
index 34c20ef..d2d1a88 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java
@@ -21,8 +21,9 @@
* Parser/encoder for the "general purpose bit" field in ZIP's local
* file and central directory headers.
* @since Apache Commons Compress 1.1
+ * @NotThreadSafe
*/
-public class GeneralPurposeBit {
+public final class GeneralPurposeBit {
/**
* Indicates that the file is encrypted.
*/
@@ -147,4 +148,22 @@
b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0);
return b;
}
+
+ public int hashCode() {
+ return 3 * (7 * (13 * (17 * (encryptionFlag ? 1 : 0)
+ + (strongEncryptionFlag ? 1 : 0))
+ + (languageEncodingFlag ? 1 : 0))
+ + (dataDescriptorFlag ? 1 : 0));
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof GeneralPurposeBit)) {
+ return false;
+ }
+ GeneralPurposeBit g = (GeneralPurposeBit) o;
+ return g.encryptionFlag == encryptionFlag
+ && g.strongEncryptionFlag == strongEncryptionFlag
+ && g.languageEncodingFlag == languageEncodingFlag
+ && g.dataDescriptorFlag == dataDescriptorFlag;
+ }
}
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/UnsupportedZipFeatureException.java b/src/main/java/org/apache/commons/compress/archivers/zip/UnsupportedZipFeatureException.java
index 3dc1ea7..86175e2 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/UnsupportedZipFeatureException.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/UnsupportedZipFeatureException.java
@@ -70,6 +70,10 @@
* The entry used an unsupported compression method.
*/
public static Feature METHOD = new Feature("compression method");
+ /**
+ * The entry uses a data descriptor.
+ */
+ public static Feature DATA_DESCRIPTOR = new Feature("data descriptor");
private final String name;
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
index a5550f0..acc0a08 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
@@ -74,8 +74,7 @@
private LinkedHashMap/*<ZipShort, ZipExtraField>*/ extraFields = null;
private UnparseableExtraFieldData unparseableExtra = null;
private String name = null;
- private boolean encrypted;
- private boolean stronglyEncrypted;
+ private GeneralPurposeBit gpb = new GeneralPurposeBit();
/**
* Creates a new zip entry with the specified name.
@@ -479,38 +478,19 @@
}
/**
- * Whether the entry is encrypted.
+ * The "general purpose bit" field.
* @since Apache Commons Compress 1.1
*/
- public boolean isEncrypted() {
- return encrypted;
+ public GeneralPurposeBit getGeneralPurposeBit() {
+ return gpb;
}
/**
- * Whether the entry is encrypted using strong encryption.
+ * The "general purpose bit" field.
* @since Apache Commons Compress 1.1
*/
- public boolean isStronglyEncrypted() {
- return stronglyEncrypted && encrypted;
- }
-
- /**
- * Whether the entry is encrypted.
- * @since Apache Commons Compress 1.1
- */
- public void setEncrypted(boolean b) {
- encrypted = b;
- }
-
- /**
- * Whether the entry is encrypted using strong encryption.
- * @since Apache Commons Compress 1.1
- */
- public void setStronglyEncrypted(boolean b) {
- stronglyEncrypted = b;
- if (b) {
- setEncrypted(true);
- }
+ public void setGeneralPurposeBit(GeneralPurposeBit b) {
+ gpb = b;
}
/**
@@ -594,6 +574,7 @@
&& Arrays.equals(getCentralDirectoryExtra(),
other.getCentralDirectoryExtra())
&& Arrays.equals(getLocalFileDataExtra(),
- other.getLocalFileDataExtra());
+ other.getLocalFileDataExtra())
+ && gpb.equals(other.gpb);
}
}
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
index 3a8ff14..a41deb5 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
@@ -139,8 +139,7 @@
final ZipEncoding entryEncoding =
hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
hasDataDescriptor = gpFlag.usesDataDescriptor();
- current.setEncrypted(gpFlag.usesEncryption());
- current.setStronglyEncrypted(gpFlag.usesStrongEncryption());
+ current.setGeneralPurposeBit(gpFlag);
off += SHORT;
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
index 4085e41..3f0eafa 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
@@ -368,8 +368,7 @@
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding =
hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
- ze.setEncrypted(gpFlag.usesEncryption());
- ze.setStronglyEncrypted(gpFlag.usesStrongEncryption());
+ ze.setGeneralPurposeBit(gpFlag);
off += SHORT;
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java
index c6091b1..1997cc5 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java
@@ -184,7 +184,8 @@
* Whether this library is able to read or write the given entry.
*/
static boolean canHandleEntryData(ZipArchiveEntry entry) {
- return supportsEncryptionOf(entry) && supportsMethodOf(entry);
+ return supportsEncryptionOf(entry) && supportsMethodOf(entry)
+ && supportsDataDescriptorFor(entry);
}
/**
@@ -194,7 +195,7 @@
* @return true if the entry isn't encrypted at all
*/
private static boolean supportsEncryptionOf(ZipArchiveEntry entry) {
- return !entry.isEncrypted();
+ return !entry.getGeneralPurposeBit().usesEncryption();
}
/**
@@ -209,6 +210,17 @@
}
/**
+ * Whether this entry requires a data descriptor this library can work with.
+ *
+ * @return true if the entry doesn't require any data descriptor
+ * or the method is DEFLATED).
+ */
+ private static boolean supportsDataDescriptorFor(ZipArchiveEntry entry) {
+ return !entry.getGeneralPurposeBit().usesDataDescriptor()
+ || entry.getMethod() == ZipArchiveEntry.DEFLATED;
+ }
+
+ /**
* Checks whether the entry requires features not (yet) supported
* by the library and throws an exception if it does.
*/
@@ -224,5 +236,10 @@
new UnsupportedZipFeatureException(UnsupportedZipFeatureException
.Feature.METHOD, ze);
}
+ if (!supportsDataDescriptorFor(ze)) {
+ throw
+ new UnsupportedZipFeatureException(UnsupportedZipFeatureException
+ .Feature.DATA_DESCRIPTOR, ze);
+ }
}
}
\ No newline at end of file
diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/EncryptedArchiveTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/EncryptedArchiveTest.java
index babbf69..c73bf4f 100644
--- a/src/test/java/org/apache/commons/compress/archivers/zip/EncryptedArchiveTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/zip/EncryptedArchiveTest.java
@@ -36,8 +36,8 @@
try {
zf = new ZipFile(file);
ZipArchiveEntry zae = zf.getEntry("LICENSE.txt");
- assertTrue(zae.isEncrypted());
- assertFalse(zae.isStronglyEncrypted());
+ assertTrue(zae.getGeneralPurposeBit().usesEncryption());
+ assertFalse(zae.getGeneralPurposeBit().usesStrongEncryption());
assertFalse(zf.canReadEntryData(zae));
try {
zf.getInputStream(zae);
@@ -60,8 +60,8 @@
zin = new ZipArchiveInputStream(new FileInputStream(file));
ZipArchiveEntry zae = zin.getNextZipEntry();
assertEquals("LICENSE.txt", zae.getName());
- assertTrue(zae.isEncrypted());
- assertFalse(zae.isStronglyEncrypted());
+ assertTrue(zae.getGeneralPurposeBit().usesEncryption());
+ assertFalse(zae.getGeneralPurposeBit().usesStrongEncryption());
assertFalse(zin.canReadEntryData(zae));
try {
byte[] buf = new byte[1024];