Associated Vulnerability
Readme
ZIP - convenience methods
=========================
### Continuous Integration
[](https://travis-ci.org/zeroturnaround/zt-zip)
### Quick Overview
The project was started and coded by Rein Raudjärv when he needed to process a large set of large ZIP archives for
LiveRebel internals. Soon after we started using the utility in other projects because of the ease of use and it
*just worked*.
The project is built using java.util.zip.* packages for stream based access. Most convenience methods for filesystem
usage is also supported.
### Installation
[](https://maven-badges.herokuapp.com/maven-central/org.zeroturnaround/zt-zip)
The project artifacts are available in [Maven Central Repository](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22zt-zip%22).
To include it in your maven project then you have to specify the dependency.
```xml
...
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<version>1.11</version>
<type>jar</type>
</dependency>
...
```
Notice that [1.8](https://oss.sonatype.org/content/repositories/releases/org/zeroturnaround/zt-zip/1.8/) is the last Java 1.4 compatible release.
Since then Java 1.5 is required.
## Background
We had the following functional requirements:
1. pack and unpack directories recursively
1. include/exclude entries
2. rename entries
3. packing/unpacking in place - ZIP becomes directory and vice versa
2. iterate through ZIP entries
3. add or replace entries from files or byte arrays
4. transform ZIP entries
5. compare two archives - compare all entries ignoring time stamps
and these non-functional requirements:
1. use existing APIs as much as possible
2. be simple to use
3. be effective to use - do not traverse an entire ZIP file if only a single entry is needed
4. be safe to use - do not enable user to leave streams open and keep files locked
5. do not declare exceptions
6. be compatible with Java 1.5
## Examples
### Unpacking
#### Check if an entry exists in a ZIP archive
```java
boolean exists = ZipUtil.containsEntry(new File("/tmp/demo.zip"), "foo.txt");
```
#### Extract an entry from a ZIP archive into a byte array
```java
byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt");
```
#### Extract an entry from a ZIP archive with a specific Charset into a byte array
```java
byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", Charset.forName("IBM437"));
```
#### Extract an entry from a ZIP archive into file system
```java
ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", new File("/tmp/bar.txt"));
```
#### Extract a ZIP archive
```java
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"));
```
#### Extract a ZIP archive which becomes a directory
```java
ZipUtil.explode(new File("/tmp/demo.zip"));
```
#### Extract a directory from a ZIP archive including the directory name
```java
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
public String map(String name) {
return name.startsWith("doc/") ? name : null;
}
});
```
#### Extract a directory from a ZIP archive excluding the directory name
```java
final String prefix = "doc/";
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
public String map(String name) {
return name.startsWith(prefix) ? name.substring(prefix.length()) : name;
}
});
```
#### Extract files from a ZIP archive that match a name pattern
```java
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
public String map(String name) {
if (name.contains("/doc")) {
return name;
}
else {
// returning null from the map method will disregard the entry
return null;
}
}
});
```
#### Print .class entry names in a ZIP archive
```java
ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipInfoCallback() {
public void process(ZipEntry zipEntry) throws IOException {
if (zipEntry.getName().endsWith(".class"))
System.out.println("Found " + zipEntry.getName());
}
});
```
#### Print .txt entries in a ZIP archive (uses IoUtils from Commons IO)
```java
ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipEntryCallback() {
public void process(InputStream in, ZipEntry zipEntry) throws IOException {
if (zipEntry.getName().endsWith(".txt")) {
System.out.println("Found " + zipEntry.getName());
IOUtils.copy(in, System.out);
}
}
});
```
### Packing
#### Compress a directory into a ZIP archive
```java
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip"));
```
#### Compress a directory which becomes a ZIP archive
```java
ZipUtil.unexplode(new File("/tmp/demo.zip"));
```
#### Compress a directory into a ZIP archive with a parent directory
```java
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip"), new NameMapper() {
public String map(String name) {
return "foo/" + name;
}
});
```
#### Add an entry from file to a ZIP archive
```java
ZipUtil.addEntry(new File("/tmp/demo.zip"), "doc/readme.txt", new File("f/tmp/oo.txt"), new File("/tmp/new.zip"));
```
#### Add an entry from byte array to a ZIP archive
```java
ZipUtil.addEntry(new File("/tmp/demo.zip"), "doc/readme.txt", "bar".getBytes(), new File("/tmp/new.zip"));
```
#### Add an entry from file and from byte array to a ZIP archive
```java
ZipEntrySource[] entries = new ZipEntrySource[] {
new FileSource("doc/readme.txt", new File("foo.txt")),
new ByteSource("sample.txt", "bar".getBytes())
};
ZipUtil.addEntries(new File("/tmp/demo.zip"), entries, new File("/tmp/new.zip"));
```
#### Add an entry from file and from byte array to a output stream
```java
ZipEntrySource[] entries = new ZipEntrySource[] {
new FileSource("doc/readme.txt", new File("foo.txt")),
new ByteSource("sample.txt", "bar".getBytes())
};
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(new File("/tmp/new.zip")));
ZipUtil.addEntries(new File("/tmp/demo.zip"), entries, out);
}
finally {
IOUtils.closeQuietly(out);
}
```
#### Replace a ZIP archive entry from file
```java
boolean replaced = ZipUtil.replaceEntry(new File("/tmp/demo.zip"), "doc/readme.txt", new File("/tmp/foo.txt"), new File("/tmp/new.zip"));
```
#### Replace a ZIP archive entry from byte array
```java
boolean replaced = ZipUtil.replaceEntry(new File("/tmp/demo.zip"), "doc/readme.txt", "bar".getBytes(), new File("/tmp/new.zip"));
```
#### Replace a ZIP archive entry from file and byte array
```java
ZipEntrySource[] entries = new ZipEntrySource[] {
new FileSource("doc/readme.txt", new File("foo.txt")),
new ByteSource("sample.txt", "bar".getBytes())
};
boolean replaced = ZipUtil.replaceEntries(new File("/tmp/demo.zip"), entries, new File("/tmp/new.zip"));
```
#### Add or replace entries in a ZIP archive
```java
ZipEntrySource[] addedEntries = new ZipEntrySource[] {
new FileSource("/path/in/zip/File1.txt", new File("/tmp/file1.txt")),
new FileSource("/path/in/zip/File2.txt", new File("/tmp/file2.txt")),
new FileSource("/path/in/zip/File3.txt", new File("/tmp/file2.txt")),
};
ZipUtil.addOrReplaceEntries(new File("/tmp/demo.zip"), addedEntries);
```
### Transforming
#### Transform a ZIP archive entry into uppercase
```java
boolean transformed = ZipUtil.transformEntry(new File("/tmp/demo"), "sample.txt", new StringZipEntryTransformer() {
protected String transform(ZipEntry zipEntry, String input) throws IOException {
return input.toUpperCase();
}
}, new File("/tmp/demo.zip"));
```
### Comparison
#### Compare two ZIP archives (ignoring timestamps of the entries)
```java
boolean equals = ZipUtil.archiveEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"));
```
#### Compare two ZIP archive entries with same name (ignoring timestamps of the entries)
```java
boolean equals = ZipUtil.entryEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"), "foo.txt");
```
#### Compare two ZIP archive entries with different names (ignoring timestamps of the entries)
```java
boolean equals = ZipUtil.entryEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"), "foo1.txt", "foo2.txt");
```
## Debugging
The library is using the [slf4j-api](http://www.slf4j.org/) logging framework. All the log statements are either **DEBUG** or **TRACE** level. Depending on the logging framework you are using a simple ```-Dorg.slf4j.simpleLogger.defaultLogLevel=debug``` or ```System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");``` will do the trick of showing log statements from the **zt-zip** library. You can further fine tune the levels and inclusion of log messages per package with your logging framework.
File Snapshot
[4.0K] /data/pocs/2744a0d7582a9ba864e13cf2d509f288a939c992
├── [1.3K] Changelog.txt
├── [2.5K] get_release_commands.sh
├── [ 11K] LICENSE
├── [ 752] NOTICE
├── [ 722] oss-release.sh
├── [5.7K] pom.xml
├── [8.7K] README.md
└── [4.0K] src
├── [4.0K] main
│ └── [4.0K] java
│ └── [4.0K] org
│ └── [4.0K] zeroturnaround
│ └── [4.0K] zip
│ ├── [2.4K] ByteSource.java
│ ├── [1.0K] CloseShieldInputStream.java
│ ├── [4.0K] commons
│ │ ├── [1.7K] FileExistsException.java
│ │ ├── [8.6K] FilenameUtils.java
│ │ ├── [2.3K] FileUtils.java
│ │ ├── [ 39K] FileUtilsV2_2.java
│ │ ├── [ 16K] IOUtils.java
│ │ └── [4.6K] StringBuilderWriter.java
│ ├── [4.0K] extra
│ │ ├── [ 10K] AsiExtraField.java
│ │ ├── [5.6K] ExtraFieldUtils.java
│ │ ├── [4.5K] UnrecognizedExtraField.java
│ │ ├── [2.1K] ZipConstants.java
│ │ ├── [2.8K] ZipExtraField.java
│ │ ├── [5.4K] ZipLong.java
│ │ └── [4.4K] ZipShort.java
│ ├── [2.7K] FileSource.java
│ ├── [1.0K] IdentityNameMapper.java
│ ├── [2.7K] Java6FileApiPermissionsStrategy.java
│ ├── [6.0K] Java7Nio2ApiPermissionsStrategy.java
│ ├── [1.1K] NameMapper.java
│ ├── [4.0K] timestamps
│ │ ├── [1.5K] Java8TimestampStrategy.java
│ │ ├── [1.0K] PreJava8TimestampStrategy.java
│ │ ├── [1.6K] TimestampStrategyFactory.java
│ │ └── [ 963] TimestampStrategy.java
│ ├── [4.0K] transform
│ │ ├── [1.8K] ByteArrayZipEntryTransformer.java
│ │ ├── [2.1K] FileZipEntryTransformer.java
│ │ ├── [1.3K] StreamZipEntryTransformer.java
│ │ ├── [1.4K] StringZipEntryTransformer.java
│ │ ├── [1.1K] ZipEntrySourceZipEntryTransformer.java
│ │ ├── [ 603] ZipEntryTransformerEntry.java
│ │ └── [ 804] ZipEntryTransformer.java
│ ├── [ 264] ZipBreakException.java
│ ├── [1.2K] ZipEntryCallback.java
│ ├── [1014] ZipEntryOrInfoAdapter.java
│ ├── [1.3K] ZipEntrySource.java
│ ├── [6.4K] ZipEntryUtil.java
│ ├── [ 281] ZipException.java
│ ├── [ 242] ZipExceptionUtil.java
│ ├── [4.9K] ZipFileUtil.java
│ ├── [1.2K] ZipInfoCallback.java
│ ├── [ 22K] Zips.java
│ ├── [ 95K] ZipUtil.java
│ ├── [2.0K] ZTFilePermissions.java
│ ├── [ 686] ZTFilePermissionsStrategy.java
│ ├── [3.9K] ZTFilePermissionsUtil.java
│ ├── [1.9K] ZTFileUtil.java
│ └── [1.1K] ZTZipReflectionUtil.java
└── [4.0K] test
├── [4.0K] java
│ ├── [4.0K] example
│ │ ├── [ 625] AddOrReplaceEntries.java
│ │ ├── [1.2K] PackEntryExample.java
│ │ ├── [1.2K] PackExample.java
│ │ ├── [ 728] ReplaceEntryExample.java
│ │ ├── [ 993] UnpackEntryExample.java
│ │ └── [1.5K] UnpackExample.java
│ └── [4.0K] org
│ └── [4.0K] zeroturnaround
│ └── [4.0K] zip
│ ├── [5.6K] CharsetTest.java
│ ├── [6.1K] FilePermissionsTest.java
│ ├── [2.3K] FileSourceTest.java
│ ├── [7.0K] MainExamplesTest.java
│ ├── [ 730] SkipIfZipEntryFileTimeNotAvailableRule.java
│ ├── [1.3K] ZipEntryUtilTest.java
│ ├── [3.3K] ZipPreserveTimeStampJava8Test.java
│ ├── [2.7K] ZipPreserveTimeStampTest.java
│ ├── [ 24K] ZipsTest.java
│ ├── [9.0K] ZipTransformTest.java
│ ├── [1.5K] ZipUtilDirTest.java
│ ├── [4.4K] ZipUtilInPlaceTest.java
│ ├── [ 31K] ZipUtilTest.java
│ └── [2.2K] ZTFileUtilTest.java
└── [4.0K] resources
├── [ 430] backSlashTest.zip
├── [ 657] demo-copy-II.zip
├── [ 657] demo-copy.zip
├── [1.0K] demo-dirs-only.zip
├── [1.6K] demo-dirs.zip
├── [ 266] demo-keep-entries-state.zip
├── [ 154] demo-single-empty-root-dir.zip
├── [ 732] demo-single-root-dir.zip
├── [ 657] demo.zip
├── [ 214] duplicate.zip
├── [ 900] log4j.properties
├── [4.0K] testDirectory
│ ├── [ 8] testfileInTestDirectory.txt
│ └── [4.0K] testSubdirectory
│ └── [ 8] testFileInTestSubdirectory.txt
├── [ 103] TestFile-II.txt
├── [ 108] TestFile.txt
├── [ 936] umlauts-öäš.zip
└── [ 356] windows-compressed.zip
19 directories, 91 files
Remarks
1. It is advised to access via the original source first.
2. If the original source is unavailable, please email f.jinxu#gmail.com for a local snapshot (replace # with @).
3. Shenlong has snapshotted the POC code for you. To support long-term maintenance, please consider donating. Thank you for your support.