pax_global_header 0000666 0000000 0000000 00000000064 14142654472 0014523 g ustar 00root root 0000000 0000000 52 comment=860965237a746e481071a656377633f84dfb388b
zip4j-2.9.1/ 0000775 0000000 0000000 00000000000 14142654472 0012574 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/.gitignore 0000664 0000000 0000000 00000000037 14142654472 0014564 0 ustar 00root root 0000000 0000000 .idea/
target/
*.iml
.DS_Store
zip4j-2.9.1/.travis.yml 0000664 0000000 0000000 00000000360 14142654472 0014704 0 ustar 00root root 0000000 0000000 language: java
before_script:
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash trigger-android-build.sh ${CIRCLE_CI_TOKEN} || travis_terminate 1; fi'
script:
- travis_wait 45 mvn clean verify
cache:
directories:
- $HOME/.m2
zip4j-2.9.1/LICENSE 0000664 0000000 0000000 00000026135 14142654472 0013610 0 ustar 00root root 0000000 0000000 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed 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.
zip4j-2.9.1/README.md 0000664 0000000 0000000 00000065437 14142654472 0014072 0 ustar 00root root 0000000 0000000 [](https://javadoc.io/doc/net.lingala.zip4j/zip4j)
[](https://maven-badges.herokuapp.com/maven-central/net.lingala.zip4j/zip4j)
[](https://travis-ci.com/srikanth-lingala/zip4j)
[](https://circleci.com/gh/srikanth-lingala/zip4j-android-test)
[](https://snyk.io//test/github/srikanth-lingala/zip4j?targetFile=pom.xml)
Zip4j - A Java library for zip files / streams
=========================
## Thank you
for rating Zip4j as the best Java library for zip files [[1][1], [2][2], [3][3], [4][4]]. It has encouraged me to
bring this project to life again after a gap of several years. I tried to add some of the important features that
were requested over this time, and also made the API much more neater. The newer version (> 2.0.0) now supports streams,
which was understandably, one of the most requested feature. If you have any feedback, bugs to report, feature
requests, etc, please open an issue here on GitHub. I will try to address them as soon as I can. I also monitor the
tag `zip4j` on [Stack Overflow][10].
## About
Zip4j is the most comprehensive Java library for zip files or streams. As of this writing, it is the only Java library
which has support for zip encryption, apart from several other features. It tries to make handling zip files/streams
a lot more easier. No more clunky boiler plate code with input streams and output streams. As you can see in the usage
section below, working with zip files can now even be a single line of code, compared to [this][5]. I mean no offense
to the Java's built-in zip support. In fact, this library depends on Java's built-in zip code and it would have been
significantly more ~~complicated~~ challenging if I had to write compression logic as well. But lets be honest, working with zip
files or streams can be a lot of boiler plate code. The main goal of this library is to provide a simple API for all
usual actions of a zip file or streams by doing the heavy lifting within the library and not have developers worry about
having to deal with streams, etc. Apart from usability, another important goal of this library is to provide support for
as many zip features as possible, which brings me to:
## Features
* Create, Add, Extract, Update, Remove files from a zip file
* Support for streams (ZipInputStream and ZipOutputStream)
* Read/Write password protected zip files and streams
* Support for both AES and zip standard encryption methods
* Support for Zip64 format
* Store (No Compression) and Deflate compression method
* Create or extract files from split zip files (Ex: z01, z02,...zip)
* Support for Unicode file names and comments in zip
* Progress Monitor - for integration into apps and user facing applications
## Background
Zip4j was started by me (Srikanth Reddy Lingala) back in 2008/2009, when I realized the lack of support for majority of zip format
features in Java. And also working with zip files was, as mentioned several times above, a lot of boiler plate code,
having to deal with streams (worse still, it was back in the days when there was no try-with-resources in Java). There
was also no comprehensive library which supports zip features. So, I decided to write one, and approximately after a
year, the first version was out. The response was truly overwhelming, and I got a lot of support right from the next
day of release. It was not put on GitHub as git/GitHub was not as popular as it is now. Code was hosted on my website,
as, guess what, a zip file :). And unfortunately, after a year or two after the initial release, life got busy and I was
not able to support Zip4j as much as I wanted to. But the overwhelming encouragement I got over the years made me start working on Zip4j
once again, and makes me support Zip4j as much as I can.
## Requirements
JDK 7 or later** Zip4j is written on JDK 8, as some of the features (NIO) that Zip4j supports requires features available only in
JDK 8. However, considering the fact that Zip4j is widely used in Android, and to support older versions of Android,
Zip4j supports JDK 7 as well. In cases where the feature/class from JDK 8 is missing, Zip4j falls back to the features
available in JDK 7. In other words, when running on JDK 7, not all features will be supported.
## Maven
```xml
net.lingala.zip4jzip4j2.9.0
```
Please check the latest version number on [Maven Central][6].
## Usage
### Creating a zip file with single file in it / Adding single file to an existing zip
```java
new ZipFile("filename.zip").addFile("filename.ext");
```
Or
```java
new ZipFile("filename.zip").addFile(new File("filename.ext"));
```
### Creating a zip file with multiple files / Adding multiple files to an existing zip
```java
new ZipFile("filename.zip").addFiles(Arrays.asList(new File("first_file"), new File("second_file")));
```
### Creating a zip file by adding a folder to it / Adding a folder to an existing zip
```java
new ZipFile("filename.zip").addFolder(new File("/users/some_user/folder_to_add"));
```
Since v2.6, it is possible to exclude certain files when adding a folder to zip by using an ExcludeFileFilter
```java
ExcludeFileFilter excludeFileFilter = filesToExclude::contains;
ZipParameters zipParameters = new ZipParameters();
zipParameters.setExcludeFileFilter(excludeFileFilter);
new ZipFile("filename.zip").addFolder(new File("/users/some_user/folder_to_add"), zipParameters);
```
### Creating a zip file from stream / Adding a stream to an existing zip
```java
new ZipFile("filename.zip").addStream(inputStream, new ZipParameters());
```
Passing in `new ZipParameters()`, as in the above example, will make Zip4j use default zip parameters. Please look at
[ZipParameters][7] to see the default configuration.
### Creating a zip file of compression method STORE / Adding entries to zip file of compression method STORE
By default Zip4j uses Deflate compression algorithm to compress files. However, if you would like to not use any
compression (called STORE compression), you can do so as shown in the example below:
```java
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
new ZipFile("filename.zip").addFile("fileToAdd", zipParameters);
```
You can similarly pass in zip parameters to all the other examples to create a zip file of STORE compression.
### Creating a password protected zip file / Adding files to an existing zip with password protection
##### AES encryption
```java
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
// Below line is optional. AES 256 is used by default. You can override it to use AES 128. AES 192 is supported only for extracting.
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
List filesToAdd = Arrays.asList(
new File("somefile"),
new File("someotherfile")
);
ZipFile zipFile = new ZipFile("filename.zip", "password".toCharArray());
zipFile.addFiles(filesToAdd, zipParameters);
```
##### Zip standard encryption
Instead of AES, replace `zipParameters.setEncryptionMethod(EncryptionMethod.AES);` with
`zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);`. You can omit the line to set AES key strength. As
the name suggests, this is only applicable for AES encryption.
In all the above examples, you can similarly pass in zip parameters with appropriate password configuration to create
a password protected zip file.
### Creating a split zip file
If you want to split the zip file over several files when the size exceeds a particular limit, you can do so like this:
```java
List filesToAdd = Arrays.asList(
new File("somefile"),
new File("someotherfile")
);
ZipFile zipFile = new ZipFile("filename.zip");
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, 10485760); // using 10MB in this example
```
Passing in `new ZipParameters()`, as in the above example, will make Zip4j use default zip parameters. Please look at
[ZipParameters][7] to see the default configuration.
Zip file format specifies a minimum of 65536 bytes (64KB) as a minimum length for split files. Zip4j will throw an
exception if anything less than this value is specified.
To create a split zip with password protection, pass in appropriate ZipParameters as shown in the example below:
```java
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
List filesToAdd = Arrays.asList(
new File("somefile"),
new File("someotherfile")
);
ZipFile zipFile = new ZipFile("filename.zip", "password".toCharArray());
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, 10485760); // using 10MB in this example
```
### Zip64 format
Zip64 is a zip feature which allows support for zip files when the size of the zip file exceeds the maximum that can be
stored in 4 bytes (i.e., greater than 4,294,967,295 bytes). Traditionally, zip headers have a provision of 4 bytes to store
for file sizes. But with growing file sizes compared to a few decades back, zip file format extended support of file
sizes which extends 4 bytes by adding additional headers which uses 8 bytes for file sizes (compressed and
uncompressed file sizes). This feature is known as Zip64.
Zip4j will automatically make a zip file with Zip64 format and add appropriate headers, when it detects the zip file to be
crossing this file size limit. You do not have to explicitly specify any flag for Zip4j to use this feature.
### Extracting all files from a zip
```java
new ZipFile("filename.zip").extractAll("/destination_directory");
```
### Extracting all files from a password protected zip
```java
new ZipFile("filename.zip", "password".toCharArray()).extractAll("/destination_directory");
```
### Extracting a single file from zip
```java
new ZipFile("filename.zip").extractFile("fileNameInZip.txt", "/destination_directory");
```
### Extracting a folder from zip (since v2.6.0)
```java
new ZipFile("filename.zip").extractFile("folderNameInZip/", "/destination_directory");
```
### Extracting a single file from zip which is password protected
```java
new ZipFile("filename.zip", "password".toCharArray()).extractFile("fileNameInZip.txt", "/destination_directory");
```
Since v2.6.0: If the file name represents a directory, Zip4j will extract all files in the zip that are part of this directory.
### Extracting a single file from zip and giving it a new file name
Below example will extract the file `fileNameInZip.txt` from the zip file to the output directory `/destination_directory`
and will give the file the name `newfileName.txt`. Without the third parameter of the new file name, the same name as the
file in the zip will be used, which in this case is `fileNameInZip.txt`. If the file being extracted is a directory,
`newFileName` parameter will be used as the directory name.
```java
new ZipFile("filename.zip", "password".toCharArray()).extractFile("fileNameInZip.txt", "/destination_directory", "newfileName.txt");
```
### Get an input stream for an entry in a zip file
```java
ZipFile zipFile = new ZipFile("filename.zip");
FileHeader fileHeader = zipFile.getFileHeader("entry_name_in_zip.txt");
InputStream inputStream = zipFile.getInputStream(fileHeader);
```
You can now use this input stream to read content from it/write content to an output stream. Please note that the
entry/file name is relative to the directory it is in. If `entry_name_in_zip.txt` is in a folder called "root_folder" in
the zip, then you have to use `zipFile.getFileHeader("root_folder/entry_name_in_zip.txt");`.
### Remove a file/entry from a zip file
```java
new ZipFile("filename.zip").removeFile("fileNameInZipToRemove");
```
If `fileNameInZipToRemove` represents a folder all the files and folders under this folder will be removed as well
(this is valid since v2.5.0 of Zip4j. All prior versions remove just the single entry even if it is a folder).
Please note that the file name is relative the root folder in zip. That is, if the file you want to remove exists in a
folder called "folder1", which in-turn exists in a folder called "root-folder", removing this file from zip has to be done
as below:
```java
new ZipFile("filename.zip").removeFile("root-folder/folder1/fileNameInZipToRemove");
```
If you want to be sure that the file you want to remove exists in zip file or if you don't want to deal with file names
as string when using the `removeFile` API, you can use the other overloaded method which takes in a `FileHeader`:
```java
ZipFile zipFile = new ZipFile("someZip.zip");
FileHeader fileHeader = zipFile.getFileHeader("fileNameInZipToRemove");
if (fileHeader == null) {
// file does not exist
}
zipFile.removeFile(fileHeader);
```
Since v2.5.0 of Zip4j, it is possible to remove multiple files and folders from a zip file. You can now pass in a list
as shown in the code below:
```java
ZipFile zipFile = new ZipFile("someZip.zip");
List filesToRemove = Arrays.asList("file1.txt", "file2.txt", "some-folder/", "some-new-folder-1/somefile.pdf");
zipFile.removeFiles(filesToRemove);
```
The above code will remove `file1.txt`, `file2.txt`, all files and folders under `some-folder` (including `some-folder`)
and just the entry `somefile.pdf` in folder `some-new-folder-1`. All other files and folders are kept intact in the zip
file.
### Rename entries in the zip file
There are three ways to rename an entry in a zip file with Zip4j. One way is to pass in a file header and the new file
name:
```java
ZipFile zipFile = new ZipFile("sample.zip");
FileHeader fileHeader = zipFile.getFileHeader("entry-to-be-changed.pdf");
zipFile.renameFile(fileHeader, "new-file-name.pdf");
```
Second way is to pass in just the file name to be changed (instead of the file header), and the new file name.
```java
new ZipFile("filename.zip").renameFile("entry-to-be-changed.pdf", "new-file-name.pdf");
```
It is also possible to change multiple file names at once. In this case you have to use a map, with the key of the entry
in the map being the entry to be changed, and the value of the map being the new file name:
```java
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("firstFile.txt", "newFileFirst.txt");
fileNamesMap.put("secondFile.pdf", "newSecondFile.pdf");
fileNamesMap.put("some-folder/thirdFile.bin", "some-folder/newThirdFile.bin");
new ZipFile("filename.zip").renameFile("entry-to-be-changed.pdf", "new-file-name.pdf");
```
To modify an entry name which is inside a folder, the new file name should contain the complete parent path as well.
For example, if an entry by the name `some-entry.pdf` is in the folder `some-folder/some-sub-folder/`, to modify this
entry name to `some-new-entry.pdf`:
```java
new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "some-folder/some-sub-folder/new-entry.pdf");
```
If the parent path is missing, then the file will be put at the root of the zip file. In the below example, after
the file is renamed, `some-new-entry.pdf` will exist at the root of the zip file instead of at `some-folder/some-sub-folder/`:
```java
new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "some-new-entry.pdf");
```
This also gives the flexibility to "move" the entry to a different folder. The below example will move the
`some-entry.pdf` from `some-folder/some-sub-folder/` to `folder-to-be-moved-to/sub-folder/` and the file will also be
renamed to `new-entry.pdf`. To just move the file, use the same file name instead of a new file name.
```java
new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "folder-to-be-moved-to/sub-folder/new-entry.pdf");
```
If the entry being modified is a directory, all entries that are part of that directory will be renamed so that all of
them have the new folder name as parent. In zip format, all entry names under a directory will contain the full name as their file name.
For example if there is an entry by the name `filename.txt` inside a directory `directoryName`, the file name for the entry
will be `directoryName/filename.txt`. And if the name of the directory has now been changed to `newDirectoryName`, the
entry under it will also be changed to `newDirectoryName/filename.txt`, so when the zip file is extracted,
`filename.txt` will be under `newDirectoryName`.
Zip file format does not allow modifying split zip files, and Zip4j will throw an exception if an attempt is made to
rename files in a split zip file.
### Merging split zip files into a single zip
This is the reverse of creating a split zip file, that is, this feature will merge a zip file which is split across
several files into a single zip file:
```java
new ZipFile("split_zip_file.zip").mergeSplitFiles(new File("merged_zip_file.zip"));
```
This method will throw an exception if the split zip file (in this case `split_zip_file.zip`) is not a split zip file.
### List all files in a zip
```java
List fileHeaders = new ZipFile("zipfile.zip").getFileHeaders();
fileHeaders.stream().forEach(fileHeader -> System.out.println(fileHeader.getFileName()));
```
You can get all other information from the `FileHeader` object corresponding to each file/entry in the zip.
### Check if a zip file is password protected
```java
new ZipFile("encrypted_zip_file.zip").isEncrypted();
```
### Check if a zip file is a split zip file
```java
new ZipFile("split_zip_file.zip").isSplitArchive();
```
### Set comment for a zip file
```java
new ZipFile("some_zip_file.zip").setComment("Some comment");
```
### Remove comment of a zip file
```java
new ZipFile("some_zip_file.zip").setComment("");
```
### Get comment of a zip file
```java
new ZipFile("some_zip_file.zip").getComment();
```
### Check if a zip file is valid
Note: This will only check for the validity of the headers and not the validity of each entry in the zip file.
```java
new ZipFile("valid_zip_file.zip").isValidZipFile();
```
## Working with streams
### Adding entries with ZipOutputStream
```java
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class ZipOutputStreamExample {
public void zipOutputStreamExample(File outputZipFile, List filesToAdd, char[] password,
CompressionMethod compressionMethod, boolean encrypt,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength)
throws IOException {
ZipParameters zipParameters = buildZipParameters(compressionMethod, encrypt, encryptionMethod, aesKeyStrength);
byte[] buff = new byte[4096];
int readLen;
try(ZipOutputStream zos = initializeZipOutputStream(outputZipFile, encrypt, password)) {
for (File fileToAdd : filesToAdd) {
// Entry size has to be set if you want to add entries of STORE compression method (no compression)
// This is not required for deflate compression
if (zipParameters.getCompressionMethod() == CompressionMethod.STORE) {
zipParameters.setEntrySize(fileToAdd.length());
}
zipParameters.setFileNameInZip(fileToAdd.getName());
zos.putNextEntry(zipParameters);
try(InputStream inputStream = new FileInputStream(fileToAdd)) {
while ((readLen = inputStream.read(buff)) != -1) {
zos.write(buff, 0, readLen);
}
}
zos.closeEntry();
}
}
}
private ZipOutputStream initializeZipOutputStream(File outputZipFile, boolean encrypt, char[] password)
throws IOException {
FileOutputStream fos = new FileOutputStream(outputZipFile);
if (encrypt) {
return new ZipOutputStream(fos, password);
}
return new ZipOutputStream(fos);
}
private ZipParameters buildZipParameters(CompressionMethod compressionMethod, boolean encrypt,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength) {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(compressionMethod);
zipParameters.setEncryptionMethod(encryptionMethod);
zipParameters.setAesKeyStrength(aesKeyStrength);
zipParameters.setEncryptFiles(encrypt);
return zipParameters;
}
}
```
### Extract files with ZipInputStream
```java
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.LocalFileHeader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class ZipInputStreamExample {
public void extractWithZipInputStream(File zipFile, char[] password) throws IOException {
LocalFileHeader localFileHeader;
int readLen;
byte[] readBuffer = new byte[4096];
InputStream inputStream = new FileInputStream(zipFile);
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream, password)) {
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
File extractedFile = new File(localFileHeader.getFileName());
try (OutputStream outputStream = new FileOutputStream(extractedFile)) {
while ((readLen = zipInputStream.read(readBuffer)) != -1) {
outputStream.write(readBuffer, 0, readLen);
}
}
}
}
}
}
```
## Working with Progress Monitor
ProgressMonitor makes it easier for applications (especially user facing) to integrate Zip4j. It is useful to show
progress (example: updating a progress bar, displaying the current action, show file name being worked on, etc.). To use
ProgressMonitor, you have to set `ZipFile.setRunInThread(true)`. This will make any actions being done on the zip file
to run in a background thread. You can then access ProgressMonitor `Zipfile.getProgressMonitor()` and get details of the
current action being done along with the percentage work done, etc. Below is an example:
```java
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
zipFile.setRunInThread(true);
zipFile.addFolder(new File("/some/folder"));
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
System.out.println("Percentage done: " + progressMonitor.getPercentDone());
System.out.println("Current file: " + progressMonitor.getFileName());
System.out.println("Current task: " + progressMonitor.getCurrentTask());
Thread.sleep(100);
}
if (progressMonitor.getResult().equals(ProgressMonitor.Result.SUCCESS)) {
System.out.println("Successfully added folder to zip");
} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.ERROR)) {
System.out.println("Error occurred. Error message: " + progressMonitor.getException().getMessage());
} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.CANCELLED)) {
System.out.println("Task cancelled");
}
```
Note that in the above example, `addFolder()` will almost immediately return back the control to the caller. The client
code can then perform a loop until the state gets back to "Ready" as shown in the above example.
Similarly, ProgressMonitor can be used with other actions like, `addFiles`, `removeFiles` and `extractFiles`.
## Contribution
It is hard to find as much free time as I used to have when I first started Zip4j back in 2009. I would
highly appreciate any support I can get for this project. You can fork this project, and send me pull requests for
any bug fixes, issues mentioned here or new features. If you need any support in understanding the code or zip specification,
just drop me a mail and I will help you as best as I can. (See FAQ for my email address.)
## FAQ
1. **Why do I have to pass in password as char array and not as a string?**
[That's why][8]
2. **How can I contact you?**
srikanth.mailbox@gmail.com
3. **Are unicode file names supported?**
Yes, unicode file names (UTF-8) are supported as specified by the zip format specification. Zip4j will use UTF-8 file
name and file comment encoding when creating a zip file. When extracting a zip file, Zip4j will only use UTF-8 encoding,
only if the appropriate header flag is set as specified by zip file format specification. If this flag is not set,
Zip4j will use CP437 encoding which only supports extended ASCII characters.
4. **Where can I find zip file format specification?**
[Here][9]
5. **Why are there so many changes in version 2.x compared to 1.x?**
Because when version 1.x was written back in 2009, Zip4j was badly in need of a face-lift and code modernization. Also, my
coding standards have improved over the years (or at least that's what I like to think). Although I am proud of
the work I did with Zip4j back in 2009, some parts of the code make me feel like hiding my face in shame. One such example
is the usage of `ArrayList` instead of `List`. API and code should look much neater now. And also, Zip4j now supports
a minimum of JRE 8, as compared to JRE 5 with 1.x, which obviously will bring some nice features that I can make use of. (For
example: no more explicitly closing the streams all over the code). If you still feel like something can be improved (and
I am pretty sure that there are things to be improved), please let me know by opening an issue here or writing to me
(my email address is in point #2 above).
6. **What are the licensing conditions for older releases of Zip4j?**
All releases of Zip4j, from version 1.0, are licensed under Apache License 2.0
[1]: https://stackoverflow.com/questions/9324933/what-is-a-good-java-library-to-zip-unzip-files
[2]: https://stackoverflow.com/questions/5362364/java-library-to-work-with-zip-files
[3]: https://stackoverflow.com/questions/166340/recommendations-on-a-free-library-to-be-used-for-zipping-files
[4]: https://stackoverflow.com/questions/18201279/file-compression-library-for-java/18201553
[5]: https://www.baeldung.com/java-compress-and-uncompress
[6]: https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j
[7]: https://javadoc.io/doc/net.lingala.zip4j/zip4j/latest/net/lingala/zip4j/model/ZipParameters.html#ZipParameters--
[8]: https://www.baeldung.com/java-storing-passwords
[9]: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
[10]: https://stackoverflow.com/questions/tagged/zip4j
zip4j-2.9.1/pom.xml 0000664 0000000 0000000 00000015756 14142654472 0014127 0 ustar 00root root 0000000 0000000
4.0.0net.lingala.zip4jzip4j2.9.1-SNAPSHOTZip4jZip4j - A Java library for zip files and streamshttps://github.com/srikanth-lingala/zip4jgit@github.com:srikanth-lingala/zip4j.gitSrikanth Reddy Lingalasrikanth.mailbox@gmail.comApache License, Version 2.0https://www.apache.org/licenses/LICENSE-2.0.txt1.71.74.13.11.18.82.9.12.28.22.0.2UTF-8ossrhhttps://oss.sonatype.org/content/repositories/snapshotsossrhhttps://oss.sonatype.org/service/local/staging/deploy/maven2/junitjunit${junit.version}testorg.assertjassertj-core${assertj.version}testorg.mockitomockito-core${mockito.version}testorg.powermockpowermock-module-junit4${powermock.version}testorg.powermockpowermock-api-mockito2${powermock.version}testdisable-java8-doclint[1.8,)-Xdoclint:nonesrc/main/javaorg.apache.maven.pluginsmaven-compiler-plugin1.71.7org.apache.maven.pluginsmaven-failsafe-plugin3.0.0-M3integration-testverifyorg.apache.maven.pluginsmaven-source-plugin2.2.1attach-sourcesdeployjar-no-forkorg.apache.maven.pluginsmaven-javadoc-plugin2.9.1attach-javadocsdeployjarorg.apache.maven.pluginsmaven-gpg-plugin1.5sign-artifactsdeploysignorg.sonatype.pluginsnexus-staging-maven-plugin1.6.8trueossrhhttps://oss.sonatype.org/trueorg.apache.felixmaven-bundle-plugintruenet.lingala.zip4j.*bundle-manifestpackagebundle
zip4j-2.9.1/src/ 0000775 0000000 0000000 00000000000 14142654472 0013363 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/ 0000775 0000000 0000000 00000000000 14142654472 0014307 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/ 0000775 0000000 0000000 00000000000 14142654472 0015230 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/ 0000775 0000000 0000000 00000000000 14142654472 0016016 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/ 0000775 0000000 0000000 00000000000 14142654472 0017425 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/ 0000775 0000000 0000000 00000000000 14142654472 0020465 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/ZipFile.java 0000775 0000000 0000000 00000132720 14142654472 0022702 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderReader;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.inputstream.NumberedSplitRandomAccessFile;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.AddFilesToZipTask;
import net.lingala.zip4j.tasks.AddFilesToZipTask.AddFilesToZipTaskParameters;
import net.lingala.zip4j.tasks.AddFolderToZipTask;
import net.lingala.zip4j.tasks.AddFolderToZipTask.AddFolderToZipTaskParameters;
import net.lingala.zip4j.tasks.AddStreamToZipTask;
import net.lingala.zip4j.tasks.AddStreamToZipTask.AddStreamToZipTaskParameters;
import net.lingala.zip4j.tasks.AsyncZipTask;
import net.lingala.zip4j.tasks.ExtractAllFilesTask;
import net.lingala.zip4j.tasks.ExtractAllFilesTask.ExtractAllFilesTaskParameters;
import net.lingala.zip4j.tasks.ExtractFileTask;
import net.lingala.zip4j.tasks.ExtractFileTask.ExtractFileTaskParameters;
import net.lingala.zip4j.tasks.MergeSplitZipFileTask;
import net.lingala.zip4j.tasks.MergeSplitZipFileTask.MergeSplitZipFileTaskParameters;
import net.lingala.zip4j.tasks.RemoveFilesFromZipTask;
import net.lingala.zip4j.tasks.RemoveFilesFromZipTask.RemoveFilesFromZipTaskParameters;
import net.lingala.zip4j.tasks.RenameFilesTask;
import net.lingala.zip4j.tasks.RenameFilesTask.RenameFilesTaskParameters;
import net.lingala.zip4j.tasks.SetCommentTask;
import net.lingala.zip4j.tasks.SetCommentTask.SetCommentTaskTaskParameters;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import static net.lingala.zip4j.util.FileUtils.isNumberedSplitFile;
import static net.lingala.zip4j.util.InternalZipConstants.CHARSET_UTF_8;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
import static net.lingala.zip4j.util.UnzipUtil.createZipInputStream;
import static net.lingala.zip4j.util.Zip4jUtil.isStringNotNullAndNotEmpty;
/**
* Base class to handle zip files. Some of the operations supported
* in this class are:
*
*
Create Zip File
*
Add files to zip file
*
Add folder to zip file
*
Extract files from zip files
*
Remove files from zip file
*
*/
public class ZipFile implements Closeable {
private File zipFile;
private ZipModel zipModel;
private boolean isEncrypted;
private ProgressMonitor progressMonitor;
private boolean runInThread;
private char[] password;
private HeaderWriter headerWriter = new HeaderWriter();
private Charset charset = null;
private ThreadFactory threadFactory;
private ExecutorService executorService;
private int bufferSize = InternalZipConstants.BUFF_SIZE;
private List openInputStreams = new ArrayList<>();
/**
* Creates a new ZipFile instance with the zip file at the location specified in zipFile.
* This constructor does not yet create a zip file if it does not exist. Creation happens when adding files
* to this ZipFile instance
* @param zipFile
*/
public ZipFile(String zipFile) {
this(new File(zipFile), null);
}
/**
* Creates a new ZipFile instance with the zip file at the location specified in zipFile.
* Input password will be used for any zip operations like adding files or extracting files.
* This constructor does not yet create a zip file if it does not exist. Creation happens when adding files
* to this ZipFile instance
* @param zipFile
*/
public ZipFile(String zipFile, char[] password) {
this(new File(zipFile), password);
}
/**
* Creates a new Zip File Object with the input file.
* If the zip file does not exist, it is not created at this point.
*
* @param zipFile file reference to the zip file
* @throws IllegalArgumentException when zip file parameter is null
*/
public ZipFile(File zipFile) {
this(zipFile, null);
}
/**
* Creates a new Zip File Object with the input file.
* If the zip file does not exist, it is not created at this point.
*
* @param zipFile file reference to the zip file
* @param password password to use for the zip file
* @throws IllegalArgumentException when zip file parameter is null
*/
public ZipFile(File zipFile, char[] password) {
if (zipFile == null) {
throw new IllegalArgumentException("input zip file parameter is null");
}
this.zipFile = zipFile;
this.password = password;
this.runInThread = false;
this.progressMonitor = new ProgressMonitor();
}
/**
* Creates a zip file and adds the list of source file(s) to the zip file. If the zip file
* exists then this method throws an exception. Parameters such as compression type, etc
* can be set in the input parameters. While the method addFile/addFiles also creates the
* zip file if it does not exist, the main functionality of this method is to create a split
* zip file. To create a split zip file, set the splitArchive parameter to true with a valid
* splitLength. Split Length has to be more than 65536 bytes
*
* @param filesToAdd - File to be added to the zip file
* @param parameters - zip parameters for this file list
* @param splitArchive - if archive has to be split or not
* @param splitLength - if archive has to be split, then length in bytes at which it has to be split
* @throws ZipException
*/
public void createSplitZipFile(List filesToAdd, ZipParameters parameters, boolean splitArchive,
long splitLength) throws ZipException {
if (zipFile.exists()) {
throw new ZipException("zip file: " + zipFile
+ " already exists. To add files to existing zip file use addFile method");
}
if (filesToAdd == null || filesToAdd.size() == 0) {
throw new ZipException("input file List is null, cannot create zip file");
}
createNewZipModel();
zipModel.setSplitArchive(splitArchive);
zipModel.setSplitLength(splitLength);
new AddFilesToZipTask(zipModel, password, headerWriter, buildAsyncParameters()).execute(
new AddFilesToZipTaskParameters(filesToAdd, parameters, buildConfig()));
}
/**
* Creates a zip file and adds the files/folders from the specified folder to the zip file.
* This method does the same functionality as in addFolder method except that this method
* can also create split zip files when adding a folder. To create a split zip file, set the
* splitArchive parameter to true and specify the splitLength. Split length has to be more than
* or equal to 65536 bytes. Note that this method throws an exception if the zip file already
* exists.
*
* @param folderToAdd
* @param parameters
* @param splitArchive
* @param splitLength
* @throws ZipException
*/
public void createSplitZipFileFromFolder(File folderToAdd, ZipParameters parameters, boolean splitArchive,
long splitLength) throws ZipException {
if (folderToAdd == null) {
throw new ZipException("folderToAdd is null, cannot create zip file from folder");
}
if (parameters == null) {
throw new ZipException("input parameters are null, cannot create zip file from folder");
}
if (zipFile.exists()) {
throw new ZipException("zip file: " + zipFile
+ " already exists. To add files to existing zip file use addFolder method");
}
createNewZipModel();
zipModel.setSplitArchive(splitArchive);
if (splitArchive) {
zipModel.setSplitLength(splitLength);
}
addFolder(folderToAdd, parameters, false);
}
/**
* Adds input source file to the zip file with default zip parameters. If zip file does not exist,
* this method creates a new zip file.
*
* @param fileToAdd - File with path to be added to the zip file
* @throws ZipException
*/
public void addFile(String fileToAdd) throws ZipException {
addFile(fileToAdd, new ZipParameters());
}
/**
* Adds input source file to the zip file with provided zip parameters. If zip file does not exist,
* this method creates a new zip file.
*
* @param fileToAdd - File with path to be added to the zip file
* @param zipParameters - parameters for the entry to be added to zip
* @throws ZipException
*/
public void addFile(String fileToAdd, ZipParameters zipParameters) throws ZipException {
if (!isStringNotNullAndNotEmpty(fileToAdd)) {
throw new ZipException("file to add is null or empty");
}
addFiles(Collections.singletonList(new File(fileToAdd)), zipParameters);
}
/**
* Adds input source file to the zip file with default zip parameters. If zip file does not exist,
* this method creates a new zip file.
*
* @param fileToAdd - File to be added to the zip file
* @throws ZipException
*/
public void addFile(File fileToAdd) throws ZipException {
addFiles(Collections.singletonList(fileToAdd), new ZipParameters());
}
/**
* Adds input source file to the zip file. If zip file does not exist,
* this method creates a new zip file. Parameters such as compression type, etc
* can be set in the input parameters.
*
* @param fileToAdd - File to be added to the zip file
* @param parameters - zip parameters for this file
* @throws ZipException
*/
public void addFile(File fileToAdd, ZipParameters parameters) throws ZipException {
addFiles(Collections.singletonList(fileToAdd), parameters);
}
/**
* Adds the list of input files to the zip file with default zip parameters. If zip file does not exist,
* this method creates a new zip file.
*
* @param filesToAdd
* @throws ZipException
*/
public void addFiles(List filesToAdd) throws ZipException {
addFiles(filesToAdd, new ZipParameters());
}
/**
* Adds the list of input files to the zip file. If zip file does not exist, then
* this method creates a new zip file. Parameters such as compression type, etc
* can be set in the input parameters.
*
* @param filesToAdd
* @param parameters
* @throws ZipException
*/
public void addFiles(List filesToAdd, ZipParameters parameters) throws ZipException {
if (filesToAdd == null || filesToAdd.size() == 0) {
throw new ZipException("input file List is null or empty");
}
if (parameters == null) {
throw new ZipException("input parameters are null");
}
readZipInfo();
if (zipModel == null) {
throw new ZipException("internal error: zip model is null");
}
if (zipFile.exists() && zipModel.isSplitArchive()) {
throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
}
new AddFilesToZipTask(zipModel, password, headerWriter, buildAsyncParameters()).execute(
new AddFilesToZipTaskParameters(filesToAdd, parameters, buildConfig()));
}
/**
* Adds the folder in the given file object to the zip file with default zip parameters. If zip file does not exist,
* then a new zip file is created. If input folder is invalid then an exception
* is thrown.
*
* @param folderToAdd
* @throws ZipException
*/
public void addFolder(File folderToAdd) throws ZipException {
addFolder(folderToAdd, new ZipParameters());
}
/**
* Adds the folder in the given file object to the zip file. If zip file does not exist,
* then a new zip file is created. If input folder is invalid then an exception
* is thrown. Zip parameters for the files in the folder to be added can be set in
* the input parameters
*
* @param folderToAdd
* @param zipParameters
* @throws ZipException
*/
public void addFolder(File folderToAdd, ZipParameters zipParameters) throws ZipException {
if (folderToAdd == null) {
throw new ZipException("input path is null, cannot add folder to zip file");
}
if (!folderToAdd.exists()) {
throw new ZipException("folder does not exist");
}
if (!folderToAdd.isDirectory()) {
throw new ZipException("input folder is not a directory");
}
if (!folderToAdd.canRead()) {
throw new ZipException("cannot read input folder");
}
if (zipParameters == null) {
throw new ZipException("input parameters are null, cannot add folder to zip file");
}
addFolder(folderToAdd, zipParameters, true);
}
/**
* Internal method to add a folder to the zip file.
*
* @param folderToAdd
* @param zipParameters
* @param checkSplitArchive
* @throws ZipException
*/
private void addFolder(File folderToAdd, ZipParameters zipParameters, boolean checkSplitArchive) throws ZipException {
readZipInfo();
if (zipModel == null) {
throw new ZipException("internal error: zip model is null");
}
if (checkSplitArchive) {
if (zipModel.isSplitArchive()) {
throw new ZipException("This is a split archive. Zip file format does not allow updating split/spanned files");
}
}
new AddFolderToZipTask(zipModel, password, headerWriter, buildAsyncParameters()).execute(
new AddFolderToZipTaskParameters(folderToAdd, zipParameters, buildConfig()));
}
/**
* Creates a new entry in the zip file and adds the content of the input stream to the
* zip file. ZipParameters.isSourceExternalStream and ZipParameters.fileNameInZip have to be
* set before in the input parameters. If the file name ends with / or \, this method treats the
* content as a directory. Setting the flag ProgressMonitor.setRunInThread to true will have
* no effect for this method and hence this method cannot be used to add content to zip in
* thread mode
*
* @param inputStream
* @param parameters
* @throws ZipException
*/
public void addStream(InputStream inputStream, ZipParameters parameters) throws ZipException {
if (inputStream == null) {
throw new ZipException("inputstream is null, cannot add file to zip");
}
if (parameters == null) {
throw new ZipException("zip parameters are null");
}
this.setRunInThread(false);
readZipInfo();
if (zipModel == null) {
throw new ZipException("internal error: zip model is null");
}
if (zipFile.exists() && zipModel.isSplitArchive()) {
throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
}
new AddStreamToZipTask(zipModel, password, headerWriter, buildAsyncParameters()).execute(
new AddStreamToZipTaskParameters(inputStream, parameters, buildConfig()));
}
/**
* Extracts all the files in the given zip file to the input destination path.
* If zip file does not exist or destination path is invalid then an
* exception is thrown.
*
* @param destinationPath path to which the entries of the zip are to be extracted
* @throws ZipException when an issue occurs during extraction
*/
public void extractAll(String destinationPath) throws ZipException {
extractAll(destinationPath, new UnzipParameters());
}
/**
* Extracts all entries in the zip file to the destination path considering the options defined in
* UnzipParameters
*
* @param destinationPath path to which the entries of the zip are to be extracted
* @param unzipParameters parameters to be considered during extraction
* @throws ZipException when an issue occurs during extraction
*/
public void extractAll(String destinationPath, UnzipParameters unzipParameters) throws ZipException {
if (!isStringNotNullAndNotEmpty(destinationPath)) {
throw new ZipException("output path is null or invalid");
}
if (!Zip4jUtil.createDirectoryIfNotExists(new File(destinationPath))) {
throw new ZipException("invalid output path");
}
if (zipModel == null) {
readZipInfo();
}
// Throw an exception if zipModel is still null
if (zipModel == null) {
throw new ZipException("Internal error occurred when extracting zip file");
}
new ExtractAllFilesTask(zipModel, password, unzipParameters, buildAsyncParameters()).execute(
new ExtractAllFilesTaskParameters(destinationPath, buildConfig()));
}
/**
* Extracts a specific file from the zip file to the destination path.
* If destination path is invalid, then this method throws an exception.
*
* If fileHeader is a directory, this method extracts all files under this directory
*
* @param fileHeader file header corresponding to the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(FileHeader fileHeader, String destinationPath) throws ZipException {
extractFile(fileHeader, destinationPath, null, new UnzipParameters());
}
/**
* Extracts a specific file from the zip file to the destination path.
* If destination path is invalid, then this method throws an exception.
*
* If fileHeader is a directory, this method extracts all files under this directory
*
* @param fileHeader file header corresponding to the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @param unzipParameters any parameters that have to be considered during extraction
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(FileHeader fileHeader, String destinationPath, UnzipParameters unzipParameters)
throws ZipException {
extractFile(fileHeader, destinationPath, null, unzipParameters);
}
/**
* Extracts a specific file from the zip file to the destination path.
* If destination path is invalid, then this method throws an exception.
*
* If newFileName is not null or empty, newly created file name will be replaced by
* the value in newFileName. If this value is null, then the file name will be the
* value in FileHeader.getFileName. If file being extract is a directory, the directory name
* will be replaced with the newFileName
*
* If fileHeader is a directory, this method extracts all files under this directory.
*
* Any parameters that have to be considered during extraction can be passed in through unzipParameters
*
* @param fileHeader file header corresponding to the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @param newFileName if not null, this will be the name given to the file upon extraction
* @param unzipParameters any parameters that have to be considered during extraction
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(FileHeader fileHeader, String destinationPath, String newFileName,
UnzipParameters unzipParameters) throws ZipException {
if (fileHeader == null) {
throw new ZipException("input file header is null, cannot extract file");
}
extractFile(fileHeader.getFileName(), destinationPath, newFileName, unzipParameters);
}
/**
* Extracts a specific file from the zip file to the destination path.
* This method first finds the necessary file header from the input file name.
*
* File name is relative file name in the zip file. For example if a zip file contains
* a file "a.txt", then to extract this file, input file name has to be "a.txt". Another
* example is if there is a file "b.txt" in a folder "abc" in the zip file, then the
* input file name has to be abc/b.txt
*
* If fileHeader is a directory, this method extracts all files under this directory.
*
* Throws an exception of type {@link ZipException.Type#FILE_NOT_FOUND} if file header could not be found for the given file name.
* Throws an exception if the destination path is invalid.
*
* @param fileName name of the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(String fileName, String destinationPath) throws ZipException {
extractFile(fileName, destinationPath, null, new UnzipParameters());
}
/**
* Extracts a specific file from the zip file to the destination path.
* This method first finds the necessary file header from the input file name.
*
* File name is relative file name in the zip file. For example if a zip file contains
* a file "a.txt", then to extract this file, input file name has to be "a.txt". Another
* example is if there is a file "b.txt" in a folder "abc" in the zip file, then the
* input file name has to be abc/b.txt
*
* If fileHeader is a directory, this method extracts all files under this directory.
*
* Any parameters that have to be considered during extraction can be passed in through unzipParameters
*
* Throws an exception of type {@link ZipException.Type#FILE_NOT_FOUND} if file header could not be found for the given file name.
* Throws an exception if the destination path is invalid.
*
* @param fileName name of the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @param unzipParameters any parameters that have to be considered during extraction
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(String fileName, String destinationPath, UnzipParameters unzipParameters)
throws ZipException {
extractFile(fileName, destinationPath, null, unzipParameters);
}
/**
* Extracts a specific file from the zip file to the destination path.
* This method first finds the necessary file header from the input file name.
*
* File name is relative file name in the zip file. For example if a zip file contains
* a file "a.txt", then to extract this file, input file name has to be "a.txt". Another
* example is if there is a file "b.txt" in a folder "abc" in the zip file, then the
* input file name has to be abc/b.txt
*
* If newFileName is not null or empty, newly created file name will be replaced by
* the value in newFileName. If this value is null, then the file name will be the
* value in FileHeader.getFileName. If file being extract is a directory, the directory name
* will be replaced with the newFileName
*
* If fileHeader is a directory, this method extracts all files under this directory.
*
* Throws an exception of type {@link ZipException.Type#FILE_NOT_FOUND} if file header could not be found for the given file name.
* Throws an exception if the destination path is invalid.
*
* @param fileName name of the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @param newFileName if not null, this will be the name given to the file upon extraction
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(String fileName, String destinationPath, String newFileName) throws ZipException {
extractFile(fileName, destinationPath, newFileName, new UnzipParameters());
}
/**
* Extracts a specific file from the zip file to the destination path.
* If destination path is invalid, then this method throws an exception.
*
* If newFileName is not null or empty, newly created file name will be replaced by
* the value in newFileName. If this value is null, then the file name will be the
* value in FileHeader.getFileName. If file being extract is a directory, the directory name
* will be replaced with the newFileName
*
* If fileHeader is a directory, this method extracts all files under this directory.
*
* @param fileHeader file header corresponding to the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @param newFileName if not null, this will be the name given to the file upon extraction
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(FileHeader fileHeader, String destinationPath, String newFileName) throws ZipException {
extractFile(fileHeader, destinationPath, newFileName, new UnzipParameters());
}
/**
* Extracts a specific file from the zip file to the destination path.
* This method first finds the necessary file header from the input file name.
*
* File name is relative file name in the zip file. For example if a zip file contains
* a file "a.txt", then to extract this file, input file name has to be "a.txt". Another
* example is if there is a file "b.txt" in a folder "abc" in the zip file, then the
* input file name has to be abc/b.txt
*
* If newFileName is not null or empty, newly created file name will be replaced by
* the value in newFileName. If this value is null, then the file name will be the
* value in FileHeader.getFileName. If file being extract is a directory, the directory name
* will be replaced with the newFileName
*
* If fileHeader is a directory, this method extracts all files under this directory.
*
* Any parameters that have to be considered during extraction can be passed in through unzipParameters
*
* Throws an exception of type {@link ZipException.Type#FILE_NOT_FOUND} if file header could not be found for the
* given file name.
* Throws an exception if the destination path is invalid.
*
* @param fileName name of the entry which has to be extracted
* @param destinationPath path to which the entries of the zip are to be extracted
* @param newFileName if not null, this will be the name given to the file upon extraction
* @param unzipParameters any parameters that have to be considered during extraction
* @throws ZipException when an issue occurs during extraction
*/
public void extractFile(String fileName, String destinationPath, String newFileName, UnzipParameters unzipParameters)
throws ZipException {
if (!isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("file to extract is null or empty, cannot extract file");
}
if (!isStringNotNullAndNotEmpty(destinationPath)) {
throw new ZipException("destination path is empty or null, cannot extract file");
}
if (unzipParameters == null) {
unzipParameters = new UnzipParameters();
}
readZipInfo();
new ExtractFileTask(zipModel, password, unzipParameters, buildAsyncParameters()).execute(
new ExtractFileTaskParameters(destinationPath, fileName, newFileName, buildConfig()));
}
/**
* Returns the list of file headers in the zip file. Returns an empty list if the zip file does not exist.
*
* @return list of file headers
* @throws ZipException
*/
public List getFileHeaders() throws ZipException {
readZipInfo();
if (zipModel == null || zipModel.getCentralDirectory() == null) {
return Collections.emptyList();
}
return zipModel.getCentralDirectory().getFileHeaders();
}
/**
* Returns FileHeader if a file header with the given fileHeader
* string exists in the zip model: If not returns null
*
* @param fileName
* @return FileHeader
* @throws ZipException
*/
public FileHeader getFileHeader(String fileName) throws ZipException {
if (!isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("input file name is emtpy or null, cannot get FileHeader");
}
readZipInfo();
if (zipModel == null || zipModel.getCentralDirectory() == null) {
return null;
}
return HeaderUtil.getFileHeader(zipModel, fileName);
}
/**
* Checks to see if the zip file is encrypted
*
* @return true if encrypted, false if not
* @throws ZipException
*/
public boolean isEncrypted() throws ZipException {
if (zipModel == null) {
readZipInfo();
if (zipModel == null) {
throw new ZipException("Zip Model is null");
}
}
if (zipModel.getCentralDirectory() == null || zipModel.getCentralDirectory().getFileHeaders() == null) {
throw new ZipException("invalid zip file");
}
for (FileHeader fileHeader : zipModel.getCentralDirectory().getFileHeaders()) {
if (fileHeader != null) {
if (fileHeader.isEncrypted()) {
isEncrypted = true;
break;
}
}
}
return isEncrypted;
}
/**
* Checks if the zip file is a split archive
*
* @return true if split archive, false if not
* @throws ZipException
*/
public boolean isSplitArchive() throws ZipException {
if (zipModel == null) {
readZipInfo();
if (zipModel == null) {
throw new ZipException("Zip Model is null");
}
}
return zipModel.isSplitArchive();
}
/**
* Removes the file provided in the input file header from the zip file.
*
* If zip file is a split zip file, then this method throws an exception as
* zip specification does not allow for updating split zip archives.
*
* If this file header is a directory, all files and directories
* under this directory will be removed as well.
*
* @param fileHeader
* @throws ZipException
*/
public void removeFile(FileHeader fileHeader) throws ZipException {
if (fileHeader == null) {
throw new ZipException("input file header is null, cannot remove file");
}
removeFile(fileHeader.getFileName());
}
/**
* Removes the file provided in the input parameters from the zip file.
* This method first finds the file header and then removes the file.
*
* If file does not exist, then this method throws an exception.
*
* If zip file is a split zip file, then this method throws an exception as
* zip specification does not allow for updating split zip archives.
*
* If the entry representing this file name is a directory, all files and directories
* under this directory will be removed as well.
*
* @param fileName
* @throws ZipException
*/
public void removeFile(String fileName) throws ZipException {
if (!isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("file name is empty or null, cannot remove file");
}
removeFiles(Collections.singletonList(fileName));
}
/**
* Removes all files from the zip file that match the names in the input list.
*
* If any of the file is a directory, all the files and directories under this directory
* will be removed as well
*
* If zip file is a split zip file, then this method throws an exception as
* zip specification does not allow for updating split zip archives.
*
* @param fileNames
* @throws ZipException
*/
public void removeFiles(List fileNames) throws ZipException {
if (fileNames == null) {
throw new ZipException("fileNames list is null");
}
if (fileNames.isEmpty()) {
return;
}
if (zipModel == null) {
readZipInfo();
}
if (zipModel.isSplitArchive()) {
throw new ZipException("Zip file format does not allow updating split/spanned files");
}
new RemoveFilesFromZipTask(zipModel, headerWriter, buildAsyncParameters()).execute(
new RemoveFilesFromZipTaskParameters(fileNames, buildConfig()));
}
/**
* Renames file name of the entry represented by file header. If the file name in the input file header does not
* match any entry in the zip file, the zip file will not be modified.
*
* If the file header is a folder in the zip file, all sub-files and sub-folders in the zip file will also be renamed.
*
* Zip file format does not allow modifying a split zip file. Therefore if the zip file being dealt with is a split
* zip file, this method throws an exception
*
* @param fileHeader file header to be changed
* @param newFileName the file name that has to be changed to
* @throws ZipException if fileHeader is null or newFileName is null or empty or if the zip file is a split file
*/
public void renameFile(FileHeader fileHeader, String newFileName) throws ZipException {
if (fileHeader == null) {
throw new ZipException("File header is null");
}
renameFile(fileHeader.getFileName(), newFileName);
}
/**
* Renames file name of the entry represented by input fileNameToRename. If there is no entry in the zip file matching
* the file name as in fileNameToRename, the zip file will not be modified.
*
* If the entry with fileNameToRename is a folder in the zip file, all sub-files and sub-folders in the zip file will
* also be renamed. For a folder, the fileNameToRename has to end with zip file separator "/". For example, if a
* folder name "some-folder-name" has to be modified to "new-folder-name", then value of fileNameToRename should be
* "some-folder-name/". If newFileName does not end with a separator, zip4j will add a separator.
*
* Zip file format does not allow modifying a split zip file. Therefore if the zip file being dealt with is a split
* zip file, this method throws an exception
*
* @param fileNameToRename file name in the zip that has to be renamed
* @param newFileName the file name that has to be changed to
* @throws ZipException if fileNameToRename is empty or newFileName is empty or if the zip file is a split file
*/
public void renameFile(String fileNameToRename, String newFileName) throws ZipException {
if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileNameToRename)) {
throw new ZipException("file name to be changed is null or empty");
}
if (!Zip4jUtil.isStringNotNullAndNotEmpty(newFileName)) {
throw new ZipException("newFileName is null or empty");
}
renameFiles(Collections.singletonMap(fileNameToRename, newFileName));
}
/**
* Renames all the entries in the zip file that match the keys in the map to their corresponding values in the map. If
* there are no entries matching any of the keys from the map, the zip file is not modified.
*
* If any of the entry in the map represents a folder, all files and folders will be renamed so that their parent
* represents the renamed folder.
*
* Zip file format does not allow modifying a split zip file. Therefore if the zip file being dealt with is a split
* zip file, this method throws an exception
*
* @param fileNamesMap map of file names that have to be changed with values in the map being the name to be changed to
* @throws ZipException if map is null or if the zip file is a split file
*/
public void renameFiles(Map fileNamesMap) throws ZipException {
if (fileNamesMap == null) {
throw new ZipException("fileNamesMap is null");
}
if (fileNamesMap.size() == 0) {
return;
}
readZipInfo();
if (zipModel.isSplitArchive()) {
throw new ZipException("Zip file format does not allow updating split/spanned files");
}
AsyncZipTask.AsyncTaskParameters asyncTaskParameters = buildAsyncParameters();
new RenameFilesTask(zipModel, headerWriter, new RawIO(), asyncTaskParameters).execute(
new RenameFilesTaskParameters(fileNamesMap, buildConfig()));
}
/**
* Merges split zip files into a single zip file without the need to extract the
* files in the archive
*
* @param outputZipFile
* @throws ZipException
*/
public void mergeSplitFiles(File outputZipFile) throws ZipException {
if (outputZipFile == null) {
throw new ZipException("outputZipFile is null, cannot merge split files");
}
if (outputZipFile.exists()) {
throw new ZipException("output Zip File already exists");
}
readZipInfo();
if (this.zipModel == null) {
throw new ZipException("zip model is null, corrupt zip file?");
}
new MergeSplitZipFileTask(zipModel, buildAsyncParameters()).execute(
new MergeSplitZipFileTaskParameters(outputZipFile, buildConfig()));
}
/**
* Sets comment for the Zip file
*
* @param comment
* @throws ZipException
*/
public void setComment(String comment) throws ZipException {
if (comment == null) {
throw new ZipException("input comment is null, cannot update zip file");
}
if (!zipFile.exists()) {
throw new ZipException("zip file does not exist, cannot set comment for zip file");
}
readZipInfo();
if (zipModel == null) {
throw new ZipException("zipModel is null, cannot update zip file");
}
if (zipModel.getEndOfCentralDirectoryRecord() == null) {
throw new ZipException("end of central directory is null, cannot set comment");
}
new SetCommentTask(zipModel, buildAsyncParameters()).execute(
new SetCommentTaskTaskParameters(comment, buildConfig()));
}
/**
* Returns the comment set for the Zip file
*
* @return String
* @throws ZipException
*/
public String getComment() throws ZipException {
if (!zipFile.exists()) {
throw new ZipException("zip file does not exist, cannot read comment");
}
readZipInfo();
if (zipModel == null) {
throw new ZipException("zip model is null, cannot read comment");
}
if (zipModel.getEndOfCentralDirectoryRecord() == null) {
throw new ZipException("end of central directory record is null, cannot read comment");
}
return zipModel.getEndOfCentralDirectoryRecord().getComment();
}
/**
* Returns an input stream for reading the contents of the Zip file corresponding
* to the input FileHeader. Throws an exception if the FileHeader does not exist
* in the ZipFile
*
* @param fileHeader
* @return ZipInputStream
* @throws ZipException
*/
public ZipInputStream getInputStream(FileHeader fileHeader) throws IOException {
if (fileHeader == null) {
throw new ZipException("FileHeader is null, cannot get InputStream");
}
readZipInfo();
if (zipModel == null) {
throw new ZipException("zip model is null, cannot get inputstream");
}
ZipInputStream zipInputStream = createZipInputStream(zipModel, fileHeader, password);
openInputStreams.add(zipInputStream);
return zipInputStream;
}
/**
* Checks to see if the input zip file is a valid zip file. This method
* will try to read zip headers. If headers are read successfully, this
* method returns true else false.
*
* Since v2.7.0: if the zip file is a split zip file, this method also checks to see if
* all the split files of the zip exists.
*
* @return boolean - true if a valid zip file, i.e, zip4j is able to read the
* zip headers, and in case of a split zip file, all split files of the zip exists; false otherwise
*
* @since 1.2.3
*/
public boolean isValidZipFile() {
if (!zipFile.exists()) {
return false;
}
try {
readZipInfo();
if (zipModel.isSplitArchive() && !verifyAllSplitFilesOfZipExists(getSplitZipFiles())) {
return false;
}
return true;
} catch (Exception e) {
return false;
}
}
/**
* Returns the full file path+names of all split zip files
* in an ArrayList. For example: If a split zip file(abc.zip) has a 10 split parts
* this method returns an array list with path + "abc.z01", path + "abc.z02", etc.
* Returns null if the zip file does not exist
*
* @return List of Split zip Files
* @throws ZipException
*/
public List getSplitZipFiles() throws ZipException {
readZipInfo();
return FileUtils.getSplitZipFiles(zipModel);
}
/**
* Closes any open streams that were open by an instance of this class.
*
* @throws IOException when the underlying input stream throws an exception when trying to close it
*/
@Override
public void close() throws IOException {
for (InputStream inputStream : openInputStreams) {
inputStream.close();
}
openInputStreams.clear();
}
/**
* Sets a password to be used for the zip file. Will override if a password supplied via ZipFile constructor
* @param password - char array of the password to be used
*/
public void setPassword(char[] password) {
this.password = password;
}
/**
* Returns the size of the buffer used to read streams
*
* @return size of the buffer used to read streams
*/
public int getBufferSize() {
return bufferSize;
}
/**
* Sets the size of buffer that should be used when reading streams. This size cannot be less than the value defined
* in InternalZipConstants.MIN_BUFF_SIZE
*
* @param bufferSize size of the buffer that should be used when reading streams
* @throws IllegalArgumentException if bufferSize is less than value configured in InternalZipConstants.MIN_BUFF_SIZE
*/
public void setBufferSize(int bufferSize) {
if (bufferSize < MIN_BUFF_SIZE) {
throw new IllegalArgumentException("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
}
this.bufferSize = bufferSize;
}
/**
* Reads the zip header information for this zip file. If the zip file
* does not exist, it creates an empty zip model.
* Note: This method does not read local file header information
*
* @throws ZipException
*/
private void readZipInfo() throws ZipException {
if (zipModel != null) {
return;
}
if (!zipFile.exists()) {
createNewZipModel();
return;
}
if (!zipFile.canRead()) {
throw new ZipException("no read access for the input zip file");
}
try (RandomAccessFile randomAccessFile = initializeRandomAccessFileForHeaderReading()) {
HeaderReader headerReader = new HeaderReader();
zipModel = headerReader.readAllHeaders(randomAccessFile, buildConfig());
zipModel.setZipFile(zipFile);
} catch (ZipException e) {
throw e;
} catch (IOException e) {
throw new ZipException(e);
}
}
private void createNewZipModel() {
zipModel = new ZipModel();
zipModel.setZipFile(zipFile);
}
private RandomAccessFile initializeRandomAccessFileForHeaderReading() throws IOException {
if (isNumberedSplitFile(zipFile)) {
File[] allSplitFiles = FileUtils.getAllSortedNumberedSplitFiles(zipFile);
NumberedSplitRandomAccessFile numberedSplitRandomAccessFile = new NumberedSplitRandomAccessFile(zipFile,
RandomAccessFileMode.READ.getValue(), allSplitFiles);
numberedSplitRandomAccessFile.openLastSplitFileForReading();
return numberedSplitRandomAccessFile;
}
return new RandomAccessFile(zipFile, RandomAccessFileMode.READ.getValue());
}
private AsyncZipTask.AsyncTaskParameters buildAsyncParameters() {
if (runInThread) {
if (threadFactory == null) {
threadFactory = Executors.defaultThreadFactory();
}
executorService = Executors.newSingleThreadExecutor(threadFactory);
}
return new AsyncZipTask.AsyncTaskParameters(executorService, runInThread, progressMonitor);
}
private boolean verifyAllSplitFilesOfZipExists(List allSplitFiles) {
for (File splitFile : allSplitFiles) {
if (!splitFile.exists()) {
return false;
}
}
return true;
}
public ProgressMonitor getProgressMonitor() {
return progressMonitor;
}
public boolean isRunInThread() {
return runInThread;
}
public void setRunInThread(boolean runInThread) {
this.runInThread = runInThread;
}
public File getFile() {
return zipFile;
}
/**
* Returns user defined charset that was set by setCharset() method. If no charset was explicitly defined
* (by calling setCharset()), this method returns the default charset which zip4j uses, which is utf-8.
*
* @return user-defined charset or utf-8 if no charset explicitly set
*/
public Charset getCharset() {
if (charset == null) {
return CHARSET_UTF_8;
}
return charset;
}
/**
* Sets the charset to be used for encoding file names and comments
*
* @param charset charset to use to encode file names and comments
* @throws IllegalArgumentException if charset is null
*/
public void setCharset(Charset charset) throws IllegalArgumentException {
if(charset == null) {
throw new IllegalArgumentException("charset cannot be null");
}
this.charset = charset;
}
public void setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
}
public ExecutorService getExecutorService() {
return executorService;
}
@Override
public String toString() {
return zipFile.toString();
}
private Zip4jConfig buildConfig() {
return new Zip4jConfig(charset, bufferSize);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/ 0000775 0000000 0000000 00000000000 14142654472 0022005 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/AESDecrypter.java 0000775 0000000 0000000 00000006277 14142654472 0025161 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto;
import net.lingala.zip4j.crypto.PBKDF2.MacBasedPRF;
import net.lingala.zip4j.crypto.engine.AESEngine;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import java.util.Arrays;
import static net.lingala.zip4j.crypto.AesCipherUtil.prepareBuffAESIVBytes;
import static net.lingala.zip4j.exception.ZipException.Type.WRONG_PASSWORD;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
/**
* AES Decrypter supports AE-1 and AE-2 decryption for AES-CTR with 128, 192, or 256 Key Strength
*/
public class AESDecrypter implements Decrypter {
private AESEngine aesEngine;
private MacBasedPRF mac;
private int nonce = 1;
private byte[] iv;
private byte[] counterBlock;
public AESDecrypter(AESExtraDataRecord aesExtraDataRecord, char[] password, byte[] salt, byte[] passwordVerifier) throws ZipException {
iv = new byte[AES_BLOCK_SIZE];
counterBlock = new byte[AES_BLOCK_SIZE];
init(salt, passwordVerifier, password, aesExtraDataRecord);
}
private void init(byte[] salt, byte[] passwordVerifier, char[] password, AESExtraDataRecord aesExtraDataRecord)
throws ZipException {
if (password == null || password.length <= 0) {
throw new ZipException("empty or null password provided for AES decryption", WRONG_PASSWORD);
}
final AesKeyStrength aesKeyStrength = aesExtraDataRecord.getAesKeyStrength();
final byte[] derivedKey = AesCipherUtil.derivePasswordBasedKey(salt, password, aesKeyStrength);
final byte[] derivedPasswordVerifier = AesCipherUtil.derivePasswordVerifier(derivedKey, aesKeyStrength);
if (!Arrays.equals(passwordVerifier, derivedPasswordVerifier)) {
throw new ZipException("Wrong Password", ZipException.Type.WRONG_PASSWORD);
}
aesEngine = AesCipherUtil.getAESEngine(derivedKey, aesKeyStrength);
mac = AesCipherUtil.getMacBasedPRF(derivedKey, aesKeyStrength);
}
@Override
public int decryptData(byte[] buff, int start, int len) throws ZipException {
for (int j = start; j < (start + len); j += AES_BLOCK_SIZE) {
int loopCount = (j + AES_BLOCK_SIZE <= (start + len)) ?
AES_BLOCK_SIZE : ((start + len) - j);
mac.update(buff, j, loopCount);
prepareBuffAESIVBytes(iv, nonce);
aesEngine.processBlock(iv, counterBlock);
for (int k = 0; k < loopCount; k++) {
buff[j + k] = (byte) (buff[j + k] ^ counterBlock[k]);
}
nonce++;
}
return len;
}
public byte[] getCalculatedAuthenticationBytes() {
return mac.doFinal();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/AESEncrypter.java 0000664 0000000 0000000 00000011436 14142654472 0025161 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto;
import net.lingala.zip4j.crypto.PBKDF2.MacBasedPRF;
import net.lingala.zip4j.crypto.engine.AESEngine;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import java.security.SecureRandom;
import static net.lingala.zip4j.crypto.AesCipherUtil.derivePasswordBasedKey;
import static net.lingala.zip4j.crypto.AesCipherUtil.derivePasswordVerifier;
import static net.lingala.zip4j.crypto.AesCipherUtil.getAESEngine;
import static net.lingala.zip4j.crypto.AesCipherUtil.getMacBasedPRF;
import static net.lingala.zip4j.crypto.AesCipherUtil.prepareBuffAESIVBytes;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
/**
* AES Encrypter supports AE-1 and AE-2 encryption using AES-CTR with either 128 or 256 Key Strength
*/
public class AESEncrypter implements Encrypter {
private AESEngine aesEngine;
private MacBasedPRF mac;
private final SecureRandom random = new SecureRandom();
private boolean finished;
private int nonce = 1;
private int loopCount = 0;
private final byte[] iv;
private final byte[] counterBlock;
private byte[] derivedPasswordVerifier;
private byte[] saltBytes;
public AESEncrypter(char[] password, AesKeyStrength aesKeyStrength) throws ZipException {
if (password == null || password.length == 0) {
throw new ZipException("input password is empty or null");
}
if (aesKeyStrength != AesKeyStrength.KEY_STRENGTH_128 &&
aesKeyStrength != AesKeyStrength.KEY_STRENGTH_256) {
throw new ZipException("Invalid AES key strength");
}
this.finished = false;
counterBlock = new byte[AES_BLOCK_SIZE];
iv = new byte[AES_BLOCK_SIZE];
init(password, aesKeyStrength);
}
private void init(char[] password, AesKeyStrength aesKeyStrength) throws ZipException {
saltBytes = generateSalt(aesKeyStrength.getSaltLength());
byte[] derivedKey = derivePasswordBasedKey(saltBytes, password, aesKeyStrength);
derivedPasswordVerifier = derivePasswordVerifier(derivedKey, aesKeyStrength);
aesEngine = getAESEngine(derivedKey, aesKeyStrength);
mac = getMacBasedPRF(derivedKey, aesKeyStrength);
}
public int encryptData(byte[] buff) throws ZipException {
if (buff == null) {
throw new ZipException("input bytes are null, cannot perform AES encryption");
}
return encryptData(buff, 0, buff.length);
}
public int encryptData(byte[] buff, int start, int len) throws ZipException {
if (finished) {
// A non 16 byte block has already been passed to encrypter
// non 16 byte block should be the last block of compressed data in AES encryption
// any more encryption will lead to corruption of data
throw new ZipException("AES Encrypter is in finished state (A non 16 byte block has already been passed to encrypter)");
}
if (len % 16 != 0) {
this.finished = true;
}
for (int j = start; j < (start + len); j += AES_BLOCK_SIZE) {
loopCount = (j + AES_BLOCK_SIZE <= (start + len)) ?
AES_BLOCK_SIZE : ((start + len) - j);
prepareBuffAESIVBytes(iv, nonce);
aesEngine.processBlock(iv, counterBlock);
for (int k = 0; k < loopCount; k++) {
buff[j + k] = (byte) (buff[j + k] ^ counterBlock[k]);
}
mac.update(buff, j, loopCount);
nonce++;
}
return len;
}
private byte[] generateSalt(int size) throws ZipException {
if (size != 8 && size != 16) {
throw new ZipException("invalid salt size, cannot generate salt");
}
int rounds;
if (size == 8) {
rounds = 2;
} else {
rounds = 4;
}
byte[] salt = new byte[size];
for (int j = 0; j < rounds; j++) {
int i = random.nextInt();
salt[j * 4] = (byte) (i >> 24);
salt[1 + j * 4] = (byte) (i >> 16);
salt[2 + j * 4] = (byte) (i >> 8);
salt[3 + j * 4] = (byte) i;
}
return salt;
}
public byte[] getFinalMac() {
byte[] rawMacBytes = mac.doFinal();
byte[] macBytes = new byte[10];
System.arraycopy(rawMacBytes, 0, macBytes, 0, 10);
return macBytes;
}
public byte[] getDerivedPasswordVerifier() {
return derivedPasswordVerifier;
}
public byte[] getSaltBytes() {
return saltBytes;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/AesCipherUtil.java 0000664 0000000 0000000 00000010245 14142654472 0025353 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.crypto;
import net.lingala.zip4j.crypto.PBKDF2.MacBasedPRF;
import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Engine;
import net.lingala.zip4j.crypto.PBKDF2.PBKDF2Parameters;
import net.lingala.zip4j.crypto.engine.AESEngine;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import static net.lingala.zip4j.util.InternalZipConstants.AES_HASH_CHARSET;
import static net.lingala.zip4j.util.InternalZipConstants.AES_HASH_ITERATIONS;
import static net.lingala.zip4j.util.InternalZipConstants.AES_MAC_ALGORITHM;
import static net.lingala.zip4j.util.InternalZipConstants.AES_PASSWORD_VERIFIER_LENGTH;
public class AesCipherUtil {
private static final int START_INDEX = 0;
/**
* Derive Password-Based Key for AES according to AE-1 and AE-2 Specifications
*
* @param salt Salt used for PBKDF2
* @param password Password used for PBKDF2 containing characters matching ISO-8859-1 character set
* @param aesKeyStrength Requested AES Key and MAC Strength
* @return Derived Password-Based Key
* @throws ZipException Thrown when Derived Key is not valid
*/
public static byte[] derivePasswordBasedKey(final byte[] salt, final char[] password, final AesKeyStrength aesKeyStrength) throws ZipException {
final PBKDF2Parameters parameters = new PBKDF2Parameters(AES_MAC_ALGORITHM, AES_HASH_CHARSET, salt, AES_HASH_ITERATIONS);
final PBKDF2Engine engine = new PBKDF2Engine(parameters);
final int keyLength = aesKeyStrength.getKeyLength();
final int macLength = aesKeyStrength.getMacLength();
final int derivedKeyLength = keyLength + macLength + AES_PASSWORD_VERIFIER_LENGTH;
final byte[] derivedKey = engine.deriveKey(password, derivedKeyLength);
if (derivedKey != null && derivedKey.length == derivedKeyLength) {
return derivedKey;
} else {
final String message = String.format("Derived Key invalid for Key Length [%d] MAC Length [%d]", keyLength, macLength);
throw new ZipException(message);
}
}
/**
* Derive Password Verifier using Derived Key and requested AES Key Strength
*
* @param derivedKey Derived Key
* @param aesKeyStrength AES Key Strength
* @return Derived Password Verifier
*/
public static byte[] derivePasswordVerifier(final byte[] derivedKey, final AesKeyStrength aesKeyStrength) {
byte[] derivedPasswordVerifier = new byte[AES_PASSWORD_VERIFIER_LENGTH];
final int keyMacLength = aesKeyStrength.getKeyLength() + aesKeyStrength.getMacLength();
System.arraycopy(derivedKey, keyMacLength, derivedPasswordVerifier, START_INDEX, AES_PASSWORD_VERIFIER_LENGTH);
return derivedPasswordVerifier;
}
/**
* Get MAC-Based PRF using default HMAC Algorithm defined in AE-1 and AE-2 Specification
*
* @param derivedKey Derived Key
* @param aesKeyStrength AES Key Strength
* @return Initialized MAC-Based PRF
*/
public static MacBasedPRF getMacBasedPRF(final byte[] derivedKey, final AesKeyStrength aesKeyStrength) {
final int macLength = aesKeyStrength.getMacLength();
final byte[] macKey = new byte[macLength];
System.arraycopy(derivedKey, aesKeyStrength.getKeyLength(), macKey, START_INDEX, macLength);
final MacBasedPRF macBasedPRF = new MacBasedPRF(AES_MAC_ALGORITHM);
macBasedPRF.init(macKey);
return macBasedPRF;
}
/**
* Get AES Engine using derived key and requested AES Key Strength
*
* @param derivedKey Derived Key
* @param aesKeyStrength AES Key Strength
* @return AES Engine configured with AES Key
* @throws ZipException Thrown on AESEngine initialization failures
*/
public static AESEngine getAESEngine(final byte[] derivedKey, final AesKeyStrength aesKeyStrength) throws ZipException {
final int keyLength = aesKeyStrength.getKeyLength();
final byte[] aesKey = new byte[keyLength];
System.arraycopy(derivedKey, START_INDEX, aesKey, START_INDEX, keyLength);
return new AESEngine(aesKey);
}
public static void prepareBuffAESIVBytes(byte[] buff, int nonce) {
buff[0] = (byte) nonce;
buff[1] = (byte) (nonce >> 8);
buff[2] = (byte) (nonce >> 16);
buff[3] = (byte) (nonce >> 24);
for (int i = 4; i <= 15; i++) {
buff[i] = 0;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/Decrypter.java 0000775 0000000 0000000 00000001462 14142654472 0024617 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto;
import net.lingala.zip4j.exception.ZipException;
public interface Decrypter {
int decryptData(byte[] buff, int start, int len) throws ZipException;
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/Encrypter.java 0000775 0000000 0000000 00000001551 14142654472 0024630 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto;
import net.lingala.zip4j.exception.ZipException;
public interface Encrypter {
int encryptData(byte[] buff) throws ZipException;
int encryptData(byte[] buff, int start, int len) throws ZipException;
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/PBKDF2/ 0000775 0000000 0000000 00000000000 14142654472 0022715 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/PBKDF2/BinTools.java 0000775 0000000 0000000 00000004040 14142654472 0025312 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.PBKDF2;
/*
* Source referred from Matthias Gartner's PKCS#5 implementation -
* see http://rtner.de/software/PBKDF2.html
*/
class BinTools {
public static final String hex = "0123456789ABCDEF";
public static String bin2hex(final byte[] b) {
if (b == null) {
return "";
}
StringBuffer sb = new StringBuffer(2 * b.length);
for (int i = 0; i < b.length; i++) {
int v = (256 + b[i]) % 256;
sb.append(hex.charAt((v / 16) & 15));
sb.append(hex.charAt((v % 16) & 15));
}
return sb.toString();
}
public static byte[] hex2bin(final String s) {
String m = s;
if (s == null) {
// Allow empty input string.
m = "";
} else if (s.length() % 2 != 0) {
// Assume leading zero for odd string length
m = "0" + s;
}
byte r[] = new byte[m.length() / 2];
for (int i = 0, n = 0; i < m.length(); n++) {
char h = m.charAt(i++);
char l = m.charAt(i++);
r[n] = (byte) (hex2bin(h) * 16 + hex2bin(l));
}
return r;
}
public static int hex2bin(char c) {
if (c >= '0' && c <= '9') {
return (c - '0');
}
if (c >= 'A' && c <= 'F') {
return (c - 'A' + 10);
}
if (c >= 'a' && c <= 'f') {
return (c - 'a' + 10);
}
throw new IllegalArgumentException("Input string may only contain hex digits, but found '" + c + "'");
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/PBKDF2/MacBasedPRF.java 0000775 0000000 0000000 00000004014 14142654472 0025571 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.PBKDF2;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/*
* Source referred from Matthias Gartner's PKCS#5 implementation -
* see http://rtner.de/software/PBKDF2.html
*/
public class MacBasedPRF implements PRF {
private Mac mac;
private int hLen;
private String macAlgorithm;
public MacBasedPRF(String macAlgorithm) {
this.macAlgorithm = macAlgorithm;
try {
mac = Mac.getInstance(macAlgorithm);
hLen = mac.getMacLength();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public byte[] doFinal(byte[] M) {
return mac.doFinal(M);
}
public byte[] doFinal() {
return mac.doFinal();
}
public int getHLen() {
return hLen;
}
public void init(byte[] P) {
try {
mac.init(new SecretKeySpec(P, macAlgorithm));
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}
}
public void update(byte[] U) {
try {
mac.update(U);
} catch (IllegalStateException e) {
throw new RuntimeException(e);
}
}
public void update(byte[] U, int start, int len) {
try {
mac.update(U, start, len);
} catch (IllegalStateException e) {
throw new RuntimeException(e);
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/PBKDF2/PBKDF2Engine.java 0000775 0000000 0000000 00000010174 14142654472 0025624 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.PBKDF2;
import static net.lingala.zip4j.util.Zip4jUtil.convertCharArrayToByteArray;
/*
* Source referred from Matthias Gartner's PKCS#5 implementation -
* see http://rtner.de/software/PBKDF2.html
*/
public class PBKDF2Engine {
private PBKDF2Parameters parameters;
private PRF prf;
public PBKDF2Engine(PBKDF2Parameters parameters) {
this(parameters, null);
}
public PBKDF2Engine(PBKDF2Parameters parameters, PRF prf) {
this.parameters = parameters;
this.prf = prf;
}
public byte[] deriveKey(char[] inputPassword) {
return deriveKey(inputPassword, 0);
}
public byte[] deriveKey(char[] inputPassword, int dkLen) {
byte p[];
if (inputPassword == null) {
throw new NullPointerException();
}
p = convertCharArrayToByteArray(inputPassword);
assertPRF(p);
if (dkLen == 0) {
dkLen = prf.getHLen();
}
return PBKDF2(prf, parameters.getSalt(), parameters.getIterationCount(), dkLen);
}
public boolean verifyKey(char[] inputPassword) {
byte[] referenceKey = getParameters().getDerivedKey();
if (referenceKey == null || referenceKey.length == 0) {
return false;
}
byte[] inputKey = deriveKey(inputPassword, referenceKey.length);
if (inputKey == null || inputKey.length != referenceKey.length) {
return false;
}
for (int i = 0; i < inputKey.length; i++) {
if (inputKey[i] != referenceKey[i]) {
return false;
}
}
return true;
}
private void assertPRF(byte[] P) {
if (prf == null) {
prf = new MacBasedPRF(parameters.getHashAlgorithm());
}
prf.init(P);
}
public PRF getPseudoRandomFunction() {
return prf;
}
private byte[] PBKDF2(PRF prf, byte[] S, int c, int dkLen) {
if (S == null) {
S = new byte[0];
}
int hLen = prf.getHLen();
int l = ceil(dkLen, hLen);
int r = dkLen - (l - 1) * hLen;
byte T[] = new byte[l * hLen];
int ti_offset = 0;
for (int i = 1; i <= l; i++) {
_F(T, ti_offset, prf, S, c, i);
ti_offset += hLen;
}
if (r < hLen) {
// Incomplete last block
byte DK[] = new byte[dkLen];
System.arraycopy(T, 0, DK, 0, dkLen);
return DK;
}
return T;
}
private int ceil(int a, int b) {
int m = 0;
if (a % b > 0) {
m = 1;
}
return a / b + m;
}
private void _F(byte[] dest, int offset, PRF prf, byte[] S, int c,
int blockIndex) {
int hLen = prf.getHLen();
byte U_r[] = new byte[hLen];
// U0 = S || INT (i);
byte U_i[] = new byte[S.length + 4];
System.arraycopy(S, 0, U_i, 0, S.length);
INT(U_i, S.length, blockIndex);
for (int i = 0; i < c; i++) {
U_i = prf.doFinal(U_i);
xor(U_r, U_i);
}
System.arraycopy(U_r, 0, dest, offset, hLen);
}
private void xor(byte[] dest, byte[] src) {
for (int i = 0; i < dest.length; i++) {
dest[i] ^= src[i];
}
}
protected void INT(byte[] dest, int offset, int i) {
dest[offset] = (byte) (i / (256 * 256 * 256));
dest[offset + 1] = (byte) (i / (256 * 256));
dest[offset + 2] = (byte) (i / (256));
dest[offset + 3] = (byte) (i);
}
public PBKDF2Parameters getParameters() {
return parameters;
}
public void setParameters(PBKDF2Parameters parameters) {
this.parameters = parameters;
}
public void setPseudoRandomFunction(PRF prf) {
this.prf = prf;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/PBKDF2/PBKDF2HexFormatter.java 0000775 0000000 0000000 00000002765 14142654472 0027036 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.PBKDF2;
/*
* Source referred from Matthias Gartner's PKCS#5 implementation -
* see http://rtner.de/software/PBKDF2.html
*/
class PBKDF2HexFormatter {
public boolean fromString(PBKDF2Parameters p, String s) {
if (p == null || s == null) {
return true;
}
String[] pSplit = s.split(":");
if (pSplit.length != 3) {
return true;
}
byte salt[] = BinTools.hex2bin(pSplit[0]);
int iterationCount = Integer.parseInt(pSplit[1]);
byte bDK[] = BinTools.hex2bin(pSplit[2]);
p.setSalt(salt);
p.setIterationCount(iterationCount);
p.setDerivedKey(bDK);
return false;
}
public String toString(PBKDF2Parameters p) {
String s = BinTools.bin2hex(p.getSalt()) + ":" + String.valueOf(p.getIterationCount()) + ":"
+ BinTools.bin2hex(p.getDerivedKey());
return s;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/PBKDF2/PBKDF2Parameters.java 0000775 0000000 0000000 00000004660 14142654472 0026525 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.PBKDF2;
/*
* Source referred from Matthias Gartner's PKCS#5 implementation -
* see http://rtner.de/software/PBKDF2.html
*/
public class PBKDF2Parameters {
protected byte[] salt;
protected int iterationCount;
protected String hashAlgorithm;
protected String hashCharset;
protected byte[] derivedKey;
public PBKDF2Parameters() {
this.hashAlgorithm = null;
this.hashCharset = "UTF-8";
this.salt = null;
this.iterationCount = 1000;
this.derivedKey = null;
}
public PBKDF2Parameters(String hashAlgorithm, String hashCharset, byte[] salt, int iterationCount) {
this(hashAlgorithm, hashCharset, salt, iterationCount, null);
}
public PBKDF2Parameters(String hashAlgorithm, String hashCharset, byte[] salt, int iterationCount,
byte[] derivedKey) {
this.hashAlgorithm = hashAlgorithm;
this.hashCharset = hashCharset;
this.salt = salt;
this.iterationCount = iterationCount;
this.derivedKey = derivedKey;
}
public int getIterationCount() {
return iterationCount;
}
public void setIterationCount(int iterationCount) {
this.iterationCount = iterationCount;
}
public byte[] getSalt() {
return salt;
}
public void setSalt(byte[] salt) {
this.salt = salt;
}
public byte[] getDerivedKey() {
return derivedKey;
}
public void setDerivedKey(byte[] derivedKey) {
this.derivedKey = derivedKey;
}
public String getHashAlgorithm() {
return hashAlgorithm;
}
public void setHashAlgorithm(String hashAlgorithm) {
this.hashAlgorithm = hashAlgorithm;
}
public String getHashCharset() {
return hashCharset;
}
public void setHashCharset(String hashCharset) {
this.hashCharset = hashCharset;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/PBKDF2/PRF.java 0000775 0000000 0000000 00000001564 14142654472 0024220 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.PBKDF2;
/*
* Source referred from Matthias Gartner's PKCS#5 implementation -
* see http://rtner.de/software/PBKDF2.html
*/
interface PRF {
void init(byte[] P);
byte[] doFinal(byte[] M);
int getHLen();
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/StandardDecrypter.java 0000775 0000000 0000000 00000005032 14142654472 0026275 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto;
import net.lingala.zip4j.crypto.engine.ZipCryptoEngine;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.util.InternalZipConstants;
import static net.lingala.zip4j.util.InternalZipConstants.STD_DEC_HDR_SIZE;
public class StandardDecrypter implements Decrypter {
private ZipCryptoEngine zipCryptoEngine;
public StandardDecrypter(char[] password, long crc, long lastModifiedFileTime, byte[] headerBytes) throws ZipException {
this.zipCryptoEngine = new ZipCryptoEngine();
init(headerBytes, password, lastModifiedFileTime, crc);
}
public int decryptData(byte[] buff, int start, int len) throws ZipException {
if (start < 0 || len < 0) {
throw new ZipException("one of the input parameters were null in standard decrypt data");
}
for (int i = start; i < start + len; i++) {
int val = buff[i] & 0xff;
val = (val ^ zipCryptoEngine.decryptByte()) & 0xff;
zipCryptoEngine.updateKeys((byte) val);
buff[i] = (byte) val;
}
return len;
}
private void init(byte[] headerBytes, char[] password, long lastModifiedFileTime, long crc) throws ZipException {
if (password == null || password.length <= 0) {
throw new ZipException("Wrong password!", ZipException.Type.WRONG_PASSWORD);
}
zipCryptoEngine.initKeys(password);
int result = headerBytes[0];
for (int i = 0; i < STD_DEC_HDR_SIZE; i++) {
if (i + 1 == InternalZipConstants.STD_DEC_HDR_SIZE) {
byte verificationByte = (byte) (result ^ zipCryptoEngine.decryptByte());
if (verificationByte != (byte) (crc >> 24) && verificationByte != (byte) (lastModifiedFileTime >> 8)) {
throw new ZipException("Wrong password!", ZipException.Type.WRONG_PASSWORD);
}
}
zipCryptoEngine.updateKeys((byte) (result ^ zipCryptoEngine.decryptByte()));
if (i + 1 != STD_DEC_HDR_SIZE) {
result = headerBytes[i + 1];
}
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/StandardEncrypter.java 0000775 0000000 0000000 00000005173 14142654472 0026315 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto;
import net.lingala.zip4j.crypto.engine.ZipCryptoEngine;
import net.lingala.zip4j.exception.ZipException;
import java.security.SecureRandom;
import static net.lingala.zip4j.util.InternalZipConstants.STD_DEC_HDR_SIZE;
public class StandardEncrypter implements Encrypter {
private final ZipCryptoEngine zipCryptoEngine = new ZipCryptoEngine();
private byte[] headerBytes;
public StandardEncrypter(char[] password, long key) throws ZipException {
init(password, key);
}
private void init(char[] password, long key) throws ZipException {
if (password == null || password.length <= 0) {
throw new ZipException("input password is null or empty, cannot initialize standard encrypter");
}
zipCryptoEngine.initKeys(password);
headerBytes = generateRandomBytes();
// Initialize again since the generated bytes were encrypted.
zipCryptoEngine.initKeys(password);
headerBytes[STD_DEC_HDR_SIZE - 1] = (byte) ((key >>> 24));
headerBytes[STD_DEC_HDR_SIZE - 2] = (byte) ((key >>> 16));
encryptData(headerBytes);
}
public int encryptData(byte[] buff) throws ZipException {
if (buff == null) {
throw new NullPointerException();
}
return encryptData(buff, 0, buff.length);
}
public int encryptData(byte[] buff, int start, int len) throws ZipException {
if (len < 0) {
throw new ZipException("invalid length specified to decrpyt data");
}
for (int i = start; i < start + len; i++) {
buff[i] = encryptByte(buff[i]);
}
return len;
}
protected byte encryptByte(byte val) {
byte temp_val = (byte) (val ^ zipCryptoEngine.decryptByte() & 0xff);
zipCryptoEngine.updateKeys(val);
return temp_val;
}
protected byte[] generateRandomBytes() {
byte[] buff = new byte[STD_DEC_HDR_SIZE];
SecureRandom random = new SecureRandom();
for (int i = 0; i < buff.length; i++) {
buff[i] = encryptByte((byte) random.nextInt(256));
}
return buff;
}
public byte[] getHeaderBytes() {
return headerBytes;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/engine/ 0000775 0000000 0000000 00000000000 14142654472 0023252 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/engine/AESEngine.java 0000775 0000000 0000000 00000033356 14142654472 0025670 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.engine;
import net.lingala.zip4j.exception.ZipException;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
/**
* Core Engine for AES Encryption
*
* @author Srikanth Reddy Lingala
*/
public class AESEngine {
private int rounds;
private int[][] workingKey = null;
private int C0, C1, C2, C3;
public AESEngine(byte[] key) throws ZipException {
init(key);
}
private void init(byte[] key) throws ZipException {
workingKey = generateWorkingKey(key);
}
private int[][] generateWorkingKey(byte[] key) throws ZipException {
int kc = key.length / 4;
int t;
if (((kc != 4) && (kc != 6) && (kc != 8)) || ((kc * 4) != key.length)) {
throw new ZipException("invalid key length (not 128/192/256)");
}
rounds = kc + 6;
int[][] W = new int[rounds + 1][4];
t = 0;
int i = 0;
while (i < key.length) {
W[t >> 2][t & 3] = (key[i] & 0xff) | ((key[i + 1] & 0xff) << 8) | ((key[i + 2] & 0xff) << 16)
| (key[i + 3] << 24);
i += 4;
t++;
}
int k = (rounds + 1) << 2;
for (i = kc; (i < k); i++) {
int temp = W[(i - 1) >> 2][(i - 1) & 3];
if ((i % kc) == 0) {
temp = subWord(shift(temp, 8)) ^ rcon[(i / kc) - 1];
} else if ((kc > 6) && ((i % kc) == 4)) {
temp = subWord(temp);
}
W[i >> 2][i & 3] = W[(i - kc) >> 2][(i - kc) & 3] ^ temp;
}
return W;
}
public int processBlock(byte[] in, byte[] out) throws ZipException {
return processBlock(in, 0, out, 0);
}
public int processBlock(byte[] in, int inOff, byte[] out, int outOff) throws ZipException {
if (workingKey == null) {
throw new ZipException("AES engine not initialised");
}
if ((inOff + (32 / 2)) > in.length) {
throw new ZipException("input buffer too short");
}
if ((outOff + (32 / 2)) > out.length) {
throw new ZipException("output buffer too short");
}
stateIn(in, inOff);
encryptBlock(workingKey);
stateOut(out, outOff);
return AES_BLOCK_SIZE;
}
private void stateIn(byte[] bytes, int off) {
int index = off;
C0 = (bytes[index++] & 0xff);
C0 |= (bytes[index++] & 0xff) << 8;
C0 |= (bytes[index++] & 0xff) << 16;
C0 |= bytes[index++] << 24;
C1 = (bytes[index++] & 0xff);
C1 |= (bytes[index++] & 0xff) << 8;
C1 |= (bytes[index++] & 0xff) << 16;
C1 |= bytes[index++] << 24;
C2 = (bytes[index++] & 0xff);
C2 |= (bytes[index++] & 0xff) << 8;
C2 |= (bytes[index++] & 0xff) << 16;
C2 |= bytes[index++] << 24;
C3 = (bytes[index++] & 0xff);
C3 |= (bytes[index++] & 0xff) << 8;
C3 |= (bytes[index++] & 0xff) << 16;
C3 |= bytes[index++] << 24;
}
private void stateOut(byte[] bytes, int off) {
int index = off;
bytes[index++] = (byte) C0;
bytes[index++] = (byte) (C0 >> 8);
bytes[index++] = (byte) (C0 >> 16);
bytes[index++] = (byte) (C0 >> 24);
bytes[index++] = (byte) C1;
bytes[index++] = (byte) (C1 >> 8);
bytes[index++] = (byte) (C1 >> 16);
bytes[index++] = (byte) (C1 >> 24);
bytes[index++] = (byte) C2;
bytes[index++] = (byte) (C2 >> 8);
bytes[index++] = (byte) (C2 >> 16);
bytes[index++] = (byte) (C2 >> 24);
bytes[index++] = (byte) C3;
bytes[index++] = (byte) (C3 >> 8);
bytes[index++] = (byte) (C3 >> 16);
bytes[index++] = (byte) (C3 >> 24);
}
private void encryptBlock(int[][] KW) {
int r, r0, r1, r2, r3;
C0 ^= KW[0][0];
C1 ^= KW[0][1];
C2 ^= KW[0][2];
C3 ^= KW[0][3];
r = 1;
while (r < rounds - 1) {
r0 = T0[C0 & 255] ^ shift(T0[(C1 >> 8) & 255], 24) ^ shift(T0[(C2 >> 16) & 255], 16) ^ shift(T0[(C3 >> 24) & 255], 8) ^ KW[r][0];
r1 = T0[C1 & 255] ^ shift(T0[(C2 >> 8) & 255], 24) ^ shift(T0[(C3 >> 16) & 255], 16) ^ shift(T0[(C0 >> 24) & 255], 8) ^ KW[r][1];
r2 = T0[C2 & 255] ^ shift(T0[(C3 >> 8) & 255], 24) ^ shift(T0[(C0 >> 16) & 255], 16) ^ shift(T0[(C1 >> 24) & 255], 8) ^ KW[r][2];
r3 = T0[C3 & 255] ^ shift(T0[(C0 >> 8) & 255], 24) ^ shift(T0[(C1 >> 16) & 255], 16) ^ shift(T0[(C2 >> 24) & 255], 8) ^ KW[r++][3];
C0 = T0[r0 & 255] ^ shift(T0[(r1 >> 8) & 255], 24) ^ shift(T0[(r2 >> 16) & 255], 16) ^ shift(T0[(r3 >> 24) & 255], 8) ^ KW[r][0];
C1 = T0[r1 & 255] ^ shift(T0[(r2 >> 8) & 255], 24) ^ shift(T0[(r3 >> 16) & 255], 16) ^ shift(T0[(r0 >> 24) & 255], 8) ^ KW[r][1];
C2 = T0[r2 & 255] ^ shift(T0[(r3 >> 8) & 255], 24) ^ shift(T0[(r0 >> 16) & 255], 16) ^ shift(T0[(r1 >> 24) & 255], 8) ^ KW[r][2];
C3 = T0[r3 & 255] ^ shift(T0[(r0 >> 8) & 255], 24) ^ shift(T0[(r1 >> 16) & 255], 16) ^ shift(T0[(r2 >> 24) & 255], 8) ^ KW[r++][3];
}
r0 = T0[C0 & 255] ^ shift(T0[(C1 >> 8) & 255], 24) ^ shift(T0[(C2 >> 16) & 255], 16) ^ shift(T0[(C3 >> 24) & 255], 8) ^ KW[r][0];
r1 = T0[C1 & 255] ^ shift(T0[(C2 >> 8) & 255], 24) ^ shift(T0[(C3 >> 16) & 255], 16) ^ shift(T0[(C0 >> 24) & 255], 8) ^ KW[r][1];
r2 = T0[C2 & 255] ^ shift(T0[(C3 >> 8) & 255], 24) ^ shift(T0[(C0 >> 16) & 255], 16) ^ shift(T0[(C1 >> 24) & 255], 8) ^ KW[r][2];
r3 = T0[C3 & 255] ^ shift(T0[(C0 >> 8) & 255], 24) ^ shift(T0[(C1 >> 16) & 255], 16) ^ shift(T0[(C2 >> 24) & 255], 8) ^ KW[r++][3];
C0 = (S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16) ^ (S[(r3 >> 24) & 255] << 24) ^ KW[r][0];
C1 = (S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16) ^ (S[(r0 >> 24) & 255] << 24) ^ KW[r][1];
C2 = (S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16) ^ (S[(r1 >> 24) & 255] << 24) ^ KW[r][2];
C3 = (S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16) ^ (S[(r2 >> 24) & 255] << 24) ^ KW[r][3];
}
private int shift(int r, int shift) {
return (r >>> shift) | (r << -shift);
}
private int subWord(int x) {
return (S[x & 255] & 255 | ((S[(x >> 8) & 255] & 255) << 8) | ((S[(x >> 16) & 255] & 255) << 16) | S[(x >> 24) & 255] << 24);
}
private static final byte[] S = {
(byte) 99, (byte) 124, (byte) 119, (byte) 123, (byte) 242, (byte) 107, (byte) 111, (byte) 197,
(byte) 48, (byte) 1, (byte) 103, (byte) 43, (byte) 254, (byte) 215, (byte) 171, (byte) 118,
(byte) 202, (byte) 130, (byte) 201, (byte) 125, (byte) 250, (byte) 89, (byte) 71, (byte) 240,
(byte) 173, (byte) 212, (byte) 162, (byte) 175, (byte) 156, (byte) 164, (byte) 114, (byte) 192,
(byte) 183, (byte) 253, (byte) 147, (byte) 38, (byte) 54, (byte) 63, (byte) 247, (byte) 204,
(byte) 52, (byte) 165, (byte) 229, (byte) 241, (byte) 113, (byte) 216, (byte) 49, (byte) 21,
(byte) 4, (byte) 199, (byte) 35, (byte) 195, (byte) 24, (byte) 150, (byte) 5, (byte) 154,
(byte) 7, (byte) 18, (byte) 128, (byte) 226, (byte) 235, (byte) 39, (byte) 178, (byte) 117,
(byte) 9, (byte) 131, (byte) 44, (byte) 26, (byte) 27, (byte) 110, (byte) 90, (byte) 160,
(byte) 82, (byte) 59, (byte) 214, (byte) 179, (byte) 41, (byte) 227, (byte) 47, (byte) 132,
(byte) 83, (byte) 209, (byte) 0, (byte) 237, (byte) 32, (byte) 252, (byte) 177, (byte) 91,
(byte) 106, (byte) 203, (byte) 190, (byte) 57, (byte) 74, (byte) 76, (byte) 88, (byte) 207,
(byte) 208, (byte) 239, (byte) 170, (byte) 251, (byte) 67, (byte) 77, (byte) 51, (byte) 133,
(byte) 69, (byte) 249, (byte) 2, (byte) 127, (byte) 80, (byte) 60, (byte) 159, (byte) 168,
(byte) 81, (byte) 163, (byte) 64, (byte) 143, (byte) 146, (byte) 157, (byte) 56, (byte) 245,
(byte) 188, (byte) 182, (byte) 218, (byte) 33, (byte) 16, (byte) 255, (byte) 243, (byte) 210,
(byte) 205, (byte) 12, (byte) 19, (byte) 236, (byte) 95, (byte) 151, (byte) 68, (byte) 23,
(byte) 196, (byte) 167, (byte) 126, (byte) 61, (byte) 100, (byte) 93, (byte) 25, (byte) 115,
(byte) 96, (byte) 129, (byte) 79, (byte) 220, (byte) 34, (byte) 42, (byte) 144, (byte) 136,
(byte) 70, (byte) 238, (byte) 184, (byte) 20, (byte) 222, (byte) 94, (byte) 11, (byte) 219,
(byte) 224, (byte) 50, (byte) 58, (byte) 10, (byte) 73, (byte) 6, (byte) 36, (byte) 92,
(byte) 194, (byte) 211, (byte) 172, (byte) 98, (byte) 145, (byte) 149, (byte) 228, (byte) 121,
(byte) 231, (byte) 200, (byte) 55, (byte) 109, (byte) 141, (byte) 213, (byte) 78, (byte) 169,
(byte) 108, (byte) 86, (byte) 244, (byte) 234, (byte) 101, (byte) 122, (byte) 174, (byte) 8,
(byte) 186, (byte) 120, (byte) 37, (byte) 46, (byte) 28, (byte) 166, (byte) 180, (byte) 198,
(byte) 232, (byte) 221, (byte) 116, (byte) 31, (byte) 75, (byte) 189, (byte) 139, (byte) 138,
(byte) 112, (byte) 62, (byte) 181, (byte) 102, (byte) 72, (byte) 3, (byte) 246, (byte) 14,
(byte) 97, (byte) 53, (byte) 87, (byte) 185, (byte) 134, (byte) 193, (byte) 29, (byte) 158,
(byte) 225, (byte) 248, (byte) 152, (byte) 17, (byte) 105, (byte) 217, (byte) 142, (byte) 148,
(byte) 155, (byte) 30, (byte) 135, (byte) 233, (byte) 206, (byte) 85, (byte) 40, (byte) 223,
(byte) 140, (byte) 161, (byte) 137, (byte) 13, (byte) 191, (byte) 230, (byte) 66, (byte) 104,
(byte) 65, (byte) 153, (byte) 45, (byte) 15, (byte) 176, (byte) 84, (byte) 187, (byte) 22,
};
private static final int[] rcon = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91};
private static final int[] T0 =
{
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
0x3a16162c};
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/crypto/engine/ZipCryptoEngine.java 0000775 0000000 0000000 00000003402 14142654472 0027210 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.crypto.engine;
import static net.lingala.zip4j.util.Zip4jUtil.convertCharArrayToByteArray;
public class ZipCryptoEngine {
private final int[] keys = new int[3];
private static final int[] CRC_TABLE = new int[256];
static {
for (int i = 0; i < 256; i++) {
int r = i;
for (int j = 0; j < 8; j++) {
if ((r & 1) == 1) {
r = (r >>> 1) ^ 0xedb88320;
} else {
r >>>= 1;
}
}
CRC_TABLE[i] = r;
}
}
public void initKeys(char[] password) {
keys[0] = 305419896;
keys[1] = 591751049;
keys[2] = 878082192;
byte[] bytes = convertCharArrayToByteArray(password);
for (byte b : bytes) {
updateKeys((byte) (b & 0xff));
}
}
public void updateKeys(byte charAt) {
keys[0] = crc32(keys[0], charAt);
keys[1] += keys[0] & 0xff;
keys[1] = keys[1] * 134775813 + 1;
keys[2] = crc32(keys[2], (byte) (keys[1] >> 24));
}
private int crc32(int oldCrc, byte charAt) {
return ((oldCrc >>> 8) ^ CRC_TABLE[(oldCrc ^ charAt) & 0xff]);
}
public byte decryptByte() {
int temp = keys[2] | 2;
return (byte) ((temp * (temp ^ 1)) >>> 8);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/exception/ 0000775 0000000 0000000 00000000000 14142654472 0022463 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/exception/ZipException.java 0000775 0000000 0000000 00000003064 14142654472 0025755 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.exception;
import java.io.IOException;
public class ZipException extends IOException {
private static final long serialVersionUID = 1L;
private Type type = Type.UNKNOWN;
public ZipException(String message) {
super(message);
}
public ZipException(Exception rootException) {
super(rootException);
}
public ZipException(String message, Exception rootException) {
super(message, rootException);
}
public ZipException(String message, Type type) {
super(message);
this.type = type;
}
public ZipException(String message, Throwable throwable, Type type) {
super(message, throwable);
this.type = type;
}
public Type getType() {
return type;
}
public enum Type {
WRONG_PASSWORD,
TASK_CANCELLED_EXCEPTION,
CHECKSUM_MISMATCH,
UNKNOWN_COMPRESSION_METHOD,
FILE_NOT_FOUND,
UNSUPPORTED_ENCRYPTION,
UNKNOWN
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/ 0000775 0000000 0000000 00000000000 14142654472 0022100 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/FileHeaderFactory.java 0000664 0000000 0000000 00000020073 14142654472 0026265 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import net.lingala.zip4j.util.Zip4jUtil;
import java.nio.charset.Charset;
import static net.lingala.zip4j.util.BitUtils.setBit;
import static net.lingala.zip4j.util.BitUtils.unsetBit;
import static net.lingala.zip4j.util.FileUtils.isZipEntryDirectory;
import static net.lingala.zip4j.util.ZipVersionUtils.determineVersionMadeBy;
import static net.lingala.zip4j.util.ZipVersionUtils.determineVersionNeededToExtract;
public class FileHeaderFactory {
public FileHeader generateFileHeader(ZipParameters zipParameters, boolean isSplitZip, int currentDiskNumberStart,
Charset charset, RawIO rawIO)
throws ZipException {
FileHeader fileHeader = new FileHeader();
fileHeader.setSignature(HeaderSignature.CENTRAL_DIRECTORY);
fileHeader.setVersionMadeBy(determineVersionMadeBy(zipParameters, rawIO));
fileHeader.setVersionNeededToExtract(determineVersionNeededToExtract(zipParameters).getCode());
if (zipParameters.isEncryptFiles() && zipParameters.getEncryptionMethod() == EncryptionMethod.AES) {
fileHeader.setCompressionMethod(CompressionMethod.AES_INTERNAL_ONLY);
fileHeader.setAesExtraDataRecord(generateAESExtraDataRecord(zipParameters));
fileHeader.setExtraFieldLength(fileHeader.getExtraFieldLength() + InternalZipConstants.AES_EXTRA_DATA_RECORD_SIZE);
} else {
fileHeader.setCompressionMethod(zipParameters.getCompressionMethod());
}
if (zipParameters.isEncryptFiles()) {
if (zipParameters.getEncryptionMethod() == null || zipParameters.getEncryptionMethod() == EncryptionMethod.NONE) {
throw new ZipException("Encryption method has to be set when encryptFiles flag is set in zip parameters");
}
fileHeader.setEncrypted(true);
fileHeader.setEncryptionMethod(zipParameters.getEncryptionMethod());
}
String fileName = validateAndGetFileName(zipParameters.getFileNameInZip());
fileHeader.setFileName(fileName);
fileHeader.setFileNameLength(determineFileNameLength(fileName, charset));
fileHeader.setDiskNumberStart(isSplitZip ? currentDiskNumberStart : 0);
if (zipParameters.getLastModifiedFileTime() > 0) {
fileHeader.setLastModifiedTime(Zip4jUtil.epochToExtendedDosTime(zipParameters.getLastModifiedFileTime()));
} else {
fileHeader.setLastModifiedTime(Zip4jUtil.epochToExtendedDosTime(System.currentTimeMillis()));
}
boolean isDirectory = isZipEntryDirectory(fileName);
fileHeader.setDirectory(isDirectory);
fileHeader.setExternalFileAttributes(FileUtils.getDefaultFileAttributes(isDirectory));
if (zipParameters.isWriteExtendedLocalFileHeader() && zipParameters.getEntrySize() == -1) {
fileHeader.setUncompressedSize(0);
} else {
fileHeader.setUncompressedSize(zipParameters.getEntrySize());
}
if (zipParameters.isEncryptFiles() && zipParameters.getEncryptionMethod() == EncryptionMethod.ZIP_STANDARD) {
fileHeader.setCrc(zipParameters.getEntryCRC());
}
fileHeader.setGeneralPurposeFlag(determineGeneralPurposeBitFlag(fileHeader.isEncrypted(), zipParameters, charset));
fileHeader.setDataDescriptorExists(zipParameters.isWriteExtendedLocalFileHeader());
fileHeader.setFileComment(zipParameters.getFileComment());
return fileHeader;
}
public LocalFileHeader generateLocalFileHeader(FileHeader fileHeader) {
LocalFileHeader localFileHeader = new LocalFileHeader();
localFileHeader.setSignature(HeaderSignature.LOCAL_FILE_HEADER);
localFileHeader.setVersionNeededToExtract(fileHeader.getVersionNeededToExtract());
localFileHeader.setCompressionMethod(fileHeader.getCompressionMethod());
localFileHeader.setLastModifiedTime(fileHeader.getLastModifiedTime());
localFileHeader.setUncompressedSize(fileHeader.getUncompressedSize());
localFileHeader.setFileNameLength(fileHeader.getFileNameLength());
localFileHeader.setFileName(fileHeader.getFileName());
localFileHeader.setEncrypted(fileHeader.isEncrypted());
localFileHeader.setEncryptionMethod(fileHeader.getEncryptionMethod());
localFileHeader.setAesExtraDataRecord(fileHeader.getAesExtraDataRecord());
localFileHeader.setCrc(fileHeader.getCrc());
localFileHeader.setCompressedSize(fileHeader.getCompressedSize());
localFileHeader.setGeneralPurposeFlag(fileHeader.getGeneralPurposeFlag().clone());
localFileHeader.setDataDescriptorExists(fileHeader.isDataDescriptorExists());
localFileHeader.setExtraFieldLength(fileHeader.getExtraFieldLength());
return localFileHeader;
}
private byte[] determineGeneralPurposeBitFlag(boolean isEncrypted, ZipParameters zipParameters, Charset charset) {
byte[] generalPurposeBitFlag = new byte[2];
generalPurposeBitFlag[0] = generateFirstGeneralPurposeByte(isEncrypted, zipParameters);
if(charset == null || InternalZipConstants.CHARSET_UTF_8.equals(charset)) {
// set 3rd bit which corresponds to utf-8 file name charset
generalPurposeBitFlag[1] = setBit(generalPurposeBitFlag[1], 3);
}
return generalPurposeBitFlag;
}
private byte generateFirstGeneralPurposeByte(boolean isEncrypted, ZipParameters zipParameters) {
byte firstByte = 0;
if (isEncrypted) {
firstByte = setBit(firstByte, 0);
}
if (CompressionMethod.DEFLATE.equals(zipParameters.getCompressionMethod())) {
if (CompressionLevel.NORMAL.equals(zipParameters.getCompressionLevel())) {
firstByte = unsetBit(firstByte, 1);
firstByte = unsetBit(firstByte, 2);
} else if (CompressionLevel.MAXIMUM.equals(zipParameters.getCompressionLevel())) {
firstByte = setBit(firstByte, 1);
firstByte = unsetBit(firstByte, 2);
} else if (CompressionLevel.FAST.equals(zipParameters.getCompressionLevel())) {
firstByte = unsetBit(firstByte, 1);
firstByte = setBit(firstByte, 2);
} else if (CompressionLevel.FASTEST.equals(zipParameters.getCompressionLevel())
|| CompressionLevel.ULTRA.equals(zipParameters.getCompressionLevel())) {
firstByte = setBit(firstByte, 1);
firstByte = setBit(firstByte, 2);
}
}
if (zipParameters.isWriteExtendedLocalFileHeader()) {
firstByte = setBit(firstByte, 3);
}
return firstByte;
}
private String validateAndGetFileName(String fileNameInZip) throws ZipException {
if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileNameInZip)) {
throw new ZipException("fileNameInZip is null or empty");
}
return fileNameInZip;
}
private AESExtraDataRecord generateAESExtraDataRecord(ZipParameters parameters) throws ZipException {
AESExtraDataRecord aesExtraDataRecord = new AESExtraDataRecord();
if (parameters.getAesVersion() != null) {
aesExtraDataRecord.setAesVersion(parameters.getAesVersion());
}
if (parameters.getAesKeyStrength() == AesKeyStrength.KEY_STRENGTH_128) {
aesExtraDataRecord.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_128);
} else if (parameters.getAesKeyStrength() == AesKeyStrength.KEY_STRENGTH_192) {
aesExtraDataRecord.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_192);
} else if (parameters.getAesKeyStrength() == AesKeyStrength.KEY_STRENGTH_256) {
aesExtraDataRecord.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
} else {
throw new ZipException("invalid AES key strength");
}
aesExtraDataRecord.setCompressionMethod(parameters.getCompressionMethod());
return aesExtraDataRecord;
}
private int determineFileNameLength(String fileName, Charset charset) {
return HeaderUtil.getBytesFromString(fileName, charset).length;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/HeaderReader.java 0000775 0000000 0000000 00000075107 14142654472 0025273 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.inputstream.NumberedSplitRandomAccessFile;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.CentralDirectory;
import net.lingala.zip4j.model.DataDescriptor;
import net.lingala.zip4j.model.DigitalSignature;
import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.ExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryLocator;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.Zip64ExtendedInfo;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.RawIO;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static net.lingala.zip4j.headers.HeaderUtil.decodeStringWithCharset;
import static net.lingala.zip4j.util.BitUtils.isBitSet;
import static net.lingala.zip4j.util.InternalZipConstants.ENDHDR;
import static net.lingala.zip4j.util.InternalZipConstants.MAX_COMMENT_SIZE;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP4J_DEFAULT_CHARSET;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP_64_SIZE_LIMIT;
import static net.lingala.zip4j.util.Zip4jUtil.readFully;
/**
* Helper class to read header information for the zip file
*/
public class HeaderReader {
private ZipModel zipModel;
private final RawIO rawIO = new RawIO();
private final byte[] intBuff = new byte[4];
public ZipModel readAllHeaders(RandomAccessFile zip4jRaf, Zip4jConfig zip4jConfig) throws IOException {
if (zip4jRaf.length() < ENDHDR) {
throw new ZipException("Zip file size less than minimum expected zip file size. " +
"Probably not a zip file or a corrupted zip file");
}
zipModel = new ZipModel();
try {
zipModel.setEndOfCentralDirectoryRecord(readEndOfCentralDirectoryRecord(zip4jRaf, rawIO, zip4jConfig));
} catch (ZipException e) {
throw e;
} catch (IOException e) {
e.printStackTrace();
throw new ZipException("Zip headers not found. Probably not a zip file or a corrupted zip file", e);
}
if (zipModel.getEndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory() == 0) {
return zipModel;
}
// If file is Zip64 format, Zip64 headers have to be read before reading central directory
zipModel.setZip64EndOfCentralDirectoryLocator(readZip64EndOfCentralDirectoryLocator(zip4jRaf, rawIO,
zipModel.getEndOfCentralDirectoryRecord().getOffsetOfEndOfCentralDirectory()));
if (zipModel.isZip64Format()) {
zipModel.setZip64EndOfCentralDirectoryRecord(readZip64EndCentralDirRec(zip4jRaf, rawIO));
if (zipModel.getZip64EndOfCentralDirectoryRecord() != null
&& zipModel.getZip64EndOfCentralDirectoryRecord().getNumberOfThisDisk() > 0) {
zipModel.setSplitArchive(true);
} else {
zipModel.setSplitArchive(false);
}
}
zipModel.setCentralDirectory(readCentralDirectory(zip4jRaf, rawIO, zip4jConfig.getCharset()));
return zipModel;
}
private EndOfCentralDirectoryRecord readEndOfCentralDirectoryRecord(RandomAccessFile zip4jRaf, RawIO rawIO,
Zip4jConfig zip4jConfig) throws IOException {
long offsetEndOfCentralDirectory = locateOffsetOfEndOfCentralDirectory(zip4jRaf);
seekInCurrentPart(zip4jRaf, offsetEndOfCentralDirectory + 4);
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = new EndOfCentralDirectoryRecord();
endOfCentralDirectoryRecord.setSignature(HeaderSignature.END_OF_CENTRAL_DIRECTORY);
endOfCentralDirectoryRecord.setNumberOfThisDisk(rawIO.readShortLittleEndian(zip4jRaf));
endOfCentralDirectoryRecord.setNumberOfThisDiskStartOfCentralDir(rawIO.readShortLittleEndian(zip4jRaf));
endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(
rawIO.readShortLittleEndian(zip4jRaf));
endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectory(rawIO.readShortLittleEndian(zip4jRaf));
endOfCentralDirectoryRecord.setSizeOfCentralDirectory(rawIO.readIntLittleEndian(zip4jRaf));
endOfCentralDirectoryRecord.setOffsetOfEndOfCentralDirectory(offsetEndOfCentralDirectory);
zip4jRaf.readFully(intBuff);
endOfCentralDirectoryRecord.setOffsetOfStartOfCentralDirectory(rawIO.readLongLittleEndian(intBuff, 0));
int commentLength = rawIO.readShortLittleEndian(zip4jRaf);
endOfCentralDirectoryRecord.setComment(readZipComment(zip4jRaf, commentLength, zip4jConfig.getCharset()));
zipModel.setSplitArchive(endOfCentralDirectoryRecord.getNumberOfThisDisk() > 0);
return endOfCentralDirectoryRecord;
}
private CentralDirectory readCentralDirectory(RandomAccessFile zip4jRaf, RawIO rawIO, Charset charset) throws IOException {
CentralDirectory centralDirectory = new CentralDirectory();
List fileHeaders = new ArrayList<>();
long offSetStartCentralDir = HeaderUtil.getOffsetStartOfCentralDirectory(zipModel);
long centralDirEntryCount = getNumberOfEntriesInCentralDirectory(zipModel);
zip4jRaf.seek(offSetStartCentralDir);
byte[] shortBuff = new byte[2];
byte[] intBuff = new byte[4];
for (int i = 0; i < centralDirEntryCount; i++) {
FileHeader fileHeader = new FileHeader();
if (rawIO.readIntLittleEndian(zip4jRaf) != HeaderSignature.CENTRAL_DIRECTORY.getValue()) {
throw new ZipException("Expected central directory entry not found (#" + (i + 1) + ")");
}
fileHeader.setSignature(HeaderSignature.CENTRAL_DIRECTORY);
fileHeader.setVersionMadeBy(rawIO.readShortLittleEndian(zip4jRaf));
fileHeader.setVersionNeededToExtract(rawIO.readShortLittleEndian(zip4jRaf));
byte[] generalPurposeFlags = new byte[2];
zip4jRaf.readFully(generalPurposeFlags);
fileHeader.setEncrypted(isBitSet(generalPurposeFlags[0], 0));
fileHeader.setDataDescriptorExists(isBitSet(generalPurposeFlags[0], 3));
fileHeader.setFileNameUTF8Encoded(isBitSet(generalPurposeFlags[1], 3));
fileHeader.setGeneralPurposeFlag(generalPurposeFlags.clone());
fileHeader.setCompressionMethod(CompressionMethod.getCompressionMethodFromCode(rawIO.readShortLittleEndian(
zip4jRaf)));
fileHeader.setLastModifiedTime(rawIO.readIntLittleEndian(zip4jRaf));
zip4jRaf.readFully(intBuff);
fileHeader.setCrc(rawIO.readLongLittleEndian(intBuff, 0));
fileHeader.setCompressedSize(rawIO.readLongLittleEndian(zip4jRaf, 4));
fileHeader.setUncompressedSize(rawIO.readLongLittleEndian(zip4jRaf, 4));
int fileNameLength = rawIO.readShortLittleEndian(zip4jRaf);
fileHeader.setFileNameLength(fileNameLength);
fileHeader.setExtraFieldLength(rawIO.readShortLittleEndian(zip4jRaf));
int fileCommentLength = rawIO.readShortLittleEndian(zip4jRaf);
fileHeader.setFileCommentLength(fileCommentLength);
fileHeader.setDiskNumberStart(rawIO.readShortLittleEndian(zip4jRaf));
zip4jRaf.readFully(shortBuff);
fileHeader.setInternalFileAttributes(shortBuff.clone());
zip4jRaf.readFully(intBuff);
fileHeader.setExternalFileAttributes(intBuff.clone());
zip4jRaf.readFully(intBuff);
fileHeader.setOffsetLocalHeader(rawIO.readLongLittleEndian(intBuff, 0));
if (fileNameLength > 0) {
byte[] fileNameBuff = new byte[fileNameLength];
zip4jRaf.readFully(fileNameBuff);
String fileName = decodeStringWithCharset(fileNameBuff, fileHeader.isFileNameUTF8Encoded(), charset);
fileHeader.setFileName(fileName);
} else {
fileHeader.setFileName(null);
}
fileHeader.setDirectory(isDirectory(fileHeader.getExternalFileAttributes(), fileHeader.getFileName()));
readExtraDataRecords(zip4jRaf, fileHeader);
readZip64ExtendedInfo(fileHeader, rawIO);
readAesExtraDataRecord(fileHeader, rawIO);
if (fileCommentLength > 0) {
byte[] fileCommentBuff = new byte[fileCommentLength];
zip4jRaf.readFully(fileCommentBuff);
fileHeader.setFileComment(decodeStringWithCharset(fileCommentBuff, fileHeader.isFileNameUTF8Encoded(), charset));
}
if (fileHeader.isEncrypted()) {
if (fileHeader.getAesExtraDataRecord() != null) {
fileHeader.setEncryptionMethod(EncryptionMethod.AES);
} else {
fileHeader.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
}
}
fileHeaders.add(fileHeader);
}
centralDirectory.setFileHeaders(fileHeaders);
DigitalSignature digitalSignature = new DigitalSignature();
if (rawIO.readIntLittleEndian(zip4jRaf) == HeaderSignature.DIGITAL_SIGNATURE.getValue()) {
digitalSignature.setSignature(HeaderSignature.DIGITAL_SIGNATURE);
digitalSignature.setSizeOfData(rawIO.readShortLittleEndian(zip4jRaf));
if (digitalSignature.getSizeOfData() > 0) {
byte[] signatureDataBuff = new byte[digitalSignature.getSizeOfData()];
zip4jRaf.readFully(signatureDataBuff);
digitalSignature.setSignatureData(new String(signatureDataBuff));
}
}
return centralDirectory;
}
private void readExtraDataRecords(RandomAccessFile zip4jRaf, FileHeader fileHeader)
throws IOException {
int extraFieldLength = fileHeader.getExtraFieldLength();
if (extraFieldLength <= 0) {
return;
}
fileHeader.setExtraDataRecords(readExtraDataRecords(zip4jRaf, extraFieldLength));
}
private void readExtraDataRecords(InputStream inputStream, LocalFileHeader localFileHeader)
throws IOException {
int extraFieldLength = localFileHeader.getExtraFieldLength();
if (extraFieldLength <= 0) {
return;
}
localFileHeader.setExtraDataRecords(readExtraDataRecords(inputStream, extraFieldLength));
}
private List readExtraDataRecords(RandomAccessFile zip4jRaf, int extraFieldLength)
throws IOException {
if (extraFieldLength < 4) {
if (extraFieldLength > 0) {
zip4jRaf.skipBytes(extraFieldLength);
}
return null;
}
byte[] extraFieldBuf = new byte[extraFieldLength];
zip4jRaf.read(extraFieldBuf);
try {
return parseExtraDataRecords(extraFieldBuf, extraFieldLength);
} catch (Exception e) {
// Ignore any errors when parsing extra data records
return Collections.emptyList();
}
}
private List readExtraDataRecords(InputStream inputStream, int extraFieldLength)
throws IOException {
if (extraFieldLength < 4) {
if (extraFieldLength > 0) {
inputStream.skip(extraFieldLength);
}
return null;
}
byte[] extraFieldBuf = new byte[extraFieldLength];
readFully(inputStream, extraFieldBuf);
try {
return parseExtraDataRecords(extraFieldBuf, extraFieldLength);
} catch (Exception e) {
// Ignore any errors when parsing extra data records
return Collections.emptyList();
}
}
private List parseExtraDataRecords(byte[] extraFieldBuf, int extraFieldLength) {
int counter = 0;
List extraDataRecords = new ArrayList<>();
while (counter < extraFieldLength) {
ExtraDataRecord extraDataRecord = new ExtraDataRecord();
int header = rawIO.readShortLittleEndian(extraFieldBuf, counter);
extraDataRecord.setHeader(header);
counter += 2;
int sizeOfRec = rawIO.readShortLittleEndian(extraFieldBuf, counter);
extraDataRecord.setSizeOfData(sizeOfRec);
counter += 2;
if (sizeOfRec > 0) {
byte[] data = new byte[sizeOfRec];
System.arraycopy(extraFieldBuf, counter, data, 0, sizeOfRec);
extraDataRecord.setData(data);
}
counter += sizeOfRec;
extraDataRecords.add(extraDataRecord);
}
return extraDataRecords.size() > 0 ? extraDataRecords : null;
}
private Zip64EndOfCentralDirectoryLocator readZip64EndOfCentralDirectoryLocator(RandomAccessFile zip4jRaf,
RawIO rawIO, long offsetEndOfCentralDirectoryRecord) throws IOException {
Zip64EndOfCentralDirectoryLocator zip64EndOfCentralDirectoryLocator = new Zip64EndOfCentralDirectoryLocator();
setFilePointerToReadZip64EndCentralDirLoc(zip4jRaf, offsetEndOfCentralDirectoryRecord);
int signature = rawIO.readIntLittleEndian(zip4jRaf);
if (signature == HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_LOCATOR.getValue()) {
zipModel.setZip64Format(true);
zip64EndOfCentralDirectoryLocator.setSignature(HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_LOCATOR);
} else {
zipModel.setZip64Format(false);
return null;
}
zip64EndOfCentralDirectoryLocator.setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(
rawIO.readIntLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryLocator.setOffsetZip64EndOfCentralDirectoryRecord(
rawIO.readLongLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryLocator.setTotalNumberOfDiscs(rawIO.readIntLittleEndian(zip4jRaf));
return zip64EndOfCentralDirectoryLocator;
}
private Zip64EndOfCentralDirectoryRecord readZip64EndCentralDirRec(RandomAccessFile zip4jRaf, RawIO rawIO)
throws IOException {
if (zipModel.getZip64EndOfCentralDirectoryLocator() == null) {
throw new ZipException("invalid zip64 end of central directory locator");
}
long offSetStartOfZip64CentralDir = zipModel.getZip64EndOfCentralDirectoryLocator()
.getOffsetZip64EndOfCentralDirectoryRecord();
if (offSetStartOfZip64CentralDir < 0) {
throw new ZipException("invalid offset for start of end of central directory record");
}
zip4jRaf.seek(offSetStartOfZip64CentralDir);
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = new Zip64EndOfCentralDirectoryRecord();
int signature = rawIO.readIntLittleEndian(zip4jRaf);
if (signature != HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_RECORD.getValue()) {
throw new ZipException("invalid signature for zip64 end of central directory record");
}
zip64EndOfCentralDirectoryRecord.setSignature(HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_RECORD);
zip64EndOfCentralDirectoryRecord.setSizeOfZip64EndCentralDirectoryRecord(rawIO.readLongLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setVersionMadeBy(rawIO.readShortLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setVersionNeededToExtract(rawIO.readShortLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setNumberOfThisDisk(rawIO.readIntLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setNumberOfThisDiskStartOfCentralDirectory(rawIO.readIntLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(
rawIO.readLongLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectory(rawIO.readLongLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setSizeOfCentralDirectory(rawIO.readLongLittleEndian(zip4jRaf));
zip64EndOfCentralDirectoryRecord.setOffsetStartCentralDirectoryWRTStartDiskNumber(
rawIO.readLongLittleEndian(zip4jRaf));
//zip64 extensible data sector
//44 is the size of fixed variables in this record
long extDataSecSize = zip64EndOfCentralDirectoryRecord.getSizeOfZip64EndCentralDirectoryRecord() - 44;
if (extDataSecSize > 0) {
byte[] extDataSecRecBuf = new byte[(int) extDataSecSize];
zip4jRaf.readFully(extDataSecRecBuf);
zip64EndOfCentralDirectoryRecord.setExtensibleDataSector(extDataSecRecBuf);
}
return zip64EndOfCentralDirectoryRecord;
}
private void readZip64ExtendedInfo(FileHeader fileHeader, RawIO rawIO) {
if (fileHeader.getExtraDataRecords() == null || fileHeader.getExtraDataRecords().size() <= 0) {
return;
}
Zip64ExtendedInfo zip64ExtendedInfo = readZip64ExtendedInfo(fileHeader.getExtraDataRecords(), rawIO,
fileHeader.getUncompressedSize(), fileHeader.getCompressedSize(), fileHeader.getOffsetLocalHeader(),
fileHeader.getDiskNumberStart());
if (zip64ExtendedInfo == null) {
return;
}
fileHeader.setZip64ExtendedInfo(zip64ExtendedInfo);
if (zip64ExtendedInfo.getUncompressedSize() != -1) {
fileHeader.setUncompressedSize(zip64ExtendedInfo.getUncompressedSize());
}
if (zip64ExtendedInfo.getCompressedSize() != -1) {
fileHeader.setCompressedSize(zip64ExtendedInfo.getCompressedSize());
}
if (zip64ExtendedInfo.getOffsetLocalHeader() != -1) {
fileHeader.setOffsetLocalHeader(zip64ExtendedInfo.getOffsetLocalHeader());
}
if (zip64ExtendedInfo.getDiskNumberStart() != -1) {
fileHeader.setDiskNumberStart(zip64ExtendedInfo.getDiskNumberStart());
}
}
private void readZip64ExtendedInfo(LocalFileHeader localFileHeader, RawIO rawIO) throws ZipException {
if (localFileHeader == null) {
throw new ZipException("file header is null in reading Zip64 Extended Info");
}
if (localFileHeader.getExtraDataRecords() == null || localFileHeader.getExtraDataRecords().size() <= 0) {
return;
}
Zip64ExtendedInfo zip64ExtendedInfo = readZip64ExtendedInfo(localFileHeader.getExtraDataRecords(), rawIO,
localFileHeader.getUncompressedSize(), localFileHeader.getCompressedSize(), 0, 0);
if (zip64ExtendedInfo == null) {
return;
}
localFileHeader.setZip64ExtendedInfo(zip64ExtendedInfo);
if (zip64ExtendedInfo.getUncompressedSize() != -1) {
localFileHeader.setUncompressedSize(zip64ExtendedInfo.getUncompressedSize());
}
if (zip64ExtendedInfo.getCompressedSize() != -1) {
localFileHeader.setCompressedSize(zip64ExtendedInfo.getCompressedSize());
}
}
private Zip64ExtendedInfo readZip64ExtendedInfo(List extraDataRecords, RawIO rawIO,
long uncompressedSize, long compressedSize, long offsetLocalHeader,
int diskNumberStart) {
for (ExtraDataRecord extraDataRecord : extraDataRecords) {
if (extraDataRecord == null) {
continue;
}
if (HeaderSignature.ZIP64_EXTRA_FIELD_SIGNATURE.getValue() == extraDataRecord.getHeader()) {
Zip64ExtendedInfo zip64ExtendedInfo = new Zip64ExtendedInfo();
byte[] extraData = extraDataRecord.getData();
if (extraDataRecord.getSizeOfData() <= 0) {
return null;
}
int counter = 0;
if (counter < extraDataRecord.getSizeOfData() && uncompressedSize == ZIP_64_SIZE_LIMIT) {
zip64ExtendedInfo.setUncompressedSize(rawIO.readLongLittleEndian(extraData, counter));
counter += 8;
}
if (counter < extraDataRecord.getSizeOfData() && compressedSize == ZIP_64_SIZE_LIMIT) {
zip64ExtendedInfo.setCompressedSize(rawIO.readLongLittleEndian(extraData, counter));
counter += 8;
}
if (counter < extraDataRecord.getSizeOfData() && offsetLocalHeader == ZIP_64_SIZE_LIMIT) {
zip64ExtendedInfo.setOffsetLocalHeader(rawIO.readLongLittleEndian(extraData, counter));
counter += 8;
}
if (counter < extraDataRecord.getSizeOfData() && diskNumberStart == ZIP_64_NUMBER_OF_ENTRIES_LIMIT) {
zip64ExtendedInfo.setDiskNumberStart(rawIO.readIntLittleEndian(extraData, counter));
}
return zip64ExtendedInfo;
}
}
return null;
}
private void setFilePointerToReadZip64EndCentralDirLoc(RandomAccessFile zip4jRaf,
long offsetEndOfCentralDirectoryRecord) throws IOException {
// Now the file pointer is at the end of signature of Central Dir Rec
// Seek back with the following values
// 4 -> total number of disks
// 8 -> relative offset of the zip64 end of central directory record
// 4 -> number of the disk with the start of the zip64 end of central directory
// 4 -> zip64 end of central dir locator signature
// Refer to Appnote for more information
seekInCurrentPart(zip4jRaf, offsetEndOfCentralDirectoryRecord - 4 - 8 - 4 - 4);
}
public LocalFileHeader readLocalFileHeader(InputStream inputStream, Charset charset) throws IOException {
LocalFileHeader localFileHeader = new LocalFileHeader();
byte[] intBuff = new byte[4];
//signature
int sig = rawIO.readIntLittleEndian(inputStream);
if (sig == HeaderSignature.TEMPORARY_SPANNING_MARKER.getValue()) {
sig = rawIO.readIntLittleEndian(inputStream);
}
if (sig != HeaderSignature.LOCAL_FILE_HEADER.getValue()) {
return null;
}
localFileHeader.setSignature(HeaderSignature.LOCAL_FILE_HEADER);
localFileHeader.setVersionNeededToExtract(rawIO.readShortLittleEndian(inputStream));
byte[] generalPurposeFlags = new byte[2];
if (readFully(inputStream, generalPurposeFlags) != 2) {
throw new ZipException("Could not read enough bytes for generalPurposeFlags");
}
localFileHeader.setEncrypted(isBitSet(generalPurposeFlags[0], 0));
localFileHeader.setDataDescriptorExists(isBitSet(generalPurposeFlags[0], 3));
localFileHeader.setFileNameUTF8Encoded(isBitSet(generalPurposeFlags[1], 3));
localFileHeader.setGeneralPurposeFlag(generalPurposeFlags.clone());
localFileHeader.setCompressionMethod(CompressionMethod.getCompressionMethodFromCode(
rawIO.readShortLittleEndian(inputStream)));
localFileHeader.setLastModifiedTime(rawIO.readIntLittleEndian(inputStream));
readFully(inputStream, intBuff);
localFileHeader.setCrc(rawIO.readLongLittleEndian(intBuff, 0));
localFileHeader.setCompressedSize(rawIO.readLongLittleEndian(inputStream, 4));
localFileHeader.setUncompressedSize(rawIO.readLongLittleEndian(inputStream, 4));
int fileNameLength = rawIO.readShortLittleEndian(inputStream);
localFileHeader.setFileNameLength(fileNameLength);
localFileHeader.setExtraFieldLength(rawIO.readShortLittleEndian(inputStream));
if (fileNameLength > 0) {
byte[] fileNameBuf = new byte[fileNameLength];
readFully(inputStream, fileNameBuf);
String fileName = decodeStringWithCharset(fileNameBuf, localFileHeader.isFileNameUTF8Encoded(), charset);
localFileHeader.setFileName(fileName);
localFileHeader.setDirectory(fileName.endsWith("/") || fileName.endsWith("\\"));
} else {
localFileHeader.setFileName(null);
}
readExtraDataRecords(inputStream, localFileHeader);
readZip64ExtendedInfo(localFileHeader, rawIO);
readAesExtraDataRecord(localFileHeader, rawIO);
if (localFileHeader.isEncrypted()) {
if (localFileHeader.getEncryptionMethod() == EncryptionMethod.AES) {
//Do nothing
} else {
if (isBitSet(localFileHeader.getGeneralPurposeFlag()[0], 6)) {
localFileHeader.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD_VARIANT_STRONG);
} else {
localFileHeader.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
}
}
}
return localFileHeader;
}
public DataDescriptor readDataDescriptor(InputStream inputStream, boolean isZip64Format) throws IOException {
DataDescriptor dataDescriptor = new DataDescriptor();
byte[] intBuff = new byte[4];
readFully(inputStream, intBuff);
long sigOrCrc = rawIO.readLongLittleEndian(intBuff, 0);
//According to zip specification, presence of extra data record header signature is optional.
//If this signature is present, read it and read the next 4 bytes for crc
//If signature not present, assign the read 4 bytes for crc
if (sigOrCrc == HeaderSignature.EXTRA_DATA_RECORD.getValue()) {
dataDescriptor.setSignature(HeaderSignature.EXTRA_DATA_RECORD);
readFully(inputStream, intBuff);
dataDescriptor.setCrc(rawIO.readLongLittleEndian(intBuff, 0));
} else {
dataDescriptor.setCrc(sigOrCrc);
}
if (isZip64Format) {
dataDescriptor.setCompressedSize(rawIO.readLongLittleEndian(inputStream));
dataDescriptor.setUncompressedSize(rawIO.readLongLittleEndian(inputStream));
} else {
dataDescriptor.setCompressedSize(rawIO.readIntLittleEndian(inputStream));
dataDescriptor.setUncompressedSize(rawIO.readIntLittleEndian(inputStream));
}
return dataDescriptor;
}
private void readAesExtraDataRecord(FileHeader fileHeader, RawIO rawIO) throws ZipException {
if (fileHeader.getExtraDataRecords() == null || fileHeader.getExtraDataRecords().size() <= 0) {
return;
}
AESExtraDataRecord aesExtraDataRecord = readAesExtraDataRecord(fileHeader.getExtraDataRecords(), rawIO);
if (aesExtraDataRecord != null) {
fileHeader.setAesExtraDataRecord(aesExtraDataRecord);
fileHeader.setEncryptionMethod(EncryptionMethod.AES);
}
}
private void readAesExtraDataRecord(LocalFileHeader localFileHeader, RawIO rawIO) throws ZipException {
if (localFileHeader.getExtraDataRecords() == null || localFileHeader.getExtraDataRecords().size() <= 0) {
return;
}
AESExtraDataRecord aesExtraDataRecord = readAesExtraDataRecord(localFileHeader.getExtraDataRecords(), rawIO);
if (aesExtraDataRecord != null) {
localFileHeader.setAesExtraDataRecord(aesExtraDataRecord);
localFileHeader.setEncryptionMethod(EncryptionMethod.AES);
}
}
private AESExtraDataRecord readAesExtraDataRecord(List extraDataRecords, RawIO rawIO)
throws ZipException {
if (extraDataRecords == null) {
return null;
}
for (ExtraDataRecord extraDataRecord : extraDataRecords) {
if (extraDataRecord == null) {
continue;
}
if (extraDataRecord.getHeader() == HeaderSignature.AES_EXTRA_DATA_RECORD.getValue()) {
if (extraDataRecord.getData() == null) {
throw new ZipException("corrupt AES extra data records");
}
AESExtraDataRecord aesExtraDataRecord = new AESExtraDataRecord();
aesExtraDataRecord.setSignature(HeaderSignature.AES_EXTRA_DATA_RECORD);
aesExtraDataRecord.setDataSize(extraDataRecord.getSizeOfData());
byte[] aesData = extraDataRecord.getData();
aesExtraDataRecord.setAesVersion(AesVersion.getFromVersionNumber(rawIO.readShortLittleEndian(aesData, 0)));
byte[] vendorIDBytes = new byte[2];
System.arraycopy(aesData, 2, vendorIDBytes, 0, 2);
aesExtraDataRecord.setVendorID(new String(vendorIDBytes));
aesExtraDataRecord.setAesKeyStrength(AesKeyStrength.getAesKeyStrengthFromRawCode(aesData[4] & 0xFF));
aesExtraDataRecord.setCompressionMethod(
CompressionMethod.getCompressionMethodFromCode(rawIO.readShortLittleEndian(aesData, 5)));
return aesExtraDataRecord;
}
}
return null;
}
private long getNumberOfEntriesInCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory();
}
return zipModel.getEndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory();
}
private long locateOffsetOfEndOfCentralDirectory(RandomAccessFile randomAccessFile) throws IOException {
long zipFileSize = randomAccessFile.length();
if (zipFileSize < ENDHDR) {
throw new ZipException("Zip file size less than size of zip headers. Probably not a zip file.");
}
seekInCurrentPart(randomAccessFile, zipFileSize - ENDHDR);
if (rawIO.readIntLittleEndian(randomAccessFile) == HeaderSignature.END_OF_CENTRAL_DIRECTORY.getValue()) {
return zipFileSize - ENDHDR;
}
return locateOffsetOfEndOfCentralDirectoryByReverseSeek(randomAccessFile);
}
private long locateOffsetOfEndOfCentralDirectoryByReverseSeek(RandomAccessFile randomAccessFile) throws IOException {
long currentFilePointer = randomAccessFile.length() - ENDHDR;
// reverse seek for a maximum of MAX_COMMENT_SIZE bytes
long numberOfBytesToRead = randomAccessFile.length() < MAX_COMMENT_SIZE ? randomAccessFile.length() : MAX_COMMENT_SIZE;
while (numberOfBytesToRead > 0 && currentFilePointer > 0){
seekInCurrentPart(randomAccessFile, --currentFilePointer);
if (rawIO.readIntLittleEndian(randomAccessFile) == HeaderSignature.END_OF_CENTRAL_DIRECTORY.getValue()) {
return currentFilePointer;
}
numberOfBytesToRead--;
};
throw new ZipException("Zip headers not found. Probably not a zip file");
}
private void seekInCurrentPart(RandomAccessFile randomAccessFile, long pos) throws IOException {
if (randomAccessFile instanceof NumberedSplitRandomAccessFile) {
((NumberedSplitRandomAccessFile) randomAccessFile).seekInCurrentPart(pos);
} else {
randomAccessFile.seek(pos);
}
}
private String readZipComment(RandomAccessFile raf, int commentLength, Charset charset) {
if (commentLength <= 0) {
return null;
}
try {
byte[] commentBuf = new byte[commentLength];
raf.readFully(commentBuf);
return decodeStringWithCharset(commentBuf, false, charset != null ? charset : ZIP4J_DEFAULT_CHARSET);
} catch (IOException e) {
// Ignore any exception and set comment to null if comment cannot be read
return null;
}
}
public boolean isDirectory(byte[] externalFileAttributes, String fileName) {
// first check if DOS attributes are set (lower order bytes from external attributes). If yes, check if the 4th bit
// which represents a directory is set. If UNIX attributes are set (higher order two bytes), check for the 6th bit
// in 4th byte which represents a directory flag.
if (externalFileAttributes[0] != 0 && isBitSet(externalFileAttributes[0], 4)) {
return true;
} else if (externalFileAttributes[3] != 0 && isBitSet(externalFileAttributes[3], 6)) {
return true;
}
return fileName != null && (fileName.endsWith("/") || fileName.endsWith("\\"));
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/HeaderSignature.java 0000664 0000000 0000000 00000001350 14142654472 0026014 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
public enum HeaderSignature {
LOCAL_FILE_HEADER(0x04034b50L), // "PK\003\004"
EXTRA_DATA_RECORD(0x08074b50L), // "PK\007\008"
CENTRAL_DIRECTORY(0x02014b50L), // "PK\001\002"
END_OF_CENTRAL_DIRECTORY(0x06054b50L), // "PK\005\006"
TEMPORARY_SPANNING_MARKER(0x30304b50L), // See APPNOTE.TXT 8.5.4
DIGITAL_SIGNATURE(0x05054b50L),
ARCEXTDATREC(0x08064b50L),
SPLIT_ZIP(0x08074b50L),
ZIP64_END_CENTRAL_DIRECTORY_LOCATOR(0x07064b50L),
ZIP64_END_CENTRAL_DIRECTORY_RECORD(0x06064b50),
ZIP64_EXTRA_FIELD_SIGNATURE(0x0001),
AES_EXTRA_DATA_RECORD(0x9901);
private long value;
HeaderSignature(long value) {
this.value = value;
}
public long getValue() {
return value;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/HeaderUtil.java 0000664 0000000 0000000 00000010415 14142654472 0024772 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.util.InternalZipConstants;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP4J_DEFAULT_CHARSET;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP_STANDARD_CHARSET_NAME;
import static net.lingala.zip4j.util.Zip4jUtil.isStringNotNullAndNotEmpty;
public class HeaderUtil {
public static FileHeader getFileHeader(ZipModel zipModel, String fileName) throws ZipException {
FileHeader fileHeader = getFileHeaderWithExactMatch(zipModel, fileName);
if (fileHeader == null) {
fileName = fileName.replaceAll("\\\\", "/");
fileHeader = getFileHeaderWithExactMatch(zipModel, fileName);
if (fileHeader == null) {
fileName = fileName.replaceAll("/", "\\\\");
fileHeader = getFileHeaderWithExactMatch(zipModel, fileName);
}
}
return fileHeader;
}
public static String decodeStringWithCharset(byte[] data, boolean isUtf8Encoded, Charset charset) {
if (charset != null) {
return new String(data, charset);
}
if (isUtf8Encoded) {
return new String(data, InternalZipConstants.CHARSET_UTF_8);
}
try {
return new String(data, ZIP_STANDARD_CHARSET_NAME);
} catch (UnsupportedEncodingException e) {
return new String(data);
}
}
public static byte[] getBytesFromString(String string, Charset charset) {
if (charset == null) {
return string.getBytes(ZIP4J_DEFAULT_CHARSET);
}
return string.getBytes(charset);
}
public static long getOffsetStartOfCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
}
return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}
public static List getFileHeadersUnderDirectory(List allFileHeaders, String fileName) {
List fileHeadersUnderDirectory = new ArrayList<>();
for (FileHeader fileHeader : allFileHeaders) {
if (fileHeader.getFileName().startsWith(fileName)) {
fileHeadersUnderDirectory.add(fileHeader);
}
}
return fileHeadersUnderDirectory;
}
public static long getTotalUncompressedSizeOfAllFileHeaders(List fileHeaders) {
long totalUncompressedSize = 0;
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.getZip64ExtendedInfo() != null &&
fileHeader.getZip64ExtendedInfo().getUncompressedSize() > 0) {
totalUncompressedSize += fileHeader.getZip64ExtendedInfo().getUncompressedSize();
} else {
totalUncompressedSize += fileHeader.getUncompressedSize();
}
}
return totalUncompressedSize;
}
private static FileHeader getFileHeaderWithExactMatch(ZipModel zipModel, String fileName) throws ZipException {
if (zipModel == null) {
throw new ZipException("zip model is null, cannot determine file header with exact match for fileName: "
+ fileName);
}
if (!isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("file name is null, cannot determine file header with exact match for fileName: "
+ fileName);
}
if (zipModel.getCentralDirectory() == null) {
throw new ZipException("central directory is null, cannot determine file header with exact match for fileName: "
+ fileName);
}
if (zipModel.getCentralDirectory().getFileHeaders() == null) {
throw new ZipException("file Headers are null, cannot determine file header with exact match for fileName: "
+ fileName);
}
if (zipModel.getCentralDirectory().getFileHeaders().size() == 0) {
return null;
}
for (FileHeader fileHeader : zipModel.getCentralDirectory().getFileHeaders()) {
String fileNameForHdr = fileHeader.getFileName();
if (!isStringNotNullAndNotEmpty(fileNameForHdr)) {
continue;
}
if (fileName.equalsIgnoreCase(fileNameForHdr)) {
return fileHeader;
}
}
return null;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/HeaderWriter.java 0000775 0000000 0000000 00000103041 14142654472 0025332 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.outputstream.CountingOutputStream;
import net.lingala.zip4j.io.outputstream.OutputStreamWithSplitZipSupport;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.ExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryLocator;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
import static net.lingala.zip4j.headers.HeaderUtil.getBytesFromString;
import static net.lingala.zip4j.util.FileUtils.getZipFileNameWithoutExtension;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP_64_SIZE_LIMIT;
import static net.lingala.zip4j.util.Zip4jUtil.isStringNotNullAndNotEmpty;
public class HeaderWriter {
private static final short ZIP64_EXTRA_DATA_RECORD_SIZE_LFH = 16;
private static final short ZIP64_EXTRA_DATA_RECORD_SIZE_FH = 28;
private static final short AES_EXTRA_DATA_RECORD_SIZE = 11;
private final RawIO rawIO = new RawIO();
private final byte[] longBuff = new byte[8];
private final byte[] intBuff = new byte[4];
public void writeLocalFileHeader(ZipModel zipModel, LocalFileHeader localFileHeader, OutputStream outputStream,
Charset charset) throws IOException {
try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) localFileHeader.getSignature().getValue());
rawIO.writeShortLittleEndian(byteArrayOutputStream, localFileHeader.getVersionNeededToExtract());
byteArrayOutputStream.write(localFileHeader.getGeneralPurposeFlag());
rawIO.writeShortLittleEndian(byteArrayOutputStream, localFileHeader.getCompressionMethod().getCode());
rawIO.writeLongLittleEndian(longBuff, 0, localFileHeader.getLastModifiedTime());
byteArrayOutputStream.write(longBuff, 0, 4);
rawIO.writeLongLittleEndian(longBuff, 0, localFileHeader.getCrc());
byteArrayOutputStream.write(longBuff, 0, 4);
boolean writeZip64Header = localFileHeader.getCompressedSize() >= ZIP_64_SIZE_LIMIT
|| localFileHeader.getUncompressedSize() >= ZIP_64_SIZE_LIMIT;
if (writeZip64Header) {
rawIO.writeLongLittleEndian(longBuff, 0, ZIP_64_SIZE_LIMIT);
//Set the uncompressed size to ZipConstants.ZIP_64_SIZE_LIMIT as
//these values will be stored in Zip64 extra record
byteArrayOutputStream.write(longBuff, 0, 4);
byteArrayOutputStream.write(longBuff, 0, 4);
zipModel.setZip64Format(true);
localFileHeader.setWriteCompressedSizeInZip64ExtraRecord(true);
} else {
rawIO.writeLongLittleEndian(longBuff, 0, localFileHeader.getCompressedSize());
byteArrayOutputStream.write(longBuff, 0, 4);
rawIO.writeLongLittleEndian(longBuff, 0, localFileHeader.getUncompressedSize());
byteArrayOutputStream.write(longBuff, 0, 4);
localFileHeader.setWriteCompressedSizeInZip64ExtraRecord(false);
}
byte[] fileNameBytes = new byte[0];
if (isStringNotNullAndNotEmpty(localFileHeader.getFileName())) {
fileNameBytes = getBytesFromString(localFileHeader.getFileName(), charset);
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileNameBytes.length);
int extraFieldLength = 0;
if (writeZip64Header) {
extraFieldLength += ZIP64_EXTRA_DATA_RECORD_SIZE_LFH + 4; // 4 for signature + size of record
}
if (localFileHeader.getAesExtraDataRecord() != null) {
extraFieldLength += AES_EXTRA_DATA_RECORD_SIZE;
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, extraFieldLength);
if (fileNameBytes.length > 0) {
byteArrayOutputStream.write(fileNameBytes);
}
//Zip64 should be the first extra data record that should be written
//This is NOT according to any specification but if this is changed
//corresponding logic for updateLocalFileHeader for compressed size
//has to be modified as well
if (writeZip64Header) {
rawIO.writeShortLittleEndian(byteArrayOutputStream,
(int) HeaderSignature.ZIP64_EXTRA_FIELD_SIGNATURE.getValue());
rawIO.writeShortLittleEndian(byteArrayOutputStream, ZIP64_EXTRA_DATA_RECORD_SIZE_LFH);
rawIO.writeLongLittleEndian(byteArrayOutputStream, localFileHeader.getUncompressedSize());
rawIO.writeLongLittleEndian(byteArrayOutputStream, localFileHeader.getCompressedSize());
}
if (localFileHeader.getAesExtraDataRecord() != null) {
AESExtraDataRecord aesExtraDataRecord = localFileHeader.getAesExtraDataRecord();
rawIO.writeShortLittleEndian(byteArrayOutputStream, (int) aesExtraDataRecord.getSignature().getValue());
rawIO.writeShortLittleEndian(byteArrayOutputStream, aesExtraDataRecord.getDataSize());
rawIO.writeShortLittleEndian(byteArrayOutputStream, aesExtraDataRecord.getAesVersion().getVersionNumber());
byteArrayOutputStream.write(aesExtraDataRecord.getVendorID().getBytes());
byte[] aesStrengthBytes = new byte[1];
aesStrengthBytes[0] = (byte) aesExtraDataRecord.getAesKeyStrength().getRawCode();
byteArrayOutputStream.write(aesStrengthBytes);
rawIO.writeShortLittleEndian(byteArrayOutputStream, aesExtraDataRecord.getCompressionMethod().getCode());
}
outputStream.write(byteArrayOutputStream.toByteArray());
}
}
public void writeExtendedLocalHeader(LocalFileHeader localFileHeader, OutputStream outputStream)
throws IOException {
if (localFileHeader == null || outputStream == null) {
throw new ZipException("input parameters is null, cannot write extended local header");
}
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) HeaderSignature.EXTRA_DATA_RECORD.getValue());
rawIO.writeLongLittleEndian(longBuff, 0, localFileHeader.getCrc());
byteArrayOutputStream.write(longBuff, 0, 4);
if (localFileHeader.isWriteCompressedSizeInZip64ExtraRecord()) {
rawIO.writeLongLittleEndian(byteArrayOutputStream, localFileHeader.getCompressedSize());
rawIO.writeLongLittleEndian(byteArrayOutputStream, localFileHeader.getUncompressedSize());
} else {
rawIO.writeLongLittleEndian(longBuff, 0, localFileHeader.getCompressedSize());
byteArrayOutputStream.write(longBuff, 0, 4);
rawIO.writeLongLittleEndian(longBuff, 0, localFileHeader.getUncompressedSize());
byteArrayOutputStream.write(longBuff, 0, 4);
}
outputStream.write(byteArrayOutputStream.toByteArray());
}
}
public void finalizeZipFile(ZipModel zipModel, OutputStream outputStream, Charset charset) throws IOException {
if (zipModel == null || outputStream == null) {
throw new ZipException("input parameters is null, cannot finalize zip file");
}
try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
processHeaderData(zipModel, outputStream);
long offsetCentralDir = getOffsetOfCentralDirectory(zipModel);
writeCentralDirectory(zipModel, byteArrayOutputStream, rawIO, charset);
int sizeOfCentralDir = byteArrayOutputStream.size();
if (zipModel.isZip64Format() || offsetCentralDir >= InternalZipConstants.ZIP_64_SIZE_LIMIT
|| zipModel.getCentralDirectory().getFileHeaders().size() >= InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT) {
if (zipModel.getZip64EndOfCentralDirectoryRecord() == null) {
zipModel.setZip64EndOfCentralDirectoryRecord(new Zip64EndOfCentralDirectoryRecord());
}
if (zipModel.getZip64EndOfCentralDirectoryLocator() == null) {
zipModel.setZip64EndOfCentralDirectoryLocator(new Zip64EndOfCentralDirectoryLocator());
}
zipModel.getZip64EndOfCentralDirectoryLocator().setOffsetZip64EndOfCentralDirectoryRecord(offsetCentralDir
+ sizeOfCentralDir);
if (isSplitZipFile(outputStream)) {
int currentSplitFileCounter = getCurrentSplitFileCounter(outputStream);
zipModel.getZip64EndOfCentralDirectoryLocator().setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(
currentSplitFileCounter);
zipModel.getZip64EndOfCentralDirectoryLocator().setTotalNumberOfDiscs(currentSplitFileCounter + 1);
} else {
zipModel.getZip64EndOfCentralDirectoryLocator().setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(0);
zipModel.getZip64EndOfCentralDirectoryLocator().setTotalNumberOfDiscs(1);
}
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = buildZip64EndOfCentralDirectoryRecord(zipModel,
sizeOfCentralDir, offsetCentralDir);
zipModel.setZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord);
writeZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord, byteArrayOutputStream,rawIO);
writeZip64EndOfCentralDirectoryLocator(zipModel.getZip64EndOfCentralDirectoryLocator(), byteArrayOutputStream, rawIO);
}
writeEndOfCentralDirectoryRecord(zipModel, sizeOfCentralDir, offsetCentralDir, byteArrayOutputStream, rawIO, charset);
writeZipHeaderBytes(zipModel, outputStream, byteArrayOutputStream.toByteArray(), charset);
}
}
public void finalizeZipFileWithoutValidations(ZipModel zipModel, OutputStream outputStream, Charset charset) throws IOException {
if (zipModel == null || outputStream == null) {
throw new ZipException("input parameters is null, cannot finalize zip file without validations");
}
try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
long offsetCentralDir = zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
writeCentralDirectory(zipModel, byteArrayOutputStream, rawIO, charset);
int sizeOfCentralDir = byteArrayOutputStream.size();
if (zipModel.isZip64Format() || offsetCentralDir >= InternalZipConstants.ZIP_64_SIZE_LIMIT
|| zipModel.getCentralDirectory().getFileHeaders().size() >= InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT) {
if (zipModel.getZip64EndOfCentralDirectoryRecord() == null) {
zipModel.setZip64EndOfCentralDirectoryRecord(new Zip64EndOfCentralDirectoryRecord());
}
if (zipModel.getZip64EndOfCentralDirectoryLocator() == null) {
zipModel.setZip64EndOfCentralDirectoryLocator(new Zip64EndOfCentralDirectoryLocator());
}
zipModel.getZip64EndOfCentralDirectoryLocator().setOffsetZip64EndOfCentralDirectoryRecord(offsetCentralDir
+ sizeOfCentralDir);
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = buildZip64EndOfCentralDirectoryRecord(zipModel,
sizeOfCentralDir, offsetCentralDir);
zipModel.setZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord);
writeZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord, byteArrayOutputStream,rawIO);
writeZip64EndOfCentralDirectoryLocator(zipModel.getZip64EndOfCentralDirectoryLocator(), byteArrayOutputStream, rawIO);
}
writeEndOfCentralDirectoryRecord(zipModel, sizeOfCentralDir, offsetCentralDir, byteArrayOutputStream, rawIO, charset);
writeZipHeaderBytes(zipModel, outputStream, byteArrayOutputStream.toByteArray(), charset);
}
}
public void updateLocalFileHeader(FileHeader fileHeader, ZipModel zipModel, SplitOutputStream outputStream)
throws IOException {
if (fileHeader == null || zipModel == null) {
throw new ZipException("invalid input parameters, cannot update local file header");
}
boolean closeFlag = false;
SplitOutputStream currOutputStream;
if (fileHeader.getDiskNumberStart() != outputStream.getCurrentSplitFileCounter()) {
String parentFile = zipModel.getZipFile().getParent();
String fileNameWithoutExt = getZipFileNameWithoutExtension(zipModel.getZipFile().getName());
String fileName = "";
if (parentFile != null) {
fileName = parentFile + System.getProperty("file.separator");
}
if (fileHeader.getDiskNumberStart() < 9) {
fileName += fileNameWithoutExt + ".z0" + (fileHeader.getDiskNumberStart() + 1);
} else {
fileName += fileNameWithoutExt + ".z" + (fileHeader.getDiskNumberStart() + 1);
}
currOutputStream = new SplitOutputStream(new File(fileName));
closeFlag = true;
} else {
currOutputStream = outputStream;
}
long currOffset = currOutputStream.getFilePointer();
currOutputStream.seek(fileHeader.getOffsetLocalHeader() + InternalZipConstants.UPDATE_LFH_CRC);
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getCrc());
currOutputStream.write(longBuff, 0, 4);
updateFileSizesInLocalFileHeader(currOutputStream, fileHeader);
if (closeFlag) {
currOutputStream.close();
} else {
outputStream.seek(currOffset);
}
}
private void updateFileSizesInLocalFileHeader(SplitOutputStream outputStream, FileHeader fileHeader)
throws IOException {
if (fileHeader.getUncompressedSize() >= ZIP_64_SIZE_LIMIT) {
rawIO.writeLongLittleEndian(longBuff, 0, ZIP_64_SIZE_LIMIT);
outputStream.write(longBuff, 0, 4);
outputStream.write(longBuff, 0, 4);
//2 - file name length
//2 - extra field length
//variable - file name which can be determined by fileNameLength
//2 - Zip64 signature
//2 - size of zip64 data
//8 - uncompressed size
//8 - compressed size
int zip64CompressedSizeOffset = 2 + 2 + fileHeader.getFileNameLength() + 2 + 2;
if (outputStream.skipBytes(zip64CompressedSizeOffset) != zip64CompressedSizeOffset) {
throw new ZipException("Unable to skip " + zip64CompressedSizeOffset + " bytes to update LFH");
}
rawIO.writeLongLittleEndian(outputStream, fileHeader.getUncompressedSize());
rawIO.writeLongLittleEndian(outputStream, fileHeader.getCompressedSize());
} else {
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getCompressedSize());
outputStream.write(longBuff, 0, 4);
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getUncompressedSize());
outputStream.write(longBuff, 0, 4);
}
}
private boolean isSplitZipFile(OutputStream outputStream) {
if (outputStream instanceof SplitOutputStream) {
return ((SplitOutputStream) outputStream).isSplitZipFile();
} else if (outputStream instanceof CountingOutputStream) {
return ((CountingOutputStream) outputStream).isSplitZipFile();
}
return false;
}
private int getCurrentSplitFileCounter(OutputStream outputStream) {
if (outputStream instanceof SplitOutputStream) {
return ((SplitOutputStream) outputStream).getCurrentSplitFileCounter();
}
return ((CountingOutputStream) outputStream).getCurrentSplitFileCounter();
}
private void writeZipHeaderBytes(ZipModel zipModel, OutputStream outputStream, byte[] buff, Charset charset)
throws IOException {
if (buff == null) {
throw new ZipException("invalid buff to write as zip headers");
}
if (outputStream instanceof CountingOutputStream) {
if (((CountingOutputStream) outputStream).checkBuffSizeAndStartNextSplitFile(buff.length)) {
finalizeZipFile(zipModel, outputStream, charset);
return;
}
}
outputStream.write(buff);
}
private void processHeaderData(ZipModel zipModel, OutputStream outputStream) throws IOException {
int currentSplitFileCounter = 0;
if (outputStream instanceof OutputStreamWithSplitZipSupport) {
zipModel.getEndOfCentralDirectoryRecord().setOffsetOfStartOfCentralDirectory(
((OutputStreamWithSplitZipSupport) outputStream).getFilePointer());
currentSplitFileCounter = ((OutputStreamWithSplitZipSupport) outputStream).getCurrentSplitFileCounter();
}
if (zipModel.isZip64Format()) {
if (zipModel.getZip64EndOfCentralDirectoryRecord() == null) {
zipModel.setZip64EndOfCentralDirectoryRecord(new Zip64EndOfCentralDirectoryRecord());
}
if (zipModel.getZip64EndOfCentralDirectoryLocator() == null) {
zipModel.setZip64EndOfCentralDirectoryLocator(new Zip64EndOfCentralDirectoryLocator());
}
zipModel.getZip64EndOfCentralDirectoryRecord().setOffsetStartCentralDirectoryWRTStartDiskNumber(
zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory());
zipModel.getZip64EndOfCentralDirectoryLocator().setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(
currentSplitFileCounter);
zipModel.getZip64EndOfCentralDirectoryLocator().setTotalNumberOfDiscs(currentSplitFileCounter + 1);
}
zipModel.getEndOfCentralDirectoryRecord().setNumberOfThisDisk(currentSplitFileCounter);
zipModel.getEndOfCentralDirectoryRecord().setNumberOfThisDiskStartOfCentralDir(currentSplitFileCounter);
}
private void writeCentralDirectory(ZipModel zipModel, ByteArrayOutputStream byteArrayOutputStream, RawIO rawIO,
Charset charset) throws ZipException {
if (zipModel.getCentralDirectory() == null || zipModel.getCentralDirectory().getFileHeaders() == null
|| zipModel.getCentralDirectory().getFileHeaders().size() <= 0) {
return;
}
for (FileHeader fileHeader: zipModel.getCentralDirectory().getFileHeaders()) {
writeFileHeader(zipModel, fileHeader, byteArrayOutputStream, rawIO, charset);
}
}
private void writeFileHeader(ZipModel zipModel, FileHeader fileHeader, ByteArrayOutputStream byteArrayOutputStream,
RawIO rawIO, Charset charset) throws ZipException {
if (fileHeader == null) {
throw new ZipException("input parameters is null, cannot write local file header");
}
try {
final byte[] emptyShortByte = {0, 0};
boolean writeZip64ExtendedInfo = isZip64Entry(fileHeader);
rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) fileHeader.getSignature().getValue());
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileHeader.getVersionMadeBy());
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileHeader.getVersionNeededToExtract());
byteArrayOutputStream.write(fileHeader.getGeneralPurposeFlag());
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileHeader.getCompressionMethod().getCode());
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getLastModifiedTime());
byteArrayOutputStream.write(longBuff, 0, 4);
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getCrc());
byteArrayOutputStream.write(longBuff, 0, 4);
if (writeZip64ExtendedInfo) {
rawIO.writeLongLittleEndian(longBuff, 0, ZIP_64_SIZE_LIMIT);
byteArrayOutputStream.write(longBuff, 0, 4);
byteArrayOutputStream.write(longBuff, 0, 4);
zipModel.setZip64Format(true);
} else {
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getCompressedSize());
byteArrayOutputStream.write(longBuff, 0, 4);
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getUncompressedSize());
byteArrayOutputStream.write(longBuff, 0, 4);
}
byte[] fileNameBytes = new byte[0];
if (isStringNotNullAndNotEmpty(fileHeader.getFileName())) {
fileNameBytes = getBytesFromString(fileHeader.getFileName(), charset);
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileNameBytes.length);
//Compute offset bytes before extra field is written for Zip64 compatibility
//NOTE: this data is not written now, but written at a later point
byte[] offsetLocalHeaderBytes = new byte[4];
if (writeZip64ExtendedInfo) {
rawIO.writeLongLittleEndian(longBuff, 0, ZIP_64_SIZE_LIMIT);
System.arraycopy(longBuff, 0, offsetLocalHeaderBytes, 0, 4);
} else {
rawIO.writeLongLittleEndian(longBuff, 0, fileHeader.getOffsetLocalHeader());
System.arraycopy(longBuff, 0, offsetLocalHeaderBytes, 0, 4);
}
int extraFieldLength = calculateExtraDataRecordsSize(fileHeader, writeZip64ExtendedInfo);
rawIO.writeShortLittleEndian(byteArrayOutputStream, extraFieldLength);
String fileComment = fileHeader.getFileComment();
byte[] fileCommentBytes = new byte[0];
if (isStringNotNullAndNotEmpty(fileComment)) {
fileCommentBytes = getBytesFromString(fileComment, charset);
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileCommentBytes.length);
if (writeZip64ExtendedInfo) {
rawIO.writeIntLittleEndian(intBuff, 0, ZIP_64_NUMBER_OF_ENTRIES_LIMIT);
byteArrayOutputStream.write(intBuff, 0, 2);
} else {
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileHeader.getDiskNumberStart());
}
byteArrayOutputStream.write(emptyShortByte);
//External file attributes
byteArrayOutputStream.write(fileHeader.getExternalFileAttributes());
//offset local header - this data is computed above
byteArrayOutputStream.write(offsetLocalHeaderBytes);
if (fileNameBytes.length > 0) {
byteArrayOutputStream.write(fileNameBytes);
}
if (writeZip64ExtendedInfo) {
zipModel.setZip64Format(true);
//Zip64 header
rawIO.writeShortLittleEndian(byteArrayOutputStream,
(int) HeaderSignature.ZIP64_EXTRA_FIELD_SIGNATURE.getValue());
//size of data
rawIO.writeShortLittleEndian(byteArrayOutputStream, ZIP64_EXTRA_DATA_RECORD_SIZE_FH);
rawIO.writeLongLittleEndian(byteArrayOutputStream, fileHeader.getUncompressedSize());
rawIO.writeLongLittleEndian(byteArrayOutputStream, fileHeader.getCompressedSize());
rawIO.writeLongLittleEndian(byteArrayOutputStream, fileHeader.getOffsetLocalHeader());
rawIO.writeIntLittleEndian(byteArrayOutputStream, fileHeader.getDiskNumberStart());
}
if (fileHeader.getAesExtraDataRecord() != null) {
AESExtraDataRecord aesExtraDataRecord = fileHeader.getAesExtraDataRecord();
rawIO.writeShortLittleEndian(byteArrayOutputStream, (int) aesExtraDataRecord.getSignature().getValue());
rawIO.writeShortLittleEndian(byteArrayOutputStream, aesExtraDataRecord.getDataSize());
rawIO.writeShortLittleEndian(byteArrayOutputStream, aesExtraDataRecord.getAesVersion().getVersionNumber());
byteArrayOutputStream.write(aesExtraDataRecord.getVendorID().getBytes());
byte[] aesStrengthBytes = new byte[1];
aesStrengthBytes[0] = (byte) aesExtraDataRecord.getAesKeyStrength().getRawCode();
byteArrayOutputStream.write(aesStrengthBytes);
rawIO.writeShortLittleEndian(byteArrayOutputStream, aesExtraDataRecord.getCompressionMethod().getCode());
}
writeRemainingExtraDataRecordsIfPresent(fileHeader, byteArrayOutputStream);
if (fileCommentBytes.length > 0) {
byteArrayOutputStream.write(fileCommentBytes);
}
} catch (Exception e) {
throw new ZipException(e);
}
}
private int calculateExtraDataRecordsSize(FileHeader fileHeader, boolean writeZip64ExtendedInfo) {
int extraFieldLength = 0;
if (writeZip64ExtendedInfo) {
extraFieldLength += ZIP64_EXTRA_DATA_RECORD_SIZE_FH + 4; // 4 for signature + size of record
}
if (fileHeader.getAesExtraDataRecord() != null) {
extraFieldLength += AES_EXTRA_DATA_RECORD_SIZE;
}
if (fileHeader.getExtraDataRecords() != null) {
for (ExtraDataRecord extraDataRecord : fileHeader.getExtraDataRecords()) {
if (extraDataRecord.getHeader() == HeaderSignature.AES_EXTRA_DATA_RECORD.getValue()
|| extraDataRecord.getHeader() == HeaderSignature.ZIP64_EXTRA_FIELD_SIGNATURE.getValue()) {
continue;
}
extraFieldLength += 4 + extraDataRecord.getSizeOfData(); // 4 = 2 for header + 2 for size of data
}
}
return extraFieldLength;
}
private void writeRemainingExtraDataRecordsIfPresent(FileHeader fileHeader, OutputStream outputStream)
throws IOException {
if (fileHeader.getExtraDataRecords() == null || fileHeader.getExtraDataRecords().size() == 0) {
return;
}
for (ExtraDataRecord extraDataRecord : fileHeader.getExtraDataRecords()) {
if (extraDataRecord.getHeader() == HeaderSignature.AES_EXTRA_DATA_RECORD.getValue()
|| extraDataRecord.getHeader() == HeaderSignature.ZIP64_EXTRA_FIELD_SIGNATURE.getValue()) {
continue;
}
rawIO.writeShortLittleEndian(outputStream, (int) extraDataRecord.getHeader());
rawIO.writeShortLittleEndian(outputStream, extraDataRecord.getSizeOfData());
if (extraDataRecord.getSizeOfData() > 0 && extraDataRecord.getData() != null) {
outputStream.write(extraDataRecord.getData());
}
}
}
private void writeZip64EndOfCentralDirectoryRecord(Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord,
ByteArrayOutputStream byteArrayOutputStream, RawIO rawIO) throws IOException {
rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) zip64EndOfCentralDirectoryRecord.getSignature().getValue());
rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getSizeOfZip64EndCentralDirectoryRecord());
rawIO.writeShortLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getVersionMadeBy());
rawIO.writeShortLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getVersionNeededToExtract());
rawIO.writeIntLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getNumberOfThisDisk());
rawIO.writeIntLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getNumberOfThisDiskStartOfCentralDirectory());
rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectoryOnThisDisk());
rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectory());
rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getSizeOfCentralDirectory());
rawIO.writeLongLittleEndian(byteArrayOutputStream, zip64EndOfCentralDirectoryRecord.getOffsetStartCentralDirectoryWRTStartDiskNumber());
}
private void writeZip64EndOfCentralDirectoryLocator(Zip64EndOfCentralDirectoryLocator zip64EndOfCentralDirectoryLocator,
ByteArrayOutputStream byteArrayOutputStream,
RawIO rawIO) throws IOException {
rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_LOCATOR.getValue());
rawIO.writeIntLittleEndian(byteArrayOutputStream,
zip64EndOfCentralDirectoryLocator.getNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord());
rawIO.writeLongLittleEndian(byteArrayOutputStream,
zip64EndOfCentralDirectoryLocator.getOffsetZip64EndOfCentralDirectoryRecord());
rawIO.writeIntLittleEndian(byteArrayOutputStream,
zip64EndOfCentralDirectoryLocator.getTotalNumberOfDiscs());
}
private void writeEndOfCentralDirectoryRecord(ZipModel zipModel, int sizeOfCentralDir, long offsetCentralDir,
ByteArrayOutputStream byteArrayOutputStream, RawIO rawIO,
Charset charset)
throws IOException {
byte[] longByte = new byte[8];
rawIO.writeIntLittleEndian(byteArrayOutputStream, (int) HeaderSignature.END_OF_CENTRAL_DIRECTORY.getValue());
rawIO.writeShortLittleEndian(byteArrayOutputStream,
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
rawIO.writeShortLittleEndian(byteArrayOutputStream,
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDiskStartOfCentralDir());
long numEntries = zipModel.getCentralDirectory().getFileHeaders().size();
long numEntriesOnThisDisk = numEntries;
if (zipModel.isSplitArchive()) {
numEntriesOnThisDisk = countNumberOfFileHeaderEntriesOnDisk(zipModel.getCentralDirectory().getFileHeaders(),
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
}
if (numEntriesOnThisDisk > InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT) {
numEntriesOnThisDisk = InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT;
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, (int) numEntriesOnThisDisk);
if (numEntries > InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT) {
numEntries = InternalZipConstants.ZIP_64_NUMBER_OF_ENTRIES_LIMIT;
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, (int) numEntries);
rawIO.writeIntLittleEndian(byteArrayOutputStream, sizeOfCentralDir);
if (offsetCentralDir > ZIP_64_SIZE_LIMIT) {
rawIO.writeLongLittleEndian(longByte, 0, ZIP_64_SIZE_LIMIT);
byteArrayOutputStream.write(longByte, 0, 4);
} else {
rawIO.writeLongLittleEndian(longByte, 0, offsetCentralDir);
byteArrayOutputStream.write(longByte, 0, 4);
}
String comment = zipModel.getEndOfCentralDirectoryRecord().getComment();
if (isStringNotNullAndNotEmpty(comment)) {
byte[] commentBytes = getBytesFromString(comment, charset);
rawIO.writeShortLittleEndian(byteArrayOutputStream, commentBytes.length);
byteArrayOutputStream.write(commentBytes);
} else {
rawIO.writeShortLittleEndian(byteArrayOutputStream, 0);
}
}
private long countNumberOfFileHeaderEntriesOnDisk(List fileHeaders, int numOfDisk) throws ZipException {
if (fileHeaders == null) {
throw new ZipException("file headers are null, cannot calculate number of entries on this disk");
}
int noEntries = 0;
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.getDiskNumberStart() == numOfDisk) {
noEntries++;
}
}
return noEntries;
}
private boolean isZip64Entry(FileHeader fileHeader) {
return fileHeader.getCompressedSize() >= ZIP_64_SIZE_LIMIT
|| fileHeader.getUncompressedSize() >= ZIP_64_SIZE_LIMIT
|| fileHeader.getOffsetLocalHeader() >= ZIP_64_SIZE_LIMIT
|| fileHeader.getDiskNumberStart() >= ZIP_64_NUMBER_OF_ENTRIES_LIMIT;
}
private long getOffsetOfCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()
&& zipModel.getZip64EndOfCentralDirectoryRecord() != null
&& zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber() != -1) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
}
return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}
private Zip64EndOfCentralDirectoryRecord buildZip64EndOfCentralDirectoryRecord(ZipModel zipModel, int sizeOfCentralDir,
long offsetCentralDir) throws ZipException {
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = new Zip64EndOfCentralDirectoryRecord();
zip64EndOfCentralDirectoryRecord.setSignature(HeaderSignature.ZIP64_END_CENTRAL_DIRECTORY_RECORD);
zip64EndOfCentralDirectoryRecord.setSizeOfZip64EndCentralDirectoryRecord(44);
if (zipModel.getCentralDirectory() != null &&
zipModel.getCentralDirectory().getFileHeaders() != null &&
zipModel.getCentralDirectory().getFileHeaders().size() > 0) {
FileHeader firstFileHeader = zipModel.getCentralDirectory().getFileHeaders().get(0);
zip64EndOfCentralDirectoryRecord.setVersionMadeBy(firstFileHeader.getVersionMadeBy());
zip64EndOfCentralDirectoryRecord.setVersionNeededToExtract(firstFileHeader.getVersionNeededToExtract());
}
zip64EndOfCentralDirectoryRecord.setNumberOfThisDisk(zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
zip64EndOfCentralDirectoryRecord.setNumberOfThisDiskStartOfCentralDirectory(zipModel.getEndOfCentralDirectoryRecord()
.getNumberOfThisDiskStartOfCentralDir());
long numEntries = zipModel.getCentralDirectory().getFileHeaders().size();
long numEntriesOnThisDisk = numEntries;
if (zipModel.isSplitArchive()) {
numEntriesOnThisDisk = countNumberOfFileHeaderEntriesOnDisk(zipModel.getCentralDirectory().getFileHeaders(),
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
}
zip64EndOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(numEntriesOnThisDisk);
zip64EndOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectory(numEntries);
zip64EndOfCentralDirectoryRecord.setSizeOfCentralDirectory(sizeOfCentralDir);
zip64EndOfCentralDirectoryRecord.setOffsetStartCentralDirectoryWRTStartDiskNumber(offsetCentralDir);
return zip64EndOfCentralDirectoryRecord;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/VersionMadeBy.java 0000664 0000000 0000000 00000000422 14142654472 0025450 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
public enum VersionMadeBy {
SPECIFICATION_VERSION((byte) 51),
WINDOWS((byte) 0),
UNIX((byte) 3);
private final byte code;
VersionMadeBy(byte code) {
this.code = code;
}
public byte getCode() {
return code;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/headers/VersionNeededToExtract.java 0000664 0000000 0000000 00000000451 14142654472 0027333 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
public enum VersionNeededToExtract {
DEFAULT(10),
DEFLATE_COMPRESSED(20),
ZIP_64_FORMAT(45),
AES_ENCRYPTED(51);
private final int code;
VersionNeededToExtract(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/ 0000775 0000000 0000000 00000000000 14142654472 0021074 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/ 0000775 0000000 0000000 00000000000 14142654472 0023447 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/AesCipherInputStream.java 0000664 0000000 0000000 00000014354 14142654472 0030360 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.crypto.AESDecrypter;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import static net.lingala.zip4j.util.InternalZipConstants.AES_AUTH_LENGTH;
import static net.lingala.zip4j.util.Zip4jUtil.readFully;
class AesCipherInputStream extends CipherInputStream {
private byte[] singleByteBuffer = new byte[1];
private byte[] aes16ByteBlock = new byte[16];
private int aes16ByteBlockPointer = 0;
private int remainingAes16ByteBlockLength = 0;
private int lengthToRead = 0;
private int offsetWithAesBlock = 0;
private int bytesCopiedInThisIteration = 0;
private int lengthToCopyInThisIteration = 0;
private int aes16ByteBlockReadLength = 0;
public AesCipherInputStream(ZipEntryInputStream zipEntryInputStream, LocalFileHeader localFileHeader,
char[] password, int bufferSize) throws IOException {
super(zipEntryInputStream, localFileHeader, password, bufferSize);
}
@Override
protected AESDecrypter initializeDecrypter(LocalFileHeader localFileHeader, char[] password) throws IOException {
return new AESDecrypter(localFileHeader.getAesExtraDataRecord(), password, getSalt(localFileHeader), getPasswordVerifier());
}
@Override
public int read() throws IOException {
int readLen = read(singleByteBuffer);
if (readLen == -1) {
return -1;
}
return singleByteBuffer[0];
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
lengthToRead = len;
offsetWithAesBlock = off;
bytesCopiedInThisIteration = 0;
if (remainingAes16ByteBlockLength != 0) {
copyBytesFromBuffer(b, offsetWithAesBlock);
if (bytesCopiedInThisIteration == len) {
return bytesCopiedInThisIteration;
}
}
if (lengthToRead < 16) {
aes16ByteBlockReadLength = super.read(aes16ByteBlock, 0, aes16ByteBlock.length);
aes16ByteBlockPointer = 0;
if (aes16ByteBlockReadLength == -1) {
remainingAes16ByteBlockLength = 0;
if (bytesCopiedInThisIteration > 0) {
return bytesCopiedInThisIteration;
}
return -1;
}
remainingAes16ByteBlockLength = aes16ByteBlockReadLength;
copyBytesFromBuffer(b, offsetWithAesBlock);
if (bytesCopiedInThisIteration == len) {
return bytesCopiedInThisIteration;
}
}
int readLen = super.read(b, offsetWithAesBlock, (lengthToRead - lengthToRead %16));
if (readLen == -1) {
if (bytesCopiedInThisIteration > 0) {
return bytesCopiedInThisIteration;
} else {
return -1;
}
} else {
return readLen + bytesCopiedInThisIteration;
}
}
private void copyBytesFromBuffer(byte[] b, int off) {
lengthToCopyInThisIteration = lengthToRead < remainingAes16ByteBlockLength ? lengthToRead : remainingAes16ByteBlockLength;
System.arraycopy(aes16ByteBlock, aes16ByteBlockPointer, b, off, lengthToCopyInThisIteration);
incrementAesByteBlockPointer(lengthToCopyInThisIteration);
decrementRemainingAesBytesLength(lengthToCopyInThisIteration);
bytesCopiedInThisIteration += lengthToCopyInThisIteration;
lengthToRead -= lengthToCopyInThisIteration;
offsetWithAesBlock += lengthToCopyInThisIteration;
}
@Override
protected void endOfEntryReached(InputStream inputStream) throws IOException {
verifyContent(readStoredMac(inputStream));
}
private void verifyContent(byte[] storedMac) throws IOException {
if (getLocalFileHeader().isDataDescriptorExists()
&& CompressionMethod.DEFLATE.equals(Zip4jUtil.getCompressionMethod(getLocalFileHeader()))) {
// Skip content verification in case of Deflate compression and if data descriptor exists.
// In this case, we do not know the exact size of compressed data before hand and it is possible that we read
// and pass more than required data into inflater, thereby corrupting the aes mac bytes.
// See usage of PushBackInputStream in the project for how this push back of data is done
// Unfortunately, in this case we cannot perform a content verification and have to skip
return;
}
byte[] calculatedMac = getDecrypter().getCalculatedAuthenticationBytes();
byte[] first10BytesOfCalculatedMac = new byte[AES_AUTH_LENGTH];
System.arraycopy(calculatedMac, 0, first10BytesOfCalculatedMac, 0, InternalZipConstants.AES_AUTH_LENGTH);
if (!Arrays.equals(storedMac, first10BytesOfCalculatedMac)) {
throw new IOException("Reached end of data for this entry, but aes verification failed");
}
}
protected byte[] readStoredMac(InputStream inputStream) throws IOException {
byte[] storedMac = new byte[AES_AUTH_LENGTH];
int readLen = readFully(inputStream, storedMac);
if (readLen != AES_AUTH_LENGTH) {
throw new ZipException("Invalid AES Mac bytes. Could not read sufficient data");
}
return storedMac;
}
private byte[] getSalt(LocalFileHeader localFileHeader) throws IOException {
if (localFileHeader.getAesExtraDataRecord() == null) {
throw new IOException("invalid aes extra data record");
}
AESExtraDataRecord aesExtraDataRecord = localFileHeader.getAesExtraDataRecord();
byte[] saltBytes = new byte[aesExtraDataRecord.getAesKeyStrength().getSaltLength()];
readRaw(saltBytes);
return saltBytes;
}
private byte[] getPasswordVerifier() throws IOException {
byte[] pvBytes = new byte[2];
readRaw(pvBytes);
return pvBytes;
}
private void incrementAesByteBlockPointer(int incrementBy) {
aes16ByteBlockPointer += incrementBy;
if (aes16ByteBlockPointer >= 15) {
aes16ByteBlockPointer = 15;
}
}
private void decrementRemainingAesBytesLength(int decrementBy) {
remainingAes16ByteBlockLength -= decrementBy;
if (remainingAes16ByteBlockLength <= 0) {
remainingAes16ByteBlockLength = 0;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/CipherInputStream.java 0000664 0000000 0000000 00000005212 14142654472 0027720 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.crypto.Decrypter;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.IOException;
import java.io.InputStream;
import static net.lingala.zip4j.util.Zip4jUtil.readFully;
abstract class CipherInputStream extends InputStream {
private ZipEntryInputStream zipEntryInputStream;
private T decrypter;
private byte[] lastReadRawDataCache;
private byte[] singleByteBuffer = new byte[1];
private LocalFileHeader localFileHeader;
public CipherInputStream(ZipEntryInputStream zipEntryInputStream, LocalFileHeader localFileHeader,
char[] password, int bufferSize) throws IOException {
this.zipEntryInputStream = zipEntryInputStream;
this.decrypter = initializeDecrypter(localFileHeader, password);
this.localFileHeader = localFileHeader;
if (Zip4jUtil.getCompressionMethod(localFileHeader).equals(CompressionMethod.DEFLATE)) {
lastReadRawDataCache = new byte[bufferSize];
}
}
@Override
public int read() throws IOException {
int readLen = read(singleByteBuffer);
if (readLen == -1) {
return -1;
}
return singleByteBuffer[0] & 0xff;
}
@Override
public int read(byte[] b) throws IOException {
return this.read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int readLen = readFully(zipEntryInputStream, b, off, len);
if (readLen > 0) {
cacheRawData(b, readLen);
decrypter.decryptData(b, off, readLen);
}
return readLen;
}
@Override
public void close() throws IOException {
zipEntryInputStream.close();
}
public byte[] getLastReadRawDataCache() {
return lastReadRawDataCache;
}
protected int readRaw(byte[] b) throws IOException {
return zipEntryInputStream.readRawFully(b);
}
private void cacheRawData(byte[] b, int len) {
if (lastReadRawDataCache != null) {
System.arraycopy(b, 0, lastReadRawDataCache, 0, len);
}
}
public T getDecrypter() {
return decrypter;
}
protected void endOfEntryReached(InputStream inputStream) throws IOException {
// is optional but useful for AES
}
protected long getNumberOfBytesReadForThisEntry() {
return zipEntryInputStream.getNumberOfBytesRead();
}
public LocalFileHeader getLocalFileHeader() {
return localFileHeader;
}
protected abstract T initializeDecrypter(LocalFileHeader localFileHeader, char[] password) throws IOException, ZipException;
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/DecompressedInputStream.java 0000664 0000000 0000000 00000002430 14142654472 0031122 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
abstract class DecompressedInputStream extends InputStream {
private CipherInputStream cipherInputStream;
protected byte[] oneByteBuffer = new byte[1];
public DecompressedInputStream(CipherInputStream cipherInputStream) {
this.cipherInputStream = cipherInputStream;
}
@Override
public int read() throws IOException {
int readLen = read(oneByteBuffer);
if (readLen == -1) {
return -1;
}
return oneByteBuffer[0];
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return cipherInputStream.read(b, off, len);
}
@Override
public void close() throws IOException {
cipherInputStream.close();
}
public void endOfEntryReached(InputStream inputStream) throws IOException {
cipherInputStream.endOfEntryReached(inputStream);
}
public void pushBackInputStreamIfNecessary(PushbackInputStream pushbackInputStream) throws IOException {
// Do nothing by default
}
protected byte[] getLastReadRawDataCache() {
return cipherInputStream.getLastReadRawDataCache();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/InflaterInputStream.java 0000664 0000000 0000000 00000004224 14142654472 0030254 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
public class InflaterInputStream extends DecompressedInputStream {
private Inflater inflater;
private byte[] buff;
private byte[] singleByteBuffer = new byte[1];
private int len;
public InflaterInputStream(CipherInputStream cipherInputStream, int bufferSize) {
super(cipherInputStream);
this.inflater = new Inflater(true);
buff = new byte[bufferSize];
}
@Override
public int read() throws IOException {
int readLen = read(singleByteBuffer);
if (readLen == -1) {
return -1;
}
return singleByteBuffer[0];
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
try {
int n;
while ((n = inflater.inflate(b, off, len)) == 0) {
if (inflater.finished() || inflater.needsDictionary()) {
return -1;
}
if (inflater.needsInput()) {
fill();
}
}
return n;
} catch (DataFormatException e) {
throw new IOException(e);
}
}
@Override
public void endOfEntryReached(InputStream inputStream) throws IOException {
if (inflater != null) {
inflater.end();
inflater = null;
}
super.endOfEntryReached(inputStream);
}
@Override
public void pushBackInputStreamIfNecessary(PushbackInputStream pushbackInputStream) throws IOException {
int n = inflater.getRemaining();
if (n > 0) {
byte[] rawDataCache = getLastReadRawDataCache();
pushbackInputStream.unread(rawDataCache, len - n, n);
}
}
@Override
public void close() throws IOException {
if (inflater != null) {
inflater.end();
}
super.close();
}
private void fill() throws IOException {
len = super.read(buff, 0, buff.length);
if (len == -1) {
throw new EOFException("Unexpected end of input stream");
}
inflater.setInput(buff, 0, len);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/NoCipherInputStream.java 0000664 0000000 0000000 00000001413 14142654472 0030214 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.crypto.Decrypter;
import net.lingala.zip4j.model.LocalFileHeader;
import java.io.IOException;
class NoCipherInputStream extends CipherInputStream {
public NoCipherInputStream(ZipEntryInputStream zipEntryInputStream, LocalFileHeader localFileHeader,
char[] password, int bufferSize) throws IOException {
super(zipEntryInputStream, localFileHeader, password, bufferSize);
}
@Override
protected Decrypter initializeDecrypter(LocalFileHeader localFileHeader, char[] password) {
return new NoDecrypter();
}
static class NoDecrypter implements Decrypter {
@Override
public int decryptData(byte[] buff, int start, int len) {
return len;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/NumberedSplitInputStream.java 0000664 0000000 0000000 00000001760 14142654472 0031267 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import static net.lingala.zip4j.util.FileUtils.getNextNumberedSplitFileCounterAsExtension;
/**
* A split input stream for zip file split with 7-zip. They end with .zip.001, .zip.002, etc
*/
public class NumberedSplitInputStream extends SplitInputStream {
public NumberedSplitInputStream(File zipFile, boolean isSplitZipArchive, int lastSplitZipFileNumber)
throws FileNotFoundException {
super(zipFile, isSplitZipArchive, lastSplitZipFileNumber);
}
@Override
protected File getNextSplitFile(int zipFileIndex) throws IOException {
String currZipFileNameWithPath = zipFile.getCanonicalPath();
String fileNameWithPathAndWithoutExtension = currZipFileNameWithPath.substring(0,
currZipFileNameWithPath.lastIndexOf("."));
return new File(fileNameWithPathAndWithoutExtension + getNextNumberedSplitFileCounterAsExtension(zipFileIndex));
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/NumberedSplitRandomAccessFile.java 0000664 0000000 0000000 00000012124 14142654472 0032152 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* A RandomAccessFile which reads files split with 7-zip format (.z001, .z002, etc) as a single file making it easier
* for calling methods to deal with opening appropriate split file to read
*/
public class NumberedSplitRandomAccessFile extends RandomAccessFile {
private long splitLength;
private File[] allSortedSplitFiles;
private RandomAccessFile randomAccessFile;
private byte[] singleByteBuffer = new byte[1];
private int currentOpenSplitFileCounter = 0;
private String rwMode;
public NumberedSplitRandomAccessFile(String name, String mode) throws IOException {
this(new File(name), mode);
}
public NumberedSplitRandomAccessFile(File file, String mode) throws IOException {
this(file, mode, FileUtils.getAllSortedNumberedSplitFiles(file));
}
public NumberedSplitRandomAccessFile(File file, String mode, File[] allSortedSplitFiles) throws IOException {
super(file, mode);
// A (dirty) hack to be able to open any split file without relying on the Parent class
// For that the parent handle is closed, and a new RandomAccessFile is initiated
// This makes it possible for this class to still extend RandomAccessFile and be able to open any split file
// without calling code having to worry about opening a split file. Code using this class can read the
// split files as if it were one file. zip4j uses RandomAccessFile in a lot of places. This hack allows to deal
// with split files with RandomAccessFile without having to modify a lot of code, especially for a feature
// that will not be used most often
super.close();
if (RandomAccessFileMode.WRITE.getValue().equals(mode)) {
throw new IllegalArgumentException("write mode is not allowed for NumberedSplitRandomAccessFile");
}
assertAllSplitFilesExist(allSortedSplitFiles);
this.randomAccessFile = new RandomAccessFile(file, mode);
this.allSortedSplitFiles = allSortedSplitFiles;
this.splitLength = file.length();
this.rwMode = mode;
}
@Override
public int read() throws IOException {
int readLen = read(singleByteBuffer);
if (readLen == -1) {
return -1;
}
return singleByteBuffer[0] & 0xff;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int readLen = randomAccessFile.read(b, off, len);
if (readLen == -1) {
if (currentOpenSplitFileCounter == allSortedSplitFiles.length - 1) {
return -1;
}
openRandomAccessFileForIndex(currentOpenSplitFileCounter + 1);
return read(b, off, len);
}
return readLen;
}
@Override
public void write(int b) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void seek(long pos) throws IOException {
int splitPartOfPosition = (int) (pos / splitLength);
if (splitPartOfPosition != currentOpenSplitFileCounter) {
openRandomAccessFileForIndex(splitPartOfPosition);
}
randomAccessFile.seek(pos - (splitPartOfPosition * splitLength));
}
@Override
public long getFilePointer() throws IOException {
return randomAccessFile.getFilePointer();
}
@Override
public long length() throws IOException {
return randomAccessFile.length();
}
public void seekInCurrentPart(long pos) throws IOException {
randomAccessFile.seek(pos);
}
public void openLastSplitFileForReading() throws IOException {
openRandomAccessFileForIndex(allSortedSplitFiles.length - 1);
}
private void openRandomAccessFileForIndex(int splitCounter) throws IOException {
if (currentOpenSplitFileCounter == splitCounter) {
return;
}
if (splitCounter > allSortedSplitFiles.length - 1) {
throw new IOException("split counter greater than number of split files");
}
if (randomAccessFile != null) {
randomAccessFile.close();
}
randomAccessFile = new RandomAccessFile(allSortedSplitFiles[splitCounter], rwMode);
currentOpenSplitFileCounter = splitCounter;
}
private void assertAllSplitFilesExist(File[] allSortedSplitFiles) throws IOException {
int splitCounter = 1;
for (File splitFile : allSortedSplitFiles) {
String fileExtension = FileUtils.getFileExtension(splitFile);
try {
if (splitCounter != Integer.parseInt(fileExtension)) {
throw new IOException("Split file number " + splitCounter + " does not exist");
}
splitCounter++;
} catch (NumberFormatException e) {
throw new IOException("Split file extension not in expected format. Found: " + fileExtension
+ " expected of format: .001, .002, etc");
}
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/SplitInputStream.java 0000664 0000000 0000000 00000005257 14142654472 0027612 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
public abstract class SplitInputStream extends InputStream {
protected RandomAccessFile randomAccessFile;
protected File zipFile;
private boolean isSplitZipArchive;
private int currentSplitFileCounter = 0;
private byte[] singleByteArray = new byte[1];
public SplitInputStream(File zipFile, boolean isSplitZipArchive, int lastSplitZipFileNumber) throws FileNotFoundException {
this.randomAccessFile = new RandomAccessFile(zipFile, RandomAccessFileMode.READ.getValue());
this.zipFile = zipFile;
this.isSplitZipArchive = isSplitZipArchive;
if (isSplitZipArchive) {
currentSplitFileCounter = lastSplitZipFileNumber;
}
}
@Override
public int read() throws IOException {
int readLen = read(singleByteArray);
if (readLen == -1) {
return -1;
}
return singleByteArray[0];
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int readLen = randomAccessFile.read(b, off, len);
if ((readLen != len || readLen == -1) && isSplitZipArchive) {
openRandomAccessFileForIndex(currentSplitFileCounter + 1);
currentSplitFileCounter++;
if (readLen < 0) readLen = 0;
int newlyRead = randomAccessFile.read(b, readLen, len - readLen);
if (newlyRead > 0) readLen += newlyRead;
}
return readLen;
}
public void prepareExtractionForFileHeader(FileHeader fileHeader) throws IOException {
if (isSplitZipArchive && (currentSplitFileCounter != fileHeader.getDiskNumberStart())) {
openRandomAccessFileForIndex(fileHeader.getDiskNumberStart());
currentSplitFileCounter = fileHeader.getDiskNumberStart();
}
randomAccessFile.seek(fileHeader.getOffsetLocalHeader());
}
protected void openRandomAccessFileForIndex(int zipFileIndex) throws IOException {
File nextSplitFile = getNextSplitFile(zipFileIndex);
if (!nextSplitFile.exists()) {
throw new FileNotFoundException("zip split file does not exist: " + nextSplitFile);
}
randomAccessFile.close();
randomAccessFile = new RandomAccessFile(nextSplitFile, RandomAccessFileMode.READ.getValue());
}
protected abstract File getNextSplitFile(int zipFileIndex) throws IOException;
@Override
public void close() throws IOException {
if (randomAccessFile != null) {
randomAccessFile.close();
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/StoreInputStream.java 0000664 0000000 0000000 00000000312 14142654472 0027576 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
class StoreInputStream extends DecompressedInputStream {
public StoreInputStream(CipherInputStream cipherInputStream) {
super(cipherInputStream);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/ZipEntryInputStream.java 0000664 0000000 0000000 00000004376 14142654472 0030304 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import java.io.IOException;
import java.io.InputStream;
class ZipEntryInputStream extends InputStream {
private static final int MAX_RAW_READ_FULLY_RETRY_ATTEMPTS = 15;
private InputStream inputStream;
private long numberOfBytesRead = 0;
private byte[] singleByteArray = new byte[1];
private long compressedSize;
public ZipEntryInputStream(InputStream inputStream, long compressedSize) {
this.inputStream = inputStream;
this.compressedSize = compressedSize;
}
@Override
public int read() throws IOException {
int readLen = read(singleByteArray);
if (readLen == -1) {
return -1;
}
return singleByteArray[0];
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (compressedSize != -1) {
if (numberOfBytesRead >= compressedSize) {
return -1;
}
if (len > compressedSize - numberOfBytesRead) {
len = (int) (compressedSize - numberOfBytesRead);
}
}
int readLen = inputStream.read(b, off, len);
if (readLen > 0) {
numberOfBytesRead += readLen;
}
return readLen;
}
public int readRawFully(byte[] b) throws IOException {
int readLen = inputStream.read(b);
if (readLen != b.length) {
readLen = readUntilBufferIsFull(b, readLen);
if (readLen != b.length) {
throw new IOException("Cannot read fully into byte buffer");
}
}
return readLen;
}
private int readUntilBufferIsFull(byte[] b, int readLength) throws IOException {
int remainingLength = b.length - readLength;
int loopReadLength = 0;
int retryAttempt = 0;
while (readLength < b.length && loopReadLength != -1 && retryAttempt < MAX_RAW_READ_FULLY_RETRY_ATTEMPTS) {
loopReadLength += inputStream.read(b, readLength, remainingLength);
if (loopReadLength > 0) {
readLength += loopReadLength;
remainingLength -= loopReadLength;
}
retryAttempt++;
}
return readLength;
}
@Override
public void close() throws IOException {
inputStream.close();
}
public long getNumberOfBytesRead() {
return numberOfBytesRead;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/ZipInputStream.java 0000775 0000000 0000000 00000034022 14142654472 0027254 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.io.inputstream;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
import static net.lingala.zip4j.util.Zip4jUtil.getCompressionMethod;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderReader;
import net.lingala.zip4j.headers.HeaderSignature;
import net.lingala.zip4j.model.DataDescriptor;
import net.lingala.zip4j.model.ExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.PasswordCallback;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.zip.CRC32;
public class ZipInputStream extends InputStream {
private PushbackInputStream inputStream;
private DecompressedInputStream decompressedInputStream;
private HeaderReader headerReader = new HeaderReader();
private char[] password;
private PasswordCallback passwordCallback;
private LocalFileHeader localFileHeader;
private CRC32 crc32 = new CRC32();
private byte[] endOfEntryBuffer;
private boolean canSkipExtendedLocalFileHeader = false;
private Zip4jConfig zip4jConfig;
private boolean streamClosed = false;
private boolean entryEOFReached = false;
public ZipInputStream(InputStream inputStream) {
this(inputStream, (char[]) null, (Charset) null);
}
public ZipInputStream(InputStream inputStream, Charset charset) {
this(inputStream, (char[]) null, charset);
}
public ZipInputStream(InputStream inputStream, char[] password) {
this(inputStream, password, (Charset) null);
}
public ZipInputStream(InputStream inputStream, PasswordCallback passwordCallback) {
this(inputStream, passwordCallback, (Charset) null);
}
public ZipInputStream(InputStream inputStream, char[] password, Charset charset) {
this(inputStream, password, new Zip4jConfig(charset, InternalZipConstants.BUFF_SIZE));
}
public ZipInputStream(InputStream inputStream, PasswordCallback passwordCallback, Charset charset) {
this(inputStream, passwordCallback, new Zip4jConfig(charset, InternalZipConstants.BUFF_SIZE));
}
public ZipInputStream(InputStream inputStream, char[] password, Zip4jConfig zip4jConfig) {
this(inputStream, password, null, zip4jConfig);
}
public ZipInputStream(InputStream inputStream, PasswordCallback passwordCallback, Zip4jConfig zip4jConfig) {
this(inputStream, null, passwordCallback, zip4jConfig);
}
private ZipInputStream(InputStream inputStream, char[] password, PasswordCallback passwordCallback, Zip4jConfig zip4jConfig) {
if (zip4jConfig.getBufferSize() < InternalZipConstants.MIN_BUFF_SIZE) {
throw new IllegalArgumentException("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
}
this.inputStream = new PushbackInputStream(inputStream, zip4jConfig.getBufferSize());
this.password = password;
this.passwordCallback = passwordCallback;
this.zip4jConfig = zip4jConfig;
}
public LocalFileHeader getNextEntry() throws IOException {
return getNextEntry(null, true);
}
public LocalFileHeader getNextEntry(FileHeader fileHeader, boolean readUntilEndOfCurrentEntryIfOpen)
throws IOException {
if (localFileHeader != null && readUntilEndOfCurrentEntryIfOpen) {
readUntilEndOfEntry();
}
localFileHeader = headerReader.readLocalFileHeader(inputStream, zip4jConfig.getCharset());
if (localFileHeader == null) {
return null;
}
if (localFileHeader.isEncrypted() && password == null && passwordCallback != null) {
setPassword(passwordCallback.getPassword());
}
verifyLocalFileHeader(localFileHeader);
crc32.reset();
if (fileHeader != null) {
localFileHeader.setCrc(fileHeader.getCrc());
localFileHeader.setCompressedSize(fileHeader.getCompressedSize());
localFileHeader.setUncompressedSize(fileHeader.getUncompressedSize());
// file header's directory flag is more reliable than local file header's directory flag as file header has
// additional external file attributes which has a directory flag defined. In local file header, the only way
// to determine if an entry is directory is to check if the file name has a trailing forward slash "/"
localFileHeader.setDirectory(fileHeader.isDirectory());
canSkipExtendedLocalFileHeader = true;
} else {
canSkipExtendedLocalFileHeader = false;
}
this.decompressedInputStream = initializeEntryInputStream(localFileHeader);
this.entryEOFReached = false;
return localFileHeader;
}
@Override
public int read() throws IOException {
byte[] b = new byte[1];
int readLen = read(b);
if (readLen == -1) {
return -1;
}
return b[0] & 0xff;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (streamClosed) {
throw new IOException("Stream closed");
}
if (len < 0) {
throw new IllegalArgumentException("Negative read length");
}
if (len == 0) {
return 0;
}
if (localFileHeader == null) {
// localfileheader can be null when end of compressed data is reached. If null check is missing, read method will
// throw a NPE when end of compressed data is reached and read is called again.
return -1;
}
try {
int readLen = decompressedInputStream.read(b, off, len);
if (readLen == -1) {
endOfCompressedDataReached();
} else {
crc32.update(b, off, readLen);
}
return readLen;
} catch (IOException e) {
if (isEncryptionMethodZipStandard(localFileHeader)) {
throw new ZipException(e.getMessage(), e.getCause(), ZipException.Type.WRONG_PASSWORD);
}
throw e;
}
}
@Override
public void close() throws IOException {
if (streamClosed) {
return;
}
if (decompressedInputStream != null) {
decompressedInputStream.close();
}
this.streamClosed = true;
}
@Override
public int available() throws IOException {
assertStreamOpen();
return entryEOFReached ? 0 : 1;
}
/**
* Sets the password for the inputstream. This password will be used for any subsequent encrypted entries that will be
* read from this stream. If this method is called when an entry is being read, it has no effect on the read action
* of the current entry, and the password will take effect from any subsequent entry reads.
*
* @param password Password to be used for reading of entries from the zip input stream
*/
public void setPassword(char[] password) {
this.password = password;
}
private void endOfCompressedDataReached() throws IOException {
//With inflater, without knowing the compressed or uncompressed size, we over read necessary data
//In such cases, we have to push back the inputstream to the end of data
decompressedInputStream.pushBackInputStreamIfNecessary(inputStream);
//First signal the end of data for this entry so that ciphers can read any header data if applicable
decompressedInputStream.endOfEntryReached(inputStream);
readExtendedLocalFileHeaderIfPresent();
verifyCrc();
resetFields();
this.entryEOFReached = true;
}
private DecompressedInputStream initializeEntryInputStream(LocalFileHeader localFileHeader) throws IOException {
ZipEntryInputStream zipEntryInputStream = new ZipEntryInputStream(inputStream, getCompressedSize(localFileHeader));
CipherInputStream cipherInputStream = initializeCipherInputStream(zipEntryInputStream, localFileHeader);
return initializeDecompressorForThisEntry(cipherInputStream, localFileHeader);
}
private CipherInputStream initializeCipherInputStream(ZipEntryInputStream zipEntryInputStream,
LocalFileHeader localFileHeader) throws IOException {
if (!localFileHeader.isEncrypted()) {
return new NoCipherInputStream(zipEntryInputStream, localFileHeader, password, zip4jConfig.getBufferSize());
}
if (localFileHeader.getEncryptionMethod() == EncryptionMethod.AES) {
return new AesCipherInputStream(zipEntryInputStream, localFileHeader, password, zip4jConfig.getBufferSize());
} else if (localFileHeader.getEncryptionMethod() == EncryptionMethod.ZIP_STANDARD) {
return new ZipStandardCipherInputStream(zipEntryInputStream, localFileHeader, password, zip4jConfig.getBufferSize());
} else {
final String message = String.format("Entry [%s] Strong Encryption not supported", localFileHeader.getFileName());
throw new ZipException(message, ZipException.Type.UNSUPPORTED_ENCRYPTION);
}
}
private DecompressedInputStream initializeDecompressorForThisEntry(CipherInputStream cipherInputStream,
LocalFileHeader localFileHeader) {
CompressionMethod compressionMethod = getCompressionMethod(localFileHeader);
if (compressionMethod == CompressionMethod.DEFLATE) {
return new InflaterInputStream(cipherInputStream, zip4jConfig.getBufferSize());
}
return new StoreInputStream(cipherInputStream);
}
private void readExtendedLocalFileHeaderIfPresent() throws IOException {
if (!localFileHeader.isDataDescriptorExists() || canSkipExtendedLocalFileHeader) {
return;
}
DataDescriptor dataDescriptor = headerReader.readDataDescriptor(inputStream,
checkIfZip64ExtraDataRecordPresentInLFH(localFileHeader.getExtraDataRecords()));
localFileHeader.setCompressedSize(dataDescriptor.getCompressedSize());
localFileHeader.setUncompressedSize(dataDescriptor.getUncompressedSize());
localFileHeader.setCrc(dataDescriptor.getCrc());
}
private void verifyLocalFileHeader(LocalFileHeader localFileHeader) throws IOException {
if (!isEntryDirectory(localFileHeader.getFileName())
&& localFileHeader.getCompressionMethod() == CompressionMethod.STORE
&& localFileHeader.getUncompressedSize() < 0) {
throw new IOException("Invalid local file header for: " + localFileHeader.getFileName()
+ ". Uncompressed size has to be set for entry of compression type store which is not a directory");
}
}
private boolean checkIfZip64ExtraDataRecordPresentInLFH(List extraDataRecords) {
if (extraDataRecords == null) {
return false;
}
for (ExtraDataRecord extraDataRecord : extraDataRecords) {
if (extraDataRecord.getHeader() == HeaderSignature.ZIP64_EXTRA_FIELD_SIGNATURE.getValue()) {
return true;
}
}
return false;
}
private void verifyCrc() throws IOException {
if (localFileHeader.getEncryptionMethod() == EncryptionMethod.AES
&& localFileHeader.getAesExtraDataRecord().getAesVersion().equals(AesVersion.TWO)) {
// Verification will be done in this case by AesCipherInputStream
return;
}
if (localFileHeader.getCrc() != crc32.getValue()) {
ZipException.Type exceptionType = ZipException.Type.CHECKSUM_MISMATCH;
if (isEncryptionMethodZipStandard(localFileHeader)) {
exceptionType = ZipException.Type.WRONG_PASSWORD;
}
throw new ZipException("Reached end of entry, but crc verification failed for " + localFileHeader.getFileName(),
exceptionType);
}
}
private void resetFields() {
localFileHeader = null;
crc32.reset();
}
private boolean isEntryDirectory(String entryName) {
return entryName.endsWith("/") || entryName.endsWith("\\");
}
private long getCompressedSize(LocalFileHeader localFileHeader) {
if (getCompressionMethod(localFileHeader).equals(CompressionMethod.STORE)) {
return localFileHeader.getUncompressedSize();
}
if (localFileHeader.isDataDescriptorExists() && !canSkipExtendedLocalFileHeader) {
return -1;
}
return localFileHeader.getCompressedSize() - getEncryptionHeaderSize(localFileHeader);
}
private int getEncryptionHeaderSize(LocalFileHeader localFileHeader) {
if (!localFileHeader.isEncrypted()) {
return 0;
}
if (localFileHeader.getEncryptionMethod().equals(EncryptionMethod.AES)) {
return InternalZipConstants.AES_AUTH_LENGTH + InternalZipConstants.AES_PASSWORD_VERIFIER_LENGTH
+ localFileHeader.getAesExtraDataRecord().getAesKeyStrength().getSaltLength();
} else if (localFileHeader.getEncryptionMethod().equals(EncryptionMethod.ZIP_STANDARD)) {
return InternalZipConstants.STD_DEC_HDR_SIZE;
} else {
return 0;
}
}
private void readUntilEndOfEntry() throws IOException {
if ((localFileHeader.isDirectory() || localFileHeader.getCompressedSize() == 0)
&& !localFileHeader.isDataDescriptorExists()) {
return;
}
if (endOfEntryBuffer == null) {
endOfEntryBuffer = new byte[512];
}
//noinspection StatementWithEmptyBody
while (read(endOfEntryBuffer) != -1);
this.entryEOFReached = true;
}
private boolean isEncryptionMethodZipStandard(LocalFileHeader localFileHeader) {
return localFileHeader.isEncrypted() && EncryptionMethod.ZIP_STANDARD.equals(localFileHeader.getEncryptionMethod());
}
private void assertStreamOpen() throws IOException {
if (streamClosed) {
throw new IOException("Stream closed");
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/ZipStandardCipherInputStream.java 0000664 0000000 0000000 00000002073 14142654472 0032066 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.crypto.StandardDecrypter;
import net.lingala.zip4j.model.LocalFileHeader;
import java.io.IOException;
import static net.lingala.zip4j.util.InternalZipConstants.STD_DEC_HDR_SIZE;
class ZipStandardCipherInputStream extends CipherInputStream {
public ZipStandardCipherInputStream(ZipEntryInputStream zipEntryInputStream, LocalFileHeader localFileHeader,
char[] password, int bufferSize) throws IOException {
super(zipEntryInputStream, localFileHeader, password, bufferSize);
}
@Override
protected StandardDecrypter initializeDecrypter(LocalFileHeader localFileHeader, char[] password) throws IOException {
return new StandardDecrypter(password, localFileHeader.getCrc(), localFileHeader.getLastModifiedTime(),
getStandardDecrypterHeaderBytes());
}
private byte[] getStandardDecrypterHeaderBytes() throws IOException {
byte[] headerBytes = new byte[STD_DEC_HDR_SIZE];
readRaw(headerBytes);
return headerBytes;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/inputstream/ZipStandardSplitInputStream.java 0000664 0000000 0000000 00000002122 14142654472 0031742 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* A split input stream for zip file split as per zip specification. They end with .z01, .z02... .zip
*/
public class ZipStandardSplitInputStream extends SplitInputStream {
private int lastSplitZipFileNumber;
public ZipStandardSplitInputStream(File zipFile, boolean isSplitZipArchive, int lastSplitZipFileNumber) throws FileNotFoundException {
super(zipFile, isSplitZipArchive, lastSplitZipFileNumber);
this.lastSplitZipFileNumber = lastSplitZipFileNumber;
}
@Override
protected File getNextSplitFile(int zipFileIndex) throws IOException {
if (zipFileIndex == lastSplitZipFileNumber) {
return zipFile;
}
String currZipFileNameWithPath = zipFile.getCanonicalPath();
String extensionSubString = ".z0";
if (zipFileIndex >= 9) {
extensionSubString = ".z";
}
return new File(currZipFileNameWithPath.substring(0,
currZipFileNameWithPath.lastIndexOf(".")) + extensionSubString + (zipFileIndex + 1));
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/ 0000775 0000000 0000000 00000000000 14142654472 0023650 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/AesCipherOutputStream.java 0000664 0000000 0000000 00000004653 14142654472 0030763 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.crypto.AESEncrypter;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import java.io.IOException;
import java.io.OutputStream;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
class AesCipherOutputStream extends CipherOutputStream {
private byte[] pendingBuffer = new byte[AES_BLOCK_SIZE];
private int pendingBufferLength = 0;
public AesCipherOutputStream(ZipEntryOutputStream outputStream, ZipParameters zipParameters, char[] password) throws IOException, ZipException {
super(outputStream, zipParameters, password);
}
@Override
protected AESEncrypter initializeEncrypter(OutputStream outputStream, ZipParameters zipParameters, char[] password) throws IOException, ZipException {
AESEncrypter encrypter = new AESEncrypter(password, zipParameters.getAesKeyStrength());
writeAesEncryptionHeaderData(encrypter);
return encrypter;
}
private void writeAesEncryptionHeaderData(AESEncrypter encrypter) throws IOException {
writeHeaders(encrypter.getSaltBytes());
writeHeaders(encrypter.getDerivedPasswordVerifier());
}
@Override
public void write(int b) throws IOException {
write(new byte[] {(byte) b});
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (len >= (AES_BLOCK_SIZE - pendingBufferLength)) {
System.arraycopy(b, off, pendingBuffer, pendingBufferLength, (AES_BLOCK_SIZE - pendingBufferLength));
super.write(pendingBuffer, 0, pendingBuffer.length);
off = (AES_BLOCK_SIZE - pendingBufferLength);
len = len - off;
pendingBufferLength = 0;
} else {
System.arraycopy(b, off, pendingBuffer, pendingBufferLength, len);
pendingBufferLength += len;
return;
}
if (len != 0 && len % 16 != 0) {
System.arraycopy(b, (len + off) - (len % 16), pendingBuffer, 0, len % 16);
pendingBufferLength = len % 16;
len = len - pendingBufferLength;
}
super.write(b, off, len);
}
@Override
public void closeEntry() throws IOException {
if (this.pendingBufferLength != 0) {
super.write(pendingBuffer, 0, pendingBufferLength);
pendingBufferLength = 0;
}
writeHeaders(getEncrypter().getFinalMac());
super.closeEntry();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/CipherOutputStream.java 0000775 0000000 0000000 00000004406 14142654472 0030331 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.crypto.Encrypter;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import java.io.IOException;
import java.io.OutputStream;
abstract class CipherOutputStream extends OutputStream {
private ZipEntryOutputStream zipEntryOutputStream;
private T encrypter;
public CipherOutputStream(ZipEntryOutputStream zipEntryOutputStream, ZipParameters zipParameters, char[] password)
throws IOException, ZipException {
this.zipEntryOutputStream = zipEntryOutputStream;
this.encrypter = initializeEncrypter(zipEntryOutputStream, zipParameters, password);
}
@Override
public void write(int b) throws IOException {
zipEntryOutputStream.write(b);
}
@Override
public void write(byte[] b) throws IOException {
zipEntryOutputStream.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
encrypter.encryptData(b, off, len);
zipEntryOutputStream.write(b, off, len);
}
public void writeHeaders(byte[] b) throws IOException {
zipEntryOutputStream.write(b);
}
public void closeEntry() throws IOException {
zipEntryOutputStream.closeEntry();
}
@Override
public void close() throws IOException {
zipEntryOutputStream.close();
}
public long getNumberOfBytesWrittenForThisEntry() {
return zipEntryOutputStream.getNumberOfBytesWrittenForThisEntry();
}
protected T getEncrypter() {
return encrypter;
}
protected abstract T initializeEncrypter(OutputStream outputStream, ZipParameters zipParameters, char[] password)
throws IOException, ZipException;
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/CompressedOutputStream.java 0000664 0000000 0000000 00000001701 14142654472 0031213 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import java.io.IOException;
import java.io.OutputStream;
abstract class CompressedOutputStream extends OutputStream {
private CipherOutputStream cipherOutputStream;
public CompressedOutputStream(CipherOutputStream cipherOutputStream) {
this.cipherOutputStream = cipherOutputStream;
}
@Override
public void write(int b) throws IOException {
write(new byte[] {(byte) b});
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
cipherOutputStream.write(b, off, len);
}
protected void closeEntry() throws IOException {
cipherOutputStream.closeEntry();
}
@Override
public void close() throws IOException {
cipherOutputStream.close();
}
public long getCompressedSize() {
return cipherOutputStream.getNumberOfBytesWrittenForThisEntry();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/CountingOutputStream.java 0000664 0000000 0000000 00000004363 14142654472 0030704 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.exception.ZipException;
import java.io.IOException;
import java.io.OutputStream;
public class CountingOutputStream extends OutputStream implements OutputStreamWithSplitZipSupport {
private OutputStream outputStream;
private long numberOfBytesWritten = 0;
public CountingOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public void write(int b) throws IOException {
write(new byte[] {(byte) b});
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
outputStream.write(b, off, len);
numberOfBytesWritten += len;
}
@Override
public int getCurrentSplitFileCounter() {
if (isSplitZipFile()) {
return ((SplitOutputStream) outputStream).getCurrentSplitFileCounter();
}
return 0;
}
public long getOffsetForNextEntry() throws IOException {
if (outputStream instanceof SplitOutputStream) {
return ((SplitOutputStream) outputStream).getFilePointer();
}
return numberOfBytesWritten;
}
public long getSplitLength() {
if (isSplitZipFile()) {
return ((SplitOutputStream) outputStream).getSplitLength();
}
return 0;
}
public boolean isSplitZipFile() {
return outputStream instanceof SplitOutputStream
&& ((SplitOutputStream)outputStream).isSplitZipFile();
}
public long getNumberOfBytesWritten() throws IOException {
if (outputStream instanceof SplitOutputStream) {
return ((SplitOutputStream) outputStream).getFilePointer();
}
return numberOfBytesWritten;
}
public boolean checkBuffSizeAndStartNextSplitFile(int bufferSize) throws ZipException {
if (!isSplitZipFile()) {
return false;
}
return ((SplitOutputStream)outputStream).checkBufferSizeAndStartNextSplitFile(bufferSize);
}
@Override
public long getFilePointer() throws IOException {
if (outputStream instanceof SplitOutputStream) {
return ((SplitOutputStream) outputStream).getFilePointer();
}
return numberOfBytesWritten;
}
@Override
public void close() throws IOException {
outputStream.close();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/DeflaterOutputStream.java 0000775 0000000 0000000 00000003563 14142654472 0030650 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.model.enums.CompressionLevel;
import java.io.IOException;
import java.util.zip.Deflater;
class DeflaterOutputStream extends CompressedOutputStream {
private byte[] buff;
protected Deflater deflater;
public DeflaterOutputStream(CipherOutputStream cipherOutputStream, CompressionLevel compressionLevel, int bufferSize) {
super(cipherOutputStream);
deflater = new Deflater(compressionLevel.getLevel(), true);
buff = new byte[bufferSize];
}
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
public void write(int bval) throws IOException {
byte[] b = new byte[1];
b[0] = (byte) bval;
write(b, 0, 1);
}
public void write(byte[] buf, int off, int len) throws IOException {
deflater.setInput(buf, off, len);
while (!deflater.needsInput()) {
deflate();
}
}
private void deflate() throws IOException {
int len = deflater.deflate(buff, 0, buff.length);
if (len > 0) {
super.write(buff, 0, len);
}
}
public void closeEntry() throws IOException {
if (!deflater.finished()) {
deflater.finish();
while (!deflater.finished()) {
deflate();
}
}
deflater.end();
super.closeEntry();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/NoCipherOutputStream.java 0000664 0000000 0000000 00000001727 14142654472 0030626 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.crypto.Encrypter;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import java.io.IOException;
import java.io.OutputStream;
class NoCipherOutputStream extends CipherOutputStream {
public NoCipherOutputStream(ZipEntryOutputStream zipEntryOutputStream, ZipParameters zipParameters, char[] password) throws IOException, ZipException {
super(zipEntryOutputStream, zipParameters, password);
}
@Override
protected NoEncrypter initializeEncrypter(OutputStream outputStream, ZipParameters zipParameters, char[] password) {
return new NoEncrypter();
}
static class NoEncrypter implements Encrypter {
@Override
public int encryptData(byte[] buff) {
return encryptData(buff, 0, buff.length);
}
@Override
public int encryptData(byte[] buff, int start, int len) {
return len;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/OutputStreamWithSplitZipSupport.java 0000664 0000000 0000000 00000000320 14142654472 0033112 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import java.io.IOException;
public interface OutputStreamWithSplitZipSupport {
long getFilePointer() throws IOException;
int getCurrentSplitFileCounter();
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/SplitOutputStream.java 0000775 0000000 0000000 00000014530 14142654472 0030211 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderSignature;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.util.RawIO;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import static net.lingala.zip4j.util.FileUtils.getZipFileNameWithoutExtension;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_SPLIT_LENGTH;
public class SplitOutputStream extends OutputStream implements OutputStreamWithSplitZipSupport {
private RandomAccessFile raf;
private long splitLength;
private File zipFile;
private int currSplitFileCounter;
private long bytesWrittenForThisPart;
private RawIO rawIO = new RawIO();
public SplitOutputStream(File file) throws FileNotFoundException, ZipException {
this(file, -1);
}
public SplitOutputStream(File file, long splitLength) throws FileNotFoundException, ZipException {
if (splitLength >= 0 && splitLength < MIN_SPLIT_LENGTH) {
throw new ZipException("split length less than minimum allowed split length of " + MIN_SPLIT_LENGTH + " Bytes");
}
this.raf = new RandomAccessFile(file, RandomAccessFileMode.WRITE.getValue());
this.splitLength = splitLength;
this.zipFile = file;
this.currSplitFileCounter = 0;
this.bytesWrittenForThisPart = 0;
}
public void write(int b) throws IOException {
write(new byte[] {(byte) b});
}
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
public void write(byte[] b, int off, int len) throws IOException {
if (len <= 0) {
return;
}
if (splitLength == -1) {
raf.write(b, off, len);
bytesWrittenForThisPart += len;
return;
}
if (bytesWrittenForThisPart >= splitLength) {
startNextSplitFile();
raf.write(b, off, len);
bytesWrittenForThisPart = len;
} else if (bytesWrittenForThisPart + len > splitLength) {
if (isHeaderData(b)) {
startNextSplitFile();
raf.write(b, off, len);
bytesWrittenForThisPart = len;
} else {
raf.write(b, off, (int) (splitLength - bytesWrittenForThisPart));
startNextSplitFile();
raf.write(b, off + (int) (splitLength - bytesWrittenForThisPart),
(int) (len - (splitLength - bytesWrittenForThisPart)));
bytesWrittenForThisPart = len - (splitLength - bytesWrittenForThisPart);
}
} else {
raf.write(b, off, len);
bytesWrittenForThisPart += len;
}
}
private void startNextSplitFile() throws IOException {
String zipFileWithoutExt = getZipFileNameWithoutExtension(zipFile.getName());
String zipFileName = zipFile.getAbsolutePath();
String parentPath = (zipFile.getParent() == null) ? "" : zipFile.getParent()
+ System.getProperty("file.separator");
String fileExtension = ".z0" + (currSplitFileCounter + 1);
if (currSplitFileCounter >= 9) {
fileExtension = ".z" + (currSplitFileCounter + 1);
}
File currSplitFile = new File(parentPath + zipFileWithoutExt + fileExtension);
raf.close();
if (currSplitFile.exists()) {
throw new IOException("split file: " + currSplitFile.getName()
+ " already exists in the current directory, cannot rename this file");
}
if (!zipFile.renameTo(currSplitFile)) {
throw new IOException("cannot rename newly created split file");
}
zipFile = new File(zipFileName);
raf = new RandomAccessFile(zipFile, RandomAccessFileMode.WRITE.getValue());
currSplitFileCounter++;
}
private boolean isHeaderData(byte[] buff) {
int signature = rawIO.readIntLittleEndian(buff);
for (HeaderSignature headerSignature : HeaderSignature.values()) {
//Ignore split signature
if (headerSignature != HeaderSignature.SPLIT_ZIP &&
headerSignature.getValue() == signature) {
return true;
}
}
return false;
}
/**
* Checks if the buffer size is sufficient for the current split file. If not
* a new split file will be started.
*
* @param bufferSize
* @return true if a new split file was started else false
* @throws ZipException
*/
public boolean checkBufferSizeAndStartNextSplitFile(int bufferSize) throws ZipException {
if (bufferSize < 0) {
throw new ZipException("negative buffersize for checkBufferSizeAndStartNextSplitFile");
}
if (!isBufferSizeFitForCurrSplitFile(bufferSize)) {
try {
startNextSplitFile();
bytesWrittenForThisPart = 0;
return true;
} catch (IOException e) {
throw new ZipException(e);
}
}
return false;
}
/**
* Checks if the given buffer size will be fit in the current split file.
* If this output stream is a non-split file, then this method always returns true
*
* @param bufferSize
* @return true if the buffer size is fit in the current split file or else false.
*/
private boolean isBufferSizeFitForCurrSplitFile(int bufferSize) {
if (splitLength >= MIN_SPLIT_LENGTH) {
return (bytesWrittenForThisPart + bufferSize <= splitLength);
} else {
//Non split zip -- return true
return true;
}
}
public void seek(long pos) throws IOException {
raf.seek(pos);
}
public int skipBytes(int n) throws IOException {
return raf.skipBytes(n);
}
public void close() throws IOException {
raf.close();
}
@Override
public long getFilePointer() throws IOException {
return raf.getFilePointer();
}
public boolean isSplitZipFile() {
return splitLength != -1;
}
public long getSplitLength() {
return splitLength;
}
@Override
public int getCurrentSplitFileCounter() {
return currSplitFileCounter;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/StoreOutputStream.java 0000664 0000000 0000000 00000000320 14142654472 0030177 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
class StoreOutputStream extends CompressedOutputStream {
public StoreOutputStream(CipherOutputStream cipherOutputStream) {
super(cipherOutputStream);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/ZipEntryOutputStream.java 0000664 0000000 0000000 00000002275 14142654472 0030702 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import java.io.IOException;
import java.io.OutputStream;
class ZipEntryOutputStream extends OutputStream {
private long numberOfBytesWrittenForThisEntry = 0;
private OutputStream outputStream;
private boolean entryClosed;
public ZipEntryOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
entryClosed = false;
}
@Override
public void write(int b) throws IOException {
write(new byte[] {(byte) b});
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (entryClosed) {
throw new IllegalStateException("ZipEntryOutputStream is closed");
}
outputStream.write(b, off, len);
numberOfBytesWrittenForThisEntry += len;
}
public void closeEntry() throws IOException {
entryClosed = true;
}
public long getNumberOfBytesWrittenForThisEntry() {
return numberOfBytesWrittenForThisEntry;
}
@Override
public void close() throws IOException {
// Do nothing
// Do not close the outputstream yet. This will be closed by countingOutputStream
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/ZipOutputStream.java 0000775 0000000 0000000 00000023113 14142654472 0027655 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.FileHeaderFactory;
import net.lingala.zip4j.headers.HeaderSignature;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.zip.CRC32;
import static net.lingala.zip4j.util.FileUtils.isZipEntryDirectory;
import static net.lingala.zip4j.util.InternalZipConstants.BUFF_SIZE;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
public class ZipOutputStream extends OutputStream {
private CountingOutputStream countingOutputStream;
private char[] password;
private ZipModel zipModel;
private CompressedOutputStream compressedOutputStream;
private FileHeader fileHeader;
private LocalFileHeader localFileHeader;
private FileHeaderFactory fileHeaderFactory = new FileHeaderFactory();
private HeaderWriter headerWriter = new HeaderWriter();
private CRC32 crc32 = new CRC32();
private RawIO rawIO = new RawIO();
private long uncompressedSizeForThisEntry = 0;
private Zip4jConfig zip4jConfig;
private boolean streamClosed;
private boolean entryClosed = true;
public ZipOutputStream(OutputStream outputStream) throws IOException {
this(outputStream, null, null);
}
public ZipOutputStream(OutputStream outputStream, Charset charset) throws IOException {
this(outputStream, null, charset);
}
public ZipOutputStream(OutputStream outputStream, char[] password) throws IOException {
this(outputStream, password, null);
}
public ZipOutputStream(OutputStream outputStream, char[] password, Charset charset) throws IOException {
this(outputStream, password, new Zip4jConfig(charset, BUFF_SIZE), new ZipModel());
}
public ZipOutputStream(OutputStream outputStream, char[] password, Zip4jConfig zip4jConfig,
ZipModel zipModel) throws IOException {
if (zip4jConfig.getBufferSize() < InternalZipConstants.MIN_BUFF_SIZE) {
throw new IllegalArgumentException("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
}
this.countingOutputStream = new CountingOutputStream(outputStream);
this.password = password;
this.zip4jConfig = zip4jConfig;
this.zipModel = initializeZipModel(zipModel, countingOutputStream);
this.streamClosed = false;
writeSplitZipHeaderIfApplicable();
}
public void putNextEntry(ZipParameters zipParameters) throws IOException {
verifyZipParameters(zipParameters);
ZipParameters clonedZipParameters = new ZipParameters(zipParameters);
if (isZipEntryDirectory(zipParameters.getFileNameInZip())) {
clonedZipParameters.setWriteExtendedLocalFileHeader(false);
clonedZipParameters.setCompressionMethod(CompressionMethod.STORE);
clonedZipParameters.setEncryptFiles(false);
}
initializeAndWriteFileHeader(clonedZipParameters);
//Initialisation of below compressedOutputStream should happen after writing local file header
//because local header data should be written first and then the encryption header data
//and below initialisation writes encryption header data
compressedOutputStream = initializeCompressedOutputStream(clonedZipParameters);
this.entryClosed = false;
}
public void write(int b) throws IOException {
write(new byte[] {(byte)b});
}
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
public void write(byte[] b, int off, int len) throws IOException {
ensureStreamOpen();
crc32.update(b, off, len);
compressedOutputStream.write(b, off, len);
uncompressedSizeForThisEntry += len;
}
public FileHeader closeEntry() throws IOException {
compressedOutputStream.closeEntry();
long compressedSize = compressedOutputStream.getCompressedSize();
fileHeader.setCompressedSize(compressedSize);
localFileHeader.setCompressedSize(compressedSize);
fileHeader.setUncompressedSize(uncompressedSizeForThisEntry);
localFileHeader.setUncompressedSize(uncompressedSizeForThisEntry);
if (writeCrc(fileHeader)) {
fileHeader.setCrc(crc32.getValue());
localFileHeader.setCrc(crc32.getValue());
}
zipModel.getLocalFileHeaders().add(localFileHeader);
zipModel.getCentralDirectory().getFileHeaders().add(fileHeader);
if (localFileHeader.isDataDescriptorExists()) {
headerWriter.writeExtendedLocalHeader(localFileHeader, countingOutputStream);
}
reset();
this.entryClosed = true;
return fileHeader;
}
@Override
public void close() throws IOException {
if (!this.entryClosed) {
closeEntry();
}
zipModel.getEndOfCentralDirectoryRecord().setOffsetOfStartOfCentralDirectory(countingOutputStream.getNumberOfBytesWritten());
headerWriter.finalizeZipFile(zipModel, countingOutputStream, zip4jConfig.getCharset());
countingOutputStream.close();
this.streamClosed = true;
}
public void setComment(String comment) throws IOException {
ensureStreamOpen();
zipModel.getEndOfCentralDirectoryRecord().setComment(comment);
}
private void ensureStreamOpen() throws IOException {
if (streamClosed) {
throw new IOException("Stream is closed");
}
}
private ZipModel initializeZipModel(ZipModel zipModel, CountingOutputStream countingOutputStream) {
if (zipModel == null) {
zipModel = new ZipModel();
}
if (countingOutputStream.isSplitZipFile()) {
zipModel.setSplitArchive(true);
zipModel.setSplitLength(countingOutputStream.getSplitLength());
}
return zipModel;
}
private void initializeAndWriteFileHeader(ZipParameters zipParameters) throws IOException {
fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, countingOutputStream.isSplitZipFile(),
countingOutputStream.getCurrentSplitFileCounter(), zip4jConfig.getCharset(), rawIO);
fileHeader.setOffsetLocalHeader(countingOutputStream.getOffsetForNextEntry());
localFileHeader = fileHeaderFactory.generateLocalFileHeader(fileHeader);
headerWriter.writeLocalFileHeader(zipModel, localFileHeader, countingOutputStream, zip4jConfig.getCharset());
}
private void reset() throws IOException {
uncompressedSizeForThisEntry = 0;
crc32.reset();
compressedOutputStream.close();
}
private void writeSplitZipHeaderIfApplicable() throws IOException {
if (!countingOutputStream.isSplitZipFile()) {
return;
}
rawIO.writeIntLittleEndian(countingOutputStream, (int) HeaderSignature.SPLIT_ZIP.getValue());
}
private CompressedOutputStream initializeCompressedOutputStream(ZipParameters zipParameters) throws IOException {
ZipEntryOutputStream zipEntryOutputStream = new ZipEntryOutputStream(countingOutputStream);
CipherOutputStream cipherOutputStream = initializeCipherOutputStream(zipEntryOutputStream, zipParameters);
return initializeCompressedOutputStream(cipherOutputStream, zipParameters);
}
private CipherOutputStream initializeCipherOutputStream(ZipEntryOutputStream zipEntryOutputStream,
ZipParameters zipParameters) throws IOException {
if (!zipParameters.isEncryptFiles()) {
return new NoCipherOutputStream(zipEntryOutputStream, zipParameters, null);
}
if (password == null || password.length == 0) {
throw new ZipException("password not set");
}
if (zipParameters.getEncryptionMethod() == EncryptionMethod.AES) {
return new AesCipherOutputStream(zipEntryOutputStream, zipParameters, password);
} else if (zipParameters.getEncryptionMethod() == EncryptionMethod.ZIP_STANDARD) {
return new ZipStandardCipherOutputStream(zipEntryOutputStream, zipParameters, password);
} else if (zipParameters.getEncryptionMethod() == EncryptionMethod.ZIP_STANDARD_VARIANT_STRONG) {
throw new ZipException(EncryptionMethod.ZIP_STANDARD_VARIANT_STRONG + " encryption method is not supported");
} else {
throw new ZipException("Invalid encryption method");
}
}
private CompressedOutputStream initializeCompressedOutputStream(CipherOutputStream cipherOutputStream,
ZipParameters zipParameters) {
if (zipParameters.getCompressionMethod() == CompressionMethod.DEFLATE) {
return new DeflaterOutputStream(cipherOutputStream, zipParameters.getCompressionLevel(), zip4jConfig.getBufferSize());
}
return new StoreOutputStream(cipherOutputStream);
}
private void verifyZipParameters(ZipParameters zipParameters) {
if (zipParameters.getCompressionMethod() == CompressionMethod.STORE
&& zipParameters.getEntrySize() < 0
&& !isZipEntryDirectory(zipParameters.getFileNameInZip())
&& zipParameters.isWriteExtendedLocalFileHeader()) {
throw new IllegalArgumentException("uncompressed size should be set for zip entries of compression type store");
}
}
private boolean writeCrc(FileHeader fileHeader) {
boolean isAesEncrypted = fileHeader.isEncrypted() && fileHeader.getEncryptionMethod().equals(EncryptionMethod.AES);
if (!isAesEncrypted) {
return true;
}
return fileHeader.getAesExtraDataRecord().getAesVersion().equals(AesVersion.ONE);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/io/outputstream/ZipStandardCipherOutputStream.java 0000664 0000000 0000000 00000003016 14142654472 0032466 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.crypto.StandardEncrypter;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.IOException;
import java.io.OutputStream;
class ZipStandardCipherOutputStream extends CipherOutputStream {
public ZipStandardCipherOutputStream(ZipEntryOutputStream outputStream, ZipParameters zipParameters, char[] password)
throws IOException {
super(outputStream, zipParameters, password);
}
@Override
protected StandardEncrypter initializeEncrypter(OutputStream outputStream, ZipParameters zipParameters,
char[] password) throws IOException {
long key = getEncryptionKey(zipParameters);
StandardEncrypter encrypter = new StandardEncrypter(password, key);
writeHeaders(encrypter.getHeaderBytes());
return encrypter;
}
@Override
public void write(int b) throws IOException {
write(new byte[] {(byte) b});
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
super.write(b, off, len);
}
private long getEncryptionKey(ZipParameters zipParameters) {
if (zipParameters.isWriteExtendedLocalFileHeader()) {
long dosTime = Zip4jUtil.epochToExtendedDosTime(zipParameters.getLastModifiedFileTime());
return (dosTime & 0x0000ffff) << 16;
}
return zipParameters.getEntryCRC();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/ 0000775 0000000 0000000 00000000000 14142654472 0021565 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/AESExtraDataRecord.java 0000775 0000000 0000000 00000004200 14142654472 0025774 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
import net.lingala.zip4j.headers.HeaderSignature;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
public class AESExtraDataRecord extends ZipHeader {
private int dataSize;
private AesVersion aesVersion;
private String vendorID;
private AesKeyStrength aesKeyStrength;
private CompressionMethod compressionMethod;
public AESExtraDataRecord() {
setSignature(HeaderSignature.AES_EXTRA_DATA_RECORD);
dataSize = 7;
aesVersion = AesVersion.TWO;
vendorID = "AE";
aesKeyStrength = AesKeyStrength.KEY_STRENGTH_256;
compressionMethod = CompressionMethod.DEFLATE;
}
public int getDataSize() {
return dataSize;
}
public void setDataSize(int dataSize) {
this.dataSize = dataSize;
}
public AesVersion getAesVersion() {
return aesVersion;
}
public void setAesVersion(AesVersion aesVersion) {
this.aesVersion = aesVersion;
}
public String getVendorID() {
return vendorID;
}
public void setVendorID(String vendorID) {
this.vendorID = vendorID;
}
public AesKeyStrength getAesKeyStrength() {
return aesKeyStrength;
}
public void setAesKeyStrength(AesKeyStrength aesKeyStrength) {
this.aesKeyStrength = aesKeyStrength;
}
public CompressionMethod getCompressionMethod() {
return compressionMethod;
}
public void setCompressionMethod(CompressionMethod compressionMethod) {
this.compressionMethod = compressionMethod;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/AbstractFileHeader.java 0000664 0000000 0000000 00000011057 14142654472 0026110 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.Zip4jUtil;
import java.util.List;
public abstract class AbstractFileHeader extends ZipHeader {
private int versionNeededToExtract;
private byte[] generalPurposeFlag;
private CompressionMethod compressionMethod;
private long lastModifiedTime;
private long crc = 0;
private long compressedSize = 0;
private long uncompressedSize = 0;
private int fileNameLength;
private int extraFieldLength;
private String fileName;
private boolean isEncrypted;
private EncryptionMethod encryptionMethod = EncryptionMethod.NONE;
private boolean dataDescriptorExists;
private Zip64ExtendedInfo zip64ExtendedInfo;
private AESExtraDataRecord aesExtraDataRecord;
private boolean fileNameUTF8Encoded;
private List extraDataRecords;
private boolean isDirectory;
public int getVersionNeededToExtract() {
return versionNeededToExtract;
}
public void setVersionNeededToExtract(int versionNeededToExtract) {
this.versionNeededToExtract = versionNeededToExtract;
}
public byte[] getGeneralPurposeFlag() {
return generalPurposeFlag;
}
public void setGeneralPurposeFlag(byte[] generalPurposeFlag) {
this.generalPurposeFlag = generalPurposeFlag;
}
public CompressionMethod getCompressionMethod() {
return compressionMethod;
}
public void setCompressionMethod(CompressionMethod compressionMethod) {
this.compressionMethod = compressionMethod;
}
public long getLastModifiedTime() {
return lastModifiedTime;
}
public void setLastModifiedTime(long lastModifiedTime) {
this.lastModifiedTime = lastModifiedTime;
}
public long getLastModifiedTimeEpoch() {
return Zip4jUtil.dosToExtendedEpochTme(lastModifiedTime);
}
public long getCrc() {
return crc;
}
public void setCrc(long crc) {
this.crc = crc;
}
public long getCompressedSize() {
return compressedSize;
}
public void setCompressedSize(long compressedSize) {
this.compressedSize = compressedSize;
}
public long getUncompressedSize() {
return uncompressedSize;
}
public void setUncompressedSize(long uncompressedSize) {
this.uncompressedSize = uncompressedSize;
}
public int getFileNameLength() {
return fileNameLength;
}
public void setFileNameLength(int fileNameLength) {
this.fileNameLength = fileNameLength;
}
public int getExtraFieldLength() {
return extraFieldLength;
}
public void setExtraFieldLength(int extraFieldLength) {
this.extraFieldLength = extraFieldLength;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public boolean isEncrypted() {
return isEncrypted;
}
public void setEncrypted(boolean encrypted) {
isEncrypted = encrypted;
}
public EncryptionMethod getEncryptionMethod() {
return encryptionMethod;
}
public void setEncryptionMethod(EncryptionMethod encryptionMethod) {
this.encryptionMethod = encryptionMethod;
}
public boolean isDataDescriptorExists() {
return dataDescriptorExists;
}
public void setDataDescriptorExists(boolean dataDescriptorExists) {
this.dataDescriptorExists = dataDescriptorExists;
}
public Zip64ExtendedInfo getZip64ExtendedInfo() {
return zip64ExtendedInfo;
}
public void setZip64ExtendedInfo(Zip64ExtendedInfo zip64ExtendedInfo) {
this.zip64ExtendedInfo = zip64ExtendedInfo;
}
public AESExtraDataRecord getAesExtraDataRecord() {
return aesExtraDataRecord;
}
public void setAesExtraDataRecord(AESExtraDataRecord aesExtraDataRecord) {
this.aesExtraDataRecord = aesExtraDataRecord;
}
public boolean isFileNameUTF8Encoded() {
return fileNameUTF8Encoded;
}
public void setFileNameUTF8Encoded(boolean fileNameUTF8Encoded) {
this.fileNameUTF8Encoded = fileNameUTF8Encoded;
}
public List getExtraDataRecords() {
return extraDataRecords;
}
public void setExtraDataRecords(List extraDataRecords) {
this.extraDataRecords = extraDataRecords;
}
public boolean isDirectory() {
return isDirectory;
}
public void setDirectory(boolean directory) {
isDirectory = directory;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof AbstractFileHeader)) {
return false;
}
return this.getFileName().equals(((AbstractFileHeader) obj).getFileName());
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/ArchiveExtraDataRecord.java 0000775 0000000 0000000 00000002204 14142654472 0026747 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
public class ArchiveExtraDataRecord extends ZipHeader {
private int extraFieldLength;
private String extraFieldData;
public int getExtraFieldLength() {
return extraFieldLength;
}
public void setExtraFieldLength(int extraFieldLength) {
this.extraFieldLength = extraFieldLength;
}
public String getExtraFieldData() {
return extraFieldData;
}
public void setExtraFieldData(String extraFieldData) {
this.extraFieldData = extraFieldData;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/CentralDirectory.java 0000775 0000000 0000000 00000002402 14142654472 0025706 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
import java.util.ArrayList;
import java.util.List;
public class CentralDirectory {
private List fileHeaders = new ArrayList<>();
private DigitalSignature digitalSignature = new DigitalSignature();
public List getFileHeaders() {
return fileHeaders;
}
public void setFileHeaders(List fileHeaders) {
this.fileHeaders = fileHeaders;
}
public DigitalSignature getDigitalSignature() {
return digitalSignature;
}
public void setDigitalSignature(DigitalSignature digitalSignature) {
this.digitalSignature = digitalSignature;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/DataDescriptor.java 0000775 0000000 0000000 00000002315 14142654472 0025344 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
public class DataDescriptor extends ZipHeader {
private long crc;
private long compressedSize;
private long uncompressedSize;
public long getCrc() {
return crc;
}
public void setCrc(long crc) {
this.crc = crc;
}
public long getCompressedSize() {
return compressedSize;
}
public void setCompressedSize(long compressedSize) {
this.compressedSize = compressedSize;
}
public long getUncompressedSize() {
return uncompressedSize;
}
public void setUncompressedSize(long uncompressedSize) {
this.uncompressedSize = uncompressedSize;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/DigitalSignature.java 0000775 0000000 0000000 00000002116 14142654472 0025672 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
public class DigitalSignature extends ZipHeader {
private int sizeOfData;
private String signatureData;
public int getSizeOfData() {
return sizeOfData;
}
public void setSizeOfData(int sizeOfData) {
this.sizeOfData = sizeOfData;
}
public String getSignatureData() {
return signatureData;
}
public void setSignatureData(String signatureData) {
this.signatureData = signatureData;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/EndOfCentralDirectoryRecord.java 0000775 0000000 0000000 00000006263 14142654472 0027772 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
import net.lingala.zip4j.headers.HeaderSignature;
public class EndOfCentralDirectoryRecord extends ZipHeader {
private int numberOfThisDisk;
private int numberOfThisDiskStartOfCentralDir;
private int totalNumberOfEntriesInCentralDirectoryOnThisDisk;
private int totalNumberOfEntriesInCentralDirectory;
private int sizeOfCentralDirectory;
private long offsetOfStartOfCentralDirectory;
private long offsetOfEndOfCentralDirectory;
private String comment = "";
public EndOfCentralDirectoryRecord() {
setSignature(HeaderSignature.END_OF_CENTRAL_DIRECTORY);
}
public int getNumberOfThisDisk() {
return numberOfThisDisk;
}
public void setNumberOfThisDisk(int numberOfThisDisk) {
this.numberOfThisDisk = numberOfThisDisk;
}
public int getNumberOfThisDiskStartOfCentralDir() {
return numberOfThisDiskStartOfCentralDir;
}
public void setNumberOfThisDiskStartOfCentralDir(int numberOfThisDiskStartOfCentralDir) {
this.numberOfThisDiskStartOfCentralDir = numberOfThisDiskStartOfCentralDir;
}
public int getTotalNumberOfEntriesInCentralDirectoryOnThisDisk() {
return totalNumberOfEntriesInCentralDirectoryOnThisDisk;
}
public void setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(
int totalNumberOfEntriesInCentralDirectoryOnThisDisk) {
this.totalNumberOfEntriesInCentralDirectoryOnThisDisk = totalNumberOfEntriesInCentralDirectoryOnThisDisk;
}
public int getTotalNumberOfEntriesInCentralDirectory() {
return totalNumberOfEntriesInCentralDirectory;
}
public void setTotalNumberOfEntriesInCentralDirectory(int totNoOfEntrisInCentralDir) {
this.totalNumberOfEntriesInCentralDirectory = totNoOfEntrisInCentralDir;
}
public int getSizeOfCentralDirectory() {
return sizeOfCentralDirectory;
}
public void setSizeOfCentralDirectory(int sizeOfCentralDirectory) {
this.sizeOfCentralDirectory = sizeOfCentralDirectory;
}
public long getOffsetOfStartOfCentralDirectory() {
return offsetOfStartOfCentralDirectory;
}
public void setOffsetOfStartOfCentralDirectory(long offSetOfStartOfCentralDir) {
this.offsetOfStartOfCentralDirectory = offSetOfStartOfCentralDir;
}
public long getOffsetOfEndOfCentralDirectory() {
return offsetOfEndOfCentralDirectory;
}
public void setOffsetOfEndOfCentralDirectory(long offsetOfEndOfCentralDirectory) {
this.offsetOfEndOfCentralDirectory = offsetOfEndOfCentralDirectory;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
if (comment != null) {
this.comment = comment;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/ExcludeFileFilter.java 0000664 0000000 0000000 00000000204 14142654472 0025763 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model;
import java.io.File;
public interface ExcludeFileFilter {
boolean isExcluded(File file);
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/ExtraDataRecord.java 0000775 0000000 0000000 00000002247 14142654472 0025454 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
public class ExtraDataRecord extends ZipHeader {
private long header;
private int sizeOfData;
private byte[] data;
public long getHeader() {
return header;
}
public void setHeader(long header) {
this.header = header;
}
public int getSizeOfData() {
return sizeOfData;
}
public void setSizeOfData(int sizeOfData) {
this.sizeOfData = sizeOfData;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/FileHeader.java 0000775 0000000 0000000 00000006147 14142654472 0024433 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
import net.lingala.zip4j.headers.HeaderSignature;
import java.util.Objects;
public class FileHeader extends AbstractFileHeader {
private int versionMadeBy;
private int fileCommentLength = 0;
private int diskNumberStart;
private byte[] internalFileAttributes;
private byte[] externalFileAttributes;
private long offsetLocalHeader;
private String fileComment;
public FileHeader() {
setSignature(HeaderSignature.CENTRAL_DIRECTORY);
}
public int getVersionMadeBy() {
return versionMadeBy;
}
public void setVersionMadeBy(int versionMadeBy) {
this.versionMadeBy = versionMadeBy;
}
public int getFileCommentLength() {
return fileCommentLength;
}
public void setFileCommentLength(int fileCommentLength) {
this.fileCommentLength = fileCommentLength;
}
public int getDiskNumberStart() {
return diskNumberStart;
}
public void setDiskNumberStart(int diskNumberStart) {
this.diskNumberStart = diskNumberStart;
}
public byte[] getInternalFileAttributes() {
return internalFileAttributes;
}
public void setInternalFileAttributes(byte[] internalFileAttributes) {
this.internalFileAttributes = internalFileAttributes;
}
public byte[] getExternalFileAttributes() {
return externalFileAttributes;
}
public void setExternalFileAttributes(byte[] externalFileAttributes) {
this.externalFileAttributes = externalFileAttributes;
}
public long getOffsetLocalHeader() {
return offsetLocalHeader;
}
public void setOffsetLocalHeader(long offsetLocalHeader) {
this.offsetLocalHeader = offsetLocalHeader;
}
public String getFileComment() {
return fileComment;
}
public void setFileComment(String fileComment) {
this.fileComment = fileComment;
}
@Override
public String toString() {
return getFileName();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
FileHeader that = (FileHeader) o;
return determineOffsetOfLocalFileHeader(this) == determineOffsetOfLocalFileHeader(that);
}
@Override
public int hashCode() {
return Objects.hash(getFileName(), determineOffsetOfLocalFileHeader(this));
}
private long determineOffsetOfLocalFileHeader(FileHeader fileHeader) {
if (fileHeader.getZip64ExtendedInfo() != null) {
return fileHeader.getZip64ExtendedInfo().getOffsetLocalHeader();
}
return fileHeader.getOffsetLocalHeader();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/LocalFileHeader.java 0000775 0000000 0000000 00000003107 14142654472 0025377 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
import net.lingala.zip4j.headers.HeaderSignature;
public class LocalFileHeader extends AbstractFileHeader {
private byte[] extraField;
private long offsetStartOfData;
private boolean writeCompressedSizeInZip64ExtraRecord;
public LocalFileHeader() {
setSignature(HeaderSignature.LOCAL_FILE_HEADER);
}
public byte[] getExtraField() {
return extraField;
}
public void setExtraField(byte[] extraField) {
this.extraField = extraField;
}
public long getOffsetStartOfData() {
return offsetStartOfData;
}
public void setOffsetStartOfData(long offsetStartOfData) {
this.offsetStartOfData = offsetStartOfData;
}
public boolean isWriteCompressedSizeInZip64ExtraRecord() {
return writeCompressedSizeInZip64ExtraRecord;
}
public void setWriteCompressedSizeInZip64ExtraRecord(boolean writeCompressedSizeInZip64ExtraRecord) {
this.writeCompressedSizeInZip64ExtraRecord = writeCompressedSizeInZip64ExtraRecord;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/UnzipParameters.java 0000664 0000000 0000000 00000000506 14142654472 0025562 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model;
public class UnzipParameters {
private boolean extractSymbolicLinks = true;
public boolean isExtractSymbolicLinks() {
return extractSymbolicLinks;
}
public void setExtractSymbolicLinks(boolean extractSymbolicLinks) {
this.extractSymbolicLinks = extractSymbolicLinks;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/Zip4jConfig.java 0000664 0000000 0000000 00000000622 14142654472 0024556 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model;
import java.nio.charset.Charset;
public class Zip4jConfig {
private final Charset charset;
private final int bufferSize;
public Zip4jConfig(Charset charset, int bufferSize) {
this.charset = charset;
this.bufferSize = bufferSize;
}
public Charset getCharset() {
return charset;
}
public int getBufferSize() {
return bufferSize;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/Zip64EndOfCentralDirectoryLocator.java 0000775 0000000 0000000 00000003312 14142654472 0031004 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
public class Zip64EndOfCentralDirectoryLocator extends ZipHeader {
private int numberOfDiskStartOfZip64EndOfCentralDirectoryRecord;
private long offsetZip64EndOfCentralDirectoryRecord;
private int totalNumberOfDiscs;
public int getNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord() {
return numberOfDiskStartOfZip64EndOfCentralDirectoryRecord;
}
public void setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(
int noOfDiskStartOfZip64EndOfCentralDirRec) {
this.numberOfDiskStartOfZip64EndOfCentralDirectoryRecord = noOfDiskStartOfZip64EndOfCentralDirRec;
}
public long getOffsetZip64EndOfCentralDirectoryRecord() {
return offsetZip64EndOfCentralDirectoryRecord;
}
public void setOffsetZip64EndOfCentralDirectoryRecord(long offsetZip64EndOfCentralDirectoryRecord) {
this.offsetZip64EndOfCentralDirectoryRecord = offsetZip64EndOfCentralDirectoryRecord;
}
public int getTotalNumberOfDiscs() {
return totalNumberOfDiscs;
}
public void setTotalNumberOfDiscs(int totNumberOfDiscs) {
this.totalNumberOfDiscs = totNumberOfDiscs;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/Zip64EndOfCentralDirectoryRecord.java 0000775 0000000 0000000 00000007404 14142654472 0030625 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
public class Zip64EndOfCentralDirectoryRecord extends ZipHeader {
private long sizeOfZip64EndCentralDirectoryRecord;
private int versionMadeBy;
private int versionNeededToExtract;
private int numberOfThisDisk;
private int numberOfThisDiskStartOfCentralDirectory;
private long totalNumberOfEntriesInCentralDirectoryOnThisDisk;
private long totalNumberOfEntriesInCentralDirectory;
private long sizeOfCentralDirectory;
private long offsetStartCentralDirectoryWRTStartDiskNumber = -1;
private byte[] extensibleDataSector;
public long getSizeOfZip64EndCentralDirectoryRecord() {
return sizeOfZip64EndCentralDirectoryRecord;
}
public void setSizeOfZip64EndCentralDirectoryRecord(long sizeOfZip64EndCentralDirectoryRecord) {
this.sizeOfZip64EndCentralDirectoryRecord = sizeOfZip64EndCentralDirectoryRecord;
}
public int getVersionMadeBy() {
return versionMadeBy;
}
public void setVersionMadeBy(int versionMadeBy) {
this.versionMadeBy = versionMadeBy;
}
public int getVersionNeededToExtract() {
return versionNeededToExtract;
}
public void setVersionNeededToExtract(int versionNeededToExtract) {
this.versionNeededToExtract = versionNeededToExtract;
}
public int getNumberOfThisDisk() {
return numberOfThisDisk;
}
public void setNumberOfThisDisk(int numberOfThisDisk) {
this.numberOfThisDisk = numberOfThisDisk;
}
public int getNumberOfThisDiskStartOfCentralDirectory() {
return numberOfThisDiskStartOfCentralDirectory;
}
public void setNumberOfThisDiskStartOfCentralDirectory(int numberOfThisDiskStartOfCentralDirectory) {
this.numberOfThisDiskStartOfCentralDirectory = numberOfThisDiskStartOfCentralDirectory;
}
public long getTotalNumberOfEntriesInCentralDirectoryOnThisDisk() {
return totalNumberOfEntriesInCentralDirectoryOnThisDisk;
}
public void setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(
long totalNumberOfEntriesInCentralDirectoryOnThisDisk) {
this.totalNumberOfEntriesInCentralDirectoryOnThisDisk = totalNumberOfEntriesInCentralDirectoryOnThisDisk;
}
public long getTotalNumberOfEntriesInCentralDirectory() {
return totalNumberOfEntriesInCentralDirectory;
}
public void setTotalNumberOfEntriesInCentralDirectory(long totalNumberOfEntriesInCentralDirectory) {
this.totalNumberOfEntriesInCentralDirectory = totalNumberOfEntriesInCentralDirectory;
}
public long getSizeOfCentralDirectory() {
return sizeOfCentralDirectory;
}
public void setSizeOfCentralDirectory(long sizeOfCentralDirectory) {
this.sizeOfCentralDirectory = sizeOfCentralDirectory;
}
public long getOffsetStartCentralDirectoryWRTStartDiskNumber() {
return offsetStartCentralDirectoryWRTStartDiskNumber;
}
public void setOffsetStartCentralDirectoryWRTStartDiskNumber(
long offsetStartCentralDirectoryWRTStartDiskNumber) {
this.offsetStartCentralDirectoryWRTStartDiskNumber = offsetStartCentralDirectoryWRTStartDiskNumber;
}
public byte[] getExtensibleDataSector() {
return extensibleDataSector;
}
public void setExtensibleDataSector(byte[] extensibleDataSector) {
this.extensibleDataSector = extensibleDataSector;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/Zip64ExtendedInfo.java 0000775 0000000 0000000 00000003531 14142654472 0025646 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
public class Zip64ExtendedInfo extends ZipHeader {
private int size;
private long compressedSize;
private long uncompressedSize;
private long offsetLocalHeader;
private int diskNumberStart;
public Zip64ExtendedInfo() {
compressedSize = -1;
uncompressedSize = -1;
offsetLocalHeader = -1;
diskNumberStart = -1;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public long getCompressedSize() {
return compressedSize;
}
public void setCompressedSize(long compressedSize) {
this.compressedSize = compressedSize;
}
public long getUncompressedSize() {
return uncompressedSize;
}
public void setUncompressedSize(long uncompressedSize) {
this.uncompressedSize = uncompressedSize;
}
public long getOffsetLocalHeader() {
return offsetLocalHeader;
}
public void setOffsetLocalHeader(long offsetLocalHeader) {
this.offsetLocalHeader = offsetLocalHeader;
}
public int getDiskNumberStart() {
return diskNumberStart;
}
public void setDiskNumberStart(int diskNumberStart) {
this.diskNumberStart = diskNumberStart;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/ZipHeader.java 0000664 0000000 0000000 00000000501 14142654472 0024277 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model;
import net.lingala.zip4j.headers.HeaderSignature;
public abstract class ZipHeader {
private HeaderSignature signature;
public HeaderSignature getSignature() {
return signature;
}
public void setSignature(HeaderSignature signature) {
this.signature = signature;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/ZipModel.java 0000775 0000000 0000000 00000011264 14142654472 0024162 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ZipModel implements Cloneable {
private List localFileHeaders = new ArrayList<>();
private List dataDescriptors = new ArrayList<>();
private ArchiveExtraDataRecord archiveExtraDataRecord = new ArchiveExtraDataRecord();
private CentralDirectory centralDirectory = new CentralDirectory();
private EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = new EndOfCentralDirectoryRecord();
private Zip64EndOfCentralDirectoryLocator zip64EndOfCentralDirectoryLocator = new Zip64EndOfCentralDirectoryLocator();
private Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = new Zip64EndOfCentralDirectoryRecord();
private boolean splitArchive;
private long splitLength;
private File zipFile;
private boolean isZip64Format = false;
private boolean isNestedZipFile;
private long start;
private long end;
public ZipModel() {
splitLength = -1;
}
public List getLocalFileHeaders() {
return localFileHeaders;
}
public void setLocalFileHeaders(List localFileHeaderList) {
this.localFileHeaders = localFileHeaderList;
}
public List getDataDescriptors() {
return dataDescriptors;
}
public void setDataDescriptors(List dataDescriptors) {
this.dataDescriptors = dataDescriptors;
}
public CentralDirectory getCentralDirectory() {
return centralDirectory;
}
public void setCentralDirectory(CentralDirectory centralDirectory) {
this.centralDirectory = centralDirectory;
}
public EndOfCentralDirectoryRecord getEndOfCentralDirectoryRecord() {
return endOfCentralDirectoryRecord;
}
public void setEndOfCentralDirectoryRecord(EndOfCentralDirectoryRecord endOfCentralDirectoryRecord) {
this.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord;
}
public ArchiveExtraDataRecord getArchiveExtraDataRecord() {
return archiveExtraDataRecord;
}
public void setArchiveExtraDataRecord(
ArchiveExtraDataRecord archiveExtraDataRecord) {
this.archiveExtraDataRecord = archiveExtraDataRecord;
}
public boolean isSplitArchive() {
return splitArchive;
}
public void setSplitArchive(boolean splitArchive) {
this.splitArchive = splitArchive;
}
public File getZipFile() {
return zipFile;
}
public void setZipFile(File zipFile) {
this.zipFile = zipFile;
}
public Zip64EndOfCentralDirectoryLocator getZip64EndOfCentralDirectoryLocator() {
return zip64EndOfCentralDirectoryLocator;
}
public void setZip64EndOfCentralDirectoryLocator(
Zip64EndOfCentralDirectoryLocator zip64EndOfCentralDirectoryLocator) {
this.zip64EndOfCentralDirectoryLocator = zip64EndOfCentralDirectoryLocator;
}
public Zip64EndOfCentralDirectoryRecord getZip64EndOfCentralDirectoryRecord() {
return zip64EndOfCentralDirectoryRecord;
}
public void setZip64EndOfCentralDirectoryRecord(
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord) {
this.zip64EndOfCentralDirectoryRecord = zip64EndOfCentralDirectoryRecord;
}
public boolean isZip64Format() {
return isZip64Format;
}
public void setZip64Format(boolean isZip64Format) {
this.isZip64Format = isZip64Format;
}
public boolean isNestedZipFile() {
return isNestedZipFile;
}
public void setNestedZipFile(boolean isNestedZipFile) {
this.isNestedZipFile = isNestedZipFile;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
public long getSplitLength() {
return splitLength;
}
public void setSplitLength(long splitLength) {
this.splitLength = splitLength;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/ZipParameters.java 0000775 0000000 0000000 00000032766 14142654472 0025237 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.model;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
/**
* Encapsulates the parameters that that control how Zip4J encodes data
*/
public class ZipParameters {
/**
* Indicates the action to take when a symbolic link is added to the ZIP file
*/
public enum SymbolicLinkAction {
/**
* Add only the symbolic link itself, not the target file or its contents
*/
INCLUDE_LINK_ONLY,
/**
* Add only the target file and its contents, using the filename of the symbolic link
*/
INCLUDE_LINKED_FILE_ONLY,
/**
* Add the symbolic link itself and the target file with its original filename and its contents
*/
INCLUDE_LINK_AND_LINKED_FILE
};
private CompressionMethod compressionMethod = CompressionMethod.DEFLATE;
private CompressionLevel compressionLevel = CompressionLevel.NORMAL;
private boolean encryptFiles = false;
private EncryptionMethod encryptionMethod = EncryptionMethod.NONE;
private boolean readHiddenFiles = true;
private boolean readHiddenFolders = true;
private AesKeyStrength aesKeyStrength = AesKeyStrength.KEY_STRENGTH_256;
private AesVersion aesVersion = AesVersion.TWO;
private boolean includeRootFolder = true;
private long entryCRC;
private String defaultFolderPath;
private String fileNameInZip;
private long lastModifiedFileTime = System.currentTimeMillis();
private long entrySize = -1;
private boolean writeExtendedLocalFileHeader = true;
private boolean overrideExistingFilesInZip = true;
private String rootFolderNameInZip;
private String fileComment;
private SymbolicLinkAction symbolicLinkAction = SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY;
private ExcludeFileFilter excludeFileFilter;
private boolean unixMode;
/**
* Create a ZipParameters instance with default values;
* CompressionMethod.DEFLATE, CompressionLevel.NORMAL, EncryptionMethod.NONE,
* AesKeyStrength.KEY_STRENGTH_256, AesVerson.Two, SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY,
* readHiddenFiles is true, readHiddenFolders is true, includeRootInFolder is true,
* writeExtendedLocalFileHeader is true, overrideExistingFilesInZip is true
*/
public ZipParameters() {
}
/**
* Create a clone of given ZipParameters instance
* @param zipParameters the ZipParameters instance to clone
*/
public ZipParameters(ZipParameters zipParameters) {
this.compressionMethod = zipParameters.getCompressionMethod();
this.compressionLevel = zipParameters.getCompressionLevel();
this.encryptFiles = zipParameters.isEncryptFiles();
this.encryptionMethod = zipParameters.getEncryptionMethod();
this.readHiddenFiles = zipParameters.isReadHiddenFiles();
this.readHiddenFolders = zipParameters.isReadHiddenFolders();
this.aesKeyStrength = zipParameters.getAesKeyStrength();
this.aesVersion = zipParameters.getAesVersion();
this.includeRootFolder = zipParameters.isIncludeRootFolder();
this.entryCRC = zipParameters.getEntryCRC();
this.defaultFolderPath = zipParameters.getDefaultFolderPath();
this.fileNameInZip = zipParameters.getFileNameInZip();
this.lastModifiedFileTime = zipParameters.getLastModifiedFileTime();
this.entrySize = zipParameters.getEntrySize();
this.writeExtendedLocalFileHeader = zipParameters.isWriteExtendedLocalFileHeader();
this.overrideExistingFilesInZip = zipParameters.isOverrideExistingFilesInZip();
this.rootFolderNameInZip = zipParameters.getRootFolderNameInZip();
this.fileComment = zipParameters.getFileComment();
this.symbolicLinkAction = zipParameters.getSymbolicLinkAction();
this.excludeFileFilter = zipParameters.getExcludeFileFilter();
this.unixMode = zipParameters.isUnixMode();
}
/**
* Get the compression method specified in this ZipParameters
* @return the ZIP compression method
*/
public CompressionMethod getCompressionMethod() {
return compressionMethod;
}
/**
* Set the ZIP compression method
* @param compressionMethod the ZIP compression method
*/
public void setCompressionMethod(CompressionMethod compressionMethod) {
this.compressionMethod = compressionMethod;
}
/**
* Test if files files are to be encrypted
* @return true if files are to be encrypted
*/
public boolean isEncryptFiles() {
return encryptFiles;
}
/**
* Set the flag indicating that files are to be encrypted
* @param encryptFiles if true, files will be encrypted
*/
public void setEncryptFiles(boolean encryptFiles) {
this.encryptFiles = encryptFiles;
}
/**
* Get the encryption method used to encrypt files
* @return the encryption method
*/
public EncryptionMethod getEncryptionMethod() {
return encryptionMethod;
}
/**
* Set the encryption method used to encrypt files
* @param encryptionMethod the encryption method to be used
*/
public void setEncryptionMethod(EncryptionMethod encryptionMethod) {
this.encryptionMethod = encryptionMethod;
}
/**
* Get the compression level used to compress files
* @return the compression level used to compress files
*/
public CompressionLevel getCompressionLevel() {
return compressionLevel;
}
/**
* Set the compression level used to compress files
* @param compressionLevel the compression level used to compress files
*/
public void setCompressionLevel(CompressionLevel compressionLevel) {
this.compressionLevel = compressionLevel;
}
/**
* Test if hidden files will be included during folder recursion
*
* @return true if hidden files will be included when adding folders to the zip
*/
public boolean isReadHiddenFiles() {
return readHiddenFiles;
}
/**
* Indicate if hidden files will be included during folder recursion
*
* @param readHiddenFiles if true, hidden files will be included when adding folders to the zip
*/
public void setReadHiddenFiles(boolean readHiddenFiles) {
this.readHiddenFiles = readHiddenFiles;
}
/**
* Test if hidden folders will be included during folder recursion
*
* @return true if hidden folders will be included when adding folders to the zip
*/
public boolean isReadHiddenFolders() {
return readHiddenFolders;
}
/**
* Indicate if hidden folders will be included during folder recursion
* @param readHiddenFolders if true, hidden folders will be included when added folders to the zip
*/
public void setReadHiddenFolders(boolean readHiddenFolders) {
this.readHiddenFolders = readHiddenFolders;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* Get the key strength of the AES encryption key
* @return the key strength of the AES encryption key
*/
public AesKeyStrength getAesKeyStrength() {
return aesKeyStrength;
}
/**
* Set the key strength of the AES encryption key
* @param aesKeyStrength the key strength of the AES encryption key
*/
public void setAesKeyStrength(AesKeyStrength aesKeyStrength) {
this.aesKeyStrength = aesKeyStrength;
}
/**
* Get the AES format version used for encryption
* @return the AES format version used for encryption
*/
public AesVersion getAesVersion() {
return aesVersion;
}
/**
* Set the AES format version to use for encryption
* @param aesVersion the AES format version to use
*/
public void setAesVersion(AesVersion aesVersion) {
this.aesVersion = aesVersion;
}
/**
* Test if the parent folder of the added files will be included in the ZIP
* @return true if the parent folder of the added files will be included into the zip
*/
public boolean isIncludeRootFolder() {
return includeRootFolder;
}
/**
* Set the flag to indicate if the parent folder of added files will be included in the ZIP
* @param includeRootFolder if true, the parent folder of added files will be included in the ZIP
*/
public void setIncludeRootFolder(boolean includeRootFolder) {
this.includeRootFolder = includeRootFolder;
}
public long getEntryCRC() {
return entryCRC;
}
public void setEntryCRC(long entryCRC) {
this.entryCRC = entryCRC;
}
public String getDefaultFolderPath() {
return defaultFolderPath;
}
public void setDefaultFolderPath(String defaultFolderPath) {
this.defaultFolderPath = defaultFolderPath;
}
public String getFileNameInZip() {
return fileNameInZip;
}
/**
* Set the filename that will be used to include a file into the ZIP file to a different name
* that given by the source filename added to the ZIP file. The filenameInZip must
* adhere to the ZIP filename specification, including the use of forward slash '/' as the
* directory separator, and it must also be a relative file. If the filenameInZip given is not null and
* not empty, the value specified by setRootFolderNameInZip() will be ignored.
*
* @param fileNameInZip the filename to set in the ZIP. Use null or an empty String to set the default behavior
*/
public void setFileNameInZip(String fileNameInZip) {
this.fileNameInZip = fileNameInZip;
}
/**
* Get the last modified time to be used for files written to the ZIP
* @return the last modified time in milliseconds since the epoch
*/
public long getLastModifiedFileTime() {
return lastModifiedFileTime;
}
/**
* Set the last modified time recorded in the ZIP file for the added files. If less than 0,
* the last modified time is cleared and the current time is used
* @param lastModifiedFileTime the last modified time in milliseconds since the epoch
*/
public void setLastModifiedFileTime(long lastModifiedFileTime) {
if (lastModifiedFileTime <= 0) {
return;
}
this.lastModifiedFileTime = lastModifiedFileTime;
}
public long getEntrySize() {
return entrySize;
}
public void setEntrySize(long entrySize) {
this.entrySize = entrySize;
}
public boolean isWriteExtendedLocalFileHeader() {
return writeExtendedLocalFileHeader;
}
public void setWriteExtendedLocalFileHeader(boolean writeExtendedLocalFileHeader) {
this.writeExtendedLocalFileHeader = writeExtendedLocalFileHeader;
}
public boolean isOverrideExistingFilesInZip() {
return overrideExistingFilesInZip;
}
/**
* Set the behavior if a file is added that already exists in the ZIP.
* @param overrideExistingFilesInZip if true, remove the existing file in the ZIP; if false do not add the new file
*/
public void setOverrideExistingFilesInZip(boolean overrideExistingFilesInZip) {
this.overrideExistingFilesInZip = overrideExistingFilesInZip;
}
public String getRootFolderNameInZip() {
return rootFolderNameInZip;
}
/**
* Set the folder name that will be prepended to the filename in the ZIP. This value is ignored
* if setFileNameInZip() is specified with a non-null, non-empty string.
*
* @param rootFolderNameInZip the name of the folder to be prepended to the filename
* in the ZIP archive
*/
public void setRootFolderNameInZip(String rootFolderNameInZip) {
this.rootFolderNameInZip = rootFolderNameInZip;
}
/**
* Get the file comment
* @return the file comment
*/
public String getFileComment() {
return fileComment;
}
/**
* Set the file comment
* @param fileComment the file comment
*/
public void setFileComment(String fileComment) {
this.fileComment = fileComment;
}
/**
* Get the behavior when adding a symbolic link
* @return the behavior when adding a symbolic link
*/
public SymbolicLinkAction getSymbolicLinkAction() {
return symbolicLinkAction;
}
/**
* Set the behavior when adding a symbolic link
* @param symbolicLinkAction the behavior when adding a symbolic link
*/
public void setSymbolicLinkAction(SymbolicLinkAction symbolicLinkAction) {
this.symbolicLinkAction = symbolicLinkAction;
}
/**
* Returns the file exclusion filter that is currently being used when adding files/folders to zip file
* @return ExcludeFileFilter
*/
public ExcludeFileFilter getExcludeFileFilter() {
return excludeFileFilter;
}
/**
* Set a filter to exclude any files from the list of files being added to zip. Mostly used when adding a folder
* to a zip, and if certain files have to be excluded from adding to the zip file.
*/
public void setExcludeFileFilter(ExcludeFileFilter excludeFileFilter) {
this.excludeFileFilter = excludeFileFilter;
}
/**
* Returns true if zip4j is using unix mode as default. Returns False otherwise.
* @return true if zip4j is using unix mode as default, false otherwise
*/
public boolean isUnixMode() {
return unixMode;
}
/**
* When set to true, zip4j uses unix mode as default when generating file headers.
* @param unixMode
*/
public void setUnixMode(boolean unixMode) {
this.unixMode = unixMode;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/enums/ 0000775 0000000 0000000 00000000000 14142654472 0022714 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/enums/AesKeyStrength.java 0000664 0000000 0000000 00000003026 14142654472 0026460 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model.enums;
/**
* Indicates the AES encryption key length
*
*/
public enum AesKeyStrength {
/**
* 128-bit AES key length
*/
KEY_STRENGTH_128(1, 8, 16, 16),
/**
* 192-bit AES key length
*/
KEY_STRENGTH_192(2, 12, 24, 24),
/**
* 256-bit AES key length
*/
KEY_STRENGTH_256(3, 16, 32, 32);
private int rawCode;
private int saltLength;
private int macLength;
private int keyLength;
AesKeyStrength(int rawCode, int saltLength, int macLength, int keyLength) {
this.rawCode = rawCode;
this.saltLength = saltLength;
this.macLength = macLength;
this.keyLength = keyLength;
}
/**
* Get the code written to the ZIP file
* @return the code written the ZIP file
*/
public int getRawCode() {
return rawCode;
}
public int getSaltLength() {
return saltLength;
}
public int getMacLength() {
return macLength;
}
/**
* Get the key length in bytes that this AesKeyStrength represents
* @return the key length in bytes
*/
public int getKeyLength() {
return keyLength;
}
/**
* Get a AesKeyStrength given a code from the ZIP file
* @param code the code from the ZIP file
* @return the AesKeyStrength that represents the given code, or null if the code does not match
*/
public static AesKeyStrength getAesKeyStrengthFromRawCode(int code) {
for (AesKeyStrength aesKeyStrength : values()) {
if (aesKeyStrength.getRawCode() == code) {
return aesKeyStrength;
}
}
return null;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/enums/AesVersion.java 0000664 0000000 0000000 00000001725 14142654472 0025642 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model.enums;
/**
* Indicates the AES format used
*/
public enum AesVersion {
/**
* Version 1 of the AES format
*/
ONE(1),
/**
* Version 2 of the AES format
*/
TWO(2);
private int versionNumber;
AesVersion(int versionNumber) {
this.versionNumber = versionNumber;
}
/**
* Get the AES version number as an integer
* @return the AES version number
*/
public int getVersionNumber() {
return versionNumber;
}
/**
* Get the AESVersion instance from an integer AES version number
* @return the AESVersion instance for a given version
* @throws IllegalArgumentException if an unsupported version is given
*/
public static AesVersion getFromVersionNumber(int versionNumber) {
for (AesVersion aesVersion : values()) {
if (aesVersion.versionNumber == versionNumber) {
return aesVersion;
}
}
throw new IllegalArgumentException("Unsupported Aes version");
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/enums/CompressionLevel.java 0000664 0000000 0000000 00000002020 14142654472 0027042 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model.enums;
/**
* Indicates the level of compression for the DEFLATE compression method
*
*/
public enum CompressionLevel {
/**
* Level 1 Deflate compression. Fastest compression.
*/
FASTEST(1),
/**
* Level 2 Deflate compression
*/
FASTER(2),
/**
* Level 3 Deflate compression
*/
FAST(3),
/**
* Level 4 Deflate compression
*/
MEDIUM_FAST(4),
/**
* Level 5 Deflate compression. A compromise between speed and compression level.
*/
NORMAL(5),
/**
* Level 6 Deflate compression
*/
HIGHER(6),
/**
* Level 7 Deflate compression
*/
MAXIMUM(7),
/**
* Level 8 Deflate compression
*/
PRE_ULTRA(8),
/**
* Level 9 Deflate compression. Highest compression.
*/
ULTRA(9);
private int level;
CompressionLevel(int level) {
this.level = level;
}
/**
* Get the Deflate compression level (0-9) for this CompressionLevel
* @return the deflate compression level
*/
public int getLevel() {
return level;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/enums/CompressionMethod.java 0000664 0000000 0000000 00000002330 14142654472 0027217 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model.enums;
import net.lingala.zip4j.exception.ZipException;
/**
* Indicates the algorithm used for compression
*
*/
public enum CompressionMethod {
/**
* No compression is performed
*/
STORE(0),
/**
* The Deflate compression is used.
* @see java.util.zip.Deflater
*/
DEFLATE(8),
/**
* For internal use in Zip4J
*/
AES_INTERNAL_ONLY(99);
private int code;
CompressionMethod(int code) {
this.code = code;
}
/**
* Get the code used in the ZIP file for this CompressionMethod
* @return the code used in the ZIP file
*/
public int getCode() {
return code;
}
/**
* Get the CompressionMethod for a given ZIP file code
* @param code the code for a compression method
* @return the CompressionMethod related to the given code
* @throws ZipException on unknown code
*/
public static CompressionMethod getCompressionMethodFromCode(int code) throws ZipException {
for (CompressionMethod compressionMethod : values()) {
if (compressionMethod.getCode() == code) {
return compressionMethod;
}
}
throw new ZipException("Unknown compression method", ZipException.Type.UNKNOWN_COMPRESSION_METHOD);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/enums/EncryptionMethod.java 0000664 0000000 0000000 00000000763 14142654472 0027060 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model.enums;
/**
* Indicates the encryption method used in the ZIP file
*
*/
public enum EncryptionMethod {
/**
* No encryption is performed
*/
NONE,
/**
* Encrypted with the weak ZIP standard algorithm
*/
ZIP_STANDARD,
/**
* Encrypted with the stronger ZIP standard algorithm
*/
ZIP_STANDARD_VARIANT_STRONG,
/**
* Encrypted with AES, the strongest choice but currently
* cannot be expanded in Windows Explorer
*/
AES
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/model/enums/RandomAccessFileMode.java 0000664 0000000 0000000 00000000373 14142654472 0027531 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.model.enums;
public enum RandomAccessFileMode {
READ("r"),
WRITE("rw");
private String value;
RandomAccessFileMode(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/progress/ 0000775 0000000 0000000 00000000000 14142654472 0022331 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/progress/ProgressMonitor.java 0000775 0000000 0000000 00000007110 14142654472 0026352 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.progress;
/**
* If Zip4j is set to run in thread mode, this class helps retrieve current progress
*/
public class ProgressMonitor {
public enum State { READY, BUSY }
public enum Result { SUCCESS, WORK_IN_PROGRESS, ERROR, CANCELLED }
public enum Task { NONE, ADD_ENTRY, REMOVE_ENTRY, CALCULATE_CRC, EXTRACT_ENTRY, MERGE_ZIP_FILES, SET_COMMENT, RENAME_FILE}
private State state;
private long totalWork;
private long workCompleted;
private int percentDone;
private Task currentTask;
private String fileName;
private Result result;
private Exception exception;
private boolean cancelAllTasks;
private boolean pause;
public ProgressMonitor() {
reset();
}
public void updateWorkCompleted(long workCompleted) {
this.workCompleted += workCompleted;
if (totalWork > 0) {
percentDone = (int) ((this.workCompleted * 100 / totalWork));
if (percentDone > 100) {
percentDone = 100;
}
}
while (pause) {
try {
Thread.sleep(150);
} catch (InterruptedException e) {
//Do nothing
}
}
}
public void endProgressMonitor() {
result = Result.SUCCESS;
percentDone = 100;
reset();
}
public void endProgressMonitor(Exception e) {
result = Result.ERROR;
exception = e;
reset();
}
public void fullReset() {
reset();
fileName = null;
totalWork = 0;
workCompleted = 0;
percentDone = 0;
}
private void reset() {
currentTask = Task.NONE;
state = State.READY;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public long getTotalWork() {
return totalWork;
}
public void setTotalWork(long totalWork) {
this.totalWork = totalWork;
}
public long getWorkCompleted() {
return workCompleted;
}
public int getPercentDone() {
return percentDone;
}
public void setPercentDone(int percentDone) {
this.percentDone = percentDone;
}
public Task getCurrentTask() {
return currentTask;
}
public void setCurrentTask(Task currentTask) {
this.currentTask = currentTask;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
public Exception getException() {
return exception;
}
public void setException(Exception exception) {
this.exception = exception;
}
public boolean isCancelAllTasks() {
return cancelAllTasks;
}
public void setCancelAllTasks(boolean cancelAllTasks) {
this.cancelAllTasks = cancelAllTasks;
}
public boolean isPause() {
return pause;
}
public void setPause(boolean pause) {
this.pause = pause;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/ 0000775 0000000 0000000 00000000000 14142654472 0021612 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AbstractAddFileToZipTask.java 0000664 0000000 0000000 00000030357 14142654472 0027252 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.RemoveFilesFromZipTask.RemoveFilesFromZipTaskParameters;
import net.lingala.zip4j.util.BitUtils;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static net.lingala.zip4j.headers.HeaderUtil.getFileHeader;
import static net.lingala.zip4j.model.ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE;
import static net.lingala.zip4j.model.ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY;
import static net.lingala.zip4j.model.enums.CompressionMethod.DEFLATE;
import static net.lingala.zip4j.model.enums.CompressionMethod.STORE;
import static net.lingala.zip4j.model.enums.EncryptionMethod.NONE;
import static net.lingala.zip4j.model.enums.EncryptionMethod.ZIP_STANDARD;
import static net.lingala.zip4j.progress.ProgressMonitor.Task.ADD_ENTRY;
import static net.lingala.zip4j.progress.ProgressMonitor.Task.CALCULATE_CRC;
import static net.lingala.zip4j.progress.ProgressMonitor.Task.REMOVE_ENTRY;
import static net.lingala.zip4j.util.CrcUtil.computeFileCrc;
import static net.lingala.zip4j.util.FileUtils.assertFilesExist;
import static net.lingala.zip4j.util.FileUtils.getRelativeFileName;
import static net.lingala.zip4j.util.Zip4jUtil.epochToExtendedDosTime;
public abstract class AbstractAddFileToZipTask extends AsyncZipTask {
private final ZipModel zipModel;
private final char[] password;
private final HeaderWriter headerWriter;
AbstractAddFileToZipTask(ZipModel zipModel, char[] password, HeaderWriter headerWriter,
AsyncTaskParameters asyncTaskParameters) {
super(asyncTaskParameters);
this.zipModel = zipModel;
this.password = password;
this.headerWriter = headerWriter;
}
void addFilesToZip(List filesToAdd, ProgressMonitor progressMonitor, ZipParameters zipParameters,
Zip4jConfig zip4jConfig) throws IOException {
assertFilesExist(filesToAdd, zipParameters.getSymbolicLinkAction());
byte[] readBuff = new byte[zip4jConfig.getBufferSize()];
List updatedFilesToAdd = removeFilesIfExists(filesToAdd, zipParameters, progressMonitor, zip4jConfig);
try (SplitOutputStream splitOutputStream = new SplitOutputStream(zipModel.getZipFile(), zipModel.getSplitLength());
ZipOutputStream zipOutputStream = initializeOutputStream(splitOutputStream, zip4jConfig)) {
for (File fileToAdd : updatedFilesToAdd) {
verifyIfTaskIsCancelled();
ZipParameters clonedZipParameters = cloneAndAdjustZipParameters(zipParameters, fileToAdd, progressMonitor);
progressMonitor.setFileName(fileToAdd.getAbsolutePath());
if (FileUtils.isSymbolicLink(fileToAdd)) {
if (addSymlink(clonedZipParameters)) {
addSymlinkToZip(fileToAdd, zipOutputStream, clonedZipParameters, splitOutputStream);
if (INCLUDE_LINK_ONLY.equals(clonedZipParameters.getSymbolicLinkAction())) {
continue;
}
}
}
addFileToZip(fileToAdd, zipOutputStream, clonedZipParameters, splitOutputStream, progressMonitor, readBuff);
}
}
}
private void addSymlinkToZip(File fileToAdd, ZipOutputStream zipOutputStream, ZipParameters zipParameters,
SplitOutputStream splitOutputStream) throws IOException {
ZipParameters clonedZipParameters = new ZipParameters(zipParameters);
clonedZipParameters.setFileNameInZip(replaceFileNameInZip(zipParameters.getFileNameInZip(), fileToAdd.getName()));
clonedZipParameters.setEncryptFiles(false);
clonedZipParameters.setCompressionMethod(CompressionMethod.STORE);
zipOutputStream.putNextEntry(clonedZipParameters);
String symLinkTarget = FileUtils.readSymbolicLink(fileToAdd);
zipOutputStream.write(symLinkTarget.getBytes());
closeEntry(zipOutputStream, splitOutputStream, fileToAdd, true);
}
private void addFileToZip(File fileToAdd, ZipOutputStream zipOutputStream, ZipParameters zipParameters,
SplitOutputStream splitOutputStream, ProgressMonitor progressMonitor,
byte[] readBuff) throws IOException {
zipOutputStream.putNextEntry(zipParameters);
int readLen;
if (fileToAdd.exists() && !fileToAdd.isDirectory()) {
try (InputStream inputStream = new FileInputStream(fileToAdd)) {
while ((readLen = inputStream.read(readBuff)) != -1) {
zipOutputStream.write(readBuff, 0, readLen);
progressMonitor.updateWorkCompleted(readLen);
verifyIfTaskIsCancelled();
}
}
}
closeEntry(zipOutputStream, splitOutputStream, fileToAdd, false);
}
private void closeEntry(ZipOutputStream zipOutputStream, SplitOutputStream splitOutputStream, File fileToAdd,
boolean isSymlink) throws IOException {
FileHeader fileHeader = zipOutputStream.closeEntry();
byte[] fileAttributes = FileUtils.getFileAttributes(fileToAdd);
if (!isSymlink) {
// Unset the symlink byte if the entry being added is a symlink, but the original file is being added
fileAttributes[3] = BitUtils.unsetBit(fileAttributes[3], 5);
}
fileHeader.setExternalFileAttributes(fileAttributes);
updateLocalFileHeader(fileHeader, splitOutputStream);
}
long calculateWorkForFiles(List filesToAdd, ZipParameters zipParameters) throws ZipException {
long totalWork = 0;
for (File fileToAdd : filesToAdd) {
if (!fileToAdd.exists()) {
continue;
}
if (zipParameters.isEncryptFiles() && zipParameters.getEncryptionMethod() == EncryptionMethod.ZIP_STANDARD) {
totalWork += (fileToAdd.length() * 2); // for CRC calculation
} else {
totalWork += fileToAdd.length();
}
//If an entry already exists, we have to remove that entry first and then add content again.
//In this case, add corresponding work
String relativeFileName = getRelativeFileName(fileToAdd, zipParameters);
FileHeader fileHeader = getFileHeader(getZipModel(), relativeFileName);
if (fileHeader != null) {
totalWork += (getZipModel().getZipFile().length() - fileHeader.getCompressedSize());
}
}
return totalWork;
}
ZipOutputStream initializeOutputStream(SplitOutputStream splitOutputStream, Zip4jConfig zip4jConfig) throws IOException {
if (zipModel.getZipFile().exists()) {
splitOutputStream.seek(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel));
}
return new ZipOutputStream(splitOutputStream, password, zip4jConfig, zipModel);
}
void verifyZipParameters(ZipParameters parameters) throws ZipException {
if (parameters == null) {
throw new ZipException("cannot validate zip parameters");
}
if (parameters.getCompressionMethod() != STORE && parameters.getCompressionMethod() != DEFLATE) {
throw new ZipException("unsupported compression type");
}
if (parameters.isEncryptFiles()) {
if (parameters.getEncryptionMethod() == NONE) {
throw new ZipException("Encryption method has to be set, when encrypt files flag is set");
}
if (password == null || password.length <= 0) {
throw new ZipException("input password is empty or null");
}
} else {
parameters.setEncryptionMethod(NONE);
}
}
void updateLocalFileHeader(FileHeader fileHeader, SplitOutputStream splitOutputStream) throws IOException {
headerWriter.updateLocalFileHeader(fileHeader, getZipModel(), splitOutputStream);
}
private ZipParameters cloneAndAdjustZipParameters(ZipParameters zipParameters, File fileToAdd,
ProgressMonitor progressMonitor) throws IOException {
ZipParameters clonedZipParameters = new ZipParameters(zipParameters);
clonedZipParameters.setLastModifiedFileTime(epochToExtendedDosTime((fileToAdd.lastModified())));
if (fileToAdd.isDirectory()) {
clonedZipParameters.setEntrySize(0);
} else {
clonedZipParameters.setEntrySize(fileToAdd.length());
}
clonedZipParameters.setWriteExtendedLocalFileHeader(false);
clonedZipParameters.setLastModifiedFileTime(fileToAdd.lastModified());
if (!Zip4jUtil.isStringNotNullAndNotEmpty(zipParameters.getFileNameInZip())) {
String relativeFileName = getRelativeFileName(fileToAdd, zipParameters);
clonedZipParameters.setFileNameInZip(relativeFileName);
}
if (fileToAdd.isDirectory()) {
clonedZipParameters.setCompressionMethod(CompressionMethod.STORE);
clonedZipParameters.setEncryptionMethod(EncryptionMethod.NONE);
clonedZipParameters.setEncryptFiles(false);
} else {
if (clonedZipParameters.isEncryptFiles() && clonedZipParameters.getEncryptionMethod() == ZIP_STANDARD) {
progressMonitor.setCurrentTask(CALCULATE_CRC);
clonedZipParameters.setEntryCRC(computeFileCrc(fileToAdd, progressMonitor));
progressMonitor.setCurrentTask(ADD_ENTRY);
}
if (fileToAdd.length() == 0) {
clonedZipParameters.setCompressionMethod(CompressionMethod.STORE);
}
}
return clonedZipParameters;
}
private List removeFilesIfExists(List files, ZipParameters zipParameters, ProgressMonitor progressMonitor,
Zip4jConfig zip4jConfig)
throws ZipException {
List filesToAdd = new ArrayList<>(files);
if (!zipModel.getZipFile().exists()) {
return filesToAdd;
}
for (File file : files) {
// In some OS it is possible to have empty file names (even without any extension).
// Remove such files from list as this might cause incompatibility with the zip file
if (!Zip4jUtil.isStringNotNullAndNotEmpty(file.getName())) {
filesToAdd.remove(file);
}
String fileName = getRelativeFileName(file, zipParameters);
FileHeader fileHeader = getFileHeader(zipModel, fileName);
if (fileHeader != null) {
if (zipParameters.isOverrideExistingFilesInZip()) {
progressMonitor.setCurrentTask(REMOVE_ENTRY);
removeFile(fileHeader, progressMonitor, zip4jConfig);
verifyIfTaskIsCancelled();
progressMonitor.setCurrentTask(ADD_ENTRY);
} else {
filesToAdd.remove(file);
}
}
}
return filesToAdd;
}
void removeFile(FileHeader fileHeader, ProgressMonitor progressMonitor, Zip4jConfig zip4jConfig) throws ZipException {
AsyncTaskParameters asyncTaskParameters = new AsyncTaskParameters(null, false, progressMonitor);
RemoveFilesFromZipTask removeFilesFromZipTask = new RemoveFilesFromZipTask(zipModel, headerWriter, asyncTaskParameters);
RemoveFilesFromZipTaskParameters parameters = new RemoveFilesFromZipTaskParameters(
Collections.singletonList(fileHeader.getFileName()), zip4jConfig);
removeFilesFromZipTask.execute(parameters);
}
private String replaceFileNameInZip(String fileInZipWithPath, String newFileName) {
if (fileInZipWithPath.contains(InternalZipConstants.ZIP_FILE_SEPARATOR)) {
return fileInZipWithPath.substring(0, fileInZipWithPath.lastIndexOf(InternalZipConstants.ZIP_FILE_SEPARATOR) + 1) + newFileName;
}
return newFileName;
}
private boolean addSymlink(ZipParameters zipParameters) {
return INCLUDE_LINK_ONLY.equals(zipParameters.getSymbolicLinkAction()) ||
INCLUDE_LINK_AND_LINKED_FILE.equals(zipParameters.getSymbolicLinkAction());
}
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.ADD_ENTRY;
}
protected ZipModel getZipModel() {
return zipModel;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AbstractExtractFileTask.java 0000664 0000000 0000000 00000014476 14142654472 0027212 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.UnzipParameters;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.util.BitUtils;
import net.lingala.zip4j.util.UnzipUtil;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static net.lingala.zip4j.util.InternalZipConstants.FILE_SEPARATOR;
public abstract class AbstractExtractFileTask extends AsyncZipTask {
private final ZipModel zipModel;
private final UnzipParameters unzipParameters;
public AbstractExtractFileTask(ZipModel zipModel, UnzipParameters unzipParameters,
AsyncTaskParameters asyncTaskParameters) {
super(asyncTaskParameters);
this.zipModel = zipModel;
this.unzipParameters = unzipParameters;
}
protected void extractFile(ZipInputStream zipInputStream, FileHeader fileHeader, String outputPath,
String newFileName, ProgressMonitor progressMonitor, byte[] readBuff) throws IOException {
boolean isSymbolicLink = isSymbolicLink(fileHeader);
if (isSymbolicLink && !unzipParameters.isExtractSymbolicLinks()) {
return;
}
if (!outputPath.endsWith(FILE_SEPARATOR)) {
outputPath += FILE_SEPARATOR;
}
File outputFile = determineOutputFile(fileHeader, outputPath, newFileName);
progressMonitor.setFileName(outputFile.getAbsolutePath());
// make sure no file is extracted outside of the target directory (a.k.a zip slip)
String outputCanonicalPath = (new File(outputPath).getCanonicalPath()) + File.separator;
if (!outputFile.getCanonicalPath().startsWith(outputCanonicalPath)) {
throw new ZipException("illegal file name that breaks out of the target directory: "
+ fileHeader.getFileName());
}
verifyNextEntry(zipInputStream, fileHeader);
if (fileHeader.isDirectory()) {
if (!outputFile.exists()) {
if (!outputFile.mkdirs()) {
throw new ZipException("Could not create directory: " + outputFile);
}
}
} else if (isSymbolicLink(fileHeader)) {
createSymLink(zipInputStream, fileHeader, outputFile, progressMonitor);
} else {
checkOutputDirectoryStructure(outputFile);
unzipFile(zipInputStream, outputFile, progressMonitor, readBuff);
}
UnzipUtil.applyFileAttributes(fileHeader, outputFile);
}
private boolean isSymbolicLink(FileHeader fileHeader) {
byte[] externalFileAttributes = fileHeader.getExternalFileAttributes();
if (externalFileAttributes == null || externalFileAttributes.length < 4) {
return false;
}
return BitUtils.isBitSet(externalFileAttributes[3], 5);
}
private void unzipFile(ZipInputStream inputStream, File outputFile, ProgressMonitor progressMonitor, byte[] buff)
throws IOException {
int readLength;
try (OutputStream outputStream = new FileOutputStream(outputFile)) {
while ((readLength = inputStream.read(buff)) != -1) {
outputStream.write(buff, 0, readLength);
progressMonitor.updateWorkCompleted(readLength);
verifyIfTaskIsCancelled();
}
} catch (Exception e) {
if (outputFile.exists()) {
outputFile.delete();
}
throw e;
}
}
private void createSymLink(ZipInputStream zipInputStream, FileHeader fileHeader, File outputFile,
ProgressMonitor progressMonitor) throws IOException {
String symLinkPath = new String(readCompleteEntry(zipInputStream, fileHeader, progressMonitor));
if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) {
throw new ZipException("Could not create parent directories");
}
try {
Path linkTarget = Paths.get(symLinkPath);
Files.createSymbolicLink(outputFile.toPath(), linkTarget);
} catch (NoSuchMethodError error) {
try (OutputStream outputStream = new FileOutputStream(outputFile)) {
outputStream.write(symLinkPath.getBytes());
}
}
}
private byte[] readCompleteEntry(ZipInputStream zipInputStream, FileHeader fileHeader,
ProgressMonitor progressMonitor) throws IOException {
byte[] b = new byte[(int) fileHeader.getUncompressedSize()];
int readLength = zipInputStream.read(b);
if (readLength != b.length) {
throw new ZipException("Could not read complete entry");
}
progressMonitor.updateWorkCompleted(b.length);
return b;
}
private void verifyNextEntry(ZipInputStream zipInputStream, FileHeader fileHeader) throws IOException {
if (BitUtils.isBitSet(fileHeader.getGeneralPurposeFlag()[0], 6)) {
throw new ZipException("Entry with name " + fileHeader.getFileName() + " is encrypted with Strong Encryption. " +
"Zip4j does not support Strong Encryption, as this is patented.");
}
LocalFileHeader localFileHeader = zipInputStream.getNextEntry(fileHeader, false);
if (localFileHeader == null) {
throw new ZipException("Could not read corresponding local file header for file header: "
+ fileHeader.getFileName());
}
if (!fileHeader.getFileName().equals(localFileHeader.getFileName())) {
throw new ZipException("File header and local file header mismatch");
}
}
private void checkOutputDirectoryStructure(File outputFile) throws ZipException {
if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) {
throw new ZipException("Unable to create parent directories: " + outputFile.getParentFile());
}
}
private File determineOutputFile(FileHeader fileHeader, String outputPath, String newFileName) {
String outputFileName = fileHeader.getFileName();
if (Zip4jUtil.isStringNotNullAndNotEmpty(newFileName)) {
outputFileName = newFileName;
}
return new File(outputPath + FILE_SEPARATOR + outputFileName);
}
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.EXTRACT_ENTRY;
}
public ZipModel getZipModel() {
return zipModel;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AbstractModifyFileTask.java 0000664 0000000 0000000 00000010614 14142654472 0027015 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
abstract class AbstractModifyFileTask extends AsyncZipTask {
AbstractModifyFileTask(AsyncTaskParameters asyncTaskParameters) {
super(asyncTaskParameters);
}
File getTemporaryFile(String zipPathWithName) {
Random random = new Random();
File tmpFile = new File(zipPathWithName + random.nextInt(10000));
while (tmpFile.exists()) {
tmpFile = new File(zipPathWithName + random.nextInt(10000));
}
return tmpFile;
}
void updateOffsetsForAllSubsequentFileHeaders(List sortedFileHeaders, ZipModel zipModel,
FileHeader fileHeaderModified, long offsetToAdd) throws ZipException {
int indexOfFileHeader = getIndexOfFileHeader(sortedFileHeaders, fileHeaderModified);
if (indexOfFileHeader == -1) {
throw new ZipException("Could not locate modified file header in zipModel");
}
for (int i = indexOfFileHeader + 1; i < sortedFileHeaders.size(); i++) {
FileHeader fileHeaderToUpdate = sortedFileHeaders.get(i);
fileHeaderToUpdate.setOffsetLocalHeader(fileHeaderToUpdate.getOffsetLocalHeader() + offsetToAdd);
if (zipModel.isZip64Format()
&& fileHeaderToUpdate.getZip64ExtendedInfo() != null
&& fileHeaderToUpdate.getZip64ExtendedInfo().getOffsetLocalHeader() != -1) {
fileHeaderToUpdate.getZip64ExtendedInfo().setOffsetLocalHeader(
fileHeaderToUpdate.getZip64ExtendedInfo().getOffsetLocalHeader() + offsetToAdd
);
}
}
}
void cleanupFile(boolean successFlag, File zipFile, File temporaryZipFile) throws ZipException {
if (successFlag) {
restoreFileName(zipFile, temporaryZipFile);
} else {
if (!temporaryZipFile.delete()) {
throw new ZipException("Could not delete temporary file");
}
}
}
long copyFile(RandomAccessFile randomAccessFile, OutputStream outputStream, long start, long length,
ProgressMonitor progressMonitor, int bufferSize) throws IOException {
FileUtils.copyFile(randomAccessFile, outputStream, start, start + length, progressMonitor, bufferSize);
return length;
}
List cloneAndSortFileHeadersByOffset(List allFileHeaders) {
List clonedFileHeaders = new ArrayList<>(allFileHeaders);
//noinspection Java8ListSort
Collections.sort(clonedFileHeaders, new Comparator() {
@Override
public int compare(FileHeader o1, FileHeader o2) {
if (o1.getFileName().equals(o2.getFileName())) {
return 0;
}
return o1.getOffsetLocalHeader() < o2.getOffsetLocalHeader() ? -1 : 1;
}
});
return clonedFileHeaders;
}
long getOffsetOfNextEntry(List sortedFileHeaders, FileHeader fileHeader,
ZipModel zipModel) throws ZipException {
int indexOfFileHeader = getIndexOfFileHeader(sortedFileHeaders, fileHeader);
if (indexOfFileHeader == sortedFileHeaders.size() - 1) {
return HeaderUtil.getOffsetStartOfCentralDirectory(zipModel);
} else {
return sortedFileHeaders.get(indexOfFileHeader + 1).getOffsetLocalHeader();
}
}
private void restoreFileName(File zipFile, File temporaryZipFile) throws ZipException {
if (zipFile.delete()) {
if (!temporaryZipFile.renameTo(zipFile)) {
throw new ZipException("cannot rename modified zip file");
}
} else {
throw new ZipException("cannot delete old zip file");
}
}
private int getIndexOfFileHeader(List allFileHeaders, FileHeader fileHeaderForIndex) throws ZipException {
for (int i = 0; i < allFileHeaders.size(); i++) {
FileHeader fileHeader = allFileHeaders.get(i);
if (fileHeader.equals(fileHeaderForIndex)) {
return i;
}
}
throw new ZipException("Could not find file header in list of central directory file headers");
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AbstractZipTaskParameters.java 0000664 0000000 0000000 00000000423 14142654472 0027551 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.model.Zip4jConfig;
public abstract class AbstractZipTaskParameters {
protected Zip4jConfig zip4jConfig;
protected AbstractZipTaskParameters(Zip4jConfig zip4jConfig) {
this.zip4jConfig = zip4jConfig;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AddFilesToZipTask.java 0000664 0000000 0000000 00000003443 14142654472 0025745 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.AddFilesToZipTask.AddFilesToZipTaskParameters;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class AddFilesToZipTask extends AbstractAddFileToZipTask {
public AddFilesToZipTask(ZipModel zipModel, char[] password, HeaderWriter headerWriter,
AsyncTaskParameters asyncTaskParameters) {
super(zipModel, password, headerWriter, asyncTaskParameters);
}
@Override
protected void executeTask(AddFilesToZipTaskParameters taskParameters, ProgressMonitor progressMonitor)
throws IOException {
verifyZipParameters(taskParameters.zipParameters);
addFilesToZip(taskParameters.filesToAdd, progressMonitor, taskParameters.zipParameters, taskParameters.zip4jConfig);
}
@Override
protected long calculateTotalWork(AddFilesToZipTaskParameters taskParameters) throws ZipException {
return calculateWorkForFiles(taskParameters.filesToAdd, taskParameters.zipParameters);
}
@Override
protected ProgressMonitor.Task getTask() {
return super.getTask();
}
public static class AddFilesToZipTaskParameters extends AbstractZipTaskParameters {
private final List filesToAdd;
private final ZipParameters zipParameters;
public AddFilesToZipTaskParameters(List filesToAdd, ZipParameters zipParameters, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.filesToAdd = filesToAdd;
this.zipParameters = zipParameters;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AddFolderToZipTask.java 0000664 0000000 0000000 00000006456 14142654472 0026125 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.AddFolderToZipTask.AddFolderToZipTaskParameters;
import java.io.File;
import java.io.IOException;
import java.util.List;
import static net.lingala.zip4j.util.FileUtils.getFilesInDirectoryRecursive;
public class AddFolderToZipTask extends AbstractAddFileToZipTask {
public AddFolderToZipTask(ZipModel zipModel, char[] password, HeaderWriter headerWriter, AsyncTaskParameters asyncTaskParameters) {
super(zipModel, password, headerWriter, asyncTaskParameters);
}
@Override
protected void executeTask(AddFolderToZipTaskParameters taskParameters, ProgressMonitor progressMonitor)
throws IOException {
List filesToAdd = getFilesToAdd(taskParameters);
setDefaultFolderPath(taskParameters);
addFilesToZip(filesToAdd, progressMonitor, taskParameters.zipParameters, taskParameters.zip4jConfig);
}
@Override
protected long calculateTotalWork(AddFolderToZipTaskParameters taskParameters) throws ZipException {
List filesToAdd = getFilesInDirectoryRecursive(taskParameters.folderToAdd,
taskParameters.zipParameters.isReadHiddenFiles(),
taskParameters.zipParameters.isReadHiddenFolders(),
taskParameters.zipParameters.getExcludeFileFilter());
if (taskParameters.zipParameters.isIncludeRootFolder()) {
filesToAdd.add(taskParameters.folderToAdd);
}
return calculateWorkForFiles(filesToAdd, taskParameters.zipParameters);
}
private void setDefaultFolderPath(AddFolderToZipTaskParameters taskParameters) throws IOException {
String rootFolderPath;
File folderToAdd = taskParameters.folderToAdd;
if (taskParameters.zipParameters.isIncludeRootFolder()) {
File parentFile = folderToAdd.getCanonicalFile().getParentFile();
if (parentFile == null) {
rootFolderPath = folderToAdd.getCanonicalPath();
} else {
rootFolderPath = folderToAdd.getCanonicalFile().getParentFile().getCanonicalPath();
}
} else {
rootFolderPath = folderToAdd.getCanonicalPath();
}
taskParameters.zipParameters.setDefaultFolderPath(rootFolderPath);
}
private List getFilesToAdd(AddFolderToZipTaskParameters taskParameters) throws ZipException {
List filesToAdd = getFilesInDirectoryRecursive(taskParameters.folderToAdd,
taskParameters.zipParameters.isReadHiddenFiles(),
taskParameters.zipParameters.isReadHiddenFolders(),
taskParameters.zipParameters.getExcludeFileFilter());
if (taskParameters.zipParameters.isIncludeRootFolder()) {
filesToAdd.add(taskParameters.folderToAdd);
}
return filesToAdd;
}
public static class AddFolderToZipTaskParameters extends AbstractZipTaskParameters {
private final File folderToAdd;
private final ZipParameters zipParameters;
public AddFolderToZipTaskParameters(File folderToAdd, ZipParameters zipParameters, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.folderToAdd = folderToAdd;
this.zipParameters = zipParameters;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AddStreamToZipTask.java 0000664 0000000 0000000 00000010225 14142654472 0026132 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.AddStreamToZipTask.AddStreamToZipTaskParameters;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.IOException;
import java.io.InputStream;
import static net.lingala.zip4j.util.Zip4jUtil.getCompressionMethod;
public class AddStreamToZipTask extends AbstractAddFileToZipTask {
public AddStreamToZipTask(ZipModel zipModel, char[] password, HeaderWriter headerWriter, AsyncTaskParameters asyncTaskParameters) {
super(zipModel, password, headerWriter, asyncTaskParameters);
}
@Override
protected void executeTask(AddStreamToZipTaskParameters taskParameters, ProgressMonitor progressMonitor)
throws IOException {
verifyZipParameters(taskParameters.zipParameters);
if (!Zip4jUtil.isStringNotNullAndNotEmpty(taskParameters.zipParameters.getFileNameInZip())) {
throw new ZipException("fileNameInZip has to be set in zipParameters when adding stream");
}
removeFileIfExists(getZipModel(), taskParameters.zip4jConfig, taskParameters.zipParameters.getFileNameInZip(),
progressMonitor);
// For streams, it is necessary to write extended local file header because of Zip standard encryption.
// If we do not write extended local file header, zip standard encryption needs a crc upfront for key,
// which cannot be calculated until we read the complete stream. If we use extended local file header,
// last modified file time is used, or current system time if not available.
taskParameters.zipParameters.setWriteExtendedLocalFileHeader(true);
if (taskParameters.zipParameters.getCompressionMethod().equals(CompressionMethod.STORE)) {
// Set some random value here. This will be updated again when closing entry
taskParameters.zipParameters.setEntrySize(0);
}
try(SplitOutputStream splitOutputStream = new SplitOutputStream(getZipModel().getZipFile(), getZipModel().getSplitLength());
ZipOutputStream zipOutputStream = initializeOutputStream(splitOutputStream, taskParameters.zip4jConfig)) {
byte[] readBuff = new byte[taskParameters.zip4jConfig.getBufferSize()];
int readLen;
ZipParameters zipParameters = taskParameters.zipParameters;
zipOutputStream.putNextEntry(zipParameters);
if (!zipParameters.getFileNameInZip().endsWith("/") &&
!zipParameters.getFileNameInZip().endsWith("\\")) {
while ((readLen = taskParameters.inputStream.read(readBuff)) != -1) {
zipOutputStream.write(readBuff, 0, readLen);
}
}
FileHeader fileHeader = zipOutputStream.closeEntry();
if (CompressionMethod.STORE.equals(getCompressionMethod(fileHeader))) {
updateLocalFileHeader(fileHeader, splitOutputStream);
}
}
}
@Override
protected long calculateTotalWork(AddStreamToZipTaskParameters taskParameters) {
return 0;
}
private void removeFileIfExists(ZipModel zipModel, Zip4jConfig zip4jConfig, String fileNameInZip,
ProgressMonitor progressMonitor) throws ZipException {
FileHeader fileHeader = HeaderUtil.getFileHeader(zipModel, fileNameInZip);
if (fileHeader != null) {
removeFile(fileHeader, progressMonitor, zip4jConfig);
}
}
public static class AddStreamToZipTaskParameters extends AbstractZipTaskParameters {
private final InputStream inputStream;
private final ZipParameters zipParameters;
public AddStreamToZipTaskParameters(InputStream inputStream, ZipParameters zipParameters, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.inputStream = inputStream;
this.zipParameters = zipParameters;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/AsyncZipTask.java 0000664 0000000 0000000 00000006221 14142654472 0025041 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.progress.ProgressMonitor;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
public abstract class AsyncZipTask {
private final ProgressMonitor progressMonitor;
private final boolean runInThread;
private final ExecutorService executorService;
public AsyncZipTask(AsyncTaskParameters asyncTaskParameters) {
this.progressMonitor = asyncTaskParameters.progressMonitor;
this.runInThread = asyncTaskParameters.runInThread;
this.executorService = asyncTaskParameters.executorService;
}
public void execute(final T taskParameters) throws ZipException {
if (runInThread && ProgressMonitor.State.BUSY.equals(progressMonitor.getState())) {
throw new ZipException("invalid operation - Zip4j is in busy state");
}
initProgressMonitor();
if (runInThread) {
long totalWorkToBeDone = calculateTotalWork(taskParameters);
progressMonitor.setTotalWork(totalWorkToBeDone);
executorService.execute(new Runnable() {
@Override
public void run() {
try {
AsyncZipTask.this.performTaskWithErrorHandling(taskParameters, progressMonitor);
} catch (ZipException e) {
//Do nothing. Exception will be passed through progress monitor
} finally {
executorService.shutdown();
}
}
});
} else {
performTaskWithErrorHandling(taskParameters, progressMonitor);
}
}
private void performTaskWithErrorHandling(T taskParameters, ProgressMonitor progressMonitor) throws ZipException {
try {
executeTask(taskParameters, progressMonitor);
progressMonitor.endProgressMonitor();
} catch (ZipException e) {
progressMonitor.endProgressMonitor(e);
throw e;
} catch (Exception e) {
progressMonitor.endProgressMonitor(e);
throw new ZipException(e);
}
}
protected void verifyIfTaskIsCancelled() throws ZipException {
if (!progressMonitor.isCancelAllTasks()) {
return;
}
progressMonitor.setResult(ProgressMonitor.Result.CANCELLED);
progressMonitor.setState(ProgressMonitor.State.READY);
throw new ZipException("Task cancelled", ZipException.Type.TASK_CANCELLED_EXCEPTION);
}
private void initProgressMonitor() {
progressMonitor.fullReset();
progressMonitor.setState(ProgressMonitor.State.BUSY);
progressMonitor.setCurrentTask(getTask());
}
protected abstract void executeTask(T taskParameters, ProgressMonitor progressMonitor) throws IOException;
protected abstract long calculateTotalWork(T taskParameters) throws ZipException;
protected abstract ProgressMonitor.Task getTask();
public static class AsyncTaskParameters {
private final ProgressMonitor progressMonitor;
private final boolean runInThread;
private final ExecutorService executorService;
public AsyncTaskParameters(ExecutorService executorService, boolean runInThread, ProgressMonitor progressMonitor) {
this.executorService = executorService;
this.runInThread = runInThread;
this.progressMonitor = progressMonitor;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/ExtractAllFilesTask.java 0000664 0000000 0000000 00000006241 14142654472 0026331 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.io.inputstream.SplitInputStream;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.ExtractAllFilesTask.ExtractAllFilesTaskParameters;
import net.lingala.zip4j.util.UnzipUtil;
import java.io.IOException;
import static net.lingala.zip4j.headers.HeaderUtil.getTotalUncompressedSizeOfAllFileHeaders;
public class ExtractAllFilesTask extends AbstractExtractFileTask {
private final char[] password;
private SplitInputStream splitInputStream;
public ExtractAllFilesTask(ZipModel zipModel, char[] password, UnzipParameters unzipParameters,
AsyncTaskParameters asyncTaskParameters) {
super(zipModel, unzipParameters, asyncTaskParameters);
this.password = password;
}
@Override
protected void executeTask(ExtractAllFilesTaskParameters taskParameters, ProgressMonitor progressMonitor)
throws IOException {
try (ZipInputStream zipInputStream = prepareZipInputStream(taskParameters.zip4jConfig)) {
for (FileHeader fileHeader : getZipModel().getCentralDirectory().getFileHeaders()) {
if (fileHeader.getFileName().startsWith("__MACOSX")) {
progressMonitor.updateWorkCompleted(fileHeader.getUncompressedSize());
continue;
}
splitInputStream.prepareExtractionForFileHeader(fileHeader);
byte[] readBuff = new byte[taskParameters.zip4jConfig.getBufferSize()];
extractFile(zipInputStream, fileHeader, taskParameters.outputPath, null, progressMonitor, readBuff);
verifyIfTaskIsCancelled();
}
} finally {
if (splitInputStream != null) {
splitInputStream.close();
}
}
}
@Override
protected long calculateTotalWork(ExtractAllFilesTaskParameters taskParameters) {
return getTotalUncompressedSizeOfAllFileHeaders(getZipModel().getCentralDirectory().getFileHeaders());
}
private ZipInputStream prepareZipInputStream(Zip4jConfig zip4jConfig) throws IOException {
splitInputStream = UnzipUtil.createSplitInputStream(getZipModel());
FileHeader fileHeader = getFirstFileHeader(getZipModel());
if (fileHeader != null) {
splitInputStream.prepareExtractionForFileHeader(fileHeader);
}
return new ZipInputStream(splitInputStream, password, zip4jConfig);
}
private FileHeader getFirstFileHeader(ZipModel zipModel) {
if (zipModel.getCentralDirectory() == null
|| zipModel.getCentralDirectory().getFileHeaders() == null
|| zipModel.getCentralDirectory().getFileHeaders().size() == 0) {
return null;
}
return zipModel.getCentralDirectory().getFileHeaders().get(0);
}
public static class ExtractAllFilesTaskParameters extends AbstractZipTaskParameters {
private final String outputPath;
public ExtractAllFilesTaskParameters(String outputPath, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.outputPath = outputPath;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/ExtractFileTask.java 0000664 0000000 0000000 00000011035 14142654472 0025512 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.io.inputstream.SplitInputStream;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.ExtractFileTask.ExtractFileTaskParameters;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.UnzipUtil;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static net.lingala.zip4j.exception.ZipException.Type.FILE_NOT_FOUND;
import static net.lingala.zip4j.headers.HeaderUtil.getFileHeadersUnderDirectory;
import static net.lingala.zip4j.headers.HeaderUtil.getTotalUncompressedSizeOfAllFileHeaders;
public class ExtractFileTask extends AbstractExtractFileTask {
private char[] password;
private SplitInputStream splitInputStream;
public ExtractFileTask(ZipModel zipModel, char[] password, UnzipParameters unzipParameters,
AsyncTaskParameters asyncTaskParameters) {
super(zipModel, unzipParameters, asyncTaskParameters);
this.password = password;
}
@Override
protected void executeTask(ExtractFileTaskParameters taskParameters, ProgressMonitor progressMonitor)
throws IOException {
List fileHeadersUnderDirectory = getFileHeadersToExtract(taskParameters.fileToExtract);
try(ZipInputStream zipInputStream = createZipInputStream(taskParameters.zip4jConfig)) {
byte[] readBuff = new byte[taskParameters.zip4jConfig.getBufferSize()];
for (FileHeader fileHeader : fileHeadersUnderDirectory) {
splitInputStream.prepareExtractionForFileHeader(fileHeader);
String newFileName = determineNewFileName(taskParameters.newFileName, taskParameters.fileToExtract, fileHeader);
extractFile(zipInputStream, fileHeader, taskParameters.outputPath, newFileName, progressMonitor, readBuff);
}
} finally {
if (splitInputStream != null) {
splitInputStream.close();
}
}
}
@Override
protected long calculateTotalWork(ExtractFileTaskParameters taskParameters) throws ZipException {
List fileHeadersUnderDirectory = getFileHeadersToExtract(taskParameters.fileToExtract);
return getTotalUncompressedSizeOfAllFileHeaders(fileHeadersUnderDirectory);
}
private List getFileHeadersToExtract(String fileNameToExtract) throws ZipException {
if (!FileUtils.isZipEntryDirectory(fileNameToExtract)) {
FileHeader fileHeader = HeaderUtil.getFileHeader(getZipModel(), fileNameToExtract);
if (fileHeader == null) {
throw new ZipException("No file found with name " + fileNameToExtract + " in zip file", FILE_NOT_FOUND);
}
return Collections.singletonList(fileHeader);
}
return getFileHeadersUnderDirectory(getZipModel().getCentralDirectory().getFileHeaders(), fileNameToExtract);
}
private ZipInputStream createZipInputStream(Zip4jConfig zip4jConfig) throws IOException {
splitInputStream = UnzipUtil.createSplitInputStream(getZipModel());
return new ZipInputStream(splitInputStream, password, zip4jConfig);
}
private String determineNewFileName(String newFileName, String fileNameToExtract,
FileHeader fileHeaderBeingExtracted) {
if (!Zip4jUtil.isStringNotNullAndNotEmpty(newFileName)) {
return newFileName;
}
if (!FileUtils.isZipEntryDirectory(fileNameToExtract)) {
return newFileName;
}
String fileSeparator = InternalZipConstants.ZIP_FILE_SEPARATOR;
if (newFileName.endsWith(InternalZipConstants.ZIP_FILE_SEPARATOR)) {
fileSeparator = "";
}
return fileHeaderBeingExtracted.getFileName().replaceFirst(fileNameToExtract, newFileName + fileSeparator);
}
public static class ExtractFileTaskParameters extends AbstractZipTaskParameters {
private String outputPath;
private String fileToExtract;
private String newFileName;
public ExtractFileTaskParameters(String outputPath, String fileToExtract, String newFileName,
Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.outputPath = outputPath;
this.fileToExtract = fileToExtract;
this.newFileName = newFileName;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/MergeSplitZipFileTask.java 0000664 0000000 0000000 00000020474 14142654472 0026645 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderSignature;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryLocator;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.MergeSplitZipFileTask.MergeSplitZipFileTaskParameters;
import net.lingala.zip4j.util.RawIO;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.List;
import static net.lingala.zip4j.util.FileUtils.copyFile;
public class MergeSplitZipFileTask extends AsyncZipTask {
private final ZipModel zipModel;
private final RawIO rawIO = new RawIO();
public MergeSplitZipFileTask(ZipModel zipModel, AsyncTaskParameters asyncTaskParameters) {
super(asyncTaskParameters);
this.zipModel = zipModel;
}
@Override
protected void executeTask(MergeSplitZipFileTaskParameters taskParameters, ProgressMonitor progressMonitor) throws IOException {
if (!zipModel.isSplitArchive()) {
ZipException e = new ZipException("archive not a split zip file");
progressMonitor.endProgressMonitor(e);
throw e;
}
try (OutputStream outputStream = new FileOutputStream(taskParameters.outputZipFile)) {
long totalBytesWritten = 0;
int totalNumberOfSplitFiles = zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk();
if (totalNumberOfSplitFiles <= 0) {
throw new ZipException("zip archive not a split zip file");
}
int splitSignatureOverhead = 0;
for (int i = 0; i <= totalNumberOfSplitFiles; i++) {
try (RandomAccessFile randomAccessFile = createSplitZipFileStream(zipModel, i)) {
int start = 0;
long end = randomAccessFile.length();
if (i == 0) {
if (rawIO.readIntLittleEndian(randomAccessFile) == HeaderSignature.SPLIT_ZIP.getValue()) {
splitSignatureOverhead = 4;
start = 4;
} else {
randomAccessFile.seek(0);
}
}
if (i == totalNumberOfSplitFiles) {
end = zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}
copyFile(randomAccessFile, outputStream, start, end, progressMonitor, taskParameters.zip4jConfig.getBufferSize());
totalBytesWritten += (end - start);
updateFileHeaderOffsetsForIndex(zipModel.getCentralDirectory().getFileHeaders(),
i == 0 ? 0 : totalBytesWritten, i, splitSignatureOverhead);
verifyIfTaskIsCancelled();
}
}
updateHeadersForMergeSplitFileAction(zipModel, totalBytesWritten, outputStream,
taskParameters.zip4jConfig.getCharset());
progressMonitor.endProgressMonitor();
} catch (CloneNotSupportedException e) {
throw new ZipException(e);
}
}
@Override
protected long calculateTotalWork(MergeSplitZipFileTaskParameters taskParameters) {
if (!zipModel.isSplitArchive()) {
return 0;
}
long totalSize = 0;
for (int i = 0; i <= zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk(); i++) {
totalSize += getNextSplitZipFile(zipModel, i).length();
}
return totalSize;
}
private void updateFileHeaderOffsetsForIndex(List fileHeaders, long offsetToAdd, int index,
int splitSignatureOverhead) {
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.getDiskNumberStart() == index) {
fileHeader.setOffsetLocalHeader(fileHeader.getOffsetLocalHeader() + offsetToAdd - splitSignatureOverhead);
fileHeader.setDiskNumberStart(0);
}
}
}
private File getNextSplitZipFile(ZipModel zipModel, int partNumber) {
if (partNumber == zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk()) {
return zipModel.getZipFile();
}
String splitZipExtension = ".z0";
if (partNumber >= 9) {
splitZipExtension = ".z";
}
String rootZipFile = zipModel.getZipFile().getPath();
String nextSplitZipFileName = zipModel.getZipFile().getPath().substring(0, rootZipFile.lastIndexOf("."))
+ splitZipExtension + (partNumber + 1);
return new File(nextSplitZipFileName);
}
private RandomAccessFile createSplitZipFileStream(ZipModel zipModel, int partNumber) throws FileNotFoundException {
File splitFile = getNextSplitZipFile(zipModel, partNumber);
return new RandomAccessFile(splitFile, RandomAccessFileMode.READ.getValue());
}
private void updateHeadersForMergeSplitFileAction(ZipModel zipModel, long totalBytesWritten,
OutputStream outputStream, Charset charset)
throws IOException, CloneNotSupportedException {
ZipModel newZipModel = (ZipModel) zipModel.clone();
newZipModel.getEndOfCentralDirectoryRecord().setOffsetOfStartOfCentralDirectory(totalBytesWritten);
updateSplitZipModel(newZipModel, totalBytesWritten);
HeaderWriter headerWriter = new HeaderWriter();
headerWriter.finalizeZipFileWithoutValidations(newZipModel, outputStream, charset);
}
private void updateSplitZipModel(ZipModel zipModel, long totalFileSize) {
zipModel.setSplitArchive(false);
updateSplitEndCentralDirectory(zipModel);
if (zipModel.isZip64Format()) {
updateSplitZip64EndCentralDirLocator(zipModel, totalFileSize);
updateSplitZip64EndCentralDirRec(zipModel, totalFileSize);
}
}
private void updateSplitEndCentralDirectory(ZipModel zipModel) {
int numberOfFileHeaders = zipModel.getCentralDirectory().getFileHeaders().size();
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = zipModel.getEndOfCentralDirectoryRecord();
endOfCentralDirectoryRecord.setNumberOfThisDisk(0);
endOfCentralDirectoryRecord.setNumberOfThisDiskStartOfCentralDir(0);
endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectory(numberOfFileHeaders);
endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(numberOfFileHeaders);
}
private void updateSplitZip64EndCentralDirLocator(ZipModel zipModel, long totalFileSize) {
if (zipModel.getZip64EndOfCentralDirectoryLocator() == null) {
return;
}
Zip64EndOfCentralDirectoryLocator zip64EndOfCentralDirectoryLocator = zipModel
.getZip64EndOfCentralDirectoryLocator();
zip64EndOfCentralDirectoryLocator.setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(0);
zip64EndOfCentralDirectoryLocator.setOffsetZip64EndOfCentralDirectoryRecord(
zip64EndOfCentralDirectoryLocator.getOffsetZip64EndOfCentralDirectoryRecord() + totalFileSize);
zip64EndOfCentralDirectoryLocator.setTotalNumberOfDiscs(1);
}
private void updateSplitZip64EndCentralDirRec(ZipModel zipModel, long totalFileSize) {
if (zipModel.getZip64EndOfCentralDirectoryRecord() == null) {
return;
}
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = zipModel.getZip64EndOfCentralDirectoryRecord();
zip64EndOfCentralDirectoryRecord.setNumberOfThisDisk(0);
zip64EndOfCentralDirectoryRecord.setNumberOfThisDiskStartOfCentralDirectory(0);
zip64EndOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(
zipModel.getEndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory());
zip64EndOfCentralDirectoryRecord.setOffsetStartCentralDirectoryWRTStartDiskNumber(
zip64EndOfCentralDirectoryRecord.getOffsetStartCentralDirectoryWRTStartDiskNumber() + totalFileSize);
}
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.MERGE_ZIP_FILES;
}
public static class MergeSplitZipFileTaskParameters extends AbstractZipTaskParameters {
private File outputZipFile;
public MergeSplitZipFileTaskParameters(File outputZipFile, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.outputZipFile = outputZipFile;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/RemoveFilesFromZipTask.java 0000664 0000000 0000000 00000015215 14142654472 0027033 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.RemoveFilesFromZipTask.RemoveFilesFromZipTaskParameters;
import net.lingala.zip4j.util.InternalZipConstants;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
public class RemoveFilesFromZipTask extends AbstractModifyFileTask {
private final ZipModel zipModel;
private final HeaderWriter headerWriter;
public RemoveFilesFromZipTask(ZipModel zipModel, HeaderWriter headerWriter, AsyncTaskParameters asyncTaskParameters) {
super(asyncTaskParameters);
this.zipModel = zipModel;
this.headerWriter = headerWriter;
}
@Override
protected void executeTask(RemoveFilesFromZipTaskParameters taskParameters, ProgressMonitor progressMonitor)
throws IOException {
if (zipModel.isSplitArchive()) {
throw new ZipException("This is a split archive. Zip file format does not allow updating split/spanned files");
}
List entriesToRemove = filterNonExistingEntries(taskParameters.filesToRemove);
if (entriesToRemove.isEmpty()) {
return;
}
File temporaryZipFile = getTemporaryFile(zipModel.getZipFile().getPath());
boolean successFlag = false;
try (SplitOutputStream outputStream = new SplitOutputStream(temporaryZipFile);
RandomAccessFile inputStream = new RandomAccessFile(zipModel.getZipFile(), RandomAccessFileMode.READ.getValue())){
long currentFileCopyPointer = 0;
List sortedFileHeaders = cloneAndSortFileHeadersByOffset(zipModel.getCentralDirectory().getFileHeaders());
for (FileHeader fileHeader : sortedFileHeaders) {
long lengthOfCurrentEntry = getOffsetOfNextEntry(sortedFileHeaders, fileHeader, zipModel) - outputStream.getFilePointer();
if (shouldEntryBeRemoved(fileHeader, entriesToRemove)) {
updateHeaders(sortedFileHeaders, fileHeader, lengthOfCurrentEntry);
if (!zipModel.getCentralDirectory().getFileHeaders().remove(fileHeader)) {
throw new ZipException("Could not remove entry from list of central directory headers");
}
currentFileCopyPointer += lengthOfCurrentEntry;
} else {
// copy complete entry without any changes
currentFileCopyPointer += super.copyFile(inputStream, outputStream, currentFileCopyPointer,
lengthOfCurrentEntry, progressMonitor, taskParameters.zip4jConfig.getBufferSize());
}
verifyIfTaskIsCancelled();
}
headerWriter.finalizeZipFile(zipModel, outputStream, taskParameters.zip4jConfig.getCharset());
successFlag = true;
} finally {
cleanupFile(successFlag, zipModel.getZipFile(), temporaryZipFile);
}
}
@Override
protected long calculateTotalWork(RemoveFilesFromZipTaskParameters taskParameters) {
return zipModel.getZipFile().length();
}
private List filterNonExistingEntries(List filesToRemove) throws ZipException {
List filteredFilesToRemove = new ArrayList<>();
for (String fileToRemove : filesToRemove) {
if (HeaderUtil.getFileHeader(zipModel, fileToRemove) != null) {
filteredFilesToRemove.add(fileToRemove);
}
}
return filteredFilesToRemove;
}
private boolean shouldEntryBeRemoved(FileHeader fileHeaderToBeChecked, List fileNamesToBeRemoved) {
for (String fileNameToBeRemoved : fileNamesToBeRemoved) {
// If any of the files to be removed is a directory, check if the fileHeaderToBeChecked is a sub-file or
// a sub-directory of that directory
if (fileNameToBeRemoved.endsWith(InternalZipConstants.ZIP_FILE_SEPARATOR) &&
fileHeaderToBeChecked.getFileName().startsWith(fileNameToBeRemoved)) {
return true;
} else if (fileHeaderToBeChecked.getFileName().equals(fileNameToBeRemoved)) {
return true;
}
}
return false;
}
private void updateHeaders(List sortedFileHeaders, FileHeader fileHeaderThatWasRemoved,
long offsetToSubtract) throws ZipException {
updateOffsetsForAllSubsequentFileHeaders(sortedFileHeaders, zipModel, fileHeaderThatWasRemoved, negate(offsetToSubtract));
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = zipModel.getEndOfCentralDirectoryRecord();
endOfCentralDirectoryRecord.setOffsetOfStartOfCentralDirectory(
endOfCentralDirectoryRecord.getOffsetOfStartOfCentralDirectory() - offsetToSubtract);
endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectory(
endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectory() - 1);
if (endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectoryOnThisDisk() > 0) {
endOfCentralDirectoryRecord.setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(
endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectoryOnThisDisk() - 1);
}
if (zipModel.isZip64Format()) {
zipModel.getZip64EndOfCentralDirectoryRecord().setOffsetStartCentralDirectoryWRTStartDiskNumber(
zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber() - offsetToSubtract);
zipModel.getZip64EndOfCentralDirectoryRecord().setTotalNumberOfEntriesInCentralDirectoryOnThisDisk(
zipModel.getZip64EndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory() - 1);
zipModel.getZip64EndOfCentralDirectoryLocator().setOffsetZip64EndOfCentralDirectoryRecord(
zipModel.getZip64EndOfCentralDirectoryLocator().getOffsetZip64EndOfCentralDirectoryRecord() - offsetToSubtract);
}
}
private long negate(long val) {
if (val == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow");
}
return -val;
}
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.REMOVE_ENTRY;
}
public static class RemoveFilesFromZipTaskParameters extends AbstractZipTaskParameters {
private final List filesToRemove;
public RemoveFilesFromZipTaskParameters(List filesToRemove, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.filesToRemove = filesToRemove;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/RenameFilesTask.java 0000664 0000000 0000000 00000023155 14142654472 0025500 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import net.lingala.zip4j.util.Zip4jUtil;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RenameFilesTask extends AbstractModifyFileTask {
private final ZipModel zipModel;
private final HeaderWriter headerWriter;
private final RawIO rawIO;
public RenameFilesTask(ZipModel zipModel, HeaderWriter headerWriter, RawIO rawIO, AsyncTaskParameters asyncTaskParameters) {
super(asyncTaskParameters);
this.zipModel = zipModel;
this.headerWriter = headerWriter;
this.rawIO = rawIO;
}
@Override
protected void executeTask(RenameFilesTaskParameters taskParameters, ProgressMonitor progressMonitor) throws IOException {
Map fileNamesMap = filterNonExistingEntriesAndAddSeparatorIfNeeded(taskParameters.fileNamesMap);
if (fileNamesMap.size() == 0) {
return;
}
File temporaryFile = getTemporaryFile(zipModel.getZipFile().getPath());
boolean successFlag = false;
try(RandomAccessFile inputStream = new RandomAccessFile(zipModel.getZipFile(), RandomAccessFileMode.WRITE.getValue());
SplitOutputStream outputStream = new SplitOutputStream(temporaryFile)) {
long currentFileCopyPointer = 0;
Charset charset = taskParameters.zip4jConfig.getCharset();
// Maintain a different list to iterate, so that when the file name is changed in the central directory
// we still have access to the original file names. If iterating on the original list from central directory,
// it might be that a file name has changed because of other file name, ex: if a directory name has to be changed
// and the file is part of that directory, by the time the file has to be changed, its name might have changed
// when changing the name of the directory. There is some overhead with this approach, but is safer.
List sortedFileHeaders = cloneAndSortFileHeadersByOffset(zipModel.getCentralDirectory().getFileHeaders());
for (FileHeader fileHeader : sortedFileHeaders) {
Map.Entry fileNameMapForThisEntry = getCorrespondingEntryFromMap(fileHeader, fileNamesMap);
progressMonitor.setFileName(fileHeader.getFileName());
long lengthToCopy = getOffsetOfNextEntry(sortedFileHeaders, fileHeader, zipModel) - outputStream.getFilePointer();
if (fileNameMapForThisEntry == null) {
// copy complete entry without any changes
currentFileCopyPointer += copyFile(inputStream, outputStream, currentFileCopyPointer, lengthToCopy,
progressMonitor, taskParameters.zip4jConfig.getBufferSize());
} else {
String newFileName = getNewFileName(fileNameMapForThisEntry.getValue(), fileNameMapForThisEntry.getKey(), fileHeader.getFileName());
byte[] newFileNameBytes = HeaderUtil.getBytesFromString(newFileName, charset);
int headersOffset = newFileNameBytes.length - fileHeader.getFileNameLength();
currentFileCopyPointer = copyEntryAndChangeFileName(newFileNameBytes, fileHeader, currentFileCopyPointer, lengthToCopy,
inputStream, outputStream, progressMonitor, taskParameters.zip4jConfig.getBufferSize());
updateHeadersInZipModel(sortedFileHeaders, fileHeader, newFileName, newFileNameBytes, headersOffset);
}
verifyIfTaskIsCancelled();
}
headerWriter.finalizeZipFile(zipModel, outputStream, charset);
successFlag = true;
} finally {
cleanupFile(successFlag, zipModel.getZipFile(), temporaryFile);
}
}
@Override
protected long calculateTotalWork(RenameFilesTaskParameters taskParameters) {
return zipModel.getZipFile().length();
}
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.RENAME_FILE;
}
private long copyEntryAndChangeFileName(byte[] newFileNameBytes, FileHeader fileHeader, long start, long totalLengthOfEntry,
RandomAccessFile inputStream, OutputStream outputStream,
ProgressMonitor progressMonitor, int bufferSize) throws IOException {
long currentFileCopyPointer = start;
currentFileCopyPointer += copyFile(inputStream, outputStream, currentFileCopyPointer, 26, progressMonitor, bufferSize); // 26 is offset until file name length
rawIO.writeShortLittleEndian(outputStream, newFileNameBytes.length);
currentFileCopyPointer += 2; // length of file name length
currentFileCopyPointer += copyFile(inputStream, outputStream, currentFileCopyPointer, 2, progressMonitor, bufferSize); // 2 is for length of extra field length
outputStream.write(newFileNameBytes);
currentFileCopyPointer += fileHeader.getFileNameLength();
long remainingLengthToCopy = totalLengthOfEntry - (currentFileCopyPointer - start);
currentFileCopyPointer += copyFile(inputStream, outputStream, currentFileCopyPointer,
remainingLengthToCopy, progressMonitor, bufferSize);
return currentFileCopyPointer;
}
private Map.Entry getCorrespondingEntryFromMap(FileHeader fileHeaderToBeChecked, Map fileNamesMap) {
for (Map.Entry fileHeaderToBeRenamed : fileNamesMap.entrySet()) {
if (fileHeaderToBeChecked.getFileName().startsWith(fileHeaderToBeRenamed.getKey())) {
return fileHeaderToBeRenamed;
}
}
return null;
}
private void updateHeadersInZipModel(List sortedFileHeaders, FileHeader fileHeader, String newFileName,
byte[] newFileNameBytes, int headersOffset) throws ZipException {
FileHeader fileHeaderToBeChanged = HeaderUtil.getFileHeader(zipModel, fileHeader.getFileName());
if (fileHeaderToBeChanged == null) {
// If this is the case, then the file name in the header that was passed to this method was already changed.
// In theory, should never be here.
throw new ZipException("could not find any header with name: " + fileHeader.getFileName());
}
fileHeaderToBeChanged.setFileName(newFileName);
fileHeaderToBeChanged.setFileNameLength(newFileNameBytes.length);
updateOffsetsForAllSubsequentFileHeaders(sortedFileHeaders, zipModel, fileHeaderToBeChanged, headersOffset);
zipModel.getEndOfCentralDirectoryRecord().setOffsetOfStartOfCentralDirectory(
zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory() + headersOffset);
if (zipModel.isZip64Format()) {
zipModel.getZip64EndOfCentralDirectoryRecord().setOffsetStartCentralDirectoryWRTStartDiskNumber(
zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber() + headersOffset
);
zipModel.getZip64EndOfCentralDirectoryLocator().setOffsetZip64EndOfCentralDirectoryRecord(
zipModel.getZip64EndOfCentralDirectoryLocator().getOffsetZip64EndOfCentralDirectoryRecord() + headersOffset
);
}
}
private Map filterNonExistingEntriesAndAddSeparatorIfNeeded(Map inputFileNamesMap) throws ZipException {
Map fileNamesMapToBeChanged = new HashMap<>();
for (Map.Entry allNamesToBeChanged : inputFileNamesMap.entrySet()) {
if (!Zip4jUtil.isStringNotNullAndNotEmpty(allNamesToBeChanged.getKey())) {
continue;
}
FileHeader fileHeaderToBeChanged = HeaderUtil.getFileHeader(zipModel, allNamesToBeChanged.getKey());
if (fileHeaderToBeChanged != null) {
if (fileHeaderToBeChanged.isDirectory() && !allNamesToBeChanged.getValue().endsWith(InternalZipConstants.ZIP_FILE_SEPARATOR)) {
fileNamesMapToBeChanged.put(allNamesToBeChanged.getKey(), allNamesToBeChanged.getValue() + InternalZipConstants.ZIP_FILE_SEPARATOR);
} else {
fileNamesMapToBeChanged.put(allNamesToBeChanged.getKey(), allNamesToBeChanged.getValue());
}
}
}
return fileNamesMapToBeChanged;
}
private String getNewFileName(String newFileName, String oldFileName, String fileNameFromHeaderToBeChanged) throws ZipException {
if (fileNameFromHeaderToBeChanged.equals(oldFileName)) {
return newFileName;
} else if (fileNameFromHeaderToBeChanged.startsWith(oldFileName)) {
String fileNameWithoutOldName = fileNameFromHeaderToBeChanged.substring(oldFileName.length());
return newFileName + fileNameWithoutOldName;
}
// Should never be here.
// If here by any chance, it means that the file header was marked as to-be-modified, even when the file names do not
// match. Logic in the method getCorrespondingEntryFromMap() has to be checked
throw new ZipException("old file name was neither an exact match nor a partial match");
}
public static class RenameFilesTaskParameters extends AbstractZipTaskParameters {
private final Map fileNamesMap;
public RenameFilesTaskParameters(Map fileNamesMap, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.fileNamesMap = fileNamesMap;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/tasks/SetCommentTask.java 0000664 0000000 0000000 00000004334 14142654472 0025362 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.SetCommentTask.SetCommentTaskTaskParameters;
import java.io.IOException;
public class SetCommentTask extends AsyncZipTask {
private final ZipModel zipModel;
public SetCommentTask(ZipModel zipModel, AsyncTaskParameters asyncTaskParameters) {
super(asyncTaskParameters);
this.zipModel = zipModel;
}
@Override
protected void executeTask(SetCommentTaskTaskParameters taskParameters, ProgressMonitor progressMonitor) throws IOException {
if (taskParameters.comment == null) {
throw new ZipException("comment is null, cannot update Zip file with comment");
}
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = zipModel.getEndOfCentralDirectoryRecord();
endOfCentralDirectoryRecord.setComment(taskParameters.comment);
try (SplitOutputStream outputStream = new SplitOutputStream(zipModel.getZipFile())) {
if (zipModel.isZip64Format()) {
outputStream.seek(zipModel.getZip64EndOfCentralDirectoryRecord()
.getOffsetStartCentralDirectoryWRTStartDiskNumber());
} else {
outputStream.seek(endOfCentralDirectoryRecord.getOffsetOfStartOfCentralDirectory());
}
HeaderWriter headerWriter = new HeaderWriter();
headerWriter.finalizeZipFileWithoutValidations(zipModel, outputStream, taskParameters.zip4jConfig.getCharset());
}
}
@Override
protected long calculateTotalWork(SetCommentTaskTaskParameters taskParameters) {
return 0;
}
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.SET_COMMENT;
}
public static class SetCommentTaskTaskParameters extends AbstractZipTaskParameters {
private String comment;
public SetCommentTaskTaskParameters(String comment, Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.comment = comment;
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/ 0000775 0000000 0000000 00000000000 14142654472 0021442 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/BitUtils.java 0000664 0000000 0000000 00000000510 14142654472 0024040 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.util;
public class BitUtils {
public static boolean isBitSet(byte b, int pos) {
return (b & (1L << pos)) != 0;
}
public static byte setBit(byte b, int pos) {
return (byte) (b | 1 << pos);
}
public static byte unsetBit(byte b, int pos) {
return (byte) (b & ~(1 << pos));
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/CrcUtil.java 0000775 0000000 0000000 00000003576 14142654472 0023670 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.util;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.progress.ProgressMonitor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.CRC32;
public class CrcUtil {
private static final int BUF_SIZE = 1 << 14; //16384
public static long computeFileCrc(File inputFile, ProgressMonitor progressMonitor) throws IOException {
if (inputFile == null || !inputFile.exists() || !inputFile.canRead()) {
throw new ZipException("input file is null or does not exist or cannot read. " +
"Cannot calculate CRC for the file");
}
byte[] buff = new byte[BUF_SIZE];
CRC32 crc32 = new CRC32();
try(InputStream inputStream = new FileInputStream(inputFile)) {
int readLen;
while ((readLen = inputStream.read(buff)) != -1) {
crc32.update(buff, 0, readLen);
if (progressMonitor != null) {
progressMonitor.updateWorkCompleted(readLen);
if (progressMonitor.isCancelAllTasks()) {
progressMonitor.setResult(ProgressMonitor.Result.CANCELLED);
progressMonitor.setState(ProgressMonitor.State.READY);
return 0;
}
}
}
return crc32.getValue();
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/FileUtils.java 0000664 0000000 0000000 00000051020 14142654472 0024203 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.util;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ExcludeFileFilter;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.progress.ProgressMonitor;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.DosFileAttributeView;
import java.nio.file.attribute.DosFileAttributes;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE;
import static java.nio.file.attribute.PosixFilePermission.GROUP_READ;
import static java.nio.file.attribute.PosixFilePermission.GROUP_WRITE;
import static java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE;
import static java.nio.file.attribute.PosixFilePermission.OTHERS_READ;
import static java.nio.file.attribute.PosixFilePermission.OTHERS_WRITE;
import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
import static net.lingala.zip4j.util.BitUtils.isBitSet;
import static net.lingala.zip4j.util.BitUtils.setBit;
import static net.lingala.zip4j.util.InternalZipConstants.FILE_SEPARATOR;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP_FILE_SEPARATOR;
import static net.lingala.zip4j.util.Zip4jUtil.isStringNotNullAndNotEmpty;
public class FileUtils {
public static final byte[] DEFAULT_POSIX_FILE_ATTRIBUTES = new byte[] {0, 0, -92, -127}; //-rw-r--r--
public static final byte[] DEFAULT_POSIX_FOLDER_ATTRIBUTES = new byte[] {0, 0, -19, 65}; //drwxr-xr-x
public static void setFileAttributes(Path file, byte[] fileAttributes) {
if (fileAttributes == null || fileAttributes.length == 0) {
return;
}
if (isWindows()) {
applyWindowsFileAttributes(file, fileAttributes);
} else if (isMac() || isUnix()) {
applyPosixFileAttributes(file, fileAttributes);
}
}
public static void setFileLastModifiedTime(Path file, long lastModifiedTime) {
if (lastModifiedTime <= 0 || !Files.exists(file)) {
return;
}
try {
Files.setLastModifiedTime(file, FileTime.fromMillis(Zip4jUtil.dosToExtendedEpochTme(lastModifiedTime)));
} catch (Exception e) {
// Ignore
}
}
public static void setFileLastModifiedTimeWithoutNio(File file, long lastModifiedTime) {
file.setLastModified(Zip4jUtil.dosToExtendedEpochTme(lastModifiedTime));
}
public static byte[] getFileAttributes(File file) {
try {
if (file == null || (!Files.isSymbolicLink(file.toPath()) && !file.exists())) {
return new byte[4];
}
Path path = file.toPath();
if (isWindows()) {
return getWindowsFileAttributes(path);
} else if (isMac() || isUnix()) {
return getPosixFileAttributes(path);
} else {
return new byte[4];
}
} catch (NoSuchMethodError e) {
return new byte[4];
}
}
public static List getFilesInDirectoryRecursive(File path, boolean readHiddenFiles, boolean readHiddenFolders) throws ZipException {
return getFilesInDirectoryRecursive(path, readHiddenFiles, readHiddenFolders, null);
}
public static List getFilesInDirectoryRecursive(File path, boolean readHiddenFiles, boolean readHiddenFolders, ExcludeFileFilter excludedFiles)
throws ZipException {
if (path == null) {
throw new ZipException("input path is null, cannot read files in the directory");
}
List result = new ArrayList<>();
File[] filesAndDirs = path.listFiles();
if (!path.isDirectory() || !path.canRead() || filesAndDirs == null) {
return result;
}
for (File file : filesAndDirs) {
if (excludedFiles != null && excludedFiles.isExcluded(file)) {
continue;
}
if (file.isHidden()) {
if (file.isDirectory()) {
if (!readHiddenFolders) {
continue;
}
} else if (!readHiddenFiles) {
continue;
}
}
result.add(file);
if (file.isDirectory()) {
result.addAll(getFilesInDirectoryRecursive(file, readHiddenFiles, readHiddenFolders, excludedFiles));
}
}
return result;
}
public static String getFileNameWithoutExtension(String fileName) {
int pos = fileName.lastIndexOf(".");
if (pos == -1) {
return fileName;
}
return fileName.substring(0, pos);
}
public static String getZipFileNameWithoutExtension(String zipFile) throws ZipException {
if (!isStringNotNullAndNotEmpty(zipFile)) {
throw new ZipException("zip file name is empty or null, cannot determine zip file name");
}
String tmpFileName = zipFile;
if (zipFile.contains(System.getProperty("file.separator"))) {
tmpFileName = zipFile.substring(zipFile.lastIndexOf(System.getProperty("file.separator")) + 1);
}
if (tmpFileName.endsWith(".zip")) {
tmpFileName = tmpFileName.substring(0, tmpFileName.lastIndexOf("."));
}
return tmpFileName;
}
public static List getSplitZipFiles(ZipModel zipModel) throws ZipException {
if (zipModel == null) {
throw new ZipException("cannot get split zip files: zipmodel is null");
}
if (zipModel.getEndOfCentralDirectoryRecord() == null) {
return null;
}
if (!zipModel.getZipFile().exists()) {
throw new ZipException("zip file does not exist");
}
List splitZipFiles = new ArrayList<>();
File currZipFile = zipModel.getZipFile();
String partFile;
if (!zipModel.isSplitArchive()) {
splitZipFiles.add(currZipFile);
return splitZipFiles;
}
int numberOfThisDisk = zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk();
if (numberOfThisDisk == 0) {
splitZipFiles.add(currZipFile);
return splitZipFiles;
} else {
for (int i = 0; i <= numberOfThisDisk; i++) {
if (i == numberOfThisDisk) {
splitZipFiles.add(zipModel.getZipFile());
} else {
String fileExt = ".z0";
if (i >= 9) {
fileExt = ".z";
}
partFile = (currZipFile.getName().contains("."))
? currZipFile.getPath().substring(0, currZipFile.getPath().lastIndexOf(".")) : currZipFile.getPath();
partFile = partFile + fileExt + (i + 1);
splitZipFiles.add(new File(partFile));
}
}
}
return splitZipFiles;
}
public static String getRelativeFileName(File fileToAdd, ZipParameters zipParameters) throws ZipException {
String fileName;
try {
String fileCanonicalPath = fileToAdd.getCanonicalPath();
if (isStringNotNullAndNotEmpty(zipParameters.getDefaultFolderPath())) {
File rootFolderFile = new File(zipParameters.getDefaultFolderPath());
String rootFolderFileRef = rootFolderFile.getCanonicalPath();
if (!rootFolderFileRef.endsWith(FILE_SEPARATOR)) {
rootFolderFileRef += FILE_SEPARATOR;
}
String tmpFileName;
if (isSymbolicLink(fileToAdd)) {
String rootPath = new File(fileToAdd.getParentFile().getCanonicalFile().getPath() + File.separator + fileToAdd.getCanonicalFile().getName()).getPath();
tmpFileName = rootPath.substring(rootFolderFileRef.length());
} else {
tmpFileName = fileCanonicalPath.substring(rootFolderFileRef.length());
}
if (tmpFileName.startsWith(System.getProperty("file.separator"))) {
tmpFileName = tmpFileName.substring(1);
}
File tmpFile = new File(fileCanonicalPath);
if (tmpFile.isDirectory()) {
tmpFileName = tmpFileName.replaceAll("\\\\", ZIP_FILE_SEPARATOR);
tmpFileName += ZIP_FILE_SEPARATOR;
} else {
String bkFileName = tmpFileName.substring(0, tmpFileName.lastIndexOf(tmpFile.getName()));
bkFileName = bkFileName.replaceAll("\\\\", ZIP_FILE_SEPARATOR);
tmpFileName = bkFileName + getNameOfFileInZip(tmpFile, zipParameters.getFileNameInZip());
}
fileName = tmpFileName;
} else {
File relFile = new File(fileCanonicalPath);
fileName = getNameOfFileInZip(relFile, zipParameters.getFileNameInZip());
if (relFile.isDirectory()) {
fileName += ZIP_FILE_SEPARATOR;
}
}
} catch (IOException e) {
throw new ZipException(e);
}
String rootFolderNameInZip = zipParameters.getRootFolderNameInZip();
if (Zip4jUtil.isStringNotNullAndNotEmpty(rootFolderNameInZip)) {
if (!rootFolderNameInZip.endsWith("\\") && !rootFolderNameInZip.endsWith("/")) {
rootFolderNameInZip = rootFolderNameInZip + InternalZipConstants.FILE_SEPARATOR;
}
rootFolderNameInZip = rootFolderNameInZip.replaceAll("\\\\", ZIP_FILE_SEPARATOR);
fileName = rootFolderNameInZip + fileName;
}
if (!isStringNotNullAndNotEmpty(fileName)) {
String errorMessage = "fileName to add to zip is empty or null. fileName: '" + fileName + "' "
+ "DefaultFolderPath: '" + zipParameters.getDefaultFolderPath() + "' "
+ "FileNameInZip: " + zipParameters.getFileNameInZip();
if (isSymbolicLink(fileToAdd)) {
errorMessage += "isSymlink: true ";
}
if (Zip4jUtil.isStringNotNullAndNotEmpty(rootFolderNameInZip)) {
errorMessage = "rootFolderNameInZip: '" + rootFolderNameInZip + "' ";
}
throw new ZipException(errorMessage);
}
return fileName;
}
private static String getNameOfFileInZip(File fileToAdd, String fileNameInZip) throws IOException {
if (isStringNotNullAndNotEmpty(fileNameInZip)) {
return fileNameInZip;
}
if (isSymbolicLink(fileToAdd)) {
return fileToAdd.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).getFileName().toString();
}
return fileToAdd.getName();
}
public static boolean isZipEntryDirectory(String fileNameInZip) {
return fileNameInZip.endsWith("/") || fileNameInZip.endsWith("\\");
}
public static void copyFile(RandomAccessFile randomAccessFile, OutputStream outputStream, long start, long end,
ProgressMonitor progressMonitor, int bufferSize) throws ZipException {
if (start < 0 || end < 0 || start > end) {
throw new ZipException("invalid offsets");
}
if (start == end) {
return;
}
try {
randomAccessFile.seek(start);
int readLen;
byte[] buff;
long bytesRead = 0;
long bytesToRead = end - start;
if ((end - start) < bufferSize) {
buff = new byte[(int) bytesToRead];
} else {
buff = new byte[bufferSize];
}
while ((readLen = randomAccessFile.read(buff)) != -1) {
outputStream.write(buff, 0, readLen);
progressMonitor.updateWorkCompleted(readLen);
if (progressMonitor.isCancelAllTasks()) {
progressMonitor.setResult(ProgressMonitor.Result.CANCELLED);
return;
}
bytesRead += readLen;
if (bytesRead == bytesToRead) {
break;
} else if (bytesRead + buff.length > bytesToRead) {
buff = new byte[(int) (bytesToRead - bytesRead)];
}
}
} catch (IOException e) {
throw new ZipException(e);
}
}
public static void assertFilesExist(List files, ZipParameters.SymbolicLinkAction symLinkAction) throws ZipException {
for (File file : files) {
if (isSymbolicLink(file)) {
// If symlink is INCLUDE_LINK_ONLY, and if the above condition is true, it means that the link exists and there
// will be no need to check for link existence explicitly, check only for target file existence if required
if (symLinkAction.equals(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE)
|| symLinkAction.equals(ZipParameters.SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY)) {
assertSymbolicLinkTargetExists(file);
}
} else {
assertFileExists(file);
}
}
}
public static boolean isNumberedSplitFile(File file) {
return file.getName().endsWith(InternalZipConstants.SEVEN_ZIP_SPLIT_FILE_EXTENSION_PATTERN);
}
public static String getFileExtension(File file) {
String fileName = file.getName();
if (!fileName.contains(".")) {
return "";
}
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
/**
* A helper method to retrieve all split files which are of the format split by 7-zip, i.e, .zip.001, .zip.002, etc.
* This method also sorts all the files by their split part
* @param firstNumberedFile - first split file
* @return sorted list of split files. Returns an empty list if no files of that pattern are found in the current directory
*/
public static File[] getAllSortedNumberedSplitFiles(File firstNumberedFile) {
final String zipFileNameWithoutExtension = FileUtils.getFileNameWithoutExtension(firstNumberedFile.getName());
File[] allSplitFiles = firstNumberedFile.getParentFile().listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith(zipFileNameWithoutExtension + ".");
}
});
if(allSplitFiles == null) {
return new File[0];
}
Arrays.sort(allSplitFiles);
return allSplitFiles;
}
public static String getNextNumberedSplitFileCounterAsExtension(int index) {
return "." + getExtensionZerosPrefix(index) + (index + 1);
}
public static boolean isSymbolicLink(File file) {
try {
return Files.isSymbolicLink(file.toPath());
} catch (Exception | Error e) {
return false;
}
}
public static String readSymbolicLink(File file) {
try {
return Files.readSymbolicLink(file.toPath()).toString();
} catch (Exception | Error e) {
return "";
}
}
public static byte[] getDefaultFileAttributes(boolean isDirectory) {
byte[] permissions = new byte[4];
if (isUnix() || isMac()) {
if (isDirectory) {
System.arraycopy(DEFAULT_POSIX_FOLDER_ATTRIBUTES, 0, permissions, 0, permissions.length);
} else {
System.arraycopy(DEFAULT_POSIX_FILE_ATTRIBUTES, 0, permissions, 0, permissions.length);
}
} else if (isWindows() && isDirectory) {
permissions[0] = setBit(permissions[0], 4);
}
return permissions;
}
public static boolean isWindows() {
String os = System.getProperty("os.name").toLowerCase();
return (os.contains("win"));
}
public static boolean isMac() {
String os = System.getProperty("os.name").toLowerCase();
return (os.contains("mac"));
}
public static boolean isUnix() {
String os = System.getProperty("os.name").toLowerCase();
return (os.contains("nux"));
}
private static String getExtensionZerosPrefix(int index) {
if (index < 9) {
return "00";
} else if (index < 99) {
return "0";
} else {
return "";
}
}
private static void applyWindowsFileAttributes(Path file, byte[] fileAttributes) {
if (fileAttributes[0] == 0) {
// No file attributes defined in the archive
return;
}
DosFileAttributeView fileAttributeView = Files.getFileAttributeView(file, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
try {
fileAttributeView.setReadOnly(isBitSet(fileAttributes[0], 0));
fileAttributeView.setHidden(isBitSet(fileAttributes[0], 1));
fileAttributeView.setSystem(isBitSet(fileAttributes[0], 2));
fileAttributeView.setArchive(isBitSet(fileAttributes[0], 5));
} catch (IOException e) {
//Ignore
}
}
private static void applyPosixFileAttributes(Path file, byte[] fileAttributes) {
if (fileAttributes[2] == 0 && fileAttributes[3] == 0) {
// No file attributes defined
return;
}
try {
Set posixFilePermissions = new HashSet<>();
addIfBitSet(fileAttributes[3], 0, posixFilePermissions, PosixFilePermission.OWNER_READ);
addIfBitSet(fileAttributes[2], 7, posixFilePermissions, PosixFilePermission.OWNER_WRITE);
addIfBitSet(fileAttributes[2], 6, posixFilePermissions, PosixFilePermission.OWNER_EXECUTE);
addIfBitSet(fileAttributes[2], 5, posixFilePermissions, PosixFilePermission.GROUP_READ);
addIfBitSet(fileAttributes[2], 4, posixFilePermissions, PosixFilePermission.GROUP_WRITE);
addIfBitSet(fileAttributes[2], 3, posixFilePermissions, PosixFilePermission.GROUP_EXECUTE);
addIfBitSet(fileAttributes[2], 2, posixFilePermissions, PosixFilePermission.OTHERS_READ);
addIfBitSet(fileAttributes[2], 1, posixFilePermissions, PosixFilePermission.OTHERS_WRITE);
addIfBitSet(fileAttributes[2], 0, posixFilePermissions, PosixFilePermission.OTHERS_EXECUTE);
Files.setPosixFilePermissions(file, posixFilePermissions);
} catch (IOException e) {
// Ignore
}
}
private static byte[] getWindowsFileAttributes(Path file) {
byte[] fileAttributes = new byte[4];
try {
DosFileAttributeView dosFileAttributeView = Files.getFileAttributeView(file, DosFileAttributeView.class,
LinkOption.NOFOLLOW_LINKS);
DosFileAttributes dosFileAttributes = dosFileAttributeView.readAttributes();
byte windowsAttribute = 0;
windowsAttribute = setBitIfApplicable(dosFileAttributes.isReadOnly(), windowsAttribute, 0);
windowsAttribute = setBitIfApplicable(dosFileAttributes.isHidden(), windowsAttribute, 1);
windowsAttribute = setBitIfApplicable(dosFileAttributes.isSystem(), windowsAttribute, 2);
windowsAttribute = setBitIfApplicable(dosFileAttributes.isDirectory(), windowsAttribute, 4);
windowsAttribute = setBitIfApplicable(dosFileAttributes.isArchive(), windowsAttribute, 5);
fileAttributes[0] = windowsAttribute;
} catch (IOException e) {
// ignore
}
return fileAttributes;
}
private static void assertFileExists(File file) throws ZipException {
if (!file.exists()) {
throw new ZipException("File does not exist: " + file);
}
}
private static void assertSymbolicLinkTargetExists(File file) throws ZipException {
if (!file.exists()) {
throw new ZipException("Symlink target '" + readSymbolicLink(file) + "' does not exist for link '" + file + "'");
}
}
private static byte[] getPosixFileAttributes(Path file) {
byte[] fileAttributes = new byte[4];
try {
PosixFileAttributeView posixFileAttributeView = Files.getFileAttributeView(file, PosixFileAttributeView.class,
LinkOption.NOFOLLOW_LINKS);
Set posixFilePermissions = posixFileAttributeView.readAttributes().permissions();
fileAttributes[3] = setBitIfApplicable(Files.isRegularFile(file), fileAttributes[3], 7);
fileAttributes[3] = setBitIfApplicable(Files.isDirectory(file), fileAttributes[3], 6);
fileAttributes[3] = setBitIfApplicable(Files.isSymbolicLink(file), fileAttributes[3], 5);
fileAttributes[3] = setBitIfApplicable(posixFilePermissions.contains(OWNER_READ), fileAttributes[3], 0);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(OWNER_WRITE), fileAttributes[2], 7);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(OWNER_EXECUTE), fileAttributes[2], 6);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(GROUP_READ), fileAttributes[2], 5);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(GROUP_WRITE), fileAttributes[2], 4);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(GROUP_EXECUTE), fileAttributes[2], 3);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(OTHERS_READ), fileAttributes[2], 2);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(OTHERS_WRITE), fileAttributes[2], 1);
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(OTHERS_EXECUTE), fileAttributes[2], 0);
} catch (IOException e) {
// Ignore
}
return fileAttributes;
}
private static byte setBitIfApplicable(boolean applicable, byte b, int pos) {
if (applicable) {
b = BitUtils.setBit(b, pos);
}
return b;
}
private static void addIfBitSet(byte b, int pos, Set posixFilePermissions,
PosixFilePermission posixFilePermissionToAdd) {
if (isBitSet(b, pos)) {
posixFilePermissions.add(posixFilePermissionToAdd);
}
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/InternalZipConstants.java 0000775 0000000 0000000 00000004721 14142654472 0026450 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.util;
import java.io.File;
import java.nio.charset.Charset;
public final class InternalZipConstants {
private InternalZipConstants() {
}
public static final int ENDHDR = 22; // END header size
public static final int STD_DEC_HDR_SIZE = 12;
public static final int MAX_COMMENT_SIZE = 65536;
//AES Constants
public static final int AES_AUTH_LENGTH = 10;
public static final int AES_BLOCK_SIZE = 16;
public static final int AES_EXTRA_DATA_RECORD_SIZE = 11;
public static final String AES_MAC_ALGORITHM = "HmacSHA1";
public static final String AES_HASH_CHARSET = "ISO-8859-1";
public static final int AES_HASH_ITERATIONS = 1000;
public static final int AES_PASSWORD_VERIFIER_LENGTH = 2;
public static final int MIN_SPLIT_LENGTH = 65536;
public static final long ZIP_64_SIZE_LIMIT = 4294967295L;
public static final int ZIP_64_NUMBER_OF_ENTRIES_LIMIT = 65535;
public static final int BUFF_SIZE = 1024 * 4;
public static final int MIN_BUFF_SIZE = 512;
// Update local file header constants
// This value holds the number of bytes to skip from
// the offset of start of local header
public static final int UPDATE_LFH_CRC = 14;
public static final int UPDATE_LFH_COMP_SIZE = 18;
public static final int UPDATE_LFH_UNCOMP_SIZE = 22;
public static final String FILE_SEPARATOR = File.separator;
public static final String ZIP_FILE_SEPARATOR = "/";
public static final int MAX_ALLOWED_ZIP_COMMENT_LENGTH = 0xFFFF;
public static final String ZIP_STANDARD_CHARSET_NAME = "Cp437";
// StandardCharset.UTF-8 could have been used below but StandardCharset does not exist in older versions of Android
public static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8");
public static final Charset ZIP4J_DEFAULT_CHARSET = CHARSET_UTF_8;
public static final String SEVEN_ZIP_SPLIT_FILE_EXTENSION_PATTERN = ".zip.001";
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/PasswordCallback.java 0000664 0000000 0000000 00000000142 14142654472 0025521 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.util;
public interface PasswordCallback {
char[] getPassword();
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/RawIO.java 0000775 0000000 0000000 00000012274 14142654472 0023277 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.util;
import net.lingala.zip4j.exception.ZipException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Arrays;
public class RawIO {
private final byte[] shortBuff = new byte[2];
private final byte[] intBuff = new byte[4];
private final byte[] longBuff = new byte[8];
public long readLongLittleEndian(RandomAccessFile randomAccessFile) throws IOException {
randomAccessFile.readFully(longBuff);
return readLongLittleEndian(longBuff, 0);
}
public long readLongLittleEndian(RandomAccessFile randomAccessFile, int readLen) throws IOException {
resetBytes(longBuff);
randomAccessFile.readFully(longBuff, 0, readLen);
return readLongLittleEndian(longBuff, 0);
}
public long readLongLittleEndian(InputStream inputStream) throws IOException {
readFully(inputStream, longBuff, longBuff.length);
return readLongLittleEndian(longBuff, 0);
}
public long readLongLittleEndian(InputStream inputStream, int readLen) throws IOException {
resetBytes(longBuff);
readFully(inputStream, longBuff, readLen);
return readLongLittleEndian(longBuff, 0);
}
public long readLongLittleEndian(byte[] array, int pos) {
if (array.length - pos < 8) {
resetBytes(longBuff);
}
System.arraycopy(array, pos, longBuff, 0, array.length < 8 ? array.length - pos : 8);
long temp = 0;
temp |= longBuff[7] & 0xff;
temp <<= 8;
temp |= longBuff[6] & 0xff;
temp <<= 8;
temp |= longBuff[5] & 0xff;
temp <<= 8;
temp |= longBuff[4] & 0xff;
temp <<= 8;
temp |= longBuff[3] & 0xff;
temp <<= 8;
temp |= longBuff[2] & 0xff;
temp <<= 8;
temp |= longBuff[1] & 0xff;
temp <<= 8;
temp |= longBuff[0] & 0xff;
return temp;
}
public int readIntLittleEndian(RandomAccessFile randomAccessFile) throws IOException {
randomAccessFile.readFully(intBuff);
return readIntLittleEndian(intBuff);
}
public int readIntLittleEndian(InputStream inputStream) throws IOException {
readFully(inputStream, intBuff, 4);
return readIntLittleEndian(intBuff);
}
public int readIntLittleEndian(byte[] b) {
return readIntLittleEndian(b, 0);
}
public int readIntLittleEndian(byte[] b, int pos) {
return ((b[pos] & 0xff) | (b[1 + pos] & 0xff) << 8)
| ((b[2 + pos] & 0xff) | (b[3 + pos] & 0xff) << 8) << 16;
}
public int readShortLittleEndian(RandomAccessFile randomAccessFile) throws IOException {
randomAccessFile.readFully(shortBuff);
return readShortLittleEndian(shortBuff, 0);
}
public int readShortLittleEndian(InputStream inputStream) throws IOException {
readFully(inputStream, shortBuff, shortBuff.length);
return readShortLittleEndian(shortBuff, 0);
}
public int readShortLittleEndian(byte[] buff, int position) {
return (buff[position] & 0xff) | (buff[1 + position] & 0xff) << 8;
}
public void writeShortLittleEndian(OutputStream outputStream, int value) throws IOException {
writeShortLittleEndian(shortBuff, 0, value);
outputStream.write(shortBuff);
}
public void writeShortLittleEndian(byte[] array, int pos, int value) {
array[pos + 1] = (byte) (value >>> 8);
array[pos] = (byte) (value & 0xFF);
}
public void writeIntLittleEndian(OutputStream outputStream, int value) throws IOException {
writeIntLittleEndian(intBuff, 0, value);
outputStream.write(intBuff);
}
public void writeIntLittleEndian(byte[] array, int pos, int value) {
array[pos + 3] = (byte) (value >>> 24);
array[pos + 2] = (byte) (value >>> 16);
array[pos + 1] = (byte) (value >>> 8);
array[pos] = (byte) (value & 0xFF);
}
public void writeLongLittleEndian(OutputStream outputStream, long value) throws IOException {
writeLongLittleEndian(longBuff, 0, value);
outputStream.write(longBuff);
}
public void writeLongLittleEndian(byte[] array, int pos, long value) {
array[pos + 7] = (byte) (value >>> 56);
array[pos + 6] = (byte) (value >>> 48);
array[pos + 5] = (byte) (value >>> 40);
array[pos + 4] = (byte) (value >>> 32);
array[pos + 3] = (byte) (value >>> 24);
array[pos + 2] = (byte) (value >>> 16);
array[pos + 1] = (byte) (value >>> 8);
array[pos] = (byte) (value & 0xFF);
}
private void readFully(InputStream inputStream, byte[] buff, int readLen) throws IOException {
int actualReadLength = Zip4jUtil.readFully(inputStream, buff, 0, readLen);
if (actualReadLength != readLen) {
throw new ZipException("Could not fill buffer");
}
}
private void resetBytes(byte[] b) {
Arrays.fill(b, (byte) 0);
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/UnzipUtil.java 0000775 0000000 0000000 00000004617 14142654472 0024263 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.util;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.inputstream.NumberedSplitInputStream;
import net.lingala.zip4j.io.inputstream.SplitInputStream;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.io.inputstream.ZipStandardSplitInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipModel;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static net.lingala.zip4j.util.FileUtils.setFileAttributes;
import static net.lingala.zip4j.util.FileUtils.setFileLastModifiedTime;
import static net.lingala.zip4j.util.FileUtils.setFileLastModifiedTimeWithoutNio;
public class UnzipUtil {
public static ZipInputStream createZipInputStream(ZipModel zipModel, FileHeader fileHeader, char[] password)
throws IOException {
SplitInputStream splitInputStream = null;
try {
splitInputStream = createSplitInputStream(zipModel);
splitInputStream.prepareExtractionForFileHeader(fileHeader);
ZipInputStream zipInputStream = new ZipInputStream(splitInputStream, password);
if (zipInputStream.getNextEntry(fileHeader, false) == null) {
throw new ZipException("Could not locate local file header for corresponding file header");
}
return zipInputStream;
} catch (IOException e) {
if (splitInputStream != null) {
splitInputStream.close();
}
throw e;
}
}
public static void applyFileAttributes(FileHeader fileHeader, File file) {
try {
Path path = file.toPath();
setFileAttributes(path, fileHeader.getExternalFileAttributes());
setFileLastModifiedTime(path, fileHeader.getLastModifiedTime());
} catch (NoSuchMethodError e) {
setFileLastModifiedTimeWithoutNio(file, fileHeader.getLastModifiedTime());
}
}
public static SplitInputStream createSplitInputStream(ZipModel zipModel) throws IOException {
File zipFile = zipModel.getZipFile();
if (zipFile.getName().endsWith(InternalZipConstants.SEVEN_ZIP_SPLIT_FILE_EXTENSION_PATTERN)) {
return new NumberedSplitInputStream(zipModel.getZipFile(), true,
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
}
return new ZipStandardSplitInputStream(zipModel.getZipFile(), zipModel.isSplitArchive(),
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/Zip4jUtil.java 0000775 0000000 0000000 00000013717 14142654472 0024157 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed 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 net.lingala.zip4j.util;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.AbstractFileHeader;
import net.lingala.zip4j.model.enums.CompressionMethod;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Calendar;
public class Zip4jUtil {
private static final long DOSTIME_BEFORE_1980 = (1 << 21) | (1 << 16);
private static final int MAX_RAW_READ_FULLY_RETRY_ATTEMPTS = 15;
public static boolean isStringNotNullAndNotEmpty(String str) {
return str != null && str.trim().length() > 0;
}
public static boolean createDirectoryIfNotExists(File file) throws ZipException {
if (file == null) {
throw new ZipException("output path is null");
}
if (file.exists()) {
if (!file.isDirectory()) {
throw new ZipException("output directory is not valid");
}
} else {
if (!file.mkdirs()) {
throw new ZipException("Cannot create output directories");
}
}
return true;
}
public static long epochToExtendedDosTime(long time) {
if (time < 0) {
return DOSTIME_BEFORE_1980;
}
long dostime = epochToDosTime(time);
return (dostime != DOSTIME_BEFORE_1980)
? dostime + ((time % 2000) << 32)
: DOSTIME_BEFORE_1980;
}
private static long epochToDosTime(long time) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
int year = cal.get(Calendar.YEAR);
if (year < 1980) {
return DOSTIME_BEFORE_1980;
}
return (year - 1980) << 25 | (cal.get(Calendar.MONTH) + 1) << 21 |
cal.get(Calendar.DATE) << 16 | cal.get(Calendar.HOUR_OF_DAY) << 11 | cal.get(Calendar.MINUTE) << 5 |
cal.get(Calendar.SECOND) >> 1;
}
public static long dosToExtendedEpochTme(long dosTime) {
long time = dosToEpochTime(dosTime);
return time + (dosTime >> 32);
}
private static long dosToEpochTime(long dosTime) {
int sec = (int) ((dosTime << 1) & 0x3e);
int min = (int) ((dosTime >> 5) & 0x3f);
int hrs = (int) ((dosTime >> 11) & 0x1f);
int day = (int) ((dosTime >> 16) & 0x1f);
int mon = (int) (((dosTime >> 21) & 0xf) - 1);
int year = (int) (((dosTime >> 25) & 0x7f) + 1980);
Calendar cal = Calendar.getInstance();
cal.set(year, mon, day, hrs, min, sec);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime().getTime();
}
public static byte[] convertCharArrayToByteArray(char[] charArray) {
try {
ByteBuffer buf = InternalZipConstants.CHARSET_UTF_8.encode(CharBuffer.wrap(charArray));
byte[] bytes = new byte[buf.limit()];
buf.get(bytes);
return bytes;
} catch (Exception e) {
byte[] bytes = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++) {
bytes[i] = (byte) charArray[i];
}
return bytes;
}
}
public static CompressionMethod getCompressionMethod(AbstractFileHeader localFileHeader) {
if (localFileHeader.getCompressionMethod() != CompressionMethod.AES_INTERNAL_ONLY) {
return localFileHeader.getCompressionMethod();
}
if (localFileHeader.getAesExtraDataRecord() == null) {
throw new RuntimeException("AesExtraDataRecord not present in local header for aes encrypted data");
}
return localFileHeader.getAesExtraDataRecord().getCompressionMethod();
}
public static int readFully(InputStream inputStream, byte[] bufferToReadInto) throws IOException {
int readLen = inputStream.read(bufferToReadInto);
if (readLen != bufferToReadInto.length) {
readLen = readUntilBufferIsFull(inputStream, bufferToReadInto, readLen);
if (readLen != bufferToReadInto.length) {
throw new IOException("Cannot read fully into byte buffer");
}
}
return readLen;
}
public static int readFully(InputStream inputStream, byte[] b, int offset, int length) throws IOException {
int numberOfBytesRead = 0;
if (offset < 0) {
throw new IllegalArgumentException("Negative offset");
}
if (length < 0) {
throw new IllegalArgumentException("Negative length");
}
if (length == 0) {
return 0;
}
if (offset + length > b.length) {
throw new IllegalArgumentException("Length greater than buffer size");
}
while (numberOfBytesRead != length) {
int currentReadLength = inputStream.read(b, offset + numberOfBytesRead, length - numberOfBytesRead);
if (currentReadLength == -1) {
if (numberOfBytesRead == 0) {
return -1;
}
return numberOfBytesRead;
}
numberOfBytesRead += currentReadLength;
}
return numberOfBytesRead;
}
private static int readUntilBufferIsFull(InputStream inputStream, byte[] bufferToReadInto, int readLength)
throws IOException {
int remainingLength = bufferToReadInto.length - readLength;
int loopReadLength = 0;
int retryAttempt = 1; // first attempt is already done before this method is called
while (readLength < bufferToReadInto.length
&& loopReadLength != -1
&& retryAttempt < MAX_RAW_READ_FULLY_RETRY_ATTEMPTS) {
loopReadLength = inputStream.read(bufferToReadInto, readLength, remainingLength);
if (loopReadLength > 0) {
readLength += loopReadLength;
remainingLength -= loopReadLength;
}
retryAttempt++;
}
return readLength;
}
}
zip4j-2.9.1/src/main/java/net/lingala/zip4j/util/ZipVersionUtils.java 0000664 0000000 0000000 00000002755 14142654472 0025447 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.util;
import net.lingala.zip4j.headers.VersionMadeBy;
import net.lingala.zip4j.headers.VersionNeededToExtract;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
public class ZipVersionUtils {
public static int determineVersionMadeBy(ZipParameters zipParameters, RawIO rawIO) {
byte[] versionMadeBy = new byte[2];
versionMadeBy[0] = VersionMadeBy.SPECIFICATION_VERSION.getCode();
versionMadeBy[1] = VersionMadeBy.UNIX.getCode();
if (FileUtils.isWindows() && !zipParameters.isUnixMode()) { // skip setting windows mode if unix mode is forced
versionMadeBy[1] = VersionMadeBy.WINDOWS.getCode();
}
return rawIO.readShortLittleEndian(versionMadeBy, 0);
}
public static VersionNeededToExtract determineVersionNeededToExtract(ZipParameters zipParameters) {
VersionNeededToExtract versionRequired = VersionNeededToExtract.DEFAULT;
if (zipParameters.getCompressionMethod() == CompressionMethod.DEFLATE) {
versionRequired = VersionNeededToExtract.DEFLATE_COMPRESSED;
}
if (zipParameters.getEntrySize() > InternalZipConstants.ZIP_64_SIZE_LIMIT) {
versionRequired = VersionNeededToExtract.ZIP_64_FORMAT;
}
if (zipParameters.isEncryptFiles() && zipParameters.getEncryptionMethod().equals(EncryptionMethod.AES)) {
versionRequired = VersionNeededToExtract.AES_ENCRYPTED;
}
return versionRequired;
}
}
zip4j-2.9.1/src/test/ 0000775 0000000 0000000 00000000000 14142654472 0014342 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/ 0000775 0000000 0000000 00000000000 14142654472 0015263 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/ 0000775 0000000 0000000 00000000000 14142654472 0016051 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/ 0000775 0000000 0000000 00000000000 14142654472 0017460 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/ 0000775 0000000 0000000 00000000000 14142654472 0020520 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/AbstractIT.java 0000664 0000000 0000000 00000006365 14142654472 0023375 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static org.assertj.core.api.Assertions.assertThat;
public abstract class AbstractIT {
protected static final char[] PASSWORD = "test123!".toCharArray();
protected static final List FILES_TO_ADD = Arrays.asList(
getTestFileFromResources("sample_text1.txt"),
getTestFileFromResources("sample_text_large.txt"),
getTestFileFromResources("sample.pdf")
);
protected static final Charset CHARSET_MS_932 = Charset.forName("Ms932");
protected static final Charset CHARSET_GBK = Charset.forName("GBK");
protected static final Charset CHARSET_CP_949 = Charset.forName("Cp949");
protected File generatedZipFile;
protected File outputFolder;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Before
public void before() throws IOException {
generatedZipFile = temporaryFolder.newFile("output.zip");
outputFolder = temporaryFolder.newFolder("output");
cleanupDirectory(temporaryFolder.getRoot());
}
protected ZipParameters createZipParameters(EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength) {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(encryptionMethod);
zipParameters.setAesKeyStrength(aesKeyStrength);
return zipParameters;
}
protected void verifyFileHeadersContainsFiles(List fileHeaders, List fileNames) {
for (String fileName : fileNames) {
boolean fileFound = false;
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.getFileName().equals(fileName)) {
fileFound = true;
break;
}
}
assertThat(fileFound).as("File with name %s not found in zip file", fileName).isTrue();
}
}
protected File getTestArchiveFromResources(String archiveName) {
return TestUtils.getTestArchiveFromResources(archiveName);
}
protected void cleanupOutputFolder() {
cleanupDirectory(outputFolder);
}
protected Zip4jConfig buildDefaultConfig() {
return buildConfig(null);
}
protected Zip4jConfig buildConfig(Charset charset) {
return new Zip4jConfig(charset, InternalZipConstants.BUFF_SIZE);
}
protected Zip4jConfig buildConfig(int bufferSize) {
return new Zip4jConfig(null, bufferSize);
}
private void cleanupDirectory(File directory) {
File[] allTempFiles = directory.listFiles();
if (allTempFiles == null) {
return;
}
for (File file : allTempFiles) {
if (!file.delete()) {
throw new RuntimeException("Could not clean up directory. Error deleting file: " + file);
}
}
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/AddFilesToZipIT.java 0000664 0000000 0000000 00000140770 14142654472 0024272 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.AbstractFileHeader;
import net.lingala.zip4j.model.ExcludeFileFilter;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.BitUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import net.lingala.zip4j.util.ZipVersionUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static net.lingala.zip4j.testutils.HeaderVerifier.verifyLocalFileHeaderUncompressedSize;
import static net.lingala.zip4j.testutils.TestUtils.getFileNamesOfFiles;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class AddFilesToZipIT extends AbstractIT {
private RawIO rawIO = new RawIO();
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testAddFileAsStringParameterThrowsExceptionWhenFileDoesNotExist() throws ZipException {
expectedException.expectMessage("File does not exist: somefile.txt");
expectedException.expect(ZipException.class);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile("somefile.txt");
}
@Test
public void testAddFileAsStringParameterWithoutZipParameterAddsAsDeflate() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(TestUtils.getTestFileFromResources("sample.pdf").getPath());
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample.pdf"), CompressionMethod.DEFLATE, null, null);
verifyZipVersions(zipFile.getFileHeaders().get(0), new ZipParameters());
}
@Test
public void testAddFileAsStringWithZipParametersStoreAndStandardEncryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt").getPath(), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.STORE,
EncryptionMethod.ZIP_STANDARD, null);
}
@Test
public void testAddFileAsStringWithZipParametersStoreAndStandardEncryptionAndCharsetCp949() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.setCharset(CHARSET_CP_949);
String koreanFileName = "가나다.abc";
zipFile.addFile(TestUtils.getTestFileFromResources(koreanFileName).getPath(), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1, true, CHARSET_CP_949);
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(koreanFileName);
verifyZipVersions(zipFile.getFileHeaders().get(0), zipParameters);
}
@Test
public void testAddFileThrowsExceptionWhenFileDoesNotExist() throws ZipException {
expectedException.expectMessage("File does not exist: somefile.txt");
expectedException.expect(ZipException.class);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(new File("somefile.txt"));
}
@Test
public void testAddFileThrowsExceptionWhenPasswordNotSet() throws ZipException {
expectedException.expectMessage("input password is empty or null");
expectedException.expect(ZipException.class);
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"), zipParameters);
}
@Test
public void testAddFileWithoutZipParameterAddsAsDeflate() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("file_PDF_1MB.pdf"), CompressionMethod.DEFLATE, null,
null);
}
@Test
public void testAddFileWithZipParametersStoreAndStandardZip() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.STORE,
EncryptionMethod.ZIP_STANDARD, null);
}
@Test
public void testAddFileWithZipParametersStoreAndAes128Encryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.STORE,
EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
verifyZipVersions(zipFile.getFileHeaders().get(0), zipParameters);
}
@Test
public void testAddFileWithZipParametersStoreAndAes256Encryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.STORE,
EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
}
@Test
public void testAddFileRemovesExistingFileNoEncryption() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 3);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.DEFLATE,
null, null);
}
@Test
public void testAddFileDoesNotOverrideFileIfFlagIsDisabled() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setOverrideExistingFilesInZip(false);
zipFile.setPassword(PASSWORD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 3);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.DEFLATE,
null, null);
}
@Test
public void testAddFileRemovesExistingFileNoEncryptionSingleFileInZip() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"));
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.STORE,
null, null);
}
@Test
public void testAddFileWithDifferentFileNameSetsTheNewFileName() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip("/data/newfile.txt");
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getFileHeaders()).hasSize(1);
assertThat(zipFile.getFileHeader("/data/newfile.txt")).isNotNull();
assertThat(zipFile.getFileHeader("sample_text_large.txt")).isNull();
zipFile.extractAll(outputFolder.getPath());
}
@Test
public void testAddFileRemovesExistingFileWithAesEncryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(1, TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.addFiles(filesToAdd, zipParameters);
zipFile.addFile(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size()
+ 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("file_PDF_1MB.pdf"), CompressionMethod.DEFLATE,
EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
}
@Test
public void testAddFileWithAfterDeflateRemainingBytesTestFile() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setAesVersion(AesVersion.TWO);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFile(TestUtils.getTestFileFromResources("after_deflate_remaining_bytes.bin"), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("after_deflate_remaining_bytes.bin"),
CompressionMethod.DEFLATE, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
}
@Test
public void testAddFileProgressMonitorThrowsExceptionWhenPerformingActionInBusyState() throws ZipException {
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
expectedException.expect(ZipException.class);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.setRunInThread(true);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
progressMonitor.setState(ProgressMonitor.State.BUSY);
zipFile.addFile(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
}
@Test
public void testAddFileWithProgressMonitor() throws IOException, InterruptedException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
boolean percentBetweenZeroAndHundred = false;
boolean fileNameSet = false;
boolean taskNameSet = false;
zipFile.setRunInThread(true);
zipFile.addFile(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"),
createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256));
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
int percentDone = progressMonitor.getPercentDone();
String fileName = progressMonitor.getFileName();
if (percentDone > 0 && percentDone < 100) {
percentBetweenZeroAndHundred = true;
}
if (fileName != null) {
assertThat(fileName).contains("file_PDF_1MB.pdf");
fileNameSet = true;
}
Thread.sleep(10);
if (!progressMonitor.getCurrentTask().equals(ProgressMonitor.Task.NONE)) {
assertThat(progressMonitor.getCurrentTask()).isEqualTo(ProgressMonitor.Task.ADD_ENTRY);
taskNameSet = true;
}
}
assertThat(progressMonitor.getResult()).isEqualTo(ProgressMonitor.Result.SUCCESS);
assertThat(progressMonitor.getState().equals(ProgressMonitor.State.READY));
assertThat(progressMonitor.getException()).isNull();
assertThat(percentBetweenZeroAndHundred).isTrue();
assertThat(fileNameSet).isTrue();
assertThat(taskNameSet).isTrue();
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
}
@Test
public void testAddFilesWithoutParametersWhenZipFileDoesNotExistCreatesSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(asList(
TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"),
TestUtils.getTestFileFromResources("zero_byte_file.txt")
));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 2);
verifyZipFileContainsFiles(generatedZipFile, asList("file_PDF_1MB.pdf", "zero_byte_file.txt"),
CompressionMethod.DEFLATE, null, null);
}
@Test
public void testAddFilesWhenZipFileDoesNotExistCreatesSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(asList(
TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"),
TestUtils.getTestFileFromResources("sample_text1.txt")
), new ZipParameters());
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 2);
verifyZipFileContainsFiles(generatedZipFile, asList("file_PDF_1MB.pdf", "sample_text1.txt"),
CompressionMethod.DEFLATE, null, null);
}
@Test
public void testAddFilesWithZeroByteFileWithAes128Encryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(singletonList(TestUtils.getTestFileFromResources("zero_byte_file.txt")), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("zero_byte_file.txt"),
CompressionMethod.DEFLATE, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
}
@Test
public void testAddFilesWithAes256EncryptionV1() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setAesVersion(AesVersion.ONE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
List fileNames = getFileNamesOfFiles(FILES_TO_ADD);
verifyZipFileContainsFiles(generatedZipFile, fileNames, CompressionMethod.DEFLATE, EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_256, AesVersion.ONE);
}
@Test
public void testAddFilesWithAes256EncryptionV2() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
List fileNames = getFileNamesOfFiles(FILES_TO_ADD);
verifyZipFileContainsFiles(generatedZipFile, fileNames, CompressionMethod.DEFLATE, EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_256);
}
@Test
public void testAddFilesWithZipStandardEncryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
List fileNames = getFileNamesOfFiles(FILES_TO_ADD);
verifyZipFileContainsFiles(generatedZipFile, fileNames, CompressionMethod.DEFLATE, EncryptionMethod.ZIP_STANDARD,
null);
}
@Test
public void testAddFilesWhenFilesAlreadyExistsRemovesFiles() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
char[] newPassword = "SOME_OTHER_PASSWORD".toCharArray();
zipFile = new ZipFile(generatedZipFile, newPassword);
zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, newPassword, outputFolder, FILES_TO_ADD.size());
List fileNames = getFileNamesOfFiles(FILES_TO_ADD);
verifyZipFileContainsFiles(generatedZipFile, fileNames, CompressionMethod.DEFLATE, EncryptionMethod.ZIP_STANDARD,
null);
}
@Test
public void testAddFilesThrowsExceptionForAES192() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("Invalid AES key strength");
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_192);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
}
@Test
public void testAddFilesToSplitZipThrowsException() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(singletonList(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf")), new ZipParameters(),
true, InternalZipConstants.MIN_SPLIT_LENGTH);
expectedException.expect(ZipException.class);
expectedException.expectMessage("Zip file already exists. " +
"Zip file format does not allow updating split/spanned files");
zipFile.addFiles(singletonList(TestUtils.getTestFileFromResources("sample.pdf")));
}
@Test
public void testAddFilesWithDifferentEncryptionType() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(singletonList(TestUtils.getTestFileFromResources("sample.pdf")), zipParameters);
zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
zipFile.addFiles(singletonList(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf")), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 2);
}
@Test
public void testAddFilesWithUtf8Characters() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(asList(
TestUtils.getTestFileFromResources("sample.pdf"),
TestUtils.getTestFileFromResources("бореиская.txt"),
TestUtils.getTestFileFromResources("zero_byte_file.txt"),
TestUtils.getTestFileFromResources("sample_text1.txt"),
TestUtils.getTestFileFromResources("가나다.abc")
), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 5);
List fileNamesThatShouldExistInZip = asList(
"sample.pdf",
"бореиская.txt",
"zero_byte_file.txt",
"sample_text1.txt",
"가나다.abc"
);
verifyZipFileContainsFiles(generatedZipFile, fileNamesThatShouldExistInZip, CompressionMethod.DEFLATE,
EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
}
@Test
public void testAddFilesWithProgressMonitor() throws IOException, InterruptedException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
boolean percentBetweenZeroAndHundred = false;
boolean fileNameSet = false;
boolean taskNameSet = false;
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.setRunInThread(true);
zipFile.addFiles(filesToAdd, createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256));
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
int percentDone = progressMonitor.getPercentDone();
String fileName = progressMonitor.getFileName();
if (percentDone > 0 && percentDone < 100) {
percentBetweenZeroAndHundred = true;
}
if (fileName != null) {
fileNameSet = true;
}
Thread.sleep(10);
if (!progressMonitor.getCurrentTask().equals(ProgressMonitor.Task.NONE)) {
assertThat(progressMonitor.getCurrentTask()).isEqualTo(ProgressMonitor.Task.ADD_ENTRY);
taskNameSet = true;
}
}
assertThat(progressMonitor.getResult()).isEqualTo(ProgressMonitor.Result.SUCCESS);
assertThat(progressMonitor.getState().equals(ProgressMonitor.State.READY));
assertThat(progressMonitor.getException()).isNull();
assertThat(percentBetweenZeroAndHundred).isTrue();
assertThat(fileNameSet).isTrue();
assertThat(taskNameSet).isTrue();
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 4);
}
@Test
public void testAddFolderWithoutZipParameters() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFolder(TestUtils.getTestFileFromResources(""));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 13);
List fileHeaders = getFileHeaders(generatedZipFile);
verifyAllFilesInZipContainsPath(fileHeaders, "test-files/");
verifyFoldersInZip(fileHeaders, generatedZipFile, null);
}
@Test
public void testAddFolderWithStoreAndAes128() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 13);
List fileHeaders = getFileHeaders(generatedZipFile);
verifyAllFilesInZipContainsPath(fileHeaders, "test-files/");
verifyFoldersInZip(fileHeaders, generatedZipFile, PASSWORD);
}
@Test
public void testAddFolderWithDeflateAndAes256AndWithoutRootFolder() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setIncludeRootFolder(false);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 12);
List fileHeaders = getFileHeaders(generatedZipFile);
verifyAllFilesInZipDoesNotContainPath(fileHeaders, "test-files/");
verifyFoldersInZip(fileHeaders, generatedZipFile, PASSWORD);
}
@Test
public void testAddFolderWithRootFolderNameInZipAndWithoutRootFolder() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setIncludeRootFolder(false);
zipParameters.setRootFolderNameInZip("root_folder_name");
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
List fileHeaders = getFileHeaders(generatedZipFile);
verifyAllFilesInZipContainsPath(fileHeaders, "root_folder_name/");
verifyAllFilesInZipDoesNotContainPath(fileHeaders, "root_folder_name/test-files/");
verifyFoldersInZip(fileHeaders, generatedZipFile, PASSWORD);
}
@Test
public void testAddFolderWithRootFolderNameInZipAndWithRootFolder() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setIncludeRootFolder(true);
zipParameters.setRootFolderNameInZip("root_folder_name");
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
List fileHeaders = getFileHeaders(generatedZipFile);
verifyAllFilesInZipContainsPath(fileHeaders, "root_folder_name/");
verifyAllFilesInZipContainsPath(fileHeaders, "root_folder_name/test-files/");
verifyFoldersInZip(fileHeaders, generatedZipFile, PASSWORD);
}
@Test
public void testAddFolderWithProgressMonitor() throws IOException, InterruptedException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
boolean percentBetweenZeroAndHundred = false;
boolean fileNameSet = false;
zipFile.setRunInThread(true);
zipFile.addFolder(TestUtils.getTestFileFromResources(""),
createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256));
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
int percentDone = progressMonitor.getPercentDone();
String fileName = progressMonitor.getFileName();
if (percentDone > 0 && percentDone < 100) {
percentBetweenZeroAndHundred = true;
}
if (fileName != null) {
fileNameSet = true;
}
Thread.sleep(10);
}
assertThat(progressMonitor.getResult()).isEqualTo(ProgressMonitor.Result.SUCCESS);
assertThat(progressMonitor.getState().equals(ProgressMonitor.State.READY));
assertThat(progressMonitor.getException()).isNull();
assertThat(percentBetweenZeroAndHundred).isTrue();
assertThat(fileNameSet).isTrue();
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 13);
}
@Test
public void testAddFolderProgressMonitorThrowsExceptionWhenPerformingActionInBusyState() throws ZipException {
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
expectedException.expect(ZipException.class);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.setRunInThread(true);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
progressMonitor.setState(ProgressMonitor.State.BUSY);
zipFile.addFile(TestUtils.getTestFileFromResources(""));
}
@Test
public void testAddFolderWithNotNormalizedPath() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters parameters = new ZipParameters();
String folderToAddPath = TestUtils.getTestFileFromResources("").getPath()
+ InternalZipConstants.FILE_SEPARATOR + ".."
+ InternalZipConstants.FILE_SEPARATOR
+ TestUtils.getTestFileFromResources("").getName();
File folderToAdd = new File(folderToAddPath);
zipFile.addFolder(folderToAdd, parameters);
File fileToAdd = TestUtils.getTestFileFromResources("file_PDF_1MB.pdf");
zipFile.addFile(fileToAdd, parameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 13);
}
@Test
public void testAddFolderWithExcludeFileFilter() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
final List filesToExclude = Arrays.asList(
TestUtils.getTestFileFromResources("sample.pdf"),
TestUtils.getTestFileFromResources("sample_directory/favicon.ico")
);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setIncludeRootFolder(false);
zipParameters.setExcludeFileFilter(new ExcludeFileFilter() {
@Override
public boolean isExcluded(File o) {
return filesToExclude.contains(o);
}
});
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 10);
verifyZipFileDoesNotContainFiles(generatedZipFile, Arrays.asList("sample.pdf", "sample_directory/favicon.ico"));
}
@Test
public void testAddStreamToZipThrowsExceptionWhenFileNameIsNull() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
InputStream inputStream = new FileInputStream(TestUtils.getTestFileFromResources("бореиская.txt"));
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(null);
expectedException.expectMessage("fileNameInZip has to be set in zipParameters when adding stream");
expectedException.expect(ZipException.class);
zipFile.addStream(inputStream, zipParameters);
}
@Test
public void testAddStreamToZipThrowsExceptionWhenFileNameIsEmpty() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
InputStream inputStream = new FileInputStream(TestUtils.getTestFileFromResources("бореиская.txt"));
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip("");
expectedException.expectMessage("fileNameInZip has to be set in zipParameters when adding stream");
expectedException.expect(ZipException.class);
zipFile.addStream(inputStream, zipParameters);
}
@Test
public void testAddStreamToZipWithoutEncryptionForNewZipAddsSuccessfully() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("бореиская.txt");
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("бореиская.txt"), CompressionMethod.DEFLATE, null, null);
}
@Test
public void testAddStreamToWithStoreCompressionAndWithoutEncryption() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("бореиская.txt");
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("бореиская.txt"), CompressionMethod.STORE, null, null);
zipFile = new ZipFile(generatedZipFile);
byte[] generalPurposeBytes = zipFile.getFileHeaders().get(0).getGeneralPurposeFlag();
// assert that extra data record is not present
assertThat(BitUtils.isBitSet(generalPurposeBytes[0], 3)).isTrue();
}
@Test
public void testAddStreamToWithStoreCompressionAndZipStandardEncryption() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("sample_text_large.txt");
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.STORE,
EncryptionMethod.ZIP_STANDARD, null);
zipFile = new ZipFile(generatedZipFile, PASSWORD);
byte[] generalPurposeBytes = zipFile.getFileHeaders().get(0).getGeneralPurposeFlag();
// assert that extra data record is not present
assertThat(BitUtils.isBitSet(generalPurposeBytes[0], 3)).isTrue();
}
@Test
public void testAddStreamWithStoreCompressionAndCharset() throws IOException {
String koreanFileName = "가나다.abc";
File fileToAdd = TestUtils.getTestFileFromResources(koreanFileName);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.setCharset(CHARSET_CP_949);
zipFile.addStream(inputStream, zipParameters);
byte[] generalPurposeBytes = zipFile.getFileHeaders().get(0).getGeneralPurposeFlag();
// assert that extra data record is not present
assertThat(BitUtils.isBitSet(generalPurposeBytes[1], 3)).isFalse();
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(koreanFileName);
}
@Test
public void testAddStreamWithStoreCompressionAndDefaultCharset() throws IOException {
String koreanFileName = "가나다.abc";
File fileToAdd = TestUtils.getTestFileFromResources(koreanFileName);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
byte[] generalPurposeBytes = zipFile.getFileHeaders().get(0).getGeneralPurposeFlag();
// assert that extra data record is not present
assertThat(BitUtils.isBitSet(generalPurposeBytes[1], 3)).isTrue();
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(koreanFileName);
}
@Test
public void testAddStreamToZipWithAesEncryptionForNewZipAddsSuccessfully() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("бореиская.txt");
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1);
verifyZipFileContainsFiles(generatedZipFile, singletonList("бореиская.txt"), CompressionMethod.DEFLATE,
EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
verifyLocalFileHeaderUncompressedSize(generatedZipFile, "бореиская.txt", 0);
}
@Test
public void testAddStreamToZipWithoutEncryptionForExistingZipAddsSuccessfully() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("가나다.abc");
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 4);
verifyFileIsOf(generatedZipFile, "가나다.abc", CompressionMethod.DEFLATE, EncryptionMethod.NONE, null, null);
}
@Test
public void testAddStreamToZipWithAesEncryptionV2ForExistingZipAddsSuccessfully() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("가나다.abc");
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 4);
verifyFileIsOf(generatedZipFile, "가나다.abc", CompressionMethod.DEFLATE, EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_128, AesVersion.TWO);
}
@Test
public void testAddStreamToZipWithAesEncryptionV1ForExistingZipAddsSuccessfully() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("가나다.abc");
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setAesVersion(AesVersion.ONE);
zipParameters.setFileNameInZip(fileToAdd.getName());
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD);
InputStream inputStream = new FileInputStream(fileToAdd);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 4);
verifyFileIsOf(generatedZipFile, "가나다.abc", CompressionMethod.DEFLATE, EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_256, AesVersion.ONE);
}
@Test
public void testAddStreamToZipWithCharsetCp949() throws IOException {
String koreanFileName = "가나다.abc";
ZipFile zipFile = new ZipFile(generatedZipFile);
File fileToAdd = TestUtils.getTestFileFromResources(koreanFileName);
InputStream inputStream = new FileInputStream(fileToAdd);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(fileToAdd.getName());
zipFile.setCharset(CHARSET_CP_949);
zipFile.addStream(inputStream, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, true, CHARSET_CP_949);
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(koreanFileName);
}
@Test
public void testAddStreamToZipWithSameEntryNameRemovesOldEntry() throws IOException {
File fileToAdd = TestUtils.getTestFileFromResources("sample.pdf");
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(fileToAdd);
try(InputStream inputStream = new FileInputStream(fileToAdd)) {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip("sample.pdf");
zipFile.addStream(inputStream, zipParameters);
}
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
}
@Test
public void testAddStreamWithStoreCompressionAndAesEncryptionWorksFine() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
File fileToAdd = TestUtils.getTestFileFromResources("sample.pdf");
try(InputStream inputStream = new FileInputStream(fileToAdd)) {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setEncryptFiles(true);
zipParameters.setFileNameInZip(fileToAdd.getName());
zipFile.addStream(inputStream, zipParameters);
}
extractZipFileWithStream(generatedZipFile, PASSWORD);
}
@Test
public void testAddFolderWithCustomBufferSize() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.setBufferSize(16 * 1024);
zipFile.addFolder(TestUtils.getTestFileFromResources(""));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 13);
}
private void verifyZipFileContainsFiles(File generatedZipFile, List fileNames,
CompressionMethod compressionMethod, EncryptionMethod encryptionMethod,
AesKeyStrength aesKeyStrength) throws ZipException {
verifyZipFileContainsFiles(generatedZipFile, fileNames, compressionMethod, encryptionMethod, aesKeyStrength,
AesVersion.TWO);
}
private void verifyZipFileContainsFiles(File generatedZipFile, List fileNames,
CompressionMethod compressionMethod, EncryptionMethod encryptionMethod,
AesKeyStrength aesKeyStrength, AesVersion aesVersion) throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List fileHeaders = zipFile.getFileHeaders();
verifyFileHeadersContainsFiles(fileHeaders, fileNames);
verifyAllFilesAreOf(fileHeaders, compressionMethod, encryptionMethod, aesKeyStrength, aesVersion);
}
private void verifyZipFileDoesNotContainFiles(File generatedZipFile, List fileNamesNotInZip) throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
for (FileHeader fileHeader : zipFile.getFileHeaders()) {
for (String fileNameNotInZip : fileNamesNotInZip) {
assertThat(fileHeader.getFileName())
.withFailMessage("Expected file " + fileNameNotInZip + " to not be present in zip file")
.isNotEqualTo(fileNameNotInZip);
}
}
}
private void verifyFoldersInZip(List fileHeaders, File generatedZipFile, char[] password)
throws IOException {
verifyFoldersInFileHeaders(fileHeaders);
verifyFoldersInLocalFileHeaders(generatedZipFile, password);
}
private void verifyFoldersInFileHeaders(List fileHeaders) {
for (FileHeader fileHeader : fileHeaders){
if (fileHeader.isDirectory()) {
verifyFolderEntryInZip(fileHeader);
}
}
}
private void verifyFoldersInLocalFileHeaders(File generatedZipFile, char[] password) throws IOException {
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(generatedZipFile), password)) {
LocalFileHeader localFileHeader;
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
if (localFileHeader.isDirectory()) {
verifyFolderEntryInZip(localFileHeader);
}
}
}
}
private void verifyFolderEntryInZip(AbstractFileHeader fileHeader) {
assertThat(fileHeader.getCrc()).isZero();
assertThat(fileHeader.getCompressedSize()).isZero();
assertThat(fileHeader.getUncompressedSize()).isZero();
assertThat(fileHeader.getCompressionMethod()).isEqualTo(CompressionMethod.STORE);
assertThat(fileHeader.getEncryptionMethod()).isEqualTo(EncryptionMethod.NONE);
}
private void verifyAllFilesInZipContainsPath(List fileHeaders, String pathToBeChecked) {
for (FileHeader fileHeader : fileHeaders) {
assertThat(fileHeader.getFileName()).startsWith(pathToBeChecked);
}
}
private void verifyAllFilesInZipDoesNotContainPath(List fileHeaders, String pathToBeChecked) {
for (FileHeader fileHeader : fileHeaders) {
assertThat(fileHeader.getFileName()).doesNotStartWith(pathToBeChecked);
}
}
private void verifyAllFilesAreOf(List fileHeaders, CompressionMethod compressionMethod,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength,
AesVersion aesVersion) {
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.isDirectory()) {
assertThat(fileHeader.getCompressionMethod()).isEqualTo(CompressionMethod.STORE);
assertThat(fileHeader.isEncrypted()).isFalse();
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
assertThat(fileHeader.getCrc()).isZero();
} else {
CompressionMethod shouldBeCompressionMethod = getShouldBeCompressionMethod(
encryptionMethod == EncryptionMethod.AES, compressionMethod, fileHeader.getUncompressedSize());
assertThat(fileHeader.getCompressionMethod()).isEqualTo(shouldBeCompressionMethod);
if (encryptionMethod == null) {
assertThat(fileHeader.getEncryptionMethod()).isEqualTo(EncryptionMethod.NONE);
} else {
assertThat(fileHeader.getEncryptionMethod()).isEqualTo(encryptionMethod);
}
if (encryptionMethod == EncryptionMethod.AES) {
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), aesKeyStrength, aesVersion);
if (fileHeader.getAesExtraDataRecord().getAesVersion().equals(AesVersion.TWO)) {
assertThat(fileHeader.getCrc()).isZero();
} else {
if (fileHeader.getCompressedSize() != 0) {
assertThat(fileHeader.getCrc()).isNotZero();
}
}
} else {
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
}
}
}
}
private void verifyFileIsOf(File generatedZipFile, String fileName, CompressionMethod compressionMethod,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength, AesVersion aesVersion)
throws ZipException {
List fileHeaders = getFileHeaders(generatedZipFile);
FileHeader fileHeader = getFileHeaderFrom(fileHeaders, fileName);
if (encryptionMethod == null || encryptionMethod == EncryptionMethod.NONE) {
assertThat(fileHeader.isEncrypted()).isFalse();
assertThat(fileHeader.getEncryptionMethod()).isIn(null, EncryptionMethod.NONE);
} else {
verifyAllFilesAreOf(singletonList(fileHeader), compressionMethod, encryptionMethod, aesKeyStrength, aesVersion);
}
}
private FileHeader getFileHeaderFrom(List fileHeaders, String fileName) {
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.getFileName().equals(fileName)) {
return fileHeader;
}
}
fail("Could not find a file header by filename: " + fileName);
return null;
}
private List getFileHeaders(File generatedZipFile) throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List fileHeaders = zipFile.getFileHeaders();
assertThat(fileHeaders.size()).isNotZero();
return fileHeaders;
}
private void verifyAesExtraDataRecord(AESExtraDataRecord aesExtraDataRecord, AesKeyStrength aesKeyStrength,
AesVersion aesVersion) {
assertThat(aesExtraDataRecord).isNotNull();
assertThat(aesExtraDataRecord.getAesKeyStrength()).isEqualTo(aesKeyStrength);
assertThat(aesExtraDataRecord.getAesVersion()).isEqualTo(aesVersion);
}
private CompressionMethod getShouldBeCompressionMethod(boolean isAesEncrypted, CompressionMethod compressionMethod,
long uncompressedSize) {
if (isAesEncrypted) {
return CompressionMethod.AES_INTERNAL_ONLY;
}
if (uncompressedSize == 0) {
return CompressionMethod.STORE;
}
return compressionMethod;
}
private void verifyZipVersions(FileHeader fileHeader, ZipParameters zipParameters) {
int versionMadeBy = ZipVersionUtils.determineVersionMadeBy(zipParameters, rawIO);
int versionNeededToExtract = ZipVersionUtils.determineVersionNeededToExtract(zipParameters).getCode();
assertThat(fileHeader.getVersionMadeBy()).isEqualTo(versionMadeBy);
assertThat(fileHeader.getVersionNeededToExtract()).isEqualTo(versionNeededToExtract);
}
@SuppressWarnings("StatementWithEmptyBody")
private void extractZipFileWithStream(File zipFileToExtract, char[] password) throws IOException {
byte[] readBuff = new byte[InternalZipConstants.BUFF_SIZE];
try (ZipInputStream inputStream = new ZipInputStream(new FileInputStream(zipFileToExtract), password)) {
while ((inputStream.getNextEntry()) != null) {
while (inputStream.read(readBuff) != -1) {
}
}
}
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/CreateZipFileIT.java 0000664 0000000 0000000 00000073536 14142654472 0024324 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import org.assertj.core.data.Offset;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import static net.lingala.zip4j.testutils.TestUtils.createSymlink;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static net.lingala.zip4j.testutils.ZipFileVerifier.verifyZipFileByExtractingAllFiles;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
/**
* Contains Integration tests for create operations of ZipFile
*/
public class CreateZipFileIT extends AbstractIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testCreateSplitZipFileNotSplitArchiveWithZipNameAsString() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile.getPath());
zipFile.createSplitZipFile(FILES_TO_ADD, new ZipParameters(), false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size());
}
@Test
public void testCreateSplitZipFileNotSplitArchiveWithZipNameAsStringAndCharsetCp949() throws IOException {
String koreanFileName = "가나다.abc";
ZipFile zipFile = new ZipFile(generatedZipFile.getPath());
List filesToAdd = new ArrayList<>();
filesToAdd.add(getTestFileFromResources(koreanFileName));
zipFile.setCharset(CHARSET_CP_949);
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, filesToAdd.size(), true, CHARSET_CP_949);
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(koreanFileName);
}
@Test
public void testCreateSplitZipFileNotSplitArchiveWithZipNameAsStringWithAESEncryption256() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile.getPath(), PASSWORD);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
verifyFileHeadersEncrypted(zipFile.getFileHeaders(), EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256,
CompressionMethod.DEFLATE);
}
@Test
public void testCreateSplitZipFileNotSplitArchiveWithZipNameAsStringWithAESEncryption128() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile.getPath(), PASSWORD);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
verifyFileHeadersEncrypted(zipFile.getFileHeaders(), EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128,
CompressionMethod.DEFLATE);
}
@Test
public void testCreateSplitZipFileNotSplitArchiveWithFile() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(FILES_TO_ADD, new ZipParameters(), false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size());
}
@Test
public void testCreateSplitZipFileNotSplitArchiveWithFileAndWithAESEncryption256() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile.getPath(), PASSWORD);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
verifyFileHeadersEncrypted(zipFile.getFileHeaders(), EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256,
CompressionMethod.DEFLATE);
}
@Test
public void testCreateSplitZipFileNotSplitArchiveWithFileAndWithAESEncryption128() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile.getPath(), PASSWORD);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
verifyFileHeadersEncrypted(zipFile.getFileHeaders(), EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128,
CompressionMethod.DEFLATE);
}
@Test
public void testCreateSplitZipFileNotSplitArchiveWithFileAndWithStandardEncryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD,
AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile.getPath(), PASSWORD);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, false, -1);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
verifyFileHeadersEncrypted(zipFile.getFileHeaders(), EncryptionMethod.ZIP_STANDARD, AesKeyStrength.KEY_STRENGTH_128,
CompressionMethod.DEFLATE);
}
@Test
public void testCreateSplitZipFileThrowsExceptionWhenSplitSizeLessThanMinimumAllowed() throws ZipException {
expectedException.expectMessage("split length less than minimum allowed split length of "
+ InternalZipConstants.MIN_SPLIT_LENGTH + " Bytes");
expectedException.expect(ZipException.class);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(FILES_TO_ADD, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH - 1);
}
@Test
public void testCreateSplitZipFileStoreAndWithoutEncryption() throws IOException {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH);
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size());
verifySplitZip(generatedZipFile, 2, InternalZipConstants.MIN_SPLIT_LENGTH);
}
@Test
public void testCreateSplitZipFileStoreAndStandardZipEncryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH);
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
verifySplitZip(generatedZipFile, 2, InternalZipConstants.MIN_SPLIT_LENGTH);
}
@Test
public void testCreateSplitZipFileStoreAndWithAesEncryptionKeyStrength256() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.createSplitZipFile(FILES_TO_ADD, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH);
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
verifySplitZip(generatedZipFile, 2, InternalZipConstants.MIN_SPLIT_LENGTH);
}
@Test
public void testCreateSplitZipFileStoreAndWithAesEncryptionKeyStrength128() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_128);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH);
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size() + 1);
verifySplitZip(generatedZipFile, 18, InternalZipConstants.MIN_SPLIT_LENGTH);
}
@Test
public void testCreateSplitZipFileDeflateAndWithoutEncryption() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, 716800);
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size() + 1);
verifySplitZip(generatedZipFile, 2, InternalZipConstants.MIN_SPLIT_LENGTH);
}
@Test
public void testCreateSplitZipFileDeflateAndStandardZipEncryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.DEFLATE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, 512000);
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size() + 1);
verifySplitZip(generatedZipFile, 2, InternalZipConstants.MIN_SPLIT_LENGTH);
}
@Test
public void testCreateSplitZipFileDeflateAndWithAesEncryptionKeyStrength256() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH);
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size() + 1);
verifySplitZip(generatedZipFile, 15, InternalZipConstants.MIN_SPLIT_LENGTH);
}
@Test
public void testCreateSplitZipFileDeflateAndWithAesEncryptionKeyStrength128() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES,
AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH + 2000);
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size() + 1);
verifySplitZip(generatedZipFile, 15, InternalZipConstants.MIN_SPLIT_LENGTH + 2000);
}
@Test
public void testCreateZipFileWithSetPasswordSetter() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile, "WRONG_PASSWORD".toCharArray());
zipFile.setPassword(PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size());
}
@Test
public void testAddFileWithFileEntryCommentAndUtf8Charset() throws IOException {
testCreateZipFileWithFileEntryComment("FILE_COMMET_", StandardCharsets.UTF_8);
}
@Test
public void testAddFileWithFileEntryCommentAndNullCharsetUsesUtf8() throws IOException {
testCreateZipFileWithFileEntryComment("FILE_COMMET_", null);
}
@Test
public void testAddFileWithFileEntryCommentAndGBKCharset() throws IOException {
testCreateZipFileWithFileEntryComment("测试中文_", Charset.forName("GBK"));
}
@Test
public void testAddingSameFileMultipleTimesResultsInOnlyOneFileInZip() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip("renamed-file.pdf");
zipFile.addFile(getTestFileFromResources("sample.pdf"), zipParameters);
zipFile.addFile(getTestFileFromResources("sample.pdf"), zipParameters);
zipFile.addFile(getTestFileFromResources("sample.pdf"), zipParameters);
assertThat(zipFile.getFileHeaders()).hasSize(1);
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo("renamed-file.pdf");
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, false);
}
@Test
public void testAddSymlinkWithLinkOnly() throws IOException {
File targetFile = getTestFileFromResources("sample.pdf");
File symlink = createSymlink(targetFile, temporaryFolder.getRoot());
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
zipFile.addFile(symlink, zipParameters);
assertThat(zipFile.getFileHeaders()).hasSize(1);
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(symlink.getName());
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, false);
verifyGeneratedSymlink(symlink, targetFile);
}
@Test
public void testAddSymlinkWithLinkedFileOnly() throws IOException {
File targetFile = getTestFileFromResources("sample.pdf");
File symlink = createSymlink(targetFile, temporaryFolder.getRoot());
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY);
zipFile.addFile(symlink, zipParameters);
assertThat(zipFile.getFileHeaders()).hasSize(1);
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(targetFile.getName());
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
}
@Test
public void testAddSymlinkWithLinkAndLinkedFile() throws IOException {
File targetFile = getTestFileFromResources("sample.pdf");
File symlink = createSymlink(targetFile, temporaryFolder.getRoot());
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE);
zipFile.addFile(symlink, zipParameters);
List fileHeaders = zipFile.getFileHeaders();
assertThat(fileHeaders).hasSize(2);
assertThat(fileHeaders.get(0).getFileName()).isEqualTo(symlink.getName());
assertThat(fileHeaders.get(1).getFileName()).isEqualTo(targetFile.getName());
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 2, false);
verifyGeneratedSymlink(symlink, targetFile);
File generatedTargetFile = Paths.get(outputFolder.getAbsolutePath(), targetFile.getName()).toFile();
ZipFileVerifier.verifyFileCrc(targetFile, generatedTargetFile);
}
@Test
public void testAddSymlinksInAFolderWithLinkOnly() throws IOException {
File testFolder = createTestFolderWithSymlinks();
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
zipFile.addFolder(testFolder, zipParameters);
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
verifyFileNamesInZip(zipFile,
"test-folder/",
"test-folder/symlink.link",
"test-folder/sub-folder1/",
"test-folder/sub-folder1/symlink.link",
"test-folder/sub-folder2/",
"test-folder/sub-folder2/symlink.link");
}
@Test
public void testAddSymlinksInAFolderWithLinkedFilesOnly() throws IOException {
File testFolder = createTestFolderWithSymlinks();
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY);
zipFile.addFolder(testFolder, zipParameters);
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
verifyFileNamesInZip(zipFile,
"test-folder/",
"test-folder/sample.pdf",
"test-folder/sub-folder1/",
"test-folder/sub-folder1/file_PDF_1MB.pdf",
"test-folder/sub-folder2/",
"test-folder/sub-folder2/sample_text_large.txt");
}
@Test
public void testAddSymlinksInAFolderWithLinkAndLinkedFilesOnly() throws IOException {
File testFolder = createTestFolderWithSymlinks();
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE);
zipFile.addFolder(testFolder, zipParameters);
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 9, false);
verifyFileNamesInZip(zipFile,
"test-folder/",
"test-folder/symlink.link",
"test-folder/sample.pdf",
"test-folder/sub-folder1/",
"test-folder/sub-folder1/symlink.link",
"test-folder/sub-folder1/file_PDF_1MB.pdf",
"test-folder/sub-folder2/",
"test-folder/sub-folder2/sample_text_large.txt",
"test-folder/sub-folder2/symlink.link");
}
@Test
public void testAddSymlinksInAFolderWithLinkAndLinkedFilesOnlyWithoutRootFolder() throws IOException {
File testFolder = createTestFolderWithSymlinks();
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setIncludeRootFolder(false);
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE);
zipFile.addFolder(testFolder, zipParameters);
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 8, false);
verifyFileNamesInZip(zipFile,
"symlink.link",
"sample.pdf",
"sub-folder1/",
"sub-folder1/symlink.link",
"sub-folder1/file_PDF_1MB.pdf",
"sub-folder2/",
"sub-folder2/sample_text_large.txt",
"sub-folder2/symlink.link");
}
@Test
public void testAddSymlinkWithLinkOnlyMissingTarget() throws IOException {
File targetFile = Paths.get(temporaryFolder.getRoot().getAbsolutePath(), "foo").toFile();
File symlink = createSymlink(targetFile, temporaryFolder.getRoot());
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
zipFile.addFile(symlink, zipParameters);
assertThat(zipFile.getFileHeaders()).hasSize(1);
assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(symlink.getName());
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, false);
verifyGeneratedSymlink(symlink, targetFile);
}
@Test
public void testAddSymlinkWithLinkedFileOnlyMissingTargetThrowsException() throws IOException {
testAddSymlinkThrowsExceptionForMissingTarget(ZipParameters.SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY);
}
@Test
public void testAddSymlinkWithLinkAndLinkedFileMissingTargetThrowsException() throws IOException {
testAddSymlinkThrowsExceptionForMissingTarget(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE);
}
@Test
public void testAddSymlinksInAFolderWithLinkOnlyMissingTarget() throws IOException {
Path testFolderPath = temporaryFolder.newFolder("test-folder").toPath();
Path subFolder1 = Files.createDirectory(Paths.get(testFolderPath.toString(), "sub-folder1"));
Path subFolder2 = Files.createDirectory(Paths.get(testFolderPath.toString(), "sub-folder2"));
File targetFile = Paths.get(temporaryFolder.getRoot().getAbsolutePath(), "foo").toFile();
createSymlink(targetFile, testFolderPath.toFile());
createSymlink(getTestFileFromResources("file_PDF_1MB.pdf"), subFolder1.toFile());
createSymlink(getTestFileFromResources("sample_text_large.txt"), subFolder2.toFile());
File testFolder = testFolderPath.toFile();
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
zipFile.addFolder(testFolder, zipParameters);
verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
verifyFileNamesInZip(zipFile,
"test-folder/",
"test-folder/symlink.link",
"test-folder/sub-folder1/",
"test-folder/sub-folder1/symlink.link",
"test-folder/sub-folder2/",
"test-folder/sub-folder2/symlink.link");
}
@Test
public void testEncryptWithZipStrongEncryptionThrowsException() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD_VARIANT_STRONG);
zipParameters.setEncryptFiles(true);
expectedException.expect(ZipException.class);
expectedException.expectMessage("ZIP_STANDARD_VARIANT_STRONG encryption method is not supported");
zipFile.addFiles(FILES_TO_ADD, zipParameters);
}
@Test
public void testCreateZipFileWithFasterCompressionLevel() throws IOException {
createZipFileWithCompressionLevel(CompressionLevel.FASTER);
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 3);
}
@Test
public void testCreateZipFileWithMediumFastCompressionLevel() throws IOException {
createZipFileWithCompressionLevel(CompressionLevel.MEDIUM_FAST);
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 3);
}
@Test
public void testCreateZipFileWithHigherCompressionLevel() throws IOException {
createZipFileWithCompressionLevel(CompressionLevel.HIGHER);
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 3);
}
@Test
public void testCreateZipFileWithPreUltraCompressionLevel() throws IOException {
createZipFileWithCompressionLevel(CompressionLevel.PRE_ULTRA);
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 3);
}
private void testAddSymlinkThrowsExceptionForMissingTarget(ZipParameters.SymbolicLinkAction symbolicLinkAction)
throws IOException {
File targetFile = Paths.get(temporaryFolder.getRoot().getAbsolutePath(), "foo").toFile();
File symlink = createSymlink(targetFile, temporaryFolder.getRoot());
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(symbolicLinkAction);
expectedException.expect(ZipException.class);
expectedException.expectMessage("Symlink target '" + targetFile + "' does not exist for link '" + symlink + "'");
zipFile.addFile(symlink, zipParameters);
}
private void testCreateZipFileWithFileEntryComment(String fileCommentPrefix, Charset charset) throws IOException {
ZipParameters zipParameters = new ZipParameters();
ZipFile zipFile = initializeZipFileWithCharset(charset);
for (int i = 0; i < FILES_TO_ADD.size(); i++) {
if (i == 0) {
zipParameters.setFileComment(fileCommentPrefix + i);
} else {
zipParameters.setFileComment(null);
}
zipFile.addFile(FILES_TO_ADD.get(i), zipParameters);
}
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size());
verifyFileEntryComment(fileCommentPrefix, charset);
}
private void verifySplitZip(File zipFile, int numberOfExpectedSplitFiles, long splitLength) throws ZipException {
assertNumberOfSplitFile(zipFile, numberOfExpectedSplitFiles);
assertSplitFileSizes(zipFile, numberOfExpectedSplitFiles, splitLength);
}
private void assertSplitFileSizes(File zipFile, int numberOfExpectedSplitFiles, long splitLength) {
for (int i = 0; i < numberOfExpectedSplitFiles - 2; i++) {
String zipExtension = ".z0";
if (i >= 9) {
zipExtension = ".z";
}
String fileNameWithoutExtension = zipFile.getPath().substring(0, zipFile.getPath().lastIndexOf(".zip"));
File splitZip = new File(fileNameWithoutExtension + zipExtension + (i + 1));
assertThat(splitZip).exists();
assertThat(splitZip.length()).isCloseTo(splitLength, Offset.offset(1000L));
}
}
private void assertNumberOfSplitFile(File zipFile, int numberOfExpectedSplitFiles) throws ZipException {
File[] allSplitFiles = getAllSplitZipFilesInFolder(zipFile.getParentFile(),
FileUtils.getZipFileNameWithoutExtension(zipFile.getName()));
assertThat(allSplitFiles.length).as("Number of split files").isEqualTo(numberOfExpectedSplitFiles);
}
private void verifyFileHeadersEncrypted(List fileHeaders, EncryptionMethod encryptionMethod,
AesKeyStrength aesKeyStrength, CompressionMethod compressionMethod) {
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.isDirectory()) {
assertThat(fileHeader.isEncrypted()).isFalse();
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
} else {
assertThat(fileHeader.isEncrypted()).isTrue();
assertThat(fileHeader.getEncryptionMethod()).isEqualTo(encryptionMethod);
if (encryptionMethod == EncryptionMethod.AES) {
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), compressionMethod, aesKeyStrength);
} else {
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
}
}
}
}
private void verifyAesExtraDataRecord(AESExtraDataRecord aesExtraDataRecord, CompressionMethod compressionMethod,
AesKeyStrength aesKeyStrength) {
assertThat(aesExtraDataRecord).isNotNull();
assertThat(aesExtraDataRecord.getCompressionMethod()).isEqualTo(compressionMethod);
assertThat(aesExtraDataRecord.getAesKeyStrength()).isEqualTo(aesKeyStrength);
}
private File[] getAllSplitZipFilesInFolder(File folder, final String fileNameWithoutExtension) {
FilenameFilter filenameFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.contains(fileNameWithoutExtension + ".");
}
};
return folder.listFiles(filenameFilter);
}
private void verifyFileEntryComment(String commentPrefix, Charset charset) throws IOException {
ZipFile zipFile = initializeZipFileWithCharset(charset);
List fileHeaders = zipFile.getFileHeaders();
for (int i = 0; i < fileHeaders.size(); i++) {
FileHeader fileHeader = fileHeaders.get(i);
if (i == 0) {
assertThat(fileHeader.getFileComment()).isEqualTo(commentPrefix + i);
} else {
assertThat(fileHeader.getFileComment()).isNull();
}
}
}
private ZipFile initializeZipFileWithCharset(Charset charset) {
ZipFile zipFile = new ZipFile(generatedZipFile);
if (charset != null) {
zipFile.setCharset(charset);
}
return zipFile;
}
private void verifyGeneratedSymlink(File actualSymlink, File targetFile) throws IOException {
File extractedSymlink = Paths.get(outputFolder.getAbsolutePath(), actualSymlink.getName()).toFile();
assertThat(Files.isSymbolicLink(extractedSymlink.toPath())).isTrue();
assertThat(actualSymlink.length()).isEqualTo(extractedSymlink.length());
File generatedTarget = Files.readSymbolicLink(extractedSymlink.toPath()).toFile();
assertThat(generatedTarget).isEqualTo(targetFile);
}
private File createTestFolderWithSymlinks() throws IOException {
Path testFolder = temporaryFolder.newFolder("test-folder").toPath();
Path subFolder1 = Files.createDirectory(Paths.get(testFolder.toString(), "sub-folder1"));
Path subFolder2 = Files.createDirectory(Paths.get(testFolder.toString(), "sub-folder2"));
createSymlink(getTestFileFromResources("sample.pdf"), testFolder.toFile());
createSymlink(getTestFileFromResources("file_PDF_1MB.pdf"), subFolder1.toFile());
createSymlink(getTestFileFromResources("sample_text_large.txt"), subFolder2.toFile());
return testFolder.toFile();
}
private void verifyFileNamesInZip(ZipFile zipFile, String... fileNames) throws ZipException {
List fileHeaders = zipFile.getFileHeaders();
for (String fileName : fileNames) {
boolean entryFound = false;
for (FileHeader fileHeader : fileHeaders) {
if (fileHeader.getFileName().equals(fileName)) {
entryFound = true;
break;
}
}
if (!entryFound) {
fail("Could not find entry: " + fileName + " in zip");
}
}
}
private ZipFile createZipFileWithCompressionLevel(CompressionLevel compressionLevel) throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionLevel(compressionLevel);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
return zipFile;
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/ExtractZipFileIT.java 0000664 0000000 0000000 00000103714 14142654472 0024523 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.lingala.zip4j.testutils.TestUtils.getFileNamesOfFiles;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static net.lingala.zip4j.testutils.ZipFileVerifier.verifyZipFileByExtractingAllFiles;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class ExtractZipFileIT extends AbstractIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testExtractAllStoreAndNoEncryptionExtractsSuccessfully() throws IOException {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllStoreAndZipStandardEncryptionExtractsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllStoreAndAes128EncryptionExtractsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllStoreAndAes256EncryptionExtractsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllDeflateAndNoEncryptionExtractsSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllDeflateAndZipStandardEncryptionExtractsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllDeflateAndAes128EncryptionExtractsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllDeflateAndAes256EncryptionExtractsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 3);
}
@Test
public void testExtractAllSkipsSymlinksWhenSymlinkExtractionSetToFalse() throws IOException {
ZipFile zipFile = createZipFileWithASymlink(createSymlink());
zipFile.extractAll(outputFolder.getPath(), buildUnzipParameters(false));
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 4);
}
@Test
public void testExtractAllExtractsSymlinksWhenSymlinkExtractionSetToTrue() throws IOException {
ZipFile zipFile = createZipFileWithASymlink(createSymlink());
zipFile.extractAll(outputFolder.getPath(), buildUnzipParameters(true));
verifyNumberOfFilesInOutputFolder(outputFolder, 5);
}
@Test
public void testExtractFileWithFileHeaderWithAes128() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
FileHeader fileHeader = zipFile.getFileHeader("sample_text_large.txt");
zipFile.extractFile(fileHeader, outputFolder.getPath());
File[] outputFiles = outputFolder.listFiles();
assertThat(outputFiles).hasSize(1);
ZipFileVerifier.verifyFileContent(getTestFileFromResources("sample_text_large.txt"), outputFiles[0]);
}
@Test
public void testExtractFileWithFileHeaderWithAes128AndInDirectory() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(getTestFileFromResources(""), zipParameters);
FileHeader fileHeader = zipFile.getFileHeader("test-files/öüäöäö/asöäööl");
zipFile.extractFile(fileHeader, outputFolder.getPath());
File outputFile = getFileWithNameFrom(outputFolder, "asöäööl");
ZipFileVerifier.verifyFileContent(getTestFileFromResources("öüäöäö/asöäööl"), outputFile);
}
@Test
public void testExtractFileWithFileHeaderWithAes256AndWithANewFileName() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
String newFileName = "newFileName";
FileHeader fileHeader = zipFile.getFileHeader("sample_text_large.txt");
zipFile.extractFile(fileHeader, outputFolder.getPath(), newFileName);
File outputFile = getFileWithNameFrom(outputFolder, newFileName);
ZipFileVerifier.verifyFileContent(getTestFileFromResources("sample_text_large.txt"), outputFile);
}
@Test
public void testExtractFileWithFileHeaderDoesNotExtractSymlinkWhenSymlinkExtractionIsNotSet() throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
FileHeader fileHeader = zipFile.getFileHeader(symlink.getName());
zipFile.extractFile(fileHeader, outputFolder.getPath(), buildUnzipParameters(false));
assertThat(outputFolder.listFiles()).isNull();
}
@Test
public void testExtractFileWithFileHeaderExtractsSymlinkWhenSymlinkExtractionIsSet() throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
FileHeader fileHeader = zipFile.getFileHeader(symlink.getName());
zipFile.extractFile(fileHeader, outputFolder.getPath(), buildUnzipParameters(true));
verifyNumberOfFilesInOutputFolder(outputFolder, 1);
assertThat(outputFolder.listFiles()[0].getName()).isEqualTo(symlink.getName());
}
@Test
public void testExtractFileWithFileHeaderAndNewFileDoesNotExtractSymlinkWhenSymlinkExtractionIsNotSet()
throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
FileHeader fileHeader = zipFile.getFileHeader(symlink.getName());
zipFile.extractFile(fileHeader, outputFolder.getPath(), "newFileName", buildUnzipParameters(false));
assertThat(outputFolder.listFiles()).isNull();
}
@Test
public void testExtractFileWithFileHeaderAndNewFileNameExtractsSymlinkWhenSymlinkExtractionIsSet()
throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
FileHeader fileHeader = zipFile.getFileHeader(symlink.getName());
String newFileName = "newName.link";
zipFile.extractFile(fileHeader, outputFolder.getPath(), newFileName, buildUnzipParameters(true));
verifyNumberOfFilesInOutputFolder(outputFolder, 1);
assertThat(outputFolder.listFiles()[0].getName()).isEqualTo(newFileName);
}
@Test
public void testExtractFileWithFileNameThrowsExceptionWhenFileNotFound() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD);
try {
zipFile.extractFile("NOT_EXISTING", outputFolder.getPath());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e).isNotNull();
assertThat(e.getType()).isEqualTo(ZipException.Type.FILE_NOT_FOUND);
assertThat(e.getMessage()).isEqualTo("No file found with name NOT_EXISTING in zip file");
}
}
@Test
public void testExtractFileWithFileNameWithZipStandardEncryption() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(getTestFileFromResources(""), zipParameters);
zipFile.extractFile("test-files/sample_directory/favicon.ico", outputFolder.getPath());
File outputFile = getFileWithNameFrom(outputFolder, "favicon.ico");
ZipFileVerifier.verifyFileContent(getTestFileFromResources("sample_directory/favicon.ico"), outputFile);
}
@Test
public void testExtractFileWithFileNameWithZipStandardEncryptionAndNewFileName() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(getTestFileFromResources(""), zipParameters);
String newFileName = "newFileName";
zipFile.extractFile("test-files/sample_directory/favicon.ico", outputFolder.getPath(), newFileName);
File outputFile = getFileWithNameFrom(outputFolder, newFileName);
ZipFileVerifier.verifyFileContent(getTestFileFromResources("sample_directory/favicon.ico"), outputFile);
}
@Test
public void testExtractFileWithFileNameDoesNotExtractSymlinkWhenSymlinkExtractionIsNotSet() throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
zipFile.extractFile(symlink.getName(), outputFolder.getPath(), buildUnzipParameters(false));
assertThat(outputFolder.listFiles()).isNull();
}
@Test
public void testExtractFileWithFileNameExtractsSymlinkWhenSymlinkExtractionIsSet() throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
zipFile.extractFile(symlink.getName(), outputFolder.getPath(), buildUnzipParameters(true));
verifyNumberOfFilesInOutputFolder(outputFolder, 1);
assertThat(outputFolder.listFiles()[0].getName()).isEqualTo(symlink.getName());
}
@Test
public void testExtractFileWithFileNameAndNewFileNameDoesNotExtractSymlinkWhenSymlinkExtractionIsNotSet()
throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
zipFile.extractFile(symlink.getName(), outputFolder.getPath(), "newFileName", buildUnzipParameters(false));
assertThat(outputFolder.listFiles()).isNull();
}
@Test
public void testExtractFileWithFileNameAndNewFileNameExtractsSymlinkWhenSymlinkExtractionIsSet() throws IOException {
File symlink = createSymlink();
ZipFile zipFile = createZipFileWithASymlink(symlink);
String newFileName = "newName.link";
zipFile.extractFile(symlink.getName(), outputFolder.getPath(), newFileName, buildUnzipParameters(true));
verifyNumberOfFilesInOutputFolder(outputFolder, 1);
assertThat(outputFolder.listFiles()[0].getName()).isEqualTo(newFileName);
}
@Test
public void testExtractFilesThrowsExceptionForWrongPasswordForAes() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
try {
zipFile = new ZipFile(generatedZipFile, "WRONG_PASSWORD".toCharArray());
zipFile.extractAll(outputFolder.getPath());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e).isNotNull();
assertThat(e.getType()).isEqualTo(ZipException.Type.WRONG_PASSWORD);
}
}
@Test
public void testExtractFilesThrowsExceptionForWrongPasswordForZipStandardAndDeflate() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
try {
zipFile = new ZipFile(generatedZipFile, "WRONG_PASSWORD".toCharArray());
zipFile.extractAll(outputFolder.getPath());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e).isNotNull();
assertThat(e.getType()).isEqualTo(ZipException.Type.WRONG_PASSWORD);
}
}
@Test
public void testExtractFilesThrowsExceptionForWrongPasswordForZipStandardAndStore() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
try {
zipFile = new ZipFile(generatedZipFile, "WRONG_PASSWORD".toCharArray());
zipFile.extractAll(outputFolder.getPath());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e).isNotNull();
assertThat(e.getType()).isEqualTo(ZipException.Type.WRONG_PASSWORD);
}
}
@Test
public void testExtractFilesForAZipMadeWithZip4jv1AndStoreCompressionWithAES() throws IOException {
File zipArchiveToTest = getTestArchiveFromResources("store_compression_made_with_v1.3.3.zip");
verifyZipFileByExtractingAllFiles(zipArchiveToTest, "aaaaaaaa".toCharArray(), outputFolder, 5,
false);
}
@Test
public void testExtractFilesForZipFileWhileWithCorruptExtraDataRecordLength() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("corrupt_extra_data_record_length.zip"));
zipFile.extractAll(outputFolder.getPath());
assertThat(zipFile.getFileHeaders()).hasSize(44);
assertThat(getRegularFilesFromFolder(outputFolder)).hasSize(44);
}
@Test
public void testExtractFilesWithSetPasswordSetter() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile = new ZipFile(generatedZipFile, "WRONG_PASSWORD".toCharArray());
zipFile.setPassword(PASSWORD);
zipFile.extractAll(outputFolder.getCanonicalPath());
}
@Test
public void testExtractZipFileWithMissingExtendedLocalFileHeader() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("missing_exended_local_file_header.zip"));
zipFile.extractAll(outputFolder.getPath());
assertThat(zipFile.getFileHeaders()).hasSize(3);
assertThat(getRegularFilesFromFolder(outputFolder)).hasSize(3);
}
@Test
public void testExtractZipFileWithZip64ExtraDataRecordWithOnlyFileSizesInIt() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("zip64_with_only_file_sizes.zip"),
"Shu1an@2019GTS".toCharArray());
zipFile.extractAll(outputFolder.getPath());
assertThat(zipFile.getFileHeaders()).hasSize(1);
assertThat(getRegularFilesFromFolder(outputFolder)).hasSize(1);
}
@Test
public void testExtractZipFileWithChineseCharsetGBK() throws IOException {
String expectedFileName = "fff - 副本.txt";
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("testfile_with_chinese_filename_by_7zip.zip"));
zipFile.setCharset(CHARSET_GBK);
zipFile.extractAll(outputFolder.getPath());
assertThat(zipFile.getFileHeaders()).hasSize(2);
@SuppressWarnings("ConstantConditions")
List filenameSet = getFileNamesOfFiles(Arrays.asList(outputFolder.listFiles()));
assertThat(filenameSet.contains(expectedFileName)).isTrue();
}
@Test
public void testExtractZipFileWithCheckoutMismatchThrowsExceptionWithType() {
try {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("entry_with_checksum_mismatch.zip"));
zipFile.extractAll(outputFolder.getPath());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e.getType()).isEqualTo(ZipException.Type.CHECKSUM_MISMATCH);
assertThat(e.getMessage()).isEqualTo("Reached end of entry, but crc verification failed for sample_text1.txt");
}
}
@Test
public void testExtractNestedZipFileWithNoEncryptionOnInnerAndOuter() throws IOException {
testExtractNestedZipFileWithEncrpytion(EncryptionMethod.NONE, EncryptionMethod.NONE);
}
@Test
public void testExtractNestedZipFileWithNoEncryptionOnInnerAndZipStandardOuter() throws IOException {
testExtractNestedZipFileWithEncrpytion(EncryptionMethod.NONE, EncryptionMethod.ZIP_STANDARD);
}
@Test
public void testExtractNestedZipFileWithNoEncryptionOnInnerAndAesdOuter() throws IOException {
testExtractNestedZipFileWithEncrpytion(EncryptionMethod.NONE, EncryptionMethod.AES);
}
@Test
public void testExtractNestedZipFileWithZipStandardEncryptionOnInnerAndNoneOuter() throws IOException {
testExtractNestedZipFileWithEncrpytion(EncryptionMethod.ZIP_STANDARD, EncryptionMethod.NONE);
}
@Test
public void testExtractNestedZipFileWitAesOnInnerAndNoneOuter() throws IOException {
testExtractNestedZipFileWithEncrpytion(EncryptionMethod.AES, EncryptionMethod.NONE);
}
@Test
public void testExtractNestedZipFileWithZipStandardEncryptionOnInnerAndAesOuter() throws IOException {
testExtractNestedZipFileWithEncrpytion(EncryptionMethod.ZIP_STANDARD, EncryptionMethod.AES);
}
@Test
public void testExtractNestedZipFileWithAesOnInnerAndZipStandardOuter() throws IOException {
testExtractNestedZipFileWithEncrpytion(EncryptionMethod.AES, EncryptionMethod.ZIP_STANDARD);
}
@Test
public void testExtractZipFileLessThanMinimumExpectedZipFileSizeThrowsException() throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("Zip file size less than minimum expected zip file size. " +
"Probably not a zip file or a corrupted zip file");
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("invalid_zip_file_size_less_than_22kb.zip"));
zipFile.extractAll(temporaryFolder.toString());
}
@Test
public void testExtractZipFileEmptyZipFileExtractsNone() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("valid_empty_zip_file.zip"));
zipFile.extractAll(outputFolder.getPath());
assertThat(outputFolder.listFiles()).isEmpty();
}
@Test
public void testExtractZipFileCRCError() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("archive_with_invalid_zip64_headers.zip"));
zipFile.extractAll(outputFolder.getPath());
assertThat(outputFolder.listFiles()).contains(
new File(outputFolder, "index.html"),
new File(outputFolder, "images"));
}
@Test
public void testExtractZipFileOf7ZipFormatSplitWithoutEncryption() throws IOException {
List filesToAddToZip = new ArrayList<>(FILES_TO_ADD);
filesToAddToZip.add(getTestFileFromResources("file_PDF_1MB.pdf"));
File firstSplitFile = createZipFileAndSplit(filesToAddToZip, 102400, false, null);
verifyZipFileByExtractingAllFiles(firstSplitFile, outputFolder, 4);
}
@Test
public void testExtractZipFileOf7ZipFormatSplitWithAESEncryption() throws IOException {
List filesToAddToZip = new ArrayList<>(FILES_TO_ADD);
filesToAddToZip.add(getTestFileFromResources("file_PDF_1MB.pdf"));
File firstSplitFile = createZipFileAndSplit(filesToAddToZip, 102000, true, EncryptionMethod.AES);
verifyZipFileByExtractingAllFiles(firstSplitFile, PASSWORD, outputFolder, 4);
}
@Test
public void testExtractDifferentPasswordsInSameZip() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
addFileToZip(zipFile, "sample.pdf", EncryptionMethod.AES, "password1");
addFileToZip(zipFile, "sample_text1.txt", EncryptionMethod.AES, "password2");
addFileToZip(zipFile, "file_PDF_1MB.pdf", null, null);
zipFile.setPassword("password1".toCharArray());
zipFile.extractFile("sample.pdf", outputFolder.getPath());
zipFile.setPassword("password2".toCharArray());
zipFile.extractFile("sample_text1.txt", outputFolder.getPath());
zipFile.setPassword(null);
zipFile.extractFile("file_PDF_1MB.pdf", outputFolder.getPath());
}
@Test
public void testExtractZipFileWithCommentLengthGreaterThanZipFileLength() throws IOException {
verifyZipFileByExtractingAllFiles(getTestArchiveFromResources("zip_with_corrupt_comment_length.zip"), outputFolder, 1);
}
@Test
public void testExtractZipFileWithEndOfCentralDirectoryNotAtExpectedPosition() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("end_of_cen_dir_not_at_expected_position.zip"));
zipFile.extractAll(outputFolder.getPath());
List outputFiles = FileUtils.getFilesInDirectoryRecursive(outputFolder, true, true);
assertThat(outputFiles).hasSize(24);
assertThat(zipFile.getFileHeaders()).hasSize(19);
}
@Test
public void testExtractFileHeaderExtractAllFilesIfFileHeaderIsDirectory() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setIncludeRootFolder(false);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
zipFile.extractFile(zipFile.getFileHeader("öüäöäö/"), outputFolder.getPath());
File outputFile = Paths.get(outputFolder.getPath(), "öüäöäö", "asöäööl").toFile();
assertThat(outputFile).exists();
ZipFileVerifier.verifyFileContent(TestUtils.getTestFileFromResources("öüäöäö/asöäööl"), outputFile);
}
@Test
public void testExtractFileHeaderExtractAllFilesIfFileHeaderIsDirectoryAndRenameFile() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setIncludeRootFolder(false);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
zipFile.extractFile(zipFile.getFileHeader("öüäöäö/"), outputFolder.getPath(), "new_folder_name/");
File outputFile = Paths.get(outputFolder.getPath(), "new_folder_name", "asöäööl").toFile();
assertThat(outputFile).exists();
ZipFileVerifier.verifyFileContent(TestUtils.getTestFileFromResources("öüäöäö/asöäööl"), outputFile);
}
@Test
public void testExtractFileWhichIsAFolderExtractsContentsEvenWhenFolderEntryIsNotInZip() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("archive-with-no-dir-entries.zip"));
String outputFolderPath = outputFolder.getPath();
zipFile.extractFile("items/", outputFolderPath);
List extractedFiles = FileUtils.getFilesInDirectoryRecursive(outputFolder, false, false);
assertThat(extractedFiles).isNotEmpty();
assertThat(extractedFiles).hasSize(3);
assertThat(extractedFiles).contains(
Paths.get(outputFolderPath, "items").toFile(),
Paths.get(outputFolderPath, "items/subitems").toFile(),
Paths.get(outputFolderPath, "items/subitems/beta.txt").toFile());
}
@Test
public void testExtractJarFileWithFileHeaderCompressedSize2() throws IOException {
extractFile(TestUtils.getTestArchiveFromResources("jar-dir-fh-entry-size-2.jar"));
}
@Test
public void testExtractJarFileWithOnlyFileAndLocalFileHeaderCompressedSize2() throws IOException {
extractFile(TestUtils.getTestArchiveFromResources("jar-dir-lfh-and-fh-entry-size-2.jar"));
}
@Test
public void testExtractZipStrongEncryptionThrowsException() throws IOException {
ZipFile zipFile = new ZipFile(getTestArchiveFromResources("strong_encrypted.zip"), "12345678".toCharArray());
expectedException.expect(ZipException.class);
expectedException.expectMessage("Entry with name test.txt is encrypted with Strong Encryption. " +
"Zip4j does not support Strong Encryption, as this is patented.");
zipFile.extractAll(outputFolder.getPath());
}
@Test
public void testExtractAllWithCustomBufferSize() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setIncludeRootFolder(false);
zipFile.addFolder(getTestFileFromResources(""), zipParameters);
zipFile.setBufferSize(32 * 1024);
zipFile.extractAll(outputFolder.getPath());
ZipFileVerifier.verifyFolderContentsSameAsSourceFiles(outputFolder);
verifyNumberOfFilesInOutputFolder(outputFolder, 10);
}
@Test
public void testExtractingZipStandardEncryptedZipOverLoopAlwaysThrowsWrongPasswordTypeException() throws IOException {
for (int i = 0; i < 1000; i++) {
if (generatedZipFile.exists() && !generatedZipFile.delete()) {
throw new RuntimeException("Could not delete test zip file");
}
ZipFile zipFile = new ZipFile(generatedZipFile, "password".toCharArray());
addFileToZip(zipFile, "sample.pdf", EncryptionMethod.ZIP_STANDARD, "password");
try {
zipFile = new ZipFile(generatedZipFile, "WRONG_password".toCharArray());
zipFile.extractAll(outputFolder.getPath());
} catch (ZipException e) {
assertThat(e).isNotNull();
assertThat(e.getType()).isEqualTo(ZipException.Type.WRONG_PASSWORD);
}
}
}
@Test
public void testExtractZipFileByFileNameWhichTheDirectoryEntryAtTheEndOfCentralDirectoryExtractsSuccessfully()
throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFolder(getTestFileFromResources("/"));
zipFile.extractFile("test-files/", outputFolder.getPath());
zipFile = new ZipFile(generatedZipFile);
zipFile.extractFile("test-files/", outputFolder.getPath());
}
@Test
public void testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullAesPassword() throws ZipException {
testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullOrEmptyAesPassword(null);
}
@Test
public void testExtractZipFileThrowsExceptionOfTypeWrongPasswordForEmptyAesPassword() throws ZipException {
testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullOrEmptyAesPassword("".toCharArray());
}
private void addFileToZip(ZipFile zipFile, String fileName, EncryptionMethod encryptionMethod, String password) throws ZipException {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(encryptionMethod != null);
zipParameters.setEncryptionMethod(encryptionMethod);
if (password != null) {
zipFile.setPassword(password.toCharArray());
}
zipFile.addFile(getTestFileFromResources(fileName), zipParameters);
}
private void testExtractNestedZipFileWithEncrpytion(EncryptionMethod innerZipEncryption,
EncryptionMethod outerZipEncryption) throws IOException {
File innerZipFile = temporaryFolder.newFile("inner.zip");
File outerZipFile = temporaryFolder.newFile("outer.zip");
innerZipFile.delete();
outerZipFile.delete();
createNestedZip(innerZipFile, outerZipFile, innerZipEncryption, outerZipEncryption);
verifyNestedZipFile(outerZipFile, FILES_TO_ADD.size());
}
private void createNestedZip(File innerSourceZipFile, File outerSourceZipFile, EncryptionMethod innerEncryption,
EncryptionMethod outerEncryption) throws ZipException {
ZipFile innerZipFile = new ZipFile(innerSourceZipFile, PASSWORD);
ZipParameters innerZipParameters = createZipParametersForNestedZip(innerEncryption);
innerZipFile.addFiles(FILES_TO_ADD, innerZipParameters);
ZipFile outerZipFile = new ZipFile(outerSourceZipFile, PASSWORD);
ZipParameters outerZipParameters = createZipParametersForNestedZip(outerEncryption);
outerZipFile.addFile(innerSourceZipFile, outerZipParameters);
}
private void verifyNestedZipFile(File outerZipFileToVerify, int numberOfFilesInNestedZip) throws IOException {
ZipFile zipFile = new ZipFile(outerZipFileToVerify, PASSWORD);
FileHeader fileHeader = zipFile.getFileHeader("inner.zip");
assertThat(fileHeader).isNotNull();
int actualNumberOfFilesInNestedZip = 0;
try(InputStream inputStream = zipFile.getInputStream(fileHeader)) {
try(ZipInputStream zipInputStream = new ZipInputStream(inputStream, PASSWORD)) {
while (zipInputStream.getNextEntry() != null) {
actualNumberOfFilesInNestedZip++;
}
}
}
assertThat(actualNumberOfFilesInNestedZip).isEqualTo(numberOfFilesInNestedZip);
}
private ZipParameters createZipParametersForNestedZip(EncryptionMethod encryptionMethod) {
ZipParameters zipParameters = new ZipParameters();
if (encryptionMethod != null && !encryptionMethod.equals(EncryptionMethod.NONE)) {
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(encryptionMethod);
}
return zipParameters;
}
private void verifyNumberOfFilesInOutputFolder(File outputFolder, int numberOfExpectedFiles) {
assertThat(outputFolder.listFiles()).hasSize(numberOfExpectedFiles);
}
private File getFileWithNameFrom(File outputFolder, String fileName) throws ZipException {
List filesInFolder = FileUtils.getFilesInDirectoryRecursive(outputFolder, true, true);
for (File file : filesInFolder) {
if (file.getName().equals(fileName)) {
return file;
}
}
fail("Could not find a file by name " + fileName);
return null;
}
private File createZipFileAndSplit(List filesToAddToZip, long splitLength, boolean encrypt,
EncryptionMethod encryptionMethod) throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(encrypt);
zipParameters.setEncryptionMethod(encryptionMethod);
zipFile.addFiles(filesToAddToZip, zipParameters);
return TestUtils.splitFileWith7ZipFormat(zipFile.getFile(), temporaryFolder.getRoot(), splitLength);
}
private void extractFile(File fileToExtract) throws IOException {
ZipFile zipFile = new ZipFile(fileToExtract);
zipFile.extractAll(outputFolder.getPath());
}
private ZipFile createZipFileWithASymlink(File symlink) throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
zipFile.addFile(symlink, zipParameters);
return zipFile;
}
private UnzipParameters buildUnzipParameters(boolean extractSymlinks) {
UnzipParameters unzipParameters = new UnzipParameters();
unzipParameters.setExtractSymbolicLinks(extractSymlinks);
return unzipParameters;
}
private File createSymlink() throws IOException {
File targetFile = getTestFileFromResources("file_PDF_1MB.pdf");
return TestUtils.createSymlink(targetFile, temporaryFolder.getRoot());
}
private List getRegularFilesFromFolder(File folder) throws ZipException {
List filesInFolder = FileUtils.getFilesInDirectoryRecursive(folder, false, false);
List regularFiles = new ArrayList<>();
for (File file : filesInFolder) {
if (Files.isRegularFile(file.toPath())) {
regularFiles.add(file);
}
}
return regularFiles;
}
private void testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullOrEmptyAesPassword(char[] password) throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
addFileToZip(zipFile, "sample.pdf", EncryptionMethod.AES, new String(PASSWORD));
expectedException.expect(ZipException.class);
expectedException.expectMessage("empty or null password provided for AES decryption");
zipFile = new ZipFile(generatedZipFile, password);
zipFile.extractAll(outputFolder.getPath());
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/MiscZipFileIT.java 0000664 0000000 0000000 00000064523 14142654472 0024010 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadFactory;
import static java.util.Collections.singletonList;
import static net.lingala.zip4j.testutils.TestUtils.getFileNamesOfFiles;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class MiscZipFileIT extends AbstractIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testMergeSplitZipFilesMergesSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
File mergedZipFile = new File(temporaryFolder.getRoot().getPath() + InternalZipConstants.FILE_SEPARATOR
+ "merged_zip_file.zip");
zipFile.mergeSplitFiles(mergedZipFile);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(mergedZipFile, outputFolder, 4);
}
@Test
public void testMergeSplitZipFilesWithAesEncryptionMergesSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH);
File mergedZipFile = new File(temporaryFolder.getRoot().getPath() + InternalZipConstants.FILE_SEPARATOR
+ "merged_zip_file.zip");
zipFile.mergeSplitFiles(mergedZipFile);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(mergedZipFile, PASSWORD, outputFolder, 4);
}
@Test
public void testGetFileHeadersReturnsEmptyListForNewZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getFileHeaders()).isEmpty();
}
@Test
public void testGetFileHeadersReturnsAllHeaders() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
List fileHeaders = zipFile.getFileHeaders();
assertThat(fileHeaders).isNotNull();
assertThat(fileHeaders).hasSize(FILES_TO_ADD.size());
verifyFileHeadersContainsFiles(fileHeaders, getFileNamesOfFiles(FILES_TO_ADD));
}
@Test
public void testGetFileHeadersReturnsAllHeadersAfterAddingAnotherFile() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.addFile(TestUtils.getTestFileFromResources("бореиская.txt"));
List fileHeaders = zipFile.getFileHeaders();
assertThat(fileHeaders).isNotNull();
assertThat(fileHeaders).hasSize(FILES_TO_ADD.size() + 1);
List fileNames = getFileNamesOfFiles(FILES_TO_ADD);
fileNames.add("бореиская.txt");
verifyFileHeadersContainsFiles(fileHeaders, fileNames);
}
@Test
public void testGetFileHeaderReturnsNullForNewZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getFileHeader("SOME_NAME")).isNull();
}
@Test
public void testGetFileHeaderReturnsNullWhenFileDoesNotExist() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
assertThat(zipFile.getFileHeader("SOME_NAME")).isNull();
}
@Test
public void testGetFileHeaderReturnsFileHeaderSuccessfully() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
FileHeader fileHeader = zipFile.getFileHeader("sample_text_large.txt");
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getFileName()).isEqualTo("sample_text_large.txt");
}
@Test
public void testGetFileHeaderReturnsFileHeaderSuccessfullyAfterAddingNewFile() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
String fileToAdd = "file_PDF_1MB.pdf";
zipFile.addFile(TestUtils.getTestFileFromResources(fileToAdd));
FileHeader fileHeader = zipFile.getFileHeader(fileToAdd);
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getFileName()).isEqualTo(fileToAdd);
}
@Test
public void testIsEncryptedReturnsFalseForNewZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.isEncrypted()).isFalse();
}
@Test
public void testIsEncryptedReturnsFalseForNonEncryptedZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
assertThat(zipFile.isEncrypted()).isFalse();
}
@Test
public void testIsEncryptedReturnsTrueForStandardZipEncryption() throws ZipException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, null);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
assertThat(zipFile.isEncrypted()).isTrue();
}
@Test
public void testIsEncryptedReturnsTrueForAesEncryption() throws ZipException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
assertThat(zipFile.isEncrypted()).isTrue();
}
@Test
public void testIsEncryptedReturnsTrueAfterAddingAnEncryptedFile() throws ZipException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
assertThat(zipFile.isEncrypted()).isTrue();
}
@Test
public void testIsEncryptedReturnsFalseAfterRemovingAllEncryptedFiles() throws ZipException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text_large.txt"), zipParameters);
zipFile.removeFile("sample_text_large.txt");
assertThat(zipFile.isEncrypted()).isFalse();
}
@Test
public void testIsSplitArchiveReturnsFalseForNewlyCreatedZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.isSplitArchive()).isFalse();
}
@Test
public void testIsSplitArchiveReturnsFalseForNonSplitZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
assertThat(zipFile.isSplitArchive()).isFalse();
}
@Test
public void testIsSplitArchiveReturnsTrueForSplitZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
assertThat(zipFile.isSplitArchive()).isTrue();
}
@Test
public void testIsSplitArchiveReturnsFalseWhenCreatedAsSplitZipButNotSplit() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(FILES_TO_ADD, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.isSplitArchive()).isFalse();
}
@Test
public void testIsSplitArchiveReturnsFalseForMergedZipFile() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
File mergedZipFile = new File(temporaryFolder.getRoot().getPath() + InternalZipConstants.FILE_SEPARATOR
+ "merged.zip");
zipFile.mergeSplitFiles(mergedZipFile);
zipFile = new ZipFile(mergedZipFile);
assertThat(zipFile.isSplitArchive()).isFalse();
}
@Test
public void testSetComment() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.setComment("SOME_COMMENT");
zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getComment()).isEqualTo("SOME_COMMENT");
}
@Test
public void testSetCommentWithChineseCharacters() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.setCharset(Charset.forName("GBK"));
zipFile.addFiles(FILES_TO_ADD);
zipFile.setComment("测试中文");
zipFile = new ZipFile(generatedZipFile);
zipFile.setCharset(Charset.forName("GBK"));
assertThat(zipFile.getComment()).isEqualTo("测试中文");
}
@Test
public void testSetCommentWithGermanCharacters() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.setComment("ÄÜÖÖÜSDSDS");
zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getComment()).isEqualTo("ÄÜÖÖÜSDSDS");
}
@Test
public void testSetCommentForMergedZipRetainsComment() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
String comment = "SOME_COMMENT";
zipFile.setComment(comment);
assertThat(zipFile.getComment()).isEqualTo(comment);
File mergedZipFile = new File(temporaryFolder.getRoot().getPath() + InternalZipConstants.FILE_SEPARATOR
+ "merged.zip");
zipFile.mergeSplitFiles(mergedZipFile);
zipFile = new ZipFile(mergedZipFile);
assertThat(zipFile.getComment()).isEqualTo(comment);
}
@Test
public void testSetCommentWithEmptyStringRemovesComment() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
String comment = "SOME_COMMENT";
zipFile.setComment(comment);
assertThat(zipFile.getComment()).isEqualTo(comment);
zipFile.setComment("");
assertThat(zipFile.getComment()).isEqualTo("");
//Make sure comment is empty and not null also when a new instance is now created
zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getComment()).isEqualTo("");
}
@Test
public void testGetInputStreamWithoutEncryptionReturnsSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
try (InputStream inputStream = zipFile.getInputStream(zipFile.getFileHeader("sample_text_large.txt"))) {
assertThat(inputStream).isNotNull();
verifyInputStream(inputStream, TestUtils.getTestFileFromResources("sample_text_large.txt"));
}
}
@Test
public void testGetInputStreamWithAesEncryptionReturnsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
try (InputStream inputStream = zipFile.getInputStream(zipFile.getFileHeader("sample_text_large.txt"))) {
assertThat(inputStream).isNotNull();
verifyInputStream(inputStream, TestUtils.getTestFileFromResources("sample_text_large.txt"));
}
}
@Test
public void testGetInputStreamWithAesEncryptionAndSplitFileReturnsSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, zipParameters, true, InternalZipConstants.MIN_SPLIT_LENGTH);
try (InputStream inputStream = zipFile.getInputStream(zipFile.getFileHeader("file_PDF_1MB.pdf"))) {
assertThat(inputStream).isNotNull();
verifyInputStream(inputStream, TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
}
//Check also with a new instance
zipFile = new ZipFile(generatedZipFile, PASSWORD);
try (InputStream inputStream = zipFile.getInputStream(zipFile.getFileHeader("file_PDF_1MB.pdf"))) {
verifyInputStream(inputStream, TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
}
}
@Test
public void testIsValidZipFileReturnsFalseForNonZipFile() {
assertThat(new ZipFile(TestUtils.getTestFileFromResources("sample_text_large.txt")).isValidZipFile()).isFalse();
}
@Test
public void testIsValidZipFileReturnsFalseForNonExistingZip() {
assertThat(new ZipFile("DoesNoExist").isValidZipFile()).isFalse();
}
@Test
public void testIsValidZipFileReturnsTrueForAValidZip() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
assertThat(zipFile.isValidZipFile()).isTrue();
}
@Test
public void testGetSplitZipFilesReturnsJustZipFileForNonSplit() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
List splitZipFiles = zipFile.getSplitZipFiles();
assertThat(splitZipFiles).hasSize(1);
assertThat(splitZipFiles.get(0)).hasName(generatedZipFile.getName());
}
@Test
public void testGetSplitZipFilesReturnsAllSplitZipFiles() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
List splitZipFiles = zipFile.getSplitZipFiles();
assertThat(splitZipFiles).hasSize(15);
verifySplitZipFileNames(splitZipFiles, 15, FileUtils.getZipFileNameWithoutExtension(generatedZipFile.getName()));
}
@Test
public void testRenameZipFileAfterExtractionWithInputStreamSucceeds() throws IOException {
new ZipFile(generatedZipFile).addFiles(FILES_TO_ADD);
ZipFile zipFile = new ZipFile(generatedZipFile);
FileHeader fileHeader = zipFile.getFileHeader("sample_text1.txt");
assertThat(fileHeader).isNotNull();
try(InputStream inputStream = zipFile.getInputStream(fileHeader)) {
inputStream.read(new byte[100]);
}
File newFile = temporaryFolder.newFile("NEW_FILE_NAME.ZIP");
String oldFile = generatedZipFile.getPath();
if(TestUtils.isWindows())
{
newFile.delete();
}
assertThat(generatedZipFile.renameTo(newFile)).isTrue();
assertThat(new File(oldFile)).doesNotExist();
}
@Test
public void testZipSlipFix() throws Exception {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip("../../bad.txt");
ZipFile zip = new ZipFile(generatedZipFile);
zip.addFile(TestUtils.getTestFileFromResources("sample_text1.txt"), zipParameters);
try {
zip.extractAll(outputFolder.getAbsolutePath());
fail("zip4j is vulnerable for slip zip");
} catch (ZipException e) {
assertThat(e).hasMessageStartingWith("illegal file name that breaks out of the target directory: ");
}
}
@Test
public void testZipSlipFixWithFileNameStartingWithParentDirectoryThrowsException() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip("../somename.pdf");
zipFile.addFile(FILES_TO_ADD.get(0), zipParameters);
expectedException.expectMessage("illegal file name that breaks out of the target directory");
expectedException.expect(ZipException.class);
// Important here is that the name of the file in zip ("somename.pdf") should start with the
// name of the directory being extracted to ("some"). "somename.pdf" starts with "some".
zipFile.extractAll(outputFolder.getPath() + File.separator + "some");
}
@Test
public void testUnzipFileZipSlipWithNotNormalizedTarget() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFiles(FILES_TO_ADD);
zipFile.extractAll(new File(outputFolder.getPath(),
".." + InternalZipConstants.FILE_SEPARATOR + outputFolder.getName()).getAbsolutePath());
}
@Test
public void testExtractFileDeletesOutputFileWhenWrongPassword() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.ZIP_STANDARD, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text1.txt"), zipParameters);
try {
zipFile = new ZipFile(generatedZipFile, "WRONG_PASSWORD".toCharArray());
zipFile.extractAll(outputFolder.getCanonicalPath());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(new File(outputFolder.getCanonicalPath() + "sample_text1.txt")).doesNotExist();
assertThat(e.getType()).isEqualTo(ZipException.Type.WRONG_PASSWORD);
}
}
@Test
public void testCustomThreadFactory() throws IOException {
TestUtils.copyFileToFolder(getTestFileFromResources("file_PDF_1MB.pdf"), temporaryFolder.getRoot(), 1000);
final String threadName = "CustomThreadFactoryTest";
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.setThreadFactory(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(threadName);
t.setDaemon(false);
return t;
}
});
zipFile.setRunInThread(true);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipFile.addFolder(temporaryFolder.getRoot(), zipParameters);
List zip4jThread = filterForThreadsByName(threadName);
assertThat(zip4jThread).hasSize(1);
assertThat(zip4jThread.get(0).getName()).isEqualTo(threadName);
assertThat(zip4jThread.get(0).isDaemon()).isFalse();
}
@Test
public void testGetExecutorServiceIsNullWhenNotInThreadMode() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text1.txt"));
assertThat(zipFile.getExecutorService()).isNull();
}
@Test
public void testGetExecutorServiceIsNotNullWhenInThreadMode() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.setRunInThread(true);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text1.txt"));
assertThat(zipFile.getExecutorService()).isNotNull();
}
@Test
public void testFileHeaderLastModifiedTimeEpoch() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
File fileToAdd = TestUtils.getTestFileFromResources("file_PDF_1MB.pdf");
zipFile.addFile(fileToAdd);
FileHeader fileHeader = zipFile.getFileHeader("file_PDF_1MB.pdf");
assertThat(fileHeader.getLastModifiedTimeEpoch()).isEqualTo(fileToAdd.lastModified());
}
@Test
public void testVerifyZipFileForNonSplitZipFileReturnsTrue() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
assertThat(zipFile.isValidZipFile()).isTrue();
}
@Test
public void testVerifyZipFileForNonZipFileReturnsFalse() throws IOException {
ZipFile zipFile = new ZipFile(TestUtils.getTestFileFromResources("sample.pdf"));
assertThat(zipFile.isValidZipFile()).isFalse();
}
@Test
public void testVerifyZipFileForSplitZipFileReturnsTrueWhenAllSplitFilesExists() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(singletonList(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf")), new ZipParameters(),
true, InternalZipConstants.MIN_SPLIT_LENGTH);
assertThat(zipFile.isValidZipFile()).isTrue();
}
@Test
public void testVerifyZipFileForSplitZipFileReturnsFalseWhenOneSplitFileDoesNotExist() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(singletonList(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf")), new ZipParameters(),
true, InternalZipConstants.MIN_SPLIT_LENGTH);
String firstSplitFileName = zipFile.getFile().getName().replace(".zip", ".z02");
File firstSplitFile = Paths.get(zipFile.getFile().getParentFile().getPath(), firstSplitFileName).toFile();
if (!firstSplitFile.delete()) {
throw new RuntimeException("Unable to delete a split file of zip which is a requirement to run this test");
}
assertThat(zipFile.isValidZipFile()).isFalse();
}
@Test
public void testCloseSuccessfullyClosesAllInputStreams() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFile(TestUtils.getTestFileFromResources("after_deflate_remaining_bytes.bin"));
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipFile.addFile(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"), zipParameters);
zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
zipFile.addFile(TestUtils.getTestFileFromResources("sample.pdf"), zipParameters);
zipParameters.setCompressionMethod(CompressionMethod.DEFLATE);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipFile.addFile(TestUtils.getTestFileFromResources("sample_text1.txt"), zipParameters);
List inputStreams = new ArrayList<>();
for (FileHeader fileHeader : zipFile.getFileHeaders()) {
inputStreams.add(zipFile.getInputStream(fileHeader));
}
zipFile.close();
assertThat(inputStreams).hasSize(4);
assertInputStreamsAreClosed(inputStreams);
}
@Test
public void testCloseZipFileByTryWithResourceSuccessfullyClosesAllOpenStreams() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
List inputStreams = new ArrayList<>();
try(ZipFile closeableZipFile = new ZipFile(generatedZipFile)) {
for (FileHeader fileHeader : closeableZipFile.getFileHeaders()) {
inputStreams.add(closeableZipFile.getInputStream(fileHeader));
}
}
assertThat(inputStreams).hasSize(3);
assertInputStreamsAreClosed(inputStreams);
}
@Test
public void testCloseZipFileMultipleTimesClosesAllStreams() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
List inputStreams = new ArrayList<>();
// First open the inputstreams
for (FileHeader fileHeader : zipFile.getFileHeaders()) {
inputStreams.add(zipFile.getInputStream(fileHeader));
}
// Close it for the first time
zipFile.close();
assertInputStreamsAreClosed(inputStreams);
//Now open an inputstream again
InputStream inputStream = zipFile.getInputStream(zipFile.getFileHeader(FILES_TO_ADD.get(0).getName()));
// Closing it now again should close the inputstream as well
zipFile.close();
assertInputStreamsAreClosed(Collections.singletonList(inputStream));
}
private void assertInputStreamsAreClosed(List inputStreams) {
for (InputStream inputStream : inputStreams) {
try {
//noinspection ResultOfMethodCallIgnored
inputStream.read();
fail("Should have thrown an exception");
} catch (IOException e) {
assertThat(e.getMessage()).isEqualTo("Stream closed");
}
}
}
private void verifyInputStream(InputStream inputStream, File fileToCompareAgainst) throws IOException {
File outputFile = temporaryFolder.newFile();
try (OutputStream outputStream = new FileOutputStream(outputFile)) {
byte[] b = new byte[InternalZipConstants.BUFF_SIZE];
int readLen = -1;
while ((readLen = inputStream.read(b)) != -1) {
outputStream.write(b, 0, readLen);
}
}
ZipFileVerifier.verifyFileContent(fileToCompareAgainst, outputFile);
}
private void verifySplitZipFileNames(List files, int expectedNumberOfZipFiles,
String fileNameWithoutExtension) {
assertThat(files).hasSize(expectedNumberOfZipFiles);
for (int i = 0; i < expectedNumberOfZipFiles; i++) {
File file = files.get(i);
String fileExtensionPrefix = ".z0";
if (i >= 9) {
fileExtensionPrefix = ".z";
}
String expectedFileName = fileNameWithoutExtension + fileExtensionPrefix + (i + 1);
if (i == expectedNumberOfZipFiles - 1) {
expectedFileName = fileNameWithoutExtension + ".zip";
}
assertThat(file).hasName(expectedFileName);
}
}
private List filterForThreadsByName(String threadName) {
Set threadSet = Thread.getAllStackTraces().keySet();
List filteredThreads = new ArrayList<>();
for (Thread thread : threadSet) {
if (thread.getName().equals(threadName)) {
filteredThreads.add(thread);
}
}
return filteredThreads;
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/RemoveFilesFromZipIT.java 0000664 0000000 0000000 00000030207 14142654472 0025351 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static net.lingala.zip4j.testutils.HeaderVerifier.verifyFileHeadersDoesNotExist;
import static net.lingala.zip4j.testutils.HeaderVerifier.verifyZipFileDoesNotContainFolders;
import static org.assertj.core.api.Assertions.assertThat;
public class RemoveFilesFromZipIT extends AbstractIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testRemoveFileAsFileNameThrowsExceptionForSplitArchive() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("file_PDF_1MB.pdf"));
zipFile.createSplitZipFile(filesToAdd, new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
expectedException.expect(ZipException.class);
expectedException.expectMessage("Zip file format does not allow updating split/spanned files");
zipFile.removeFile("file_PDF_1MB.pdf");
}
@Test
public void testRemoveFileAsFileNameDoesNotModifyZipFileWhenFileDoesNotExistInZip() throws IOException {
String fileNameToRemove = "SOME_NAME";
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.removeFile(fileNameToRemove);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size());
}
@Test
public void testRemoveFileAsFileNameRemovesSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.removeFile("sample_text1.txt");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 2);
verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("sample_text1.txt"));
}
@Test
public void testRemoveFileAsFileNameWithCharsetCp949RemovesSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToAdd = new ArrayList<>();
filesToAdd.add(TestUtils.getTestFileFromResources("가나다.abc"));
filesToAdd.add(TestUtils.getTestFileFromResources("sample_text1.txt"));
zipFile.setCharset(CHARSET_CP_949);
zipFile.addFiles(filesToAdd);
zipFile.removeFile("sample_text1.txt");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, true, CHARSET_CP_949);
verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("sample_text1.txt"));
}
@Test
public void testRemoveFileAsFileNameRemovesSuccessfullyWithFolderNameInPath() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
zipFile.removeFile("test-files/öüäöäö/asöäööl");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 12);
verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("test-files/öüäöäö/asöäööl"));
}
@Test
public void testRemoveFileAsFileHeaderRemovesSuccessfully() throws IOException {
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
zipFile.removeFile(zipFile.getFileHeader("test-files/sample_directory/favicon.ico"));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 12);
verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("sample_directory/favicon.ico"));
}
@Test
public void testRemoveFilesRemovesFirstEntrySuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.removeFiles(Collections.singletonList("sample_text1.txt"));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size() - 1);
verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("sample_text1.txt"));
}
@Test
public void testRemoveFilesRemovesLastEntrySuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
zipFile.removeFiles(Collections.singletonList("sample.pdf"));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size() - 1);
verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("sample.pdf"));
}
@Test
public void testRemoveFilesRemovesMultipleEntriesSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFiles(FILES_TO_ADD);
List filesToRemove = Arrays.asList("sample_text1.txt", "sample.pdf");
zipFile.removeFiles(filesToRemove);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, FILES_TO_ADD.size() - 2);
verifyFileHeadersDoesNotExist(zipFile, filesToRemove);
}
@Test
public void testRemoveFilesRemovesMultipleEntriesFromEncryptedZipSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
List filesToRemove = Arrays.asList("sample_text1.txt", "sample.pdf");
zipFile.removeFiles(filesToRemove);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, FILES_TO_ADD.size() - 2);
verifyFileHeadersDoesNotExist(zipFile, filesToRemove);
}
@Test
public void testRemoveFilesRemovesDirectorySuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFolder(TestUtils.getTestFileFromResources(""));
zipFile.removeFiles(Collections.singletonList("test-files/öüäöäö/"));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 11);
verifyZipFileDoesNotContainFolders(zipFile, Collections.singletonList("test-files/öüäöäö/"));
}
@Test
public void testRemoveFilesRemovesMultipleFilesAndDirectoriesSuccessfully() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFolder(TestUtils.getTestFileFromResources(""));
zipFile.removeFiles(Arrays.asList(
"test-files/öüäöäö/",
"test-files/sample_directory/",
"test-files/after_deflate_remaining_bytes.bin",
"test-files/бореиская.txt"
));
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 7);
verifyZipFileDoesNotContainFolders(zipFile, Arrays.asList("test-files/öüäöäö/", "test-files/sample_directory/"));
verifyFileHeadersDoesNotExist(zipFile, Arrays.asList("test-files/after_deflate_remaining_bytes.bin", "test-files/бореиская.txt"));
}
@Test
public void testRemoveFilesRemovesSingleEntryFromAFolderInAZip() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.addFolder(TestUtils.getTestFileFromResources(""));
List fileToRemove = Collections.singletonList("test-files/öüäöäö/asöäööl");
zipFile.removeFiles(fileToRemove);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 12);
verifyFileHeadersDoesNotExist(zipFile, fileToRemove);
}
@Test
public void testRemoveFilesFromZipWithDataDescriptors() throws IOException {
TestUtils.createZipFileWithZipOutputStream(generatedZipFile, FILES_TO_ADD);
ZipFile zipFile = new ZipFile(generatedZipFile);
List filesToRemove = Collections.singletonList("sample_text_large.txt");
zipFile.removeFiles(filesToRemove);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 2);
verifyFileHeadersDoesNotExist(zipFile, filesToRemove);
}
@Test
public void testRemoveFirstEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries() throws IOException {
testRemoveEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries("test-files/zero_byte_file.txt");
}
@Test
public void testRemoveLastEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries() throws IOException {
testRemoveEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries("test-files/бореиская.txt");
}
@Test
public void testRemoveMiddleEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries() throws IOException {
testRemoveEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries("test-files/file_PDF_1MB.pdf");
}
@Test
public void testRemoveEntryWithAnotherSimilarNameFromZipRemovesOnlyTheEntryToBeRemoved() throws IOException {
File sourceFileToTest = TestUtils.getTestArchiveFromResources("remove_file_with_similar_file_names.zip");
File zipFileUnderTest = new File(temporaryFolder.getRoot().getPath() + InternalZipConstants.FILE_SEPARATOR + sourceFileToTest.getName());
TestUtils.copyFile(sourceFileToTest, zipFileUnderTest);
ZipFile zipFile = new ZipFile(zipFileUnderTest);
String fileNameToRemove ="a.js";
assertZipFileContainsFileByName(zipFile, fileNameToRemove);
zipFile.removeFile("a.js");
assertZipFileDoesNotContainsFileByName(zipFile, fileNameToRemove);
assertZipFileDoesNotContainsFileByName(new ZipFile(zipFileUnderTest), fileNameToRemove);
}
@Test
public void testRemoveEntryFromAZipFileWithDuplicateEntriesRemovesSuccessfully() throws IOException {
TestUtils.copyFile(TestUtils.getTestArchiveFromResources("zip_with_duplicate_entries.zip"), generatedZipFile);
ZipFile zipFile = new ZipFile(generatedZipFile);
int actualNumberOfEntries = zipFile.getFileHeaders().size();
zipFile.removeFile("sample.pdf");
zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getFileHeaders().size()).isEqualTo(actualNumberOfEntries - 1);
assertZipFileDoesNotContainsFileByName(zipFile, "sample.pdf");
}
private void testRemoveEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries(
String fileNameToRemove) throws IOException {
TestUtils.copyFile(TestUtils.getTestArchiveFromResources("cen_dir_entries_diff_order_as_local_entries.zip"),
generatedZipFile);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.removeFile(fileNameToRemove);
zipFile = new ZipFile(generatedZipFile);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 12);
verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList(fileNameToRemove));
}
private void assertZipFileContainsFileByName(ZipFile zipFile, String fileNameToExpect) throws IOException {
List fileNamesInZip = getFileNamesFromZip(zipFile);
assertThat(fileNamesInZip).contains(fileNameToExpect);
}
private void assertZipFileDoesNotContainsFileByName(ZipFile zipFile, String fileNameToExpect) throws IOException {
List fileNamesInZip = getFileNamesFromZip(zipFile);
assertThat(fileNamesInZip).doesNotContain(fileNameToExpect);
}
private List getFileNamesFromZip(ZipFile zipFile) throws IOException {
List fileHeaders = zipFile.getFileHeaders();
assertThat(fileHeaders).isNotEmpty();
List fileNames = new ArrayList<>();
for (FileHeader fileHeader :fileHeaders) {
fileNames.add(fileHeader.getFileName());
}
return fileNames;
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/RenameFilesInZipIT.java 0000664 0000000 0000000 00000035347 14142654472 0025000 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static net.lingala.zip4j.testutils.HeaderVerifier.verifyFileHeadersDoesNotExist;
import static net.lingala.zip4j.testutils.HeaderVerifier.verifyFileHeadersExist;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static org.assertj.core.api.Assertions.assertThat;
public class RenameFilesInZipIT extends AbstractIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testRenameSplitZipFileThrowsException() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(Collections.singletonList(getTestFileFromResources("file_PDF_1MB.pdf")),
new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);
expectedException.expect(ZipException.class);
expectedException.expectMessage("Zip file format does not allow updating split/spanned files");
zipFile.renameFile("file_PDF_1MB.pdf", "some_name.pdf");
}
@Test
public void testRenameWithFileHeaderRenamesSuccessfully() throws IOException {
ZipFile zipFile = createDefaultZipFile();
zipFile.renameFile(zipFile.getFileHeader("sample.pdf"), "changed.pdf");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, Collections.singletonMap("sample.pdf", "changed.pdf"));
}
@Test
public void testRenameWithFileHeaderRenamesAFolderSuccessfully() throws IOException {
ZipFile zipFile = createZipFileWithFolder();
zipFile.renameFile(zipFile.getFileHeader("test-files/sample_directory/"), "test-files/new_directory_name");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 13, false);
verifyFileNamesChanged(zipFile, Collections.singletonMap("test-files/sample_directory/", "test-files/new_directory_name/"));
}
@Test
public void testRenameWithFileNameRenamesSuccessfully() throws IOException {
ZipFile zipFile = createDefaultZipFile();
zipFile.renameFile("sample_text_large.txt", "changed.txt");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, Collections.singletonMap("sample_text_large.txt", "changed.txt"));
}
@Test
public void testRenameWithFileNameRenamesAFolderSuccessfully() throws IOException {
ZipFile zipFile = createZipFileWithFolder();
zipFile.renameFile(zipFile.getFileHeader("test-files/sample_directory/"), "test-files/가나다");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 13, false);
verifyFileNamesChanged(zipFile, Collections.singletonMap("test-files/sample_directory/", "test-files/가나다/"));
}
@Test
public void testRenameWithMapWhenNoEntriesExistWithThatNameDoesNotChangeZipFile() throws IOException {
ZipFile zipFile = createDefaultZipFile();
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("does_not_exist_1", "does_not_matter_1");
fileNamesMap.put("does_not_exist_2", "does_not_matter_2");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 3);
verifyFileHeadersDoesNotExist(zipFile, Arrays.asList("does_not_matter_1", "does_not_matter_2"));
}
@Test
public void testRenameWithMapSingleEntry() throws IOException {
ZipFile zipFile = createDefaultZipFile();
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("sample_text_large.txt", "new-name.txt");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, fileNamesMap);
}
@Test
public void testRenameWithMapForAllEntriesInZip() throws IOException {
ZipFile zipFile = createDefaultZipFile();
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("sample_text1.txt", "new-sample_text1.txt");
fileNamesMap.put("sample_text_large.txt", "new-sample_text_large.txt");
fileNamesMap.put("sample.pdf", "new-sample.pdf");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, fileNamesMap);
}
@Test
public void testRenameWithMapRenamesRootFolder() throws IOException {
ZipFile zipFile = createZipFileWithFolder();
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("test-files/", "new-test-files/");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 13, false);
verifyFileNamesChanged(zipFile, fileNamesMap);
}
@Test
public void testRenameWithMapRenamesSubFolder() throws IOException {
ZipFile zipFile = createZipFileWithFolder();
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("test-files/sample_directory/", "new-test-files/new_sample_directory/");
zipFile.renameFiles(fileNamesMap);
zipFile.extractAll(outputFolder.getPath());
verifyFileNamesChanged(zipFile, fileNamesMap);
}
@Test
public void testRenameWithMapForStoreCompressionMethod() throws IOException {
ZipFile zipFile = createZipFile(CompressionMethod.STORE, false, null);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("sample_text1.txt", "new-sample_text1.txt");
fileNamesMap.put("sample_text_large.txt", "new-sample_text_large.txt");
fileNamesMap.put("sample.pdf", "new-sample.pdf");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, fileNamesMap);
}
@Test
public void testRenameWithMapWithAesEncryption() throws IOException {
ZipFile zipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("sample_text1.txt", "new-sample_text1.txt");
fileNamesMap.put("sample_text_large.txt", "new-sample_text_large.txt");
fileNamesMap.put("sample.pdf", "new-sample.pdf");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, fileNamesMap);
}
@Test
public void testRenameWithMapWithZipStandardEncryption() throws IOException {
ZipFile zipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("sample_text1.txt", "new-sample_text1.txt");
fileNamesMap.put("sample_text_large.txt", "new-sample_text_large.txt");
fileNamesMap.put("sample.pdf", "new-sample.pdf");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, fileNamesMap);
}
@Test
public void testRenameWithMapWithAESEncryptionAndUtf8FileName() throws IOException {
ZipFile zipFile = createZipFileWithFolder(CompressionMethod.DEFLATE, true, EncryptionMethod.AES);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("test-files/가나다.abc", "test-files/üßööß.abc");
fileNamesMap.put("test-files/öüäöäö/", "test-files/가나다/");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 13, false);
verifyFileNamesChanged(zipFile, fileNamesMap, false);
}
@Test
public void testRenameForZipFileContainingExtraDataRecords() throws IOException {
TestUtils.createZipFileWithZipOutputStream(generatedZipFile, FILES_TO_ADD);
ZipFile zipFile = new ZipFile(generatedZipFile);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("sample_text_large.txt", "new_file.txt");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 3, false);
verifyFileNamesChanged(zipFile, fileNamesMap, false);
}
@Test
public void testRenameWithMapProgressMonitor() throws IOException, InterruptedException {
TestUtils.copyFileToFolder(getTestFileFromResources("file_PDF_1MB.pdf"), temporaryFolder.getRoot(), 100);
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ZipParameters zipParameters = buildZipParameters(CompressionMethod.DEFLATE, true, EncryptionMethod.AES);
zipParameters.setIncludeRootFolder(false);
zipFile.addFolder(temporaryFolder.getRoot(), zipParameters);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("1.pdf", "1_new.pdf");
fileNamesMap.put("25.pdf", "25_new.pdf");
zipFile.setRunInThread(true);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
zipFile.renameFiles(fileNamesMap);
boolean percentBetweenZeroAndHundred = false;
boolean fileNameSet = true;
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
int percentDone = progressMonitor.getPercentDone();
String fileName = progressMonitor.getFileName();
if (percentDone > 0 && percentDone < 100) {
percentBetweenZeroAndHundred = true;
}
if (fileName != null) {
fileNameSet = true;
}
Thread.sleep(10);
}
assertThat(progressMonitor.getResult()).isEqualTo(ProgressMonitor.Result.SUCCESS);
assertThat(progressMonitor.getState().equals(ProgressMonitor.State.READY));
assertThat(progressMonitor.getException()).isNull();
assertThat(percentBetweenZeroAndHundred).isTrue();
assertThat(fileNameSet).isTrue();
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 100, false);
verifyFileNamesChanged(zipFile, fileNamesMap, false);
}
@Test
public void testRenameFirstEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries() throws IOException {
testRenameEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries("test-files/zero_byte_file.txt");
}
@Test
public void testRenameLastEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries() throws IOException {
testRenameEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries("test-files/бореиская.txt");
}
@Test
public void testRenameMiddleEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries() throws IOException {
testRenameEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries("test-files/file_PDF_1MB.pdf");
}
private void testRenameEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries(
String fileNameToRename) throws IOException {
TestUtils.copyFile(TestUtils.getTestArchiveFromResources("cen_dir_entries_diff_order_as_local_entries.zip"),
generatedZipFile);
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.renameFile(fileNameToRename, "somename.txt");
zipFile = new ZipFile(generatedZipFile);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 13, false);
verifyFileNamesChanged(zipFile, Collections.singletonMap(fileNameToRename, "somename.txt"), false);
}
private void verifyFileNamesChanged(ZipFile zipFile, Map fileNamesMap) throws IOException {
verifyFileNamesChanged(zipFile, fileNamesMap, true);
}
private void verifyFileNamesChanged(ZipFile zipFile, Map fileNamesMap, boolean verifyFileContent) throws IOException {
verifyFileHeadersDoesNotExist(zipFile, fileNamesMap.keySet());
verifyFileHeadersExist(zipFile, fileNamesMap.values());
for (Map.Entry changedFileNameEntry : fileNamesMap.entrySet()) {
if (changedFileNameEntry.getValue().endsWith(InternalZipConstants.ZIP_FILE_SEPARATOR)) {
List allFileHeaders = zipFile.getFileHeaders();
for (FileHeader fileHeader : allFileHeaders) {
assertThat(fileHeader.getFileName()).doesNotStartWith(changedFileNameEntry.getKey());
}
} else {
if (verifyFileContent) {
verifyContentOfChangedFile(changedFileNameEntry.getKey(), changedFileNameEntry.getValue());
}
}
}
}
private void verifyContentOfChangedFile(String oldFileName, String newFileName) throws IOException {
File sourceFile = getTestFileFromResources(oldFileName);
File extractedFile = Paths.get(outputFolder.getAbsolutePath(), newFileName).toFile();
ZipFileVerifier.verifyFileCrc(sourceFile, extractedFile);
}
private ZipFile createDefaultZipFile() throws ZipException {
return createZipFile(CompressionMethod.DEFLATE, false, null);
}
private ZipFile createZipFile(CompressionMethod compressionMethod, boolean encrypt, EncryptionMethod encryptionMethod) throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ZipParameters zipParameters = buildZipParameters(compressionMethod, encrypt, encryptionMethod);
zipFile.addFiles(FILES_TO_ADD, zipParameters);
return zipFile;
}
private ZipFile createZipFileWithFolder() throws ZipException {
return createZipFileWithFolder(CompressionMethod.DEFLATE, false, null);
}
private ZipFile createZipFileWithFolder(CompressionMethod compressionMethod, boolean encrypt, EncryptionMethod encryptionMethod) throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ZipParameters zipParameters = buildZipParameters(compressionMethod, encrypt, encryptionMethod);
zipFile.addFolder(TestUtils.getTestFileFromResources(""), zipParameters);
return zipFile;
}
private ZipParameters buildZipParameters(CompressionMethod compressionMethod, boolean encrypt, EncryptionMethod encryptionMethod) {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(encrypt);
zipParameters.setEncryptionMethod(encryptionMethod);
zipParameters.setCompressionMethod(compressionMethod);
return zipParameters;
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/ZipFileTest.java 0000664 0000000 0000000 00000054702 14142654472 0023575 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.progress.ProgressMonitor;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
// Tests only failure scenarios. All other tests are covered in the corresponding Integration test
public class ZipFileTest {
private File sourceZipFile;
private ZipFile zipFile;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
public void setup() {
sourceZipFile = mockFile(false);
zipFile = new ZipFile(sourceZipFile);
}
@Test
public void testZipFileConstructorThrowsIllegalArgumentExceptionWhenFileParameterIsNull() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("input zip file parameter is null");
new ZipFile((File) null);
}
@Test
public void testZipFileConstructorWithPasswordThrowsIllegalArgumentExceptionWhenFileParameterIsNull() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("input zip file parameter is null");
new ZipFile((File) null, "password".toCharArray());
}
@Test
public void testCreateZipFileThrowsExceptionWhenZipFileExists() throws ZipException {
reset(sourceZipFile);
when(sourceZipFile.exists()).thenReturn(true);
expectedException.expect(ZipException.class);
expectedException.expectMessage("zip file: " + sourceZipFile + " already exists. " +
"To add files to existing zip file use addFile method");
zipFile.createSplitZipFile(Collections.emptyList(), new ZipParameters(), true, 10000);
}
@Test
public void testCreateZipFileThrowsExceptionWhenFileListIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input file List is null, cannot create zip file");
zipFile.createSplitZipFile(null, new ZipParameters(), true, 10000);
}
@Test
public void testCreateZipFileThrowsExceptionWhenFileListIsEmpty() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input file List is null, cannot create zip file");
zipFile.createSplitZipFile(Collections.emptyList(), new ZipParameters(), true, 10000);
}
@Test
public void testCreateZipFileFromFolderThrowsExceptionWheFolderIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("folderToAdd is null, cannot create zip file from folder");
zipFile.createSplitZipFileFromFolder(null, new ZipParameters(), true, 10000);
}
@Test
public void testCreateZipFileFromFolderThrowsExceptionWhenParametersAreNull() throws ZipException {
File folderToAdd = mockFile(true);
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters are null, cannot create zip file from folder");
zipFile.createSplitZipFileFromFolder(folderToAdd, null, true, 10000);
}
@Test
public void testCreateZipFileFromFolderThrowsExceptionWhenZipFileExists() throws ZipException {
reset(sourceZipFile);
when(sourceZipFile.exists()).thenReturn(true);
File folderToAdd = mockFile(true);
expectedException.expect(ZipException.class);
expectedException.expectMessage("zip file: " + sourceZipFile
+ " already exists. To add files to existing zip file use addFolder method");
zipFile.createSplitZipFileFromFolder(folderToAdd, new ZipParameters(), true, 10000);
}
@Test
public void testAddFileAsStringThrowsExceptionWhenFileIsNull() throws ZipException {
expectedException.expectMessage("file to add is null or empty");
expectedException.expect(ZipException.class);
zipFile.addFile((String) null);
}
@Test
public void testAddFileAsStringThrowsExceptionWhenFileIsEmpty() throws ZipException {
expectedException.expectMessage("file to add is null or empty");
expectedException.expect(ZipException.class);
zipFile.addFile(" ");
}
@Test
public void testAddFileAsStringWithParametersThrowsExceptionWhenFileIsNull() throws ZipException {
expectedException.expectMessage("file to add is null or empty");
expectedException.expect(ZipException.class);
zipFile.addFile((String) null, new ZipParameters());
}
@Test
public void testAddFileAsStringWithParametersThrowsExceptionWhenFileIsEmpty() throws ZipException {
expectedException.expectMessage("file to add is null or empty");
expectedException.expect(ZipException.class);
zipFile.addFile("", new ZipParameters());
}
@Test
public void testAddFileAsFileThrowsExceptionWhenParametersIsNull() throws ZipException {
File fileToAdd = mockFile(true);
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters are null");
zipFile.addFile(fileToAdd, null);
}
@Test
public void testAddFileAsFileThrowsExceptionWhenProgressMonitorStateIsBusy() throws ZipException {
File fileToAdd = mockFile(true);
zipFile.setRunInThread(true);
zipFile.getProgressMonitor().setState(ProgressMonitor.State.BUSY);
expectedException.expect(ZipException.class);
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
zipFile.addFile(fileToAdd, new ZipParameters());
}
@Test
public void testAddFilesThrowsExceptionWhenInputFilesIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input file List is null or empty");
zipFile.addFiles(null);
}
@Test
public void testAddFilesThrowsExceptionWhenInputFilesIsEmpty() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input file List is null or empty");
zipFile.addFiles(Collections.emptyList());
}
@Test
public void testAddFilesThrowsExceptionWhenProgressMonitorStateIsBusy() throws ZipException {
zipFile.getProgressMonitor().setState(ProgressMonitor.State.BUSY);
zipFile.setRunInThread(true);
expectedException.expect(ZipException.class);
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
zipFile.addFiles(Collections.singletonList(new File("Some_File")));
}
@Test
public void testAddFilesWithParametersThrowsExceptionWhenInputFilesIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input file List is null or empty");
zipFile.addFiles(null, new ZipParameters());
}
@Test
public void testAddFilesWithParametersThrowsExceptionWhenInputFilesIsEmpty() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input file List is null or empty");
zipFile.addFiles(Collections.emptyList(), new ZipParameters());
}
@Test
public void testAddFilesWithParametersThrowsExceptionWhenParametersAreNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters are null");
zipFile.addFiles(Collections.singletonList(new File("Some_File")), null);
}
@Test
public void testAddFilesWithParametersThrowsExceptionWhenProgressMonitorStateIsBusy() throws ZipException {
zipFile.setRunInThread(true);
zipFile.getProgressMonitor().setState(ProgressMonitor.State.BUSY);
expectedException.expect(ZipException.class);
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
zipFile.addFiles(Collections.singletonList(new File("Some_File")), new ZipParameters());
}
@Test
public void testAddFolderThrowsExceptionWhenFolderIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input path is null, cannot add folder to zip file");
zipFile.addFolder(null);
}
@Test
public void testAddFolderThrowsExceptionWhenFolderDoesNotExist() throws ZipException {
File folderToAdd = mockFile(false);
expectedException.expect(ZipException.class);
expectedException.expectMessage("folder does not exist");
zipFile.addFolder(folderToAdd);
}
@Test
public void testAddFolderThrowsExceptionWhenFolderNotADirectory() throws ZipException {
File folderToAdd = mockFile(true);
when(folderToAdd.isDirectory()).thenReturn(false);
expectedException.expect(ZipException.class);
expectedException.expectMessage("input folder is not a directory");
zipFile.addFolder(folderToAdd);
}
@Test
public void testAddFolderThrowsExceptionWhenCannotReadFolder() throws ZipException {
File folderToAdd = mockFile(true);
when(folderToAdd.isDirectory()).thenReturn(true);
when(folderToAdd.canRead()).thenReturn(false);
expectedException.expect(ZipException.class);
expectedException.expectMessage("cannot read input folder");
zipFile.addFolder(folderToAdd);
}
@Test
public void testAddFolderWithParametersThrowsExceptionWhenFolderIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input path is null, cannot add folder to zip file");
zipFile.addFolder(null, new ZipParameters());
}
@Test
public void testAddFolderWithParametersThrowsExceptionWhenFolderDoesNotExist() throws ZipException {
File folderToAdd = mockFile(false);
expectedException.expect(ZipException.class);
expectedException.expectMessage("folder does not exist");
zipFile.addFolder(folderToAdd, new ZipParameters());
}
@Test
public void testAddFolderWithParametersThrowsExceptionWhenFolderNotADirectory() throws ZipException {
File folderToAdd = mockFile(true);
when(folderToAdd.isDirectory()).thenReturn(false);
expectedException.expect(ZipException.class);
expectedException.expectMessage("input folder is not a directory");
zipFile.addFolder(folderToAdd, new ZipParameters());
}
@Test
public void testAddFolderWithParametersThrowsExceptionWhenCannotReadFolder() throws ZipException {
File folderToAdd = mockFile(true);
when(folderToAdd.isDirectory()).thenReturn(true);
when(folderToAdd.canRead()).thenReturn(false);
expectedException.expect(ZipException.class);
expectedException.expectMessage("cannot read input folder");
zipFile.addFolder(folderToAdd, new ZipParameters());
}
@Test
public void testAddFolderWithParametersThrowsExceptionWhenInputParametersAreNull() throws ZipException {
File folderToAdd = mockFile(true);
when(folderToAdd.isDirectory()).thenReturn(true);
when(folderToAdd.canRead()).thenReturn(true);
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters are null, cannot add folder to zip file");
zipFile.addFolder(folderToAdd, null);
}
@Test
public void testAddFolderThrowsExceptionWhenProgressMonitorStateIsBusy() throws ZipException {
File folderToAdd = mockFolder();
zipFile.setRunInThread(true);
zipFile.getProgressMonitor().setState(ProgressMonitor.State.BUSY);
expectedException.expect(ZipException.class);
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
zipFile.addFolder(folderToAdd, new ZipParameters());
}
@Test
public void testAddStreamThrowsExceptionWhenInputStreamIsNull() throws ZipException {
expectedException.expectMessage("inputstream is null, cannot add file to zip");
expectedException.expect(ZipException.class);
zipFile.addStream(null, new ZipParameters());
}
@Test
public void testAddStreamThrowsExceptionWhenParametersIsNull() throws ZipException {
expectedException.expectMessage("zip parameters are null");
expectedException.expect(ZipException.class);
zipFile.addStream(new ByteArrayInputStream(new byte[2]), null);
}
@Test
public void testExtractAllThrowsExceptionWhenDestinationIsNull() throws ZipException {
expectedException.expectMessage("output path is null or invalid");
expectedException.expect(ZipException.class);
zipFile.extractAll(null);
}
@Test
public void testExtractAllThrowsExceptionWhenDestinationIsEmpty() throws ZipException {
expectedException.expectMessage("output path is null or invalid");
expectedException.expect(ZipException.class);
zipFile.extractAll(" ");
}
@Test
public void testExtractFileWithFileHeaderWhenFileHeaderIsNullThrowsException() throws ZipException {
expectedException.expectMessage("input file header is null, cannot extract file");
expectedException.expect(ZipException.class);
zipFile.extractFile((FileHeader) null, "SOME_DESTINATION");
}
@Test
public void testExtractFileWithFileHeaderWhenDestinationIsNullThrowsException() throws ZipException {
expectedException.expectMessage("destination path is empty or null, cannot extract file");
expectedException.expect(ZipException.class);
zipFile.extractFile(createFileHeader("SOME_NAME"), null);
}
@Test
public void testExtractFileWithFileHeaderWhenDestinationIsEmptyThrowsException() throws ZipException {
expectedException.expectMessage("destination path is empty or null, cannot extract file");
expectedException.expect(ZipException.class);
zipFile.extractFile(createFileHeader("SOME_NAME"), "");
}
@Test
public void testExtractFileWithFileHeaderWhenBusyStateThrowsException() throws ZipException {
zipFile.setRunInThread(true);
zipFile.getProgressMonitor().setState(ProgressMonitor.State.BUSY);
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
expectedException.expect(ZipException.class);
zipFile.extractFile(createFileHeader("SOME_NAME"), "SOME_DESTINATION");
}
@Test
public void testExtractFileWithFileNameThrowsExceptionWhenNameIsNull() throws ZipException {
expectedException.expectMessage("file to extract is null or empty, cannot extract file");
expectedException.expect(ZipException.class);
zipFile.extractFile((String) null, "SOME_DESTINATION");
}
@Test
public void testExtractFileWithFileNameThrowsExceptionWhenNameIsEmpty() throws ZipException {
expectedException.expectMessage("file to extract is null or empty, cannot extract file");
expectedException.expect(ZipException.class);
zipFile.extractFile("", "SOME_DESTINATION");
}
@Test
public void testExtractFileWithNewFileNameThrowsExceptionWhenNameIsNull() throws ZipException {
expectedException.expectMessage("file to extract is null or empty, cannot extract file");
expectedException.expect(ZipException.class);
zipFile.extractFile((String) null, "SOME_DESTINATION", "NEW_FILE_NAME");
}
@Test
public void testExtractFileWithNewFileNameThrowsExceptionWhenNameIsEmpty() throws ZipException {
expectedException.expectMessage("file to extract is null or empty, cannot extract file");
expectedException.expect(ZipException.class);
zipFile.extractFile("", "SOME_DESTINATION");
}
@Test
public void testGetFileHeadersReturnsEmptyListWhenZipFileDoesNotExist() throws ZipException {
File mockFile = mockFile(false);
ZipFile zipFile = new ZipFile(mockFile);
assertThat(zipFile.getFileHeaders()).isEmpty();
}
@Test
public void testGetFileHeaderThrowsExceptionWhenFileNameIsNull() throws ZipException {
expectedException.expectMessage("input file name is emtpy or null, cannot get FileHeader");
expectedException.expect(ZipException.class);
zipFile.getFileHeader(null);
}
@Test
public void testGetFileHeaderThrowsExceptionWhenFileNameIsEmpty() throws ZipException {
expectedException.expectMessage("input file name is emtpy or null, cannot get FileHeader");
expectedException.expect(ZipException.class);
zipFile.getFileHeader("");
}
@Test
public void testRemoveFileWithFileNameThrowsExceptionWhenFileNameIsNull() throws ZipException {
expectedException.expectMessage("file name is empty or null, cannot remove file");
expectedException.expect(ZipException.class);
zipFile.removeFile((String) null);
}
@Test
public void testRemoveFileWithFileNameThrowsExceptionWhenFileNameIsEmpty() throws ZipException {
expectedException.expectMessage("file name is empty or null, cannot remove file");
expectedException.expect(ZipException.class);
zipFile.removeFile("");
}
@Test
public void testRemoveFileWithFileHeaderThrowsExceptionWhenFileNameIsNull() throws ZipException {
expectedException.expectMessage("input file header is null, cannot remove file");
expectedException.expect(ZipException.class);
zipFile.removeFile((FileHeader) null);
}
@Test
public void testRemoveFilesWithListThrowsExceptionWhenListIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("fileNames list is null");
zipFile.removeFiles(null);
}
@Test
public void testRenameFileWithFileHeaderThrowsExceptionWhenHeaderIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("File header is null");
zipFile.renameFile((FileHeader) null, "somename");
}
@Test
public void testRenameFileWithFileHeaderThrowsExceptionWhenNewFileNameIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("newFileName is null or empty");
FileHeader fileHeader = new FileHeader();
fileHeader.setFileName("somename");
zipFile.renameFile(fileHeader, null);
}
@Test
public void testRenameFileWithFileHeaderThrowsExceptionWhenNewFileNameIsEmpty() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("newFileName is null or empty");
FileHeader fileHeader = new FileHeader();
fileHeader.setFileName("somename");
zipFile.renameFile(fileHeader, "");
}
@Test
public void testRenameFileWithFileNameThrowsExceptionWhenFileNameToBeChangedIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("file name to be changed is null or empty");
zipFile.renameFile((String) null, "somename");
}
@Test
public void testRenameFileWithFileNameThrowsExceptionWhenFileNameToBeChangedIsEmpty() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("file name to be changed is null or empty");
zipFile.renameFile("", "somename");
}
@Test
public void testRenameFileWithFileNameThrowsExceptionWhenNewFileNameIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("newFileName is null or empty");
zipFile.renameFile("Somename", null);
}
@Test
public void testRenameFileWithFileNameThrowsExceptionWhenNewFileNameIsEmpty() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("newFileName is null or empty");
zipFile.renameFile("Somename", " ");
}
@Test
public void testRenameFileWithMapThrowsExceptionWhenMapIsNull() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("fileNamesMap is null");
zipFile.renameFiles(null);
}
@Test
public void testMergeSplitFilesWhenOutputFileIsNullThrowsException() throws ZipException {
expectedException.expectMessage("outputZipFile is null, cannot merge split files");
expectedException.expect(ZipException.class);
zipFile.mergeSplitFiles(null);
}
@Test
public void testMergeSplitFilesWhenOutputFileDoesAlreadyExistsThrowsException() throws ZipException {
expectedException.expectMessage("output Zip File already exists");
expectedException.expect(ZipException.class);
File mergedZipFile = mockFile(true);
zipFile.mergeSplitFiles(mergedZipFile);
}
@Test
public void testSetCommentWhenCommentIsNullThrowsException() throws ZipException {
expectedException.expectMessage("input comment is null, cannot update zip file");
expectedException.expect(ZipException.class);
zipFile.setComment(null);
}
@Test
public void testSetCommentWhenZipFileDoesNotExistsThrowsException() throws ZipException {
expectedException.expectMessage("zip file does not exist, cannot set comment for zip file");
expectedException.expect(ZipException.class);
zipFile.setComment("Some comment");
}
@Test
public void testGetCommentWhenZipFileDoesNotExistThrowsException() throws ZipException {
expectedException.expectMessage("zip file does not exist, cannot read comment");
expectedException.expect(ZipException.class);
zipFile.getComment();
}
@Test
public void testGetInputStreamWhenFileHeaderIsNullThrowsException() throws IOException {
expectedException.expectMessage("FileHeader is null, cannot get InputStream");
expectedException.expect(ZipException.class);
zipFile.getInputStream(null);
}
@Test
public void testSetRunInThreadSetsFlag() {
zipFile.setRunInThread(true);
assertThat(zipFile.isRunInThread()).isTrue();
zipFile.setRunInThread(false);
assertThat(zipFile.isRunInThread()).isFalse();
}
@Test
public void testGetFileReturnsValidFile() {
assertThat(zipFile.getFile()).isSameAs(sourceZipFile);
}
@Test
public void testToString() {
assertThat(zipFile.toString()).isEqualTo("SOME_PATH");
}
@Test
public void testSetBufferSizeThrowsExceptionWhenSizeLessThanExpected() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
zipFile.setBufferSize(MIN_BUFF_SIZE - 1);
}
private File mockFile(boolean fileExists) {
File file = mock(File.class);
when(file.exists()).thenReturn(fileExists);
when(file.toString()).thenReturn("SOME_PATH");
return file;
}
private File mockFolder() {
File folder = mock(File.class);
when(folder.exists()).thenReturn(true);
when(folder.toString()).thenReturn("SOME_PATH");
when(folder.isDirectory()).thenReturn(true);
when(folder.canRead()).thenReturn(true);
return folder;
}
private FileHeader createFileHeader(String fileName) {
FileHeader fileHeader = new FileHeader();
fileHeader.setFileName(fileName);
return fileHeader;
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/ZipFileZip64IT.java 0000664 0000000 0000000 00000016464 14142654472 0024032 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j;
import net.lingala.zip4j.headers.HeaderReader;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.testutils.HeaderVerifier;
import net.lingala.zip4j.testutils.RandomInputStream;
import net.lingala.zip4j.testutils.SlowTests;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@Category(SlowTests.class)
public class ZipFileZip64IT extends AbstractIT {
private byte[] readBuffer = new byte[2 * InternalZipConstants.BUFF_SIZE];
@Test
public void testZip64WithSingleLargeZipEntry() throws IOException {
long entrySize = InternalZipConstants.ZIP_64_SIZE_LIMIT + 1;
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
zipParameters.setEntrySize(entrySize);
createZip64FileWithEntries(1, entrySize, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, false);
verifyZip64HeadersPresent();
cleanupOutputFolder();
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.renameFile("FILE_0", "NEW_FILE_0");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, false);
verifyZip64HeadersPresent();
HeaderVerifier.verifyFileHeadersExist(zipFile, Collections.singletonList("NEW_FILE_0"));
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("FILE_0"));
cleanupOutputFolder();
zipFile = new ZipFile(generatedZipFile);
zipFile.removeFile("NEW_FILE_0");
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 0, false);
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, Collections.singletonList("NEW_FILE_0"));
}
@Test
public void testZip64WithCentralDirectoryOffsetGreaterThanZip64Limit() throws IOException {
long eachEntrySize = (InternalZipConstants.ZIP_64_SIZE_LIMIT / 2) + 100;
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEntrySize(eachEntrySize);
createZip64FileWithEntries(3, eachEntrySize, zipParameters);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 3, false);
verifyZip64HeadersPresent();
cleanupOutputFolder();
ZipFile zipFile = new ZipFile(generatedZipFile);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("FILE_1", "NEW_FILE_1");
fileNamesMap.put("FILE_2", "NEW_FILE_2");
zipFile.renameFiles(fileNamesMap);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 3, false);
verifyZip64HeadersPresent();
HeaderVerifier.verifyFileHeadersExist(zipFile, fileNamesMap.values());
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, fileNamesMap.keySet());
cleanupOutputFolder();
zipFile = new ZipFile(generatedZipFile);
List filesToRemove = new ArrayList<>();
filesToRemove.add("FILE_0");
filesToRemove.add("NEW_FILE_2");
zipFile.removeFiles(filesToRemove);
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, false);
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, filesToRemove);
HeaderVerifier.verifyFileHeadersExist(zipFile, Collections.singleton("NEW_FILE_1"));
}
@Test
public void testZip64WithNumberOfEntriesGreaterThan70k() throws IOException {
long eachEntrySize = 100;
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEntrySize(eachEntrySize);
createZip64FileWithEntries(70000, eachEntrySize, zipParameters);
ZipFile zipFile = new ZipFile(generatedZipFile);
assertThat(zipFile.getFileHeaders()).hasSize(70000);
verifyZip64HeadersPresent();
zipFile = new ZipFile(generatedZipFile);
Map fileNamesMap = new HashMap<>();
fileNamesMap.put("FILE_10", "NEW_FILE_10");
fileNamesMap.put("FILE_20", "NEW_FILE_20");
fileNamesMap.put("FILE_30", "NEW_FILE_30");
zipFile.renameFiles(fileNamesMap);
verifyZip64HeadersPresent();
HeaderVerifier.verifyFileHeadersExist(zipFile, fileNamesMap.values());
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, fileNamesMap.keySet());
zipFile = new ZipFile(generatedZipFile);
List filesToRemove = new ArrayList<>();
filesToRemove.add("FILE_0");
filesToRemove.add("NEW_FILE_10");
filesToRemove.add("NEW_FILE_30");
zipFile.removeFiles(filesToRemove);
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, filesToRemove);
}
@Test
public void testZip64WhenAddingFilesWithNewlyInstantiatedZipFile() throws IOException {
testZip64WhenAddingMultipleFiles(true);
}
@Test
public void testZip64WhenAddingFilesWithAlreadyInstantiatedZipFile() throws IOException {
testZip64WhenAddingMultipleFiles(false);
}
private void testZip64WhenAddingMultipleFiles(boolean reinitializeZipFile) throws IOException {
File testFileToAdd = TestUtils.generateFileOfSize(temporaryFolder, 1073741824); // 1 GB
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
ZipFile zipFile = new ZipFile(generatedZipFile);
for (int i = 0; i < 6; i++) {
zipParameters.setFileNameInZip(Integer.toString(i));
if (reinitializeZipFile) {
zipFile = new ZipFile(generatedZipFile);
}
zipFile.addFile(testFileToAdd, zipParameters);
}
ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
}
private void verifyZip64HeadersPresent() throws IOException {
HeaderReader headerReader = new HeaderReader();
ZipModel zipModel = headerReader.readAllHeaders(new RandomAccessFile(generatedZipFile,
RandomAccessFileMode.READ.getValue()), buildDefaultConfig());
assertThat(zipModel.getZip64EndOfCentralDirectoryLocator()).isNotNull();
assertThat(zipModel.getZip64EndOfCentralDirectoryRecord()).isNotNull();
assertThat(zipModel.isZip64Format()).isTrue();
}
private void createZip64FileWithEntries(int numberOfEntries, long eachEntrySize, ZipParameters zipParameters)
throws IOException {
int readLen;
try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(generatedZipFile))) {
for (int i = 0; i < numberOfEntries; i++) {
zipParameters.setFileNameInZip("FILE_" + i);
zipOutputStream.putNextEntry(zipParameters);
try(InputStream inputStream = new RandomInputStream(eachEntrySize)) {
while ((readLen = inputStream.read(readBuffer)) != -1) {
zipOutputStream.write(readBuffer, 0, readLen);
}
}
zipOutputStream.closeEntry();
}
}
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/crypto/ 0000775 0000000 0000000 00000000000 14142654472 0022040 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/crypto/PBKDF2/ 0000775 0000000 0000000 00000000000 14142654472 0022750 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/crypto/PBKDF2/BinToolsTest.java 0000664 0000000 0000000 00000002450 14142654472 0026205 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.crypto.PBKDF2;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.assertj.core.api.Assertions.assertThat;
public class BinToolsTest {
@Rule
public final ExpectedException expectedException = ExpectedException.none();
@Test
public void bin2hexForValidInputReturnsValidHex() {
final byte[] b = {(byte) 112};
assertThat(BinTools.bin2hex(b)).isEqualTo("70");
}
@Test
public void bin2hexForEmptyInputReturnsEmptyString() {
assertThat(BinTools.bin2hex(new byte[]{})).isEqualTo("");
}
@Test
public void bin2hexForNullInputReturnsEmptyString() {
assertThat(BinTools.bin2hex(null)).isEqualTo("");
}
@Test
public void bin2hexForNullInputReturnsEmptyArray() {
assertThat(BinTools.hex2bin(null)).isEqualTo(new byte[]{});
}
@Test
public void hex2binForInvalidInputOutputIllegalArgumentException() {
expectedException.expect(IllegalArgumentException.class);
BinTools.hex2bin("foo");
}
@Test
public void hex2binCharacterInputOutputPositive() {
assertThat(BinTools.hex2bin('A')).isEqualTo(10);
}
@Test
public void hex2binInvalidInputOutputIllegalArgumentException() {
expectedException.expect(IllegalArgumentException.class);
BinTools.hex2bin('\u013c');
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/exception/ 0000775 0000000 0000000 00000000000 14142654472 0022516 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/exception/ZipExceptionTest.java 0000664 0000000 0000000 00000003704 14142654472 0026646 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.exception;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class ZipExceptionTest {
@Test
public void testZipExceptionForErrorMessage() {
String message = "SOME_MESSAGE";
ZipException zipException = new ZipException(message);
assertThat(zipException.getMessage()).isEqualTo(message);
assertThat(zipException.getType()).isEqualTo(ZipException.Type.UNKNOWN);
}
@Test
public void testZipExceptionWithRootException() {
String errorMessage = "SOME_MESSAGE";
Exception rootException = new RuntimeException(errorMessage);
ZipException zipException = new ZipException(rootException);
assertThat(zipException.getCause()).isEqualTo(rootException);
assertThat(zipException.getCause().getMessage()).isEqualTo(errorMessage);
assertThat(zipException.getType()).isEqualTo(ZipException.Type.UNKNOWN);
assertThat(zipException.getMessage()).contains(errorMessage);
}
@Test
public void testZipExceptionWithMessageAndRootException() {
String errorMessage = "SOME_MESSAGE";
String rootErrorMessage = "ROOT_ERROR_MESSAGE";
Exception rootException = new RuntimeException(rootErrorMessage);
ZipException zipException = new ZipException(errorMessage, rootException);
assertThat(zipException.getCause()).isEqualTo(rootException);
assertThat(zipException.getCause().getMessage()).isEqualTo(rootErrorMessage);
assertThat(zipException.getType()).isEqualTo(ZipException.Type.UNKNOWN);
assertThat(zipException.getMessage()).isEqualTo(errorMessage);
}
@Test
public void testZipExceptionWithMessageAndExceptionType() {
String errorMessage = "SOME_MESSAGE";
ZipException.Type exceptionType = ZipException.Type.WRONG_PASSWORD;
ZipException zipException = new ZipException(errorMessage, exceptionType);
assertThat(zipException.getType()).isEqualTo(exceptionType);
assertThat(zipException.getMessage()).isEqualTo(errorMessage);
}
} zip4j-2.9.1/src/test/java/net/lingala/zip4j/headers/ 0000775 0000000 0000000 00000000000 14142654472 0022133 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/headers/FileHeaderFactoryTest.java 0000664 0000000 0000000 00000053525 14142654472 0027170 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.nio.charset.Charset;
import static net.lingala.zip4j.util.BitUtils.isBitSet;
import static net.lingala.zip4j.util.Zip4jUtil.epochToExtendedDosTime;
import static org.assertj.core.api.Assertions.assertThat;
public class FileHeaderFactoryTest {
private static final String ACTUAL_OS = System.getProperty("os.name");
private static final String FILE_NAME_IN_ZIP = "filename.txt";
private static final long ENTRY_CRC = 2323L;
private FileHeaderFactory fileHeaderFactory = new FileHeaderFactory();
private RawIO rawIO = new RawIO();
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
public void setup() {
System.setProperty("os.name", "linux");
}
@After
public void cleanup() {
System.setProperty("os.name", ACTUAL_OS);
}
@Test
public void testGenerateFileHeaderWithoutFileNameThrowsException() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("fileNameInZip is null or empty");
fileHeaderFactory.generateFileHeader(new ZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
}
@Test
public void testGenerateFileHeaderDefaults() throws ZipException {
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getCompressionMethod()).isEqualTo(CompressionMethod.DEFLATE);
verifyCompressionLevelGridForDeflate(CompressionLevel.NORMAL,
fileHeader.getGeneralPurposeFlag()[0]);
assertThat(fileHeader.isEncrypted()).isFalse();
assertThat(fileHeader.getEncryptionMethod()).isEqualTo(EncryptionMethod.NONE);
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
assertThat(fileHeader.getLastModifiedTime()).isNotZero();
assertThat(fileHeader.getCompressedSize()).isEqualTo(0);
assertThat(fileHeader.getUncompressedSize()).isEqualTo(0);
}
@Test
public void testGenerateFileHeaderForStoreWithoutEncryption() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 10, false);
}
@Test
public void testGenerateFileHeaderWhenEncryptingWithoutMethodThrowsException() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("Encryption method has to be set when encryptFiles flag is set in zip parameters");
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
}
@Test
public void testGenerateFileHeaderWithStandardEncryption() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 20, false);
}
@Test
public void testGenerateFileHeaderWithAesEncryptionWithNullKeyStrengthThrowsException() throws ZipException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("invalid AES key strength");
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(null);
fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
}
@Test
public void testGenerateFileHeaderWithAesEncryptionWithoutKeyStrengthUsesDefault() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true);
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256,
CompressionMethod.DEFLATE, AesVersion.TWO);
}
@Test
public void testGenerateFileHeaderWithAesEncryptionWithKeyStrength128() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_128);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true);
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_128,
CompressionMethod.DEFLATE, AesVersion.TWO);
}
@Test
public void testGenerateFileHeaderWithAesEncryptionWithKeyStrength192() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_192);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true);
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_192,
CompressionMethod.DEFLATE, AesVersion.TWO);
}
@Test
public void testGenerateFileHeaderWithAesEncryptionWithKeyStrength256() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true);
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256,
CompressionMethod.DEFLATE, AesVersion.TWO);
}
@Test
public void testGenerateFileHeaderWithAesEncryptionVersionV1() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setAesVersion(AesVersion.ONE);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true);
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256,
CompressionMethod.DEFLATE, AesVersion.ONE);
}
@Test
public void testGenerateFileHeaderWithAesEncryptionWithNullVersionUsesV2() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
zipParameters.setAesVersion(null);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true);
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256,
CompressionMethod.DEFLATE, AesVersion.TWO);
}
@Test
public void testGenerateFileHeaderWithLastModifiedFileTime() throws ZipException {
long lastModifiedFileTime = System.currentTimeMillis();
ZipParameters zipParameters = generateZipParameters();
zipParameters.setLastModifiedFileTime(lastModifiedFileTime);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
assertThat(fileHeader.getLastModifiedTime()).isEqualTo(epochToExtendedDosTime(zipParameters.getLastModifiedFileTime()));
}
@Test
public void testGenerateFileHeaderWithCompressionLeveUltra() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setCompressionLevel(CompressionLevel.ULTRA);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyCompressionLevelGridForDeflate(CompressionLevel.ULTRA, fileHeader.getGeneralPurposeFlag()[0]);
}
@Test
public void testGenerateFileHeaderWithCompressionLevelMaximum() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setCompressionLevel(CompressionLevel.MAXIMUM);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyCompressionLevelGridForDeflate(CompressionLevel.MAXIMUM, fileHeader.getGeneralPurposeFlag()[0]);
}
@Test
public void testGenerateFileHeaderWithCompressionLevelFast() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setCompressionLevel(CompressionLevel.FAST);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyCompressionLevelGridForDeflate(CompressionLevel.FAST, fileHeader.getGeneralPurposeFlag()[0]);
}
@Test
public void testGenerateFileHeaderWithCompressionLevelFastest() throws ZipException {
ZipParameters zipParameters = generateZipParameters();
zipParameters.setCompressionLevel(CompressionLevel.FASTEST);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
verifyCompressionLevelGridForDeflate(CompressionLevel.FASTEST, fileHeader.getGeneralPurposeFlag()[0]);
}
@Test
public void testGenerateFileHeaderWithCorrectCharset() throws ZipException {
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, Charset.forName("Cp949"), rawIO);
assertThat(isBitSet(fileHeader.getGeneralPurposeFlag()[1], 3)).isFalse();
}
@Test
public void testGenerateFileHeaderWithUTF8Charset() throws ZipException {
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
assertThat(isBitSet(fileHeader.getGeneralPurposeFlag()[1], 3)).isTrue();
}
@Test
public void testGenerateLocalFileHeader() {
long lastModifiedFileTime = epochToExtendedDosTime(System.currentTimeMillis());
FileHeader fileHeader = generateFileHeader(lastModifiedFileTime);
LocalFileHeader localFileHeader = fileHeaderFactory.generateLocalFileHeader(fileHeader);
verifyLocalFileHeader(localFileHeader, lastModifiedFileTime);
}
@Test
public void testVersionMadeByWindowsWithUnixModeOff() {
changeOsSystemPropertyToWindows();
testVersionMadeBy(generateZipParameters(), 51);
}
@Test
public void testVersionMadeByWindowsWithUnixModeOn() {
changeOsSystemPropertyToWindows();
ZipParameters zipParameters = generateZipParameters();
zipParameters.setUnixMode(true);
testVersionMadeBy(zipParameters, 819);
}
@Test
public void testVersionMadeByUnix() {
changeOsSystemPropertyToUnix();
testVersionMadeBy(generateZipParameters(), 819);
}
@Test
public void testVersionMadeByMac() {
changeOsSystemPropertyToMac();
testVersionMadeBy(generateZipParameters(), 819);
}
private void testVersionMadeBy(ZipParameters zipParameters, int expectedVersionMadeBy) {
try {
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
assertThat(fileHeader.getVersionMadeBy()).isEqualTo(expectedVersionMadeBy);
} catch (Exception e) {
restoreOsSystemProperty();
}
}
private ZipParameters generateZipParameters() {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(FILE_NAME_IN_ZIP);
zipParameters.setEntryCRC(ENTRY_CRC);
return zipParameters;
}
private FileHeader generateFileHeader(long lastModifiedFileTime) {
FileHeader fileHeader = new FileHeader();
fileHeader.setVersionNeededToExtract(20);
fileHeader.setCompressionMethod(CompressionMethod.STORE);
fileHeader.setLastModifiedTime(lastModifiedFileTime);
fileHeader.setUncompressedSize(1000L);
fileHeader.setFileName(FILE_NAME_IN_ZIP);
fileHeader.setFileNameLength(FILE_NAME_IN_ZIP.getBytes(InternalZipConstants.CHARSET_UTF_8).length);
fileHeader.setEncrypted(true);
fileHeader.setEncryptionMethod(EncryptionMethod.AES);
fileHeader.setCrc(1231231L);
fileHeader.setCompressedSize(23523L);
fileHeader.setGeneralPurposeFlag(new byte[] {2, 28});
fileHeader.setDataDescriptorExists(true);
fileHeader.setExtraFieldLength(190);
return fileHeader;
}
private void verifyFileHeader(FileHeader fileHeader, ZipParameters zipParameters, boolean isSplitZip,
int diskNumberStart, int versionNeededToExtract, boolean aesExtraDataRecordPresent) {
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getSignature()).isEqualTo(HeaderSignature.CENTRAL_DIRECTORY);
assertThat(fileHeader.getVersionMadeBy()).isEqualTo(819);
assertThat(fileHeader.getVersionNeededToExtract()).isEqualTo(versionNeededToExtract);
verifyCompressionMethod(fileHeader, zipParameters);
assertThat(fileHeader.isEncrypted()).isEqualTo(zipParameters.isEncryptFiles());
assertThat(fileHeader.getEncryptionMethod()).isEqualTo(zipParameters.isEncryptFiles()
? zipParameters.getEncryptionMethod() : EncryptionMethod.NONE);
assertThat(fileHeader.getFileName()).isEqualTo(FILE_NAME_IN_ZIP);
assertThat(fileHeader.getFileNameLength()).isEqualTo(FILE_NAME_IN_ZIP.length());
verifyGeneralPurposeBytes(fileHeader.getGeneralPurposeFlag(), zipParameters);
assertThat(fileHeader.getDiskNumberStart()).isEqualTo(isSplitZip ? diskNumberStart : 0);
verifyLastModifiedFileTime(fileHeader, zipParameters);
verifyExternalFileAttributes(fileHeader);
assertThat(fileHeader.isDirectory()).isEqualTo(false);
if (zipParameters.isWriteExtendedLocalFileHeader()) {
assertThat(fileHeader.getUncompressedSize()).isEqualTo(0);
} else {
assertThat(fileHeader.getUncompressedSize()).isEqualTo(zipParameters.getEntrySize());
}
verifyCrc(fileHeader);
assertThat(fileHeader.isDataDescriptorExists()).isEqualTo(zipParameters.isWriteExtendedLocalFileHeader());
assertThat(fileHeader.getAesExtraDataRecord() != null).isEqualTo(aesExtraDataRecordPresent);
assertThat(fileHeader.getExtraFieldLength()).isEqualTo(aesExtraDataRecordPresent ? InternalZipConstants.AES_EXTRA_DATA_RECORD_SIZE : 0);
}
private void verifyLocalFileHeader(LocalFileHeader localFileHeader, long lastModifiedFileTime) {
assertThat(localFileHeader).isNotNull();
assertThat(localFileHeader.getSignature()).isEqualTo(HeaderSignature.LOCAL_FILE_HEADER);
assertThat(localFileHeader.getVersionNeededToExtract()).isEqualTo(20);
assertThat(localFileHeader.getCompressionMethod()).isEqualTo(CompressionMethod.STORE);
assertThat(localFileHeader.getLastModifiedTime()).isEqualTo(lastModifiedFileTime);
assertThat(localFileHeader.getUncompressedSize()).isEqualTo(1000L);
assertThat(localFileHeader.getFileName()).isEqualTo(FILE_NAME_IN_ZIP);
assertThat(localFileHeader.getFileNameLength()).isEqualTo(FILE_NAME_IN_ZIP.length());
assertThat(localFileHeader.isEncrypted()).isEqualTo(true);
assertThat(localFileHeader.getEncryptionMethod()).isEqualTo(EncryptionMethod.AES);
assertThat(localFileHeader.getCrc()).isEqualTo(1231231L);
assertThat(localFileHeader.getCompressedSize()).isEqualTo(23523L);
assertThat(localFileHeader.getGeneralPurposeFlag()).containsExactly(2, 28);
assertThat(localFileHeader.isDataDescriptorExists()).isTrue();
assertThat(localFileHeader.getExtraFieldLength()).isEqualTo(190);
}
private void verifyExternalFileAttributes(FileHeader fileHeader) {
if (FileUtils.isUnix() || FileUtils.isMac()) {
if (FileUtils.isZipEntryDirectory(fileHeader.getFileName())) {
assertThat(fileHeader.getExternalFileAttributes()).isEqualTo(FileUtils.DEFAULT_POSIX_FOLDER_ATTRIBUTES);
} else {
assertThat(fileHeader.getExternalFileAttributes()).isEqualTo(FileUtils.DEFAULT_POSIX_FILE_ATTRIBUTES);
}
} else {
assertThat(fileHeader.getExternalFileAttributes()).isEqualTo(new byte[4]);
}
}
private void verifyCompressionMethod(FileHeader fileHeader, ZipParameters zipParameters) {
if (fileHeader.isEncrypted() && fileHeader.getEncryptionMethod().equals(EncryptionMethod.AES)) {
assertThat(fileHeader.getCompressionMethod()).isEqualTo(CompressionMethod.AES_INTERNAL_ONLY);
} else {
assertThat(fileHeader.getCompressionMethod()).isEqualTo(zipParameters.getCompressionMethod());
}
}
private void verifyLastModifiedFileTime(FileHeader fileHeader, ZipParameters zipParameters) {
if (zipParameters.getLastModifiedFileTime() > 0) {
assertThat(fileHeader.getLastModifiedTime()).isEqualTo(epochToExtendedDosTime(
zipParameters.getLastModifiedFileTime()));
} else {
assertThat(fileHeader.getLastModifiedTime()).isGreaterThan(0);
}
}
private void verifyGeneralPurposeBytes(byte[] generalPurposeBytes, ZipParameters zipParameters) {
assertThat(generalPurposeBytes).isNotNull();
assertThat(generalPurposeBytes.length).isEqualTo(2);
assertThat(isBitSet(generalPurposeBytes[0], 0)).isEqualTo(zipParameters.isEncryptFiles());
if (zipParameters.getCompressionMethod() == CompressionMethod.DEFLATE) {
verifyCompressionLevelGridForDeflate(zipParameters.getCompressionLevel(),
generalPurposeBytes[0]);
} else {
assertThat(isBitSet(generalPurposeBytes[0], 1)).isFalse();
assertThat(isBitSet(generalPurposeBytes[0], 2)).isFalse();
}
assertThat(isBitSet(generalPurposeBytes[0], 3)).isEqualTo(zipParameters.isWriteExtendedLocalFileHeader());
assertThat(isBitSet(generalPurposeBytes[1], 3)).isTrue();
}
private void verifyCompressionLevelGridForDeflate(CompressionLevel compressionLevel,
byte firstByteOfGeneralPurposeBytes) {
if (CompressionLevel.NORMAL.equals(compressionLevel)) {
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 1)).isFalse();
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 2)).isFalse();
} else if (CompressionLevel.MAXIMUM.equals(compressionLevel)) {
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 1)).isTrue();
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 2)).isFalse();
} else if (CompressionLevel.FAST.equals(compressionLevel)) {
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 1)).isFalse();
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 2)).isTrue();
} else if (CompressionLevel.FASTEST.equals(compressionLevel)
|| CompressionLevel.ULTRA.equals(compressionLevel)) {
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 1)).isTrue();
assertThat(isBitSet(firstByteOfGeneralPurposeBytes, 2)).isTrue();
} else {
throw new RuntimeException("Invalid compression level");
}
}
private void verifyCrc(FileHeader fileHeader) {
if (fileHeader.isEncrypted() && fileHeader.getEncryptionMethod() == EncryptionMethod.ZIP_STANDARD) {
assertThat(fileHeader.getCrc()).isEqualTo(ENTRY_CRC);
} else {
assertThat(fileHeader.getCrc()).isEqualTo(0);
}
}
private void verifyAesExtraDataRecord(AESExtraDataRecord aesExtraDataRecord, AesKeyStrength aesKeyStrength,
CompressionMethod compressionMethod, AesVersion aesVersion) {
assertThat(aesExtraDataRecord).isNotNull();
assertThat(aesExtraDataRecord.getSignature()).isEqualTo(HeaderSignature.AES_EXTRA_DATA_RECORD);
assertThat(aesExtraDataRecord.getDataSize()).isEqualTo(7);
assertThat(aesExtraDataRecord.getVendorID()).isEqualTo("AE");
assertThat(aesExtraDataRecord.getCompressionMethod()).isEqualTo(compressionMethod);
assertThat(aesExtraDataRecord.getAesVersion()).isEqualTo(aesVersion);
assertThat(aesExtraDataRecord.getAesKeyStrength()).isEqualTo(aesKeyStrength);
}
private void changeOsSystemPropertyToWindows() {
System.setProperty("os.name", "windows");
}
private void changeOsSystemPropertyToUnix() {
System.setProperty("os.name", "nux");
}
private void changeOsSystemPropertyToMac() {
System.setProperty("os.name", "mac");
}
private void restoreOsSystemProperty() {
System.setProperty("os.name", ACTUAL_OS);
}
} zip4j-2.9.1/src/test/java/net/lingala/zip4j/headers/HeaderReaderIT.java 0000664 0000000 0000000 00000046344 14142654472 0025561 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.model.CentralDirectory;
import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.util.BitUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import org.junit.Test;
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.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class HeaderReaderIT extends AbstractIT {
private static final String FILE_NAME_PREFIX = "FILE_NAME_ÄÜß_";
private static final String END_OF_CENTRAL_DIR_COMMENT = "END_OF_CENTRAL_DIR_COMMENT_ÜÄÖÖÖÄ";
private FileHeaderFactory fileHeaderFactory = new FileHeaderFactory();
private HeaderReader headerReader = new HeaderReader();
private HeaderWriter headerWriter = new HeaderWriter();
private RawIO rawIO = new RawIO();
@Test
public void testReadAllHeadersWith10Entries() throws IOException {
int numberOfEntries = 10;
ZipModel actualZipModel = generateZipHeadersFile(numberOfEntries, EncryptionMethod.NONE);
try(RandomAccessFile randomAccessFile = initializeRandomAccessFile(actualZipModel.getZipFile())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10, false);
assertThat(readZipModel.getEndOfCentralDirectoryRecord().getComment()).isEmpty();
}
}
@Test
public void testReadAllHeadersWithEndOfCentralDirectoryComment() throws IOException {
ZipModel actualZipModel = generateZipModel(1);
actualZipModel.getEndOfCentralDirectoryRecord().setComment(END_OF_CENTRAL_DIR_COMMENT);
File headersFile = writeZipHeaders(actualZipModel);
actualZipModel.setZipFile(headersFile);
try(RandomAccessFile randomAccessFile = initializeRandomAccessFile(actualZipModel.getZipFile())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 1, false);
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = readZipModel.getEndOfCentralDirectoryRecord();
assertThat(endOfCentralDirectoryRecord.getComment()).isEqualTo(END_OF_CENTRAL_DIR_COMMENT);
}
}
@Test
public void testReadAllWithoutEndOfCentralDirectoryRecordThrowsException() throws IOException {
try(RandomAccessFile randomAccessFile = new RandomAccessFile(temporaryFolder.newFile(),
RandomAccessFileMode.WRITE.getValue())) {
//Create an empty file
randomAccessFile.seek(4000);
randomAccessFile.write(1);
headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e.getMessage()).isEqualTo("Zip headers not found. Probably not a zip file");
}
}
@Test
public void testReadAllWithoutEnoughHeaderDataThrowsException() throws IOException {
try(RandomAccessFile randomAccessFile = new RandomAccessFile(temporaryFolder.newFile(),
RandomAccessFileMode.WRITE.getValue())) {
//Create an empty file
randomAccessFile.seek(1000);
randomAccessFile.write(1);
headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e.getMessage()).isEqualTo("Zip headers not found. Probably not a zip file");
assertThat(e.getCause() instanceof IOException);
}
}
@Test
public void testReadAllWithoutFileHeaderSignatureThrowsException() throws IOException {
ZipModel actualZipModel = generateZipModel(2);
actualZipModel.getCentralDirectory().getFileHeaders().get(1).setSignature(HeaderSignature.DIGITAL_SIGNATURE);
File headersFile = writeZipHeaders(actualZipModel);
actualZipModel.setZipFile(headersFile);
try(RandomAccessFile randomAccessFile = new RandomAccessFile(actualZipModel.getZipFile(),
RandomAccessFileMode.READ.getValue())) {
headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
fail("Should throw an exception");
} catch (ZipException e) {
assertThat(e.getMessage()).isEqualTo("Expected central directory entry not found (#2)");
}
}
@Test
public void testReadAllWithoutFileNameWritesNull() throws IOException {
ZipModel actualZipModel = generateZipModel(1);
actualZipModel.getCentralDirectory().getFileHeaders().get(0).setFileName(null);
File headersFile = writeZipHeaders(actualZipModel);
actualZipModel.setZipFile(headersFile);
try(RandomAccessFile randomAccessFile = new RandomAccessFile(actualZipModel.getZipFile(),
RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
FileHeader fileHeader = readZipModel.getCentralDirectory().getFileHeaders().get(0);
assertThat(fileHeader.getFileName()).isNull();
}
}
@Test
public void testReadAllWithJapaneseCharacters() throws IOException {
testWithoutUtf8FileName("公ゃ的年社", "育ざどろめ", true, false);
}
@Test
public void testReadAllWithoutUtf8FlagDecodesWithoutCharsetFlagForJapaneseCharactersMatches()
throws IOException {
testWithoutUtf8FileName("公ゃ的年社", "育ざどろめ", true, true, InternalZipConstants.CHARSET_UTF_8);
}
@Test
public void testReadAllWithoutUtf8FlagAndWithoutCharsetForJapaneseCharactersDoesNotMatch()
throws IOException {
testWithoutUtf8FileName("公ゃ的年社", "育ざどろめ", false, true, null);
}
@Test
public void testReadAllWithoutUtf8FlagDecodesWithoutCharsetFlagForEnglishCharactersMatches()
throws IOException {
testWithoutUtf8FileName("SOME_TEXT", "SOME_COMMENT", true, true);
}
@Test
public void testReadAllWithAesEncryption() throws IOException {
ZipModel actualZipModel = generateZipHeadersFile(3, EncryptionMethod.AES);
try(RandomAccessFile randomAccessFile = new RandomAccessFile(actualZipModel.getZipFile(),
RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
for (FileHeader fileHeader : readZipModel.getCentralDirectory().getFileHeaders()) {
assertThat(fileHeader.getAesExtraDataRecord()).isNotNull();
assertThat(fileHeader.getAesExtraDataRecord().getAesKeyStrength()).isEqualTo(AesKeyStrength.KEY_STRENGTH_256);
}
}
}
@Test
public void testReadAllWithStandardZipEncryption() throws IOException {
ZipModel actualZipModel = generateZipHeadersFile(3, EncryptionMethod.ZIP_STANDARD);
try(RandomAccessFile randomAccessFile = new RandomAccessFile(actualZipModel.getZipFile(),
RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
for (FileHeader fileHeader : readZipModel.getCentralDirectory().getFileHeaders()) {
assertThat(fileHeader.isEncrypted()).isTrue();
assertThat(fileHeader.getEncryptionMethod()).isEqualTo(EncryptionMethod.ZIP_STANDARD);
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
}
}
}
@Test
public void testReadAllZip64Format() throws IOException {
ZipModel actualZipModel = generateZipModel(1);
long entrySize = InternalZipConstants.ZIP_64_SIZE_LIMIT + 1;
actualZipModel.getCentralDirectory().getFileHeaders().get(0).setUncompressedSize(entrySize);
actualZipModel.getCentralDirectory().getFileHeaders().get(0).setCompressedSize(entrySize + 100);
File headersFile = writeZipHeaders(actualZipModel);
actualZipModel.setZipFile(headersFile);
try(RandomAccessFile randomAccessFile = new RandomAccessFile(actualZipModel.getZipFile(),
RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
assertThat(readZipModel.isZip64Format()).isTrue();
assertThat(readZipModel.getZip64EndOfCentralDirectoryRecord()).isNotNull();
assertThat(readZipModel.getZip64EndOfCentralDirectoryLocator()).isNotNull();
FileHeader fileHeader = actualZipModel.getCentralDirectory().getFileHeaders().get(0);
assertThat(fileHeader.getUncompressedSize()).isEqualTo(entrySize);
assertThat(fileHeader.getCompressedSize()).isEqualTo(entrySize + 100);
}
}
@Test
public void testReadLocalFileHeader() throws IOException {
long entrySize = InternalZipConstants.ZIP_64_SIZE_LIMIT + 1;
File headerFile = generateAndWriteLocalFileHeader(entrySize, EncryptionMethod.NONE);
try(InputStream inputStream = new FileInputStream(headerFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
assertThat(readLocalFileHeader).isNotNull();
assertThat(readLocalFileHeader.getCompressedSize()).isEqualTo(entrySize);
assertThat(readLocalFileHeader.getUncompressedSize()).isEqualTo(entrySize);
}
}
@Test
public void testReadLocalFileHeaderWithAesEncryption() throws IOException {
long entrySize = InternalZipConstants.ZIP_64_SIZE_LIMIT - 1001 ;
File headerFile = generateAndWriteLocalFileHeader(entrySize, EncryptionMethod.AES);
try(InputStream inputStream = new FileInputStream(headerFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
assertThat(readLocalFileHeader).isNotNull();
assertThat(readLocalFileHeader.getCompressedSize()).isEqualTo(entrySize);
assertThat(readLocalFileHeader.getUncompressedSize()).isEqualTo(entrySize);
assertThat(readLocalFileHeader.getAesExtraDataRecord()).isNotNull();
assertThat(readLocalFileHeader.getAesExtraDataRecord().getAesKeyStrength())
.isEqualTo(AesKeyStrength.KEY_STRENGTH_256);
}
}
@Test
public void testReadLocalFileHeaderWithTemporarySpanningMarker() throws IOException {
long entrySize = InternalZipConstants.ZIP_64_SIZE_LIMIT + 1;
File headerFile = generateAndWriteLocalFileHeader(HeaderSignature.TEMPORARY_SPANNING_MARKER, entrySize, EncryptionMethod.NONE);
try(InputStream inputStream = new FileInputStream(headerFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
assertThat(readLocalFileHeader).isNotNull();
assertThat(readLocalFileHeader.getCompressedSize()).isEqualTo(entrySize);
assertThat(readLocalFileHeader.getUncompressedSize()).isEqualTo(entrySize);
}
}
@Test
public void testReadDataDescriptorWithSignature() {
}
private void testWithoutUtf8FileName(String fileName, String entryComment, boolean shouldFileNamesMatch,
boolean unsetUtf8Flag) throws IOException {
testWithoutUtf8FileName(fileName, entryComment, shouldFileNamesMatch, unsetUtf8Flag, null);
}
private void testWithoutUtf8FileName(String fileName, String entryComment, boolean shouldFileNamesMatch,
boolean unsetUtf8Flag, Charset charsetToUseForReading) throws IOException {
ZipModel actualZipModel = generateZipModel(3);
FileHeader secondFileHeader = actualZipModel.getCentralDirectory().getFileHeaders().get(1);
if (unsetUtf8Flag) {
// Unset utf8 flag
byte[] generalPurposeBytes = secondFileHeader.getGeneralPurposeFlag();
generalPurposeBytes[1] = BitUtils.unsetBit(generalPurposeBytes[1], 3);
secondFileHeader.setGeneralPurposeFlag(generalPurposeBytes);
}
secondFileHeader.setFileName(fileName);
secondFileHeader.setFileComment(entryComment);
File headersFile = writeZipHeaders(actualZipModel);
actualZipModel.setZipFile(headersFile);
try(RandomAccessFile randomAccessFile = new RandomAccessFile(actualZipModel.getZipFile(),
RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildConfig(charsetToUseForReading));
FileHeader fileHeader = readZipModel.getCentralDirectory().getFileHeaders().get(1);
if (shouldFileNamesMatch) {
assertThat(fileHeader.getFileName()).isEqualTo(fileName);
assertThat(fileHeader.getFileComment()).isEqualTo(entryComment);
} else {
assertThat(fileHeader.getFileName()).isNotEqualTo(fileName);
assertThat(fileHeader.getFileComment()).isNotEqualTo(entryComment);
}
assertThat(readZipModel.getCentralDirectory().getFileHeaders().get(0).getFileCommentLength()).isEqualTo(0);
assertThat(readZipModel.getCentralDirectory().getFileHeaders().get(0).getFileComment()).isNull();
assertThat(readZipModel.getCentralDirectory().getFileHeaders().get(2).getFileCommentLength()).isEqualTo(0);
assertThat(readZipModel.getCentralDirectory().getFileHeaders().get(2).getFileComment()).isNull();
}
}
private RandomAccessFile initializeRandomAccessFile(File headersFile) throws IOException {
return new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue());
}
private void verifyZipModel(ZipModel readZipModel, int numberOfExpectedEntries, boolean isZip64) {
assertThat(readZipModel).isNotNull();
verifyEndOfCentralDirectory(readZipModel.getEndOfCentralDirectoryRecord(), numberOfExpectedEntries, isZip64);
verifyCentralDirectory(readZipModel.getCentralDirectory(), numberOfExpectedEntries);
}
private void verifyEndOfCentralDirectory(EndOfCentralDirectoryRecord endOfCentralDirectoryRecord, int numberOfEntries,
boolean isZip64) {
assertThat(endOfCentralDirectoryRecord).isNotNull();
endOfCentralDirectoryRecord.setSignature(HeaderSignature.END_OF_CENTRAL_DIRECTORY);
assertThat(endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectory()).isEqualTo(numberOfEntries);
if (!isZip64) {
assertThat(endOfCentralDirectoryRecord.getNumberOfThisDisk()).isEqualTo(0);
assertThat(endOfCentralDirectoryRecord.getNumberOfThisDiskStartOfCentralDir()).isEqualTo(0);
assertThat(endOfCentralDirectoryRecord.getTotalNumberOfEntriesInCentralDirectoryOnThisDisk())
.isEqualTo(numberOfEntries);
assertThat(endOfCentralDirectoryRecord.getSizeOfCentralDirectory()).isNotZero();
}
}
private void verifyCentralDirectory(CentralDirectory centralDirectory, int numberOfExpectedEntries) {
assertThat(centralDirectory).isNotNull();
verifyFileHeaders(centralDirectory.getFileHeaders(), numberOfExpectedEntries);
}
private void verifyFileHeaders(List fileHeaders, int numberOfExpectedEntries) {
assertThat(fileHeaders).isNotEmpty();
assertThat(fileHeaders).hasSize(numberOfExpectedEntries);
for (int i = 0; i < numberOfExpectedEntries; i++) {
String expectedFileName = FILE_NAME_PREFIX + i;
FileHeader fileHeader = fileHeaders.get(i);
assertThat(fileHeader.getFileName()).isEqualTo(expectedFileName);
int expectedFileNameLength = expectedFileName.getBytes(InternalZipConstants.CHARSET_UTF_8).length;
assertThat(fileHeader.getFileNameLength()).isEqualTo(expectedFileNameLength);
}
}
private ZipModel generateZipHeadersFile(int numberOfEntries, EncryptionMethod encryptionMethod)
throws IOException {
ZipModel zipModel = generateZipModel(numberOfEntries, encryptionMethod);
File headersFile = writeZipHeaders(zipModel);
zipModel.setZipFile(headersFile);
return zipModel;
}
private ZipModel generateZipModel(int numberOfEntries) throws ZipException {
return generateZipModel(numberOfEntries, EncryptionMethod.NONE);
}
private ZipModel generateZipModel(int numberOfEntries, EncryptionMethod encryptionMethod)
throws ZipException {
ZipParameters zipParameters = generateZipParameters(encryptionMethod);
ZipModel zipModel = new ZipModel();
zipModel.getCentralDirectory().setFileHeaders(generateFileHeaders(zipParameters, numberOfEntries));
return zipModel;
}
private ZipParameters generateZipParameters(EncryptionMethod encryptionMethod) {
ZipParameters zipParameters = new ZipParameters();
if (encryptionMethod != null && encryptionMethod != EncryptionMethod.NONE) {
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(encryptionMethod);
}
return zipParameters;
}
private List generateFileHeaders(ZipParameters zipParameters, int numberOfEntries)
throws ZipException {
List fileHeaders = new ArrayList<>();
for (int i = 0; i < numberOfEntries; i++) {
zipParameters.setFileNameInZip(FILE_NAME_PREFIX + i);
FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO);
fileHeaders.add(fileHeader);
}
return fileHeaders;
}
private LocalFileHeader generateLocalFileHeader(long entrySize, EncryptionMethod encryptionMethod)
throws ZipException {
List fileHeaders = generateFileHeaders(generateZipParameters(encryptionMethod), 1);
LocalFileHeader localFileHeader = fileHeaderFactory.generateLocalFileHeader(fileHeaders.get(0));
localFileHeader.setCompressedSize(entrySize);
localFileHeader.setUncompressedSize(entrySize);
return localFileHeader;
}
private File generateAndWriteLocalFileHeader(long entrySize, EncryptionMethod encryptionMethod)
throws IOException {
return generateAndWriteLocalFileHeader(null, entrySize, encryptionMethod);
}
private File generateAndWriteLocalFileHeader(HeaderSignature headerSignature, long entrySize, EncryptionMethod encryptionMethod)
throws IOException {
LocalFileHeader localFileHeader = generateLocalFileHeader(entrySize, encryptionMethod);
if (encryptionMethod != null && encryptionMethod != EncryptionMethod.NONE) {
localFileHeader.setEncrypted(true);
localFileHeader.setEncryptionMethod(encryptionMethod);
}
ZipModel zipModel = generateZipModel(1);
File headerFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headerFile)) {
if (headerSignature != null) {
final RawIO rawIO = new RawIO();
rawIO.writeIntLittleEndian(outputStream, (int) headerSignature.getValue());
}
headerWriter.writeLocalFileHeader(zipModel, localFileHeader, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
return headerFile;
}
private File writeZipHeaders(ZipModel zipModel) throws IOException {
File headersFile = temporaryFolder.newFile();
try(SplitOutputStream splitOutputStream = new SplitOutputStream(headersFile)) {
headerWriter.finalizeZipFile(zipModel, splitOutputStream, InternalZipConstants.CHARSET_UTF_8);
return headersFile;
}
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/headers/HeaderUtilTest.java 0000664 0000000 0000000 00000026121 14142654472 0025666 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.CentralDirectory;
import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.Zip64ExtendedInfo;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class HeaderUtilTest {
private static final String FILE_NAME = "test.txt";
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testGetFileHeaderWithNullZipModelThrowsException() throws ZipException {
expectZipException("zip model is null, cannot determine file header with exact match for fileName: " + FILE_NAME);
HeaderUtil.getFileHeader(null, FILE_NAME);
}
@Test
public void testGetFileHeaderWithNullFileNameThrowsException() throws ZipException {
expectZipException("file name is null, cannot determine file header with exact match for fileName: null");
HeaderUtil.getFileHeader(new ZipModel(), null);
}
@Test
public void testGetFileHeaderWithEmptyFileNameThrowsException() throws ZipException {
expectZipException("file name is null, cannot determine file header with exact match for fileName: ");
HeaderUtil.getFileHeader(new ZipModel(), "");
}
@Test
public void testGetFileHeaderWithNullCentralDirectoryThrowsException() throws ZipException {
expectZipException("central directory is null, cannot determine file header with exact match for fileName: "
+ FILE_NAME);
ZipModel zipModel = new ZipModel();
zipModel.setCentralDirectory(null);
HeaderUtil.getFileHeader(zipModel, FILE_NAME);
}
@Test
public void testGetFileHeaderWithNullFileHeadersThrowsException() throws ZipException {
expectedException.expect(ZipException.class);
expectZipException("file Headers are null, cannot determine file header with exact match for fileName: "
+ FILE_NAME);
ZipModel zipModel = new ZipModel();
CentralDirectory centralDirectory = new CentralDirectory();
centralDirectory.setFileHeaders(null);
zipModel.setCentralDirectory(centralDirectory);
HeaderUtil.getFileHeader(zipModel, FILE_NAME);
}
@Test
public void testGetFileHeaderWithEmptyFileHeadersReturnsNull() throws ZipException {
ZipModel zipModel = new ZipModel();
CentralDirectory centralDirectory = new CentralDirectory();
centralDirectory.setFileHeaders(Collections.emptyList());
zipModel.setCentralDirectory(centralDirectory);
FileHeader fileHeader = HeaderUtil.getFileHeader(zipModel, FILE_NAME);
assertThat(fileHeader).isNull();
}
@Test
public void testGetFileHeaderWithExactMatch() throws ZipException {
ZipModel zipModel = new ZipModel();
CentralDirectory centralDirectory = new CentralDirectory();
centralDirectory.setFileHeaders(Arrays.asList(
generateFileHeader(null),
generateFileHeader(""),
generateFileHeader("SOME_OTHER_NAME"),
generateFileHeader(FILE_NAME)
));
zipModel.setCentralDirectory(centralDirectory);
FileHeader fileHeader = HeaderUtil.getFileHeader(zipModel, FILE_NAME);
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getFileName()).isEqualTo(FILE_NAME);
}
@Test
public void testGetFileHeaderWithWindowsFileSeparator() throws ZipException {
ZipModel zipModel = new ZipModel();
CentralDirectory centralDirectory = new CentralDirectory();
centralDirectory.setFileHeaders(Arrays.asList(
generateFileHeader(FILE_NAME),
generateFileHeader("SOME_OTHER_NAME\\")
));
zipModel.setCentralDirectory(centralDirectory);
FileHeader fileHeader = HeaderUtil.getFileHeader(zipModel, "SOME_OTHER_NAME\\");
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getFileName()).isEqualTo("SOME_OTHER_NAME\\");
}
@Test
public void testGetFileHeaderWithUnixFileSeparator() throws ZipException {
ZipModel zipModel = new ZipModel();
CentralDirectory centralDirectory = new CentralDirectory();
centralDirectory.setFileHeaders(Arrays.asList(
generateFileHeader(FILE_NAME),
generateFileHeader("SOME_OTHER_NAME/")
));
zipModel.setCentralDirectory(centralDirectory);
FileHeader fileHeader = HeaderUtil.getFileHeader(zipModel, "SOME_OTHER_NAME/");
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getFileName()).isEqualTo("SOME_OTHER_NAME/");
}
@Test
public void testGetFileHeaderWithoutAMatch() throws ZipException {
ZipModel zipModel = new ZipModel();
CentralDirectory centralDirectory = new CentralDirectory();
centralDirectory.setFileHeaders(Arrays.asList(
generateFileHeader(FILE_NAME),
generateFileHeader("SOME_OTHER_NAME")
));
zipModel.setCentralDirectory(centralDirectory);
assertThat(HeaderUtil.getFileHeader(zipModel, "SHOULD_NOT_EXIST")).isNull();
}
@Test
public void testDecodeStringWithCharsetForUtf8() {
String utf8StringToEncode = "asdäüöö";
byte[] utf8EncodedBytes = utf8StringToEncode.getBytes(InternalZipConstants.CHARSET_UTF_8);
assertThat(HeaderUtil.decodeStringWithCharset(utf8EncodedBytes, true, null)).isEqualTo(utf8StringToEncode);
}
@Test
public void testDecodeStringWithCharsetWithCharsetGBKForChineseString() {
String chineseStringToEncode = "写記立要";
byte[] gbkEncodedBytes = chineseStringToEncode.getBytes(Charset.forName("GBK"));
String decodedString = HeaderUtil.decodeStringWithCharset(gbkEncodedBytes, false, Charset.forName("GBK"));
assertThat(decodedString).isEqualTo(chineseStringToEncode);
}
@Test
public void testDecodeStringWithCharsetWithoutUtf8AndWithEnglishChars() {
String plainString = "asdasda234234";
byte[] plainEncodedBytes = plainString.getBytes();
assertThat(HeaderUtil.decodeStringWithCharset(plainEncodedBytes, false, null)).isEqualTo(plainString);
}
@Test
public void testDecodeStringWithCharsetWithISO8859AndFinnishChars() {
String finnishString = "asdäüöö";
byte[] plainEncodedBytes = finnishString.getBytes(StandardCharsets.ISO_8859_1);
assertThat(HeaderUtil.decodeStringWithCharset(plainEncodedBytes, false, StandardCharsets.ISO_8859_1)).isEqualTo(finnishString);
}
@Test
public void testDecodeStringWithCharsetWithUTF8CharsetAndKoreanChars() {
String koreanString = "가나다";
byte[] plainEncodedBytes = koreanString.getBytes(InternalZipConstants.CHARSET_UTF_8);
assertThat(HeaderUtil.decodeStringWithCharset(plainEncodedBytes, true, null)).isEqualTo(koreanString);
}
@Test
public void testDecodeStringWithCharsetWithNullCharsetAndEnglishChars() {
String englishString = "asdasda234234";
byte[] plainEncodedBytes = englishString.getBytes();
assertThat(HeaderUtil.decodeStringWithCharset(plainEncodedBytes, false, null)).isEqualTo(englishString);
}
@Test
public void testGetFileHeadersUnderDirectoryWhenNotDirectoryReturnsEmptyList() {
List allFileHeaders = generateFileHeaderWithFileNames("header", 5);
assertThat(HeaderUtil.getFileHeadersUnderDirectory(allFileHeaders, "some_name")).isEmpty();
}
@Test
public void testGetFileHeadersUnderDirectoryReturnsFileHeadersUnderDirectory() {
List allFileHeaders = generateFileHeaderWithFileNames("some_name/header", 5);
allFileHeaders.add(generateFileHeader("some_name/"));
allFileHeaders.add(generateFileHeader("some_other_name.txt"));
List filHeadersUnderDirectory = HeaderUtil.getFileHeadersUnderDirectory(allFileHeaders, "some_name/");
assertThat(filHeadersUnderDirectory).hasSize(6);
for (FileHeader fileHeader : filHeadersUnderDirectory) {
assertThat(fileHeader)
.withFailMessage("file header with name some_other_name.txt should not exist")
.isNotEqualTo("some_other_name.txt");
}
}
@Test
public void testGetUncompressedSizeOfAllFileHeaders() {
FileHeader fileHeader1 = generateFileHeader("1");
fileHeader1.setUncompressedSize(1000);
FileHeader fileHeader2 = generateFileHeader("2");
fileHeader2.setUncompressedSize(2000);
FileHeader fileHeader3 = generateFileHeader("3");
Zip64ExtendedInfo zip64ExtendedInfo = new Zip64ExtendedInfo();
zip64ExtendedInfo.setUncompressedSize(3000);
fileHeader3.setZip64ExtendedInfo(zip64ExtendedInfo);
fileHeader3.setUncompressedSize(0);
List fileHeaders = Arrays.asList(fileHeader1, fileHeader2, fileHeader3);
assertThat(HeaderUtil.getTotalUncompressedSizeOfAllFileHeaders(fileHeaders)).isEqualTo(6000);
}
@Test
public void testGetOffsetStartOfCentralDirectoryForZip64Format() {
long offsetCentralDirectory = InternalZipConstants.ZIP_64_SIZE_LIMIT + 100;
ZipModel zipModel = new ZipModel();
zipModel.setZip64Format(true);
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = new Zip64EndOfCentralDirectoryRecord();
zip64EndOfCentralDirectoryRecord.setOffsetStartCentralDirectoryWRTStartDiskNumber(offsetCentralDirectory);
zipModel.setZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord);
assertThat(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel)).isEqualTo(offsetCentralDirectory);
}
@Test
public void testGetOffsetStartOfCentralDirectoryForNonZip64Format() {
long offsetStartOfCentralDirectory = InternalZipConstants.ZIP_64_SIZE_LIMIT - 100;
ZipModel zipModel = new ZipModel();
zipModel.setZip64Format(false);
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = new EndOfCentralDirectoryRecord();
endOfCentralDirectoryRecord.setOffsetOfStartOfCentralDirectory(offsetStartOfCentralDirectory);
zipModel.setEndOfCentralDirectoryRecord(endOfCentralDirectoryRecord);
assertThat(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel)).isEqualTo(offsetStartOfCentralDirectory);
}
private List generateFileHeaderWithFileNamesWithEmptyAndNullFileNames(String fileNamePrefix, int numberOfEntriesToAdd) {
List fileHeaders = generateFileHeaderWithFileNames(fileNamePrefix, numberOfEntriesToAdd);
fileHeaders.add(generateFileHeader(""));
fileHeaders.add(generateFileHeader(null));
return fileHeaders;
}
private List generateFileHeaderWithFileNames(String fileNamePrefix, int numberOfEntriesToAdd) {
List fileHeaders = new ArrayList<>();
for (int i = 0; i < numberOfEntriesToAdd; i++) {
fileHeaders.add(generateFileHeader(fileNamePrefix + i));
}
return fileHeaders;
}
private FileHeader generateFileHeader(String fileName) {
FileHeader fileHeader = new FileHeader();
fileHeader.setFileName(fileName);
return fileHeader;
}
private void expectZipException(String message) {
expectedException.expectMessage(message);
expectedException.expect(ZipException.class);
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/headers/HeaderWriterIT.java 0000664 0000000 0000000 00000103262 14142654472 0025624 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.headers;
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.outputstream.CountingOutputStream;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.CentralDirectory;
import net.lingala.zip4j.model.DataDescriptor;
import net.lingala.zip4j.model.ExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.Zip64ExtendedInfo;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.util.BitUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.RawIO;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
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.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import static net.lingala.zip4j.util.Zip4jUtil.epochToExtendedDosTime;
import static org.assertj.core.api.Assertions.assertThat;
public class HeaderWriterIT extends AbstractIT {
private static final String FILE_NAME_PREFIX = "FILE_NAME_";
private static final long COMPRESSED_SIZE = 4234L;
private static final long UNCOMPRESSED_SIZE = 23423L;
private static final long COMPRESSED_SIZE_ZIP64 = InternalZipConstants.ZIP_64_SIZE_LIMIT + 1;
private static final long UNCOMPRESSED_SIZE_ZIP64 = InternalZipConstants.ZIP_64_SIZE_LIMIT + 1;
private static final int VERSION_MADE_BY = 20;
private static final int VERSION_NEEDED_TO_EXTRACT = 20;
private static final byte[] EXTERNAL_FILE_ATTRIBUTES = new byte[] {23, 43, 0, 0};
private static final String FILE_COMMENT_PREFIX = "FILE_COMMENT_PREFIX_";
private static final long LAST_MODIFIED_FILE_TIME = epochToExtendedDosTime(System.currentTimeMillis() / 1000);
@Rule
public ExpectedException expectedException = ExpectedException.none();
private RawIO rawIO = new RawIO();
private HeaderWriter headerWriter = new HeaderWriter();
private HeaderReader headerReader = new HeaderReader();
@Test
public void testWriteLocalFileHeaderSimpleLocalFileHeaderSuccessScenario() throws IOException {
ZipModel zipModel = createZipModel(10);
LocalFileHeader localFileHeaderToWrite = createLocalFileHeader("LFH", COMPRESSED_SIZE, UNCOMPRESSED_SIZE, true);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.writeLocalFileHeader(zipModel, localFileHeaderToWrite, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(InputStream inputStream = new FileInputStream(headersFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
verifyLocalFileHeader(readLocalFileHeader, FILE_NAME_PREFIX + "LFH", COMPRESSED_SIZE, UNCOMPRESSED_SIZE);
}
}
@Test
public void testWriteLocalFileHeaderForZip64Format() throws IOException {
ZipModel zipModel = createZipModel(10);
LocalFileHeader localFileHeaderToWrite = createLocalFileHeader("LFH", COMPRESSED_SIZE_ZIP64,
UNCOMPRESSED_SIZE_ZIP64, true);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.writeLocalFileHeader(zipModel, localFileHeaderToWrite, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(InputStream inputStream = new FileInputStream(headersFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
verifyLocalFileHeader(readLocalFileHeader, FILE_NAME_PREFIX + "LFH", COMPRESSED_SIZE_ZIP64,
UNCOMPRESSED_SIZE_ZIP64);
verifyZip64ExtendedInfo(readLocalFileHeader.getZip64ExtendedInfo(), COMPRESSED_SIZE_ZIP64,
UNCOMPRESSED_SIZE_ZIP64, -1, -1);
}
verifyEntrySizesIsMaxValueInLFHWhenZip64Format(headersFile);
}
@Test
public void testWriteLocalFileHeaderJapaneseCharactersInFileNameAndWithUtf8FlagShouldMatch()
throws IOException {
testWriteLocalFileHeaderWithFileName("公ゃ的年社", true, true);
}
@Test
public void testWriteLocalFileHeaderEnglishCharactersInFileNameWithoutUtf8ShouldMatch()
throws IOException {
testWriteLocalFileHeaderWithFileName("SOME_TEXT", false, true);
}
@Test
public void testWriteLocalFileHeaderJapaneseCharactersInFileNameWithoutUtf8ShouldMatch()
throws IOException {
testWriteLocalFileHeaderWithFileName("公ゃ的年社", false, true);
}
@Test
public void testWriteLocalFileHeaderJapaneseCharactersInFileNameWithUtf8ShouldMatch()
throws IOException {
testWriteLocalFileHeaderWithFileName("公ゃ的年社", true, true);
}
@Test
public void testWriteLocalFileHeaderJapaneseCharactersInFileNameWithCharsetMs932ShouldMatch()
throws IOException {
testWriteLocalFileHeaderWithFileNameAndCharset("公ゃ的年社", false, true, CHARSET_MS_932);
}
@Test
public void testWriteLocalFileHeaderJapaneseCharactersInFileNameWithUTF8CharsetWithUtf8ShouldMatch()
throws IOException {
testWriteLocalFileHeaderWithFileNameAndCharset("公ゃ的年社", true, true, InternalZipConstants.CHARSET_UTF_8);
}
@Test
public void testWriteLocalFileHeaderJapaneseCharactersInFileNameWithUTF8CharsetWithoutUtf8ShouldMatch()
throws IOException {
testWriteLocalFileHeaderWithFileNameAndCharset("公ゃ的年社", true, true, InternalZipConstants.CHARSET_UTF_8);
}
@Test
public void testWriteLocalFileHeaderWithAes256v1() throws IOException {
testWriteLocalFileHeaderWithAes(AesKeyStrength.KEY_STRENGTH_256, AesVersion.ONE);
}
@Test
public void testWriteLocalFileHeaderWithAes192v1() throws IOException {
testWriteLocalFileHeaderWithAes(AesKeyStrength.KEY_STRENGTH_192, AesVersion.ONE);
}
@Test
public void testWriteLocalFileHeaderWithAes128v1() throws IOException {
testWriteLocalFileHeaderWithAes(AesKeyStrength.KEY_STRENGTH_128, AesVersion.ONE);
}
@Test
public void testWriteLocalFileHeaderWithAes256v2() throws IOException {
testWriteLocalFileHeaderWithAes(AesKeyStrength.KEY_STRENGTH_256, AesVersion.TWO);
}
@Test
public void testWriteLocalFileHeaderWithAes192v2() throws IOException {
testWriteLocalFileHeaderWithAes(AesKeyStrength.KEY_STRENGTH_192, AesVersion.TWO);
}
@Test
public void testWriteLocalFileHeaderWithAes128v2() throws IOException {
testWriteLocalFileHeaderWithAes(AesKeyStrength.KEY_STRENGTH_128, AesVersion.TWO);
}
@Test
public void testWriteExtendedLocalFileHeaderWhenLocalFileHeaderIsNullThrowsException() throws IOException {
expectedException.expectMessage("input parameters is null, cannot write extended local header");
expectedException.expect(ZipException.class);
headerWriter.writeExtendedLocalHeader(null, new FileOutputStream(temporaryFolder.newFile()));
}
@Test
public void testWriteExtendedLocalFileHeaderWhenOutputStreamIsNullThrowsException() throws IOException {
expectedException.expectMessage("input parameters is null, cannot write extended local header");
expectedException.expect(ZipException.class);
headerWriter.writeExtendedLocalHeader(new LocalFileHeader(), null);
}
@Test
public void testWriteExtendedLocalFileHeaderNonZip64FormatWritesSuccessfully() throws IOException {
testWriteExtendedLocalFileHeader(COMPRESSED_SIZE + 99, UNCOMPRESSED_SIZE + 423, 2342342L, false);
}
@Test
public void testWriteExtendedLocalFileHeaderZip64FormatWritesSuccessfully() throws IOException {
testWriteExtendedLocalFileHeader(COMPRESSED_SIZE_ZIP64 + 99, UNCOMPRESSED_SIZE_ZIP64 + 423, 32452342L, true);
}
@Test
public void testFinalizeZipFileWhenZipModelNullThrowsException() throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters is null, cannot finalize zip file");
headerWriter.finalizeZipFile(null, new FileOutputStream(temporaryFolder.newFile()), InternalZipConstants.CHARSET_UTF_8);
}
@Test
public void testFinalizeZipFileWhenOutputStreamIsNullThrowsException() throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters is null, cannot finalize zip file");
headerWriter.finalizeZipFile(new ZipModel(), null, InternalZipConstants.CHARSET_UTF_8);
}
@Test
public void testFinalizeZipFileForNonZip64Format() throws IOException {
ZipModel zipModel = createZipModel(10);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.finalizeZipFile(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10);
for (FileHeader fileHeader : readZipModel.getCentralDirectory().getFileHeaders()) {
assertThat(fileHeader.getZip64ExtendedInfo()).isNull();
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
assertThat(fileHeader.getExtraFieldLength()).isZero();
}
}
}
@Test
public void testFinalizeZipFileWithNullExtraDataWritesSuccessfully() throws IOException {
testFinalizeZipFileWhenExtraDataRecordIsNullOrEmpty(null);
}
@Test
public void testFinalizeZipFileWithEmptyExtraDataWritesSuccessfully() throws IOException {
testFinalizeZipFileWhenExtraDataRecordIsNullOrEmpty(new byte[0]);
}
@Test
public void testFinalizeZipFileForZip64Format() throws IOException {
ZipModel zipModel = createZipModel(10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.finalizeZipFile(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, true);
List fileHeaders = readZipModel.getCentralDirectory().getFileHeaders();
for (FileHeader fileHeader : fileHeaders) {
verifyZip64ExtendedInfo(fileHeader.getZip64ExtendedInfo(), COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, 0,
0);
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
}
}
}
@Test
public void testFinalizeZipFileForAes() throws IOException {
ZipModel zipModel = createZipModel(10);
setFileHeadersAsAesEncrypted(zipModel.getCentralDirectory().getFileHeaders(), AesKeyStrength.KEY_STRENGTH_192);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.finalizeZipFile(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10);
for (FileHeader fileHeader : readZipModel.getCentralDirectory().getFileHeaders()) {
verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_192, AesVersion.TWO);
assertThat(fileHeader.getZip64ExtendedInfo()).isNull();
}
}
}
@Test
public void testFinalizeZipFileForZip64FormatForSplitFileWithSplitOutputStream() throws IOException {
ZipModel zipModel = createZipModel(10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64);
zipModel.setZip64EndOfCentralDirectoryRecord(null);
zipModel.setZip64EndOfCentralDirectoryLocator(null);
File headersFile = temporaryFolder.newFile();
try(SplitOutputStream outputStream = new SplitOutputStream(headersFile, 65536)) {
headerWriter.finalizeZipFile(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, true);
List fileHeaders = readZipModel.getCentralDirectory().getFileHeaders();
for (FileHeader fileHeader : fileHeaders) {
verifyZip64ExtendedInfo(fileHeader.getZip64ExtendedInfo(), COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, 0,
0);
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
}
}
}
@Test
public void testFinalizeZipFileForZip64FormatForSplitFileWithCountingOutputStream() throws IOException {
ZipModel zipModel = createZipModel(10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64);
File headersFile = temporaryFolder.newFile();
try(CountingOutputStream outputStream = new CountingOutputStream(new SplitOutputStream(headersFile, 65536))) {
headerWriter.finalizeZipFile(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, true);
List fileHeaders = readZipModel.getCentralDirectory().getFileHeaders();
for (FileHeader fileHeader : fileHeaders) {
verifyZip64ExtendedInfo(fileHeader.getZip64ExtendedInfo(), COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, 0,
0);
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
}
}
}
@Test
public void testFinalizeZipFileWithoutValidationsWhenZipModelNullThrowsException() throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters is null, cannot finalize zip file");
headerWriter.finalizeZipFileWithoutValidations(null, new FileOutputStream(temporaryFolder.newFile()), null);
}
@Test
public void testFinalizeZipFileWithoutValidationsWhenOutputStreamIsNullThrowsException()
throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("input parameters is null, cannot finalize zip file");
headerWriter.finalizeZipFileWithoutValidations(new ZipModel(), null, null);
}
@Test
public void testFinalizeZipFileWithoutValidationsForNonZip64Format() throws IOException {
ZipModel zipModel = createZipModel(10);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.finalizeZipFileWithoutValidations(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10);
for (FileHeader fileHeader : readZipModel.getCentralDirectory().getFileHeaders()) {
assertThat(fileHeader.getZip64ExtendedInfo()).isNull();
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
assertThat(fileHeader.getExtraFieldLength()).isZero();
}
}
}
@Test
public void testFinalizeZipFileWithoutValidationsForZip64Format() throws IOException {
ZipModel zipModel = createZipModel(10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.finalizeZipFileWithoutValidations(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, true);
List fileHeaders = readZipModel.getCentralDirectory().getFileHeaders();
for (FileHeader fileHeader : fileHeaders) {
verifyZip64ExtendedInfo(fileHeader.getZip64ExtendedInfo(), COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, 0,
0);
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
}
}
}
@Test
public void testUpdateLocalFileHeaderWhenFileHeaderIsNullThrowsException() throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("invalid input parameters, cannot update local file header");
headerWriter.updateLocalFileHeader(null, new ZipModel(), new SplitOutputStream(temporaryFolder.newFile()));
}
@Test
public void testUpdateLocalFileHeaderWhenZipModelIsNullThrowsException() throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("invalid input parameters, cannot update local file header");
headerWriter.updateLocalFileHeader(new FileHeader(), null, new SplitOutputStream(temporaryFolder.newFile()));
}
@Test
public void testUpdateLocalFileHeaderForNonZip64() throws IOException {
File headersFile = temporaryFolder.newFile();
createAndUpdateLocalFileHeader(headersFile, COMPRESSED_SIZE, UNCOMPRESSED_SIZE, 23423);
try (InputStream inputStream = new FileInputStream(headersFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
assertThat(readLocalFileHeader.getCompressedSize()).isEqualTo(COMPRESSED_SIZE + 100);
assertThat(readLocalFileHeader.getUncompressedSize()).isEqualTo(UNCOMPRESSED_SIZE + 100);
assertThat(readLocalFileHeader.getCrc()).isEqualTo(23423);
assertThat(readLocalFileHeader.getZip64ExtendedInfo()).isNull();
}
}
@Test
public void testUpdateLocalFileHeaderForZip64() throws IOException {
File headersFile = temporaryFolder.newFile();
createAndUpdateLocalFileHeader(headersFile, COMPRESSED_SIZE_ZIP64, UNCOMPRESSED_SIZE_ZIP64, 546423);
try (InputStream inputStream = new FileInputStream(headersFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
assertThat(readLocalFileHeader.getCompressedSize()).isEqualTo(COMPRESSED_SIZE_ZIP64 + 100);
assertThat(readLocalFileHeader.getUncompressedSize()).isEqualTo(UNCOMPRESSED_SIZE_ZIP64 + 100);
assertThat(readLocalFileHeader.getCrc()).isEqualTo(546423);
verifyZip64ExtendedInfo(readLocalFileHeader.getZip64ExtendedInfo(), COMPRESSED_SIZE_ZIP64 + 100,
UNCOMPRESSED_SIZE_ZIP64 + 100, -1, -1);
}
verifyEntrySizesIsMaxValueInLFHWhenZip64Format(headersFile);
}
private void testFinalizeZipFileWhenExtraDataRecordIsNullOrEmpty(byte[] extraDataRecord) throws IOException {
ZipModel zipModel = createZipModel(10);
File headersFile = temporaryFolder.newFile();
addExtraDataRecordToFirstFileHeader(zipModel, extraDataRecord);
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.finalizeZipFile(zipModel, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
verifyZipModel(readZipModel, 10);
for (int i = 0; i < zipModel.getCentralDirectory().getFileHeaders().size(); i++) {
FileHeader fileHeader = readZipModel.getCentralDirectory().getFileHeaders().get(i);
assertThat(fileHeader.getZip64ExtendedInfo()).isNull();
assertThat(fileHeader.getAesExtraDataRecord()).isNull();
assertThat(fileHeader.getExtraFieldLength()).isEqualTo(i == 0 ? 4 : 0);
}
}
}
private void createAndUpdateLocalFileHeader(File headersFile, long compressedSize, long uncompressedSize, long crc)
throws IOException {
ZipModel zipModel = createZipModel(3);
LocalFileHeader localFileHeaderToWrite = createLocalFileHeader("LFH", compressedSize, uncompressedSize, false);
localFileHeaderToWrite.setCompressedSize(compressedSize);
localFileHeaderToWrite.setUncompressedSize(uncompressedSize);
localFileHeaderToWrite.setCrc(10);
try (OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.writeLocalFileHeader(zipModel, localFileHeaderToWrite, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try (SplitOutputStream splitOutputStream = new SplitOutputStream(headersFile)) {
FileHeader fileHeader = createFileHeaders(1, compressedSize + 100, uncompressedSize + 100).get(0);
fileHeader.setFileName(localFileHeaderToWrite.getFileName());
fileHeader.setFileNameLength(fileHeader.getFileName().getBytes(InternalZipConstants.CHARSET_UTF_8).length);
fileHeader.setCrc(crc);
headerWriter.updateLocalFileHeader(fileHeader, zipModel, splitOutputStream);
}
}
private void setFileHeadersAsAesEncrypted(List fileHeaders, AesKeyStrength aesKeyStrength) {
for (FileHeader fileHeader : fileHeaders) {
fileHeader.setEncrypted(true);
fileHeader.setEncryptionMethod(EncryptionMethod.AES);
fileHeader.setAesExtraDataRecord(createAesExtraDataRecord(aesKeyStrength, AesVersion.TWO));
}
}
private void verifyZipModel(ZipModel zipModel, int numberOFEntriesInCentralDirectory) {
verifyZipModel(zipModel, numberOFEntriesInCentralDirectory, COMPRESSED_SIZE, UNCOMPRESSED_SIZE, false);
}
private void verifyZipModel(ZipModel zipModel, int numberOFEntriesInCentralDirectory, long compressedSize,
long uncompressedSize, boolean isZip64) {
assertThat(zipModel).isNotNull();
assertThat(zipModel.getCentralDirectory()).isNotNull();
assertThat(zipModel.isZip64Format()).isEqualTo(isZip64);
assertThat(zipModel.getCentralDirectory().getFileHeaders()).hasSize(numberOFEntriesInCentralDirectory);
verifyFileHeaders(zipModel.getCentralDirectory().getFileHeaders(), compressedSize, uncompressedSize);
}
private void verifyFileHeaders(List fileHeaders, long compressedSize, long uncompressedSize) {
for (int i = 0; i < fileHeaders.size(); i++) {
FileHeader fileHeader = fileHeaders.get(i);
assertThat(fileHeader).isNotNull();
assertThat(fileHeader.getVersionMadeBy()).isEqualTo(VERSION_MADE_BY);
assertThat(fileHeader.getVersionNeededToExtract()).isEqualTo(VERSION_NEEDED_TO_EXTRACT);
assertThat(fileHeader.getFileName()).isEqualTo(FILE_NAME_PREFIX + i);
assertThat(fileHeader.getCompressedSize()).isEqualTo(compressedSize);
assertThat(fileHeader.getUncompressedSize()).isEqualTo(uncompressedSize);
assertThat(fileHeader.getFileComment()).isEqualTo(FILE_COMMENT_PREFIX + i);
}
}
private void testWriteExtendedLocalFileHeader(long compressedSize, long uncompressedSize, long crc,
boolean isZip64Format) throws IOException {
LocalFileHeader localFileHeader = createLocalFileHeader("SOME_NAME", compressedSize, uncompressedSize, true);
localFileHeader.setCrc(crc);
localFileHeader.setWriteCompressedSizeInZip64ExtraRecord(isZip64Format);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.writeExtendedLocalHeader(localFileHeader, outputStream);
}
try(InputStream inputStream = new FileInputStream(headersFile)) {
DataDescriptor dataDescriptor = headerReader.readDataDescriptor(inputStream, isZip64Format);
verifyDataDescriptor(dataDescriptor, compressedSize, uncompressedSize, crc);
}
}
private void verifyDataDescriptor(DataDescriptor dataDescriptor, long compressedSize, long uncompressedSize,
long crc) {
assertThat(dataDescriptor).isNotNull();
assertThat(dataDescriptor.getSignature()).isEqualTo(HeaderSignature.EXTRA_DATA_RECORD);
assertThat(dataDescriptor.getCompressedSize()).isEqualTo(compressedSize);
assertThat(dataDescriptor.getUncompressedSize()).isEqualTo(uncompressedSize);
assertThat(dataDescriptor.getCrc()).isEqualTo(crc);
}
private void testWriteLocalFileHeaderWithAes(AesKeyStrength aesKeyStrength, AesVersion aesVersion)
throws IOException {
ZipModel zipModel = createZipModel(10);
LocalFileHeader localFileHeaderToWrite = createLocalFileHeader("TEXT", COMPRESSED_SIZE, UNCOMPRESSED_SIZE, true);
localFileHeaderToWrite.setEncryptionMethod(EncryptionMethod.AES);
localFileHeaderToWrite.setAesExtraDataRecord(createAesExtraDataRecord(aesKeyStrength, aesVersion));
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.writeLocalFileHeader(zipModel, localFileHeaderToWrite, outputStream, InternalZipConstants.CHARSET_UTF_8);
}
try(InputStream inputStream = new FileInputStream(headersFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, InternalZipConstants.CHARSET_UTF_8);
assertThat(readLocalFileHeader.getEncryptionMethod()).isEqualTo(EncryptionMethod.AES);
verifyAesExtraDataRecord(readLocalFileHeader.getAesExtraDataRecord(), aesKeyStrength, aesVersion);
}
}
private AESExtraDataRecord createAesExtraDataRecord(AesKeyStrength aesKeyStrength, AesVersion aesVersion) {
AESExtraDataRecord aesDataRecord = new AESExtraDataRecord();
aesDataRecord.setSignature(HeaderSignature.AES_EXTRA_DATA_RECORD);
aesDataRecord.setDataSize(7);
aesDataRecord.setAesVersion(aesVersion);
aesDataRecord.setVendorID("AE");
aesDataRecord.setAesKeyStrength(aesKeyStrength);
aesDataRecord.setCompressionMethod(CompressionMethod.DEFLATE);
return aesDataRecord;
}
private void verifyAesExtraDataRecord(AESExtraDataRecord aesExtraDataRecord, AesKeyStrength aesKeyStrength,
AesVersion aesVersion) {
assertThat(aesExtraDataRecord).isNotNull();
assertThat(aesExtraDataRecord.getAesKeyStrength()).isEqualTo(aesKeyStrength);
assertThat(aesExtraDataRecord.getAesVersion()).isEqualTo(aesVersion);
assertThat(aesExtraDataRecord.getCompressionMethod()).isEqualTo(CompressionMethod.DEFLATE);
assertThat(aesExtraDataRecord.getVendorID()).isEqualTo("AE");
}
private void testWriteLocalFileHeaderWithFileName(String fileNameSuffix, boolean useUtf8,
boolean expectFileNamesToMatch) throws IOException {
testWriteLocalFileHeaderWithFileNameAndCharset(fileNameSuffix, useUtf8, expectFileNamesToMatch, InternalZipConstants.CHARSET_UTF_8);
}
private void testWriteLocalFileHeaderWithFileNameAndCharset(String fileNameSuffix, boolean useUtf8,
boolean expectFileNamesToMatch, Charset charset) throws IOException {
ZipModel zipModel = createZipModel(10);
LocalFileHeader localFileHeaderToWrite = createLocalFileHeader(fileNameSuffix, COMPRESSED_SIZE, UNCOMPRESSED_SIZE,
useUtf8);
File headersFile = temporaryFolder.newFile();
try(OutputStream outputStream = new FileOutputStream(headersFile)) {
headerWriter.writeLocalFileHeader(zipModel, localFileHeaderToWrite, outputStream, charset);
}
try(InputStream inputStream = new FileInputStream(headersFile)) {
LocalFileHeader readLocalFileHeader = headerReader.readLocalFileHeader(inputStream, charset);
if (expectFileNamesToMatch) {
assertThat(readLocalFileHeader.getFileName()).isEqualTo(FILE_NAME_PREFIX + fileNameSuffix);
} else {
assertThat(readLocalFileHeader.getFileName()).isNotEqualTo(FILE_NAME_PREFIX + fileNameSuffix);
}
}
}
private void verifyEntrySizesIsMaxValueInLFHWhenZip64Format(File headersFile) throws IOException {
try(RandomAccessFile randomAccessFile = new RandomAccessFile(headersFile, RandomAccessFileMode.READ.getValue())) {
randomAccessFile.seek(18);
long compressedSize = rawIO.readLongLittleEndian(randomAccessFile, 4);
assertThat(compressedSize).isEqualTo(InternalZipConstants.ZIP_64_SIZE_LIMIT);
long uncompressedSize = rawIO.readLongLittleEndian(randomAccessFile, 4);
assertThat(uncompressedSize).isEqualTo(InternalZipConstants.ZIP_64_SIZE_LIMIT);
}
}
private void verifyLocalFileHeader(LocalFileHeader localFileHeader, String expectedFileName, long compressedSize,
long uncompressedSize) {
assertThat(localFileHeader).isNotNull();
assertThat(localFileHeader.getVersionNeededToExtract()).isEqualTo(VERSION_NEEDED_TO_EXTRACT);
assertThat(localFileHeader.getFileName()).isEqualTo(expectedFileName);
assertThat(localFileHeader.getCompressedSize()).isEqualTo(compressedSize);
assertThat(localFileHeader.getUncompressedSize()).isEqualTo(uncompressedSize);
assertThat(localFileHeader.getCompressionMethod()).isEqualTo(CompressionMethod.DEFLATE);
assertThat(localFileHeader.getLastModifiedTime()).isEqualTo(LAST_MODIFIED_FILE_TIME);
}
private void verifyZip64ExtendedInfo(Zip64ExtendedInfo zip64ExtendedInfo, long compressedSize, long uncompressedSize,
int offsetStartOfLocalFileHeader, int diskNumberStart) {
assertThat(zip64ExtendedInfo).isNotNull();
assertThat(zip64ExtendedInfo.getCompressedSize()).isEqualTo(compressedSize);
assertThat(zip64ExtendedInfo.getUncompressedSize()).isEqualTo(uncompressedSize);
assertThat(zip64ExtendedInfo.getOffsetLocalHeader()).isEqualTo(offsetStartOfLocalFileHeader);
assertThat(zip64ExtendedInfo.getDiskNumberStart()).isEqualTo(diskNumberStart);
}
private LocalFileHeader createLocalFileHeader(String fileNameSuffix, long compressedSize, long uncompressedSize,
boolean useUtf8) {
LocalFileHeader localFileHeader = new LocalFileHeader();
localFileHeader.setVersionNeededToExtract(VERSION_NEEDED_TO_EXTRACT);
localFileHeader.setFileName(FILE_NAME_PREFIX + fileNameSuffix);
localFileHeader.setCompressedSize(compressedSize);
localFileHeader.setUncompressedSize(uncompressedSize);
localFileHeader.setGeneralPurposeFlag(generateGeneralPurposeBytes(useUtf8));
localFileHeader.setCompressionMethod(CompressionMethod.DEFLATE);
localFileHeader.setLastModifiedTime(LAST_MODIFIED_FILE_TIME);
return localFileHeader;
}
private ZipModel createZipModel(int numberOfEntriesInCentralDirectory) {
return createZipModel(numberOfEntriesInCentralDirectory, COMPRESSED_SIZE, UNCOMPRESSED_SIZE);
}
private ZipModel createZipModel(int numberOfEntriesInCentralDirectory, long compressedSize, long uncompressedSize) {
ZipModel zipModel = new ZipModel();
zipModel.setCentralDirectory(createCentralDirectory(numberOfEntriesInCentralDirectory, compressedSize,
uncompressedSize));
return zipModel;
}
private CentralDirectory createCentralDirectory(int numberOfEntriesInCentralDirectory, long compressedSize,
long uncompressedSize) {
CentralDirectory centralDirectory = new CentralDirectory();
centralDirectory.setFileHeaders(createFileHeaders(numberOfEntriesInCentralDirectory, compressedSize,
uncompressedSize));
return centralDirectory;
}
private byte[] generateGeneralPurposeBytes(boolean useUtf8) {
byte[] generalPurposeBytes = new byte[2];
if (useUtf8) {
generalPurposeBytes[1] = BitUtils.setBit(generalPurposeBytes[1], 3);
}
return generalPurposeBytes;
}
private List createFileHeaders(int numberOfEntriesInCentralDirectory, long compressedSize,
long uncompressedSize) {
List fileHeaders = new ArrayList<>();
for (int i = 0; i < numberOfEntriesInCentralDirectory; i++) {
FileHeader fileHeader = new FileHeader();
fileHeader.setVersionMadeBy(VERSION_MADE_BY);
fileHeader.setVersionNeededToExtract(VERSION_NEEDED_TO_EXTRACT);
fileHeader.setFileName(FILE_NAME_PREFIX + i);
fileHeader.setGeneralPurposeFlag(generateGeneralPurposeBytes(true));
fileHeader.setCompressedSize(compressedSize);
fileHeader.setUncompressedSize(uncompressedSize);
fileHeader.setCompressionMethod(CompressionMethod.DEFLATE);
fileHeader.setExternalFileAttributes(EXTERNAL_FILE_ATTRIBUTES);
fileHeader.setFileComment(FILE_COMMENT_PREFIX + i);
fileHeaders.add(fileHeader);
}
return fileHeaders;
}
private void addExtraDataRecordToFirstFileHeader(ZipModel zipModel, byte[] data) {
ExtraDataRecord extraDataRecord = new ExtraDataRecord();
extraDataRecord.setHeader(12345);
extraDataRecord.setSizeOfData(data == null ? 0 : data.length);
extraDataRecord.setData(data);
FileHeader firstFileHeader = zipModel.getCentralDirectory().getFileHeaders().get(0);
if (firstFileHeader.getExtraDataRecords() == null) {
firstFileHeader.setExtraDataRecords(new ArrayList());
}
firstFileHeader.getExtraDataRecords().add(extraDataRecord);
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/io/ 0000775 0000000 0000000 00000000000 14142654472 0021127 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/io/inputstream/ 0000775 0000000 0000000 00000000000 14142654472 0023502 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/io/inputstream/NumberedSplitRandomAccessFileIT.java 0000664 0000000 0000000 00000013266 14142654472 0032452 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.util.CrcUtil;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.zip.CRC32;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static org.assertj.core.api.Assertions.assertThat;
public class NumberedSplitRandomAccessFileIT extends AbstractIT {
private static final int ONE_HUNDRED_KB = 102400;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testOpenInWriteModeThrowsException() throws IOException {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("write mode is not allowed for NumberedSplitRandomAccessFile");
new NumberedSplitRandomAccessFile(getTestFileFromResources("sample.pdf"), RandomAccessFileMode.WRITE.getValue());
}
@Test
public void testWriteIntThrowsUnsupportedOperationException() throws IOException {
expectedException.expect(UnsupportedOperationException.class);
String fileName = "somefile.001";
File splitFile = temporaryFolder.newFile(fileName);
NumberedSplitRandomAccessFile numberedSplitRandomAccessFile = new NumberedSplitRandomAccessFile(
splitFile, RandomAccessFileMode.READ.getValue());
numberedSplitRandomAccessFile.write(1);
}
@Test
public void testWriteByteArrayThrowsUnsupportedOperationException() throws IOException {
expectedException.expect(UnsupportedOperationException.class);
String fileName = "somefile.001";
File splitFile = temporaryFolder.newFile(fileName);
NumberedSplitRandomAccessFile numberedSplitRandomAccessFile = new NumberedSplitRandomAccessFile(
splitFile, RandomAccessFileMode.READ.getValue());
numberedSplitRandomAccessFile.write(new byte[100]);
}
@Test
public void testWriteByteArrayWithLengthThrowsUnsupportedOperationException() throws IOException {
expectedException.expect(UnsupportedOperationException.class);
String fileName = "somefile.001";
File splitFile = temporaryFolder.newFile(fileName);
NumberedSplitRandomAccessFile numberedSplitRandomAccessFile = new NumberedSplitRandomAccessFile(
splitFile, RandomAccessFileMode.READ.getValue());
numberedSplitRandomAccessFile.write(new byte[100], 0, 10);
}
@Test
public void testReadIntReadsCompleteFileSuccessfully() throws IOException {
File fileToSplit = getTestFileFromResources("file_PDF_1MB.pdf");
long sourceFileCrc = CrcUtil.computeFileCrc(fileToSplit, null);
File firstSplitFile = TestUtils.splitFileWith7ZipFormat(fileToSplit, temporaryFolder.getRoot(), InternalZipConstants.MIN_SPLIT_LENGTH);
CRC32 crc32 = new CRC32();
int readVal;
try(NumberedSplitRandomAccessFile randomAccessFile = openSplitFile(firstSplitFile)) {
while ((readVal = randomAccessFile.read()) != -1) {
crc32.update(readVal);
}
}
assertThat(crc32.getValue()).isEqualTo(sourceFileCrc);
}
@Test
public void testReadByteArrayReadsCompleteFileSuccessfully() throws IOException {
File fileToSplit = getTestFileFromResources("file_PDF_1MB.pdf");
long sourceFileCrc = CrcUtil.computeFileCrc(fileToSplit, null);
File firstSplitFile = TestUtils.splitFileWith7ZipFormat(fileToSplit, temporaryFolder.getRoot(), ONE_HUNDRED_KB);
CRC32 crc32 = new CRC32();
byte[] buff = new byte[InternalZipConstants.BUFF_SIZE];
int readLen;
try(NumberedSplitRandomAccessFile randomAccessFile = openSplitFile(firstSplitFile)) {
while ((readLen = randomAccessFile.read(buff)) != -1) {
crc32.update(buff, 0, readLen);
}
}
assertThat(crc32.getValue()).isEqualTo(sourceFileCrc);
}
@Test
public void testReadByteArrayWithLengthReadsCompleteFileSuccessfully() throws IOException {
File fileToSplit = getTestFileFromResources("file_PDF_1MB.pdf");
long sourceFileCrc = CrcUtil.computeFileCrc(fileToSplit, null);
File firstSplitFile = TestUtils.splitFileWith7ZipFormat(fileToSplit, temporaryFolder.getRoot(), ONE_HUNDRED_KB - 100);
CRC32 crc32 = new CRC32();
byte[] buff = new byte[InternalZipConstants.BUFF_SIZE];
int readLen;
try(NumberedSplitRandomAccessFile randomAccessFile = openSplitFile(firstSplitFile)) {
while ((readLen = randomAccessFile.read(buff, 0, 100)) != -1) {
crc32.update(buff, 0, readLen);
}
}
assertThat(crc32.getValue()).isEqualTo(sourceFileCrc);
}
@Test
public void testSeek() throws IOException {
File fileToSplit = getTestFileFromResources("file_PDF_1MB.pdf");
File firstSplitFile = TestUtils.splitFileWith7ZipFormat(fileToSplit, temporaryFolder.getRoot(), ONE_HUNDRED_KB);
try(NumberedSplitRandomAccessFile splitRandomAccessFile = openSplitFile(firstSplitFile);
RandomAccessFile sourceRandomAccessFile = new RandomAccessFile(fileToSplit, RandomAccessFileMode.READ.getValue())) {
splitRandomAccessFile.seek(fileToSplit.length() - 200);
sourceRandomAccessFile.seek(fileToSplit.length() - 200);
byte[] sourceBytes = new byte[200];
byte[] splitFileBytes = new byte[200];
sourceRandomAccessFile.read(sourceBytes);
splitRandomAccessFile.read(splitFileBytes);
assertThat(splitFileBytes).isEqualTo(sourceBytes);
}
}
private NumberedSplitRandomAccessFile openSplitFile(File firstSplitFile) throws IOException {
return new NumberedSplitRandomAccessFile(firstSplitFile, RandomAccessFileMode.READ.getValue());
}
} zip4j-2.9.1/src/test/java/net/lingala/zip4j/io/inputstream/ZipInputStreamIT.java 0000664 0000000 0000000 00000043757 14142654472 0027560 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.inputstream;
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.ByteArrayInputStream;
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.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static net.lingala.zip4j.testutils.ZipFileVerifier.verifyFileContent;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
import static org.assertj.core.api.Assertions.assertThat;
public class ZipInputStreamIT extends AbstractIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testZipInputStreamConstructorThrowsExceptionWhenBufferSizeIsLessThanExpected() {
InputStream inputStream = new ByteArrayInputStream(new byte[1]);
Zip4jConfig zip4jConfig = new Zip4jConfig(null, InternalZipConstants.MIN_BUFF_SIZE - 1);
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
new ZipInputStream(inputStream, (char[]) null, zip4jConfig);
}
@Test
public void testExtractStoreWithoutEncryption() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.STORE);
extractZipFileWithInputStreams(createdZipFile, null);
}
@Test
public void testExtractStoreWithZipStandardEncryption() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.STORE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
extractZipFileWithInputStreams(createdZipFile, PASSWORD);
}
@Test
public void testExtractStoreWithAesEncryption128() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128, PASSWORD);
extractZipFileWithInputStreams(createdZipFile, PASSWORD);
}
@Test
public void testExtractStoreWithAesEncryption256() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
extractZipFileWithInputStreams(createdZipFile, PASSWORD);
}
@Test
public void testExtractDeflateWithoutEncryption() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.DEFLATE);
extractZipFileWithInputStreams(createdZipFile, null);
}
@Test
public void testExtractDeflateWithAesEncryption128() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128, PASSWORD);
extractZipFileWithInputStreams(createdZipFile, PASSWORD);
}
@Test
public void testExtractDeflateWithAesEncryption256() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
extractZipFileWithInputStreams(createdZipFile, PASSWORD);
}
@Test
public void testExtractDeflateWithAesEncryption256AndV1() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD, AesVersion.ONE);
extractZipFileWithInputStreams(createdZipFile, PASSWORD);
}
@Test
public void testExtractWithReadLengthLessThan16WithAesAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, 15);
}
@Test
public void testExtractWithReadLengthLessThan16WithAesAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, 15);
}
@Test
public void testExtractWithReadLengthLessThan16WithZipCryptoAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, 12);
}
@Test
public void testExtractWithReadLengthLessThan16WithZipCryptoAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, 5);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithAesAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 4) + 1);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithAesAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 8) - 10);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithZipCryptoAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 2) - 6);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithZipCryptoAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 10) - 11);
}
@Test
public void testExtractWithRandomLengthWithAesAndDeflateCompression() throws IOException {
Random random = new Random();
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
LocalFileHeader localFileHeader;
int readLen;
byte[] readBuffer = new byte[4096];
int numberOfEntriesExtracted = 0;
try (FileInputStream fileInputStream = new FileInputStream(createZipFile)) {
try (ZipInputStream zipInputStream = new ZipInputStream(fileInputStream, PASSWORD)) {
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
File extractedFile = temporaryFolder.newFile(localFileHeader.getFileName());
try (OutputStream outputStream = new FileOutputStream(extractedFile)) {
while ((readLen = zipInputStream.read(readBuffer, 0, random.nextInt((25 - 1) + 1) + 1)) != -1) {
outputStream.write(readBuffer, 0, readLen);
}
}
verifyFileContent(getTestFileFromResources(localFileHeader.getFileName()), extractedFile);
numberOfEntriesExtracted++;
}
}
}
assertThat(numberOfEntriesExtracted).isEqualTo(FILES_TO_ADD.size());
}
@Test
public void testExtractFilesForZipFileWithInvalidExtraDataRecordIgnoresIt() throws IOException {
InputStream inputStream = new FileInputStream(getTestArchiveFromResources("invalid_extra_data_record.zip"));
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream, "password".toCharArray())) {
byte[] b = new byte[4096];
while (zipInputStream.getNextEntry() != null) {
while (zipInputStream.read(b) != -1) {
}
}
}
}
@Test
public void testGetNextEntryReturnsNextEntryEvenIfEntryNotCompletelyRead() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE);
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(createZipFile))) {
int numberOfEntries = 0;
while (zipInputStream.getNextEntry() != null) {
numberOfEntries++;
}
assertThat(numberOfEntries).isEqualTo(FILES_TO_ADD.size());
}
}
@Test
public void testGetFileNamesWithChineseCharset() throws IOException {
InputStream inputStream = new FileInputStream(getTestArchiveFromResources("testfile_with_chinese_filename_by_7zip.zip"));
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream, CHARSET_GBK)) {
LocalFileHeader localFileHeader;
String expactedFileName = "fff - 副本.txt";
Set filenameSet = new HashSet<>();
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
filenameSet.add(localFileHeader.getFileName());
}
assertThat(filenameSet.contains(expactedFileName)).isTrue();
}
}
@Test
public void testExtractJarFile() throws IOException {
byte[] b = new byte[4096];
File jarFile = getTestArchiveFromResources("jar-dir-fh-entry-size-2.jar");
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(jarFile))) {
while (zipInputStream.getNextEntry() != null) {
zipInputStream.read(b);
}
}
}
@Test
public void testExtractZipStrongEncryptionThrowsException() throws IOException {
expectedException.expect(ZipException.class);
expectedException.expectMessage("Entry [test.txt] Strong Encryption not supported");
File strongEncryptionFile = getTestArchiveFromResources("strong_encrypted.zip");
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(strongEncryptionFile))) {
zipInputStream.getNextEntry();
}
}
@Test
public void testReadingZipBySkippingDataCreatedWithJDKZipReadsAllEntries() throws IOException {
List filesToAdd = new ArrayList<>();
// Add a directory first, then a few files, then a directory, and then a file to test all possibilities
filesToAdd.add(getTestFileFromResources("sample_directory"));
filesToAdd.addAll(FILES_TO_ADD);
filesToAdd.add(getTestFileFromResources("öüäöäö"));
filesToAdd.add(getTestFileFromResources("file_PDF_1MB.pdf"));
File generatedZipFile = createZipFileWithJdkZip(filesToAdd, getTestFileFromResources(""));
int totalNumberOfEntriesRead = 0;
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(generatedZipFile))) {
while (zipInputStream.getNextEntry() != null) {
totalNumberOfEntriesRead++;
}
}
assertThat(totalNumberOfEntriesRead).isEqualTo(6);
}
@Test
public void testAvailableThrowsExceptionWhenStreamClosed() throws IOException {
expectedException.expect(IOException.class);
expectedException.expectMessage("Stream closed");
File createZipFile = createZipFile(CompressionMethod.DEFLATE);
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(createZipFile));
zipInputStream.close();
zipInputStream.available();
}
@Test
public void testAvailableReturns1WhenEntryEOFNotReachedAnd0AfterEOFReached() throws IOException {
byte[] b = new byte[InternalZipConstants.BUFF_SIZE];
File createZipFile = createZipFile(CompressionMethod.DEFLATE);
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(createZipFile))) {
while (zipInputStream.getNextEntry() != null) {
while (zipInputStream.read(b) != -1) {
assertThat(zipInputStream.available()).isEqualTo(1);
}
assertThat(zipInputStream.available()).isEqualTo(0);
}
}
}
@Test
public void testExtractZipWithDifferentPasswords() throws IOException {
byte[] buffer = new byte[InternalZipConstants.BUFF_SIZE];
File zipFileUnderTest = TestUtils.getTestArchiveFromResources("zip_with_different_passwords.zip");
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFileUnderTest))) {
readAndAssertNextEntry(zipInputStream, "after_deflate_remaining_bytes.bin", "password_1");
readAndAssertNextEntry(zipInputStream, "file_PDF_1MB.pdf", "password_2");
// 3rd entry is not encrypted, but it should not be impacted if a password is set
readAndAssertNextEntry(zipInputStream, "sample.pdf", null);
}
}
@Test
public void testExtractZipFileWithDirectoriesContainingExtendedLocalFileHeader() throws IOException {
extractZipFileWithInputStreams(TestUtils.getTestArchiveFromResources("dirs_with_extended_local_file_headers.zip"),
null, InternalZipConstants.BUFF_SIZE, false, 2);
}
private void extractZipFileWithInputStreams(File zipFile, char[] password) throws IOException {
extractZipFileWithInputStreams(zipFile, password, InternalZipConstants.BUFF_SIZE);
}
private void extractZipFileWithInputStreams(File zipFile, char[] password, int bufferLength) throws IOException {
extractZipFileWithInputStreams(zipFile, password, bufferLength, true, FILES_TO_ADD.size());
}
private void extractZipFileWithInputStreams(File zipFile, char[] password, int bufferLength,
boolean verifyFileContents, int numberOfEntriesExpected) throws IOException {
LocalFileHeader localFileHeader;
int readLen;
byte[] readBuffer = new byte[bufferLength];
int numberOfEntriesExtracted = 0;
try (FileInputStream fileInputStream = new FileInputStream(zipFile)) {
try (ZipInputStream zipInputStream = new ZipInputStream(fileInputStream, password)) {
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
File extractedFile = temporaryFolder.newFile(localFileHeader.getFileName());
try (OutputStream outputStream = new FileOutputStream(extractedFile)) {
while ((readLen = zipInputStream.read(readBuffer)) != -1) {
outputStream.write(readBuffer, 0, readLen);
}
}
verifyLocalFileHeader(localFileHeader);
if (verifyFileContents) {
verifyFileContent(getTestFileFromResources(localFileHeader.getFileName()), extractedFile);
}
numberOfEntriesExtracted++;
}
}
}
assertThat(numberOfEntriesExtracted).isEqualTo(numberOfEntriesExpected);
}
private void verifyLocalFileHeader(LocalFileHeader localFileHeader) {
assertThat(localFileHeader).isNotNull();
if (localFileHeader.isEncrypted()
&& localFileHeader.getEncryptionMethod().equals(EncryptionMethod.AES)
&& localFileHeader.getAesExtraDataRecord().getAesVersion().equals(AesVersion.TWO)) {
assertThat(localFileHeader.getCrc()).isZero();
}
}
private File createZipFile(CompressionMethod compressionMethod) throws IOException {
return createZipFile(compressionMethod, false, null, null, null);
}
private File createZipFile(CompressionMethod compressionMethod, boolean encryptFiles,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength, char[] password)
throws IOException {
return createZipFile(compressionMethod, encryptFiles, encryptionMethod, aesKeyStrength, password, AesVersion.TWO);
}
private File createZipFile(CompressionMethod compressionMethod, boolean encryptFiles,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength, char[] password,
AesVersion aesVersion)
throws IOException {
File outputFile = temporaryFolder.newFile("output.zip");
deleteFileIfExists(outputFile);
ZipFile zipFile = new ZipFile(outputFile, password);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(compressionMethod);
zipParameters.setEncryptFiles(encryptFiles);
zipParameters.setEncryptionMethod(encryptionMethod);
zipParameters.setAesKeyStrength(aesKeyStrength);
zipParameters.setAesVersion(aesVersion);
zipFile.addFiles(AbstractIT.FILES_TO_ADD, zipParameters);
return outputFile;
}
private void deleteFileIfExists(File file) {
if (file.exists()) {
if (!file.delete()) {
throw new RuntimeException("Could not delete an existing zip file");
}
}
}
private File createZipFileWithJdkZip(List filesToAdd, File rootFolder) throws IOException {
int readLen;
byte[] readBuffer = new byte[InternalZipConstants.BUFF_SIZE];
try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(generatedZipFile))) {
for (File fileToAdd : filesToAdd) {
String path = rootFolder.toPath().relativize(fileToAdd.toPath()).toString().replaceAll("\\\\", "/");
ZipEntry entry = new ZipEntry(path);
zipOutputStream.putNextEntry(entry);
if (!fileToAdd.isDirectory()) {
try (InputStream fis = new FileInputStream(fileToAdd)) {
while ((readLen = fis.read(readBuffer)) != -1) {
zipOutputStream.write(readBuffer, 0, readLen);
}
}
}
zipOutputStream.closeEntry();
}
}
return generatedZipFile;
}
private void readAndAssertNextEntry(ZipInputStream zipInputStream, String fileNameToExpect, String passwordToUse)
throws IOException {
byte[] buffer = new byte[InternalZipConstants.BUFF_SIZE];
if (passwordToUse != null) {
zipInputStream.setPassword(passwordToUse.toCharArray());
}
LocalFileHeader localFileHeader = zipInputStream.getNextEntry();
assertThat(localFileHeader.getFileName()).isEqualTo(fileNameToExpect);
//noinspection StatementWithEmptyBody
while (zipInputStream.read(buffer) != -1);
}
}
zip4j-2.9.1/src/test/java/net/lingala/zip4j/io/outputstream/ 0000775 0000000 0000000 00000000000 14142654472 0023703 5 ustar 00root root 0000000 0000000 zip4j-2.9.1/src/test/java/net/lingala/zip4j/io/outputstream/ZipOutputStreamIT.java 0000664 0000000 0000000 00000043316 14142654472 0030151 0 ustar 00root root 0000000 0000000 package net.lingala.zip4j.io.outputstream;
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.util.BitUtils;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.ByteArrayOutputStream;
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.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import static net.lingala.zip4j.testutils.TestUtils.getTestFileFromResources;
import static net.lingala.zip4j.testutils.ZipFileVerifier.verifyZipFileByExtractingAllFiles;
import static net.lingala.zip4j.util.FileUtils.isMac;
import static net.lingala.zip4j.util.FileUtils.isUnix;
import static net.lingala.zip4j.util.FileUtils.isWindows;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
import static org.assertj.core.api.Assertions.assertThat;
public class ZipOutputStreamIT extends AbstractIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testConstructorThrowsExceptionWhenBufferSizeIsLessThanExpected() throws IOException {
OutputStream outputStream = new ByteArrayOutputStream();
Zip4jConfig zip4jConfig = new Zip4jConfig(null, InternalZipConstants.MIN_BUFF_SIZE - 1);
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
new ZipOutputStream(outputStream, null, zip4jConfig, null);
}
@Test
public void testZipOutputStreamStoreWithoutEncryption() throws IOException {
testZipOutputStream(CompressionMethod.STORE, false, null, null, null);
}
@Test
public void testZipOutputStreamStoreWithStandardEncryption() throws IOException {
testZipOutputStream(CompressionMethod.STORE, true, EncryptionMethod.ZIP_STANDARD, null, null);
}
@Test
public void testZipOutputStreamStoreWithAES256V1() throws IOException {
testZipOutputStream(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, AesVersion.ONE);
}
@Test
public void testZipOutputStreamStoreWithAES128V2() throws IOException {
testZipOutputStream(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128, AesVersion.TWO);
}
@Test
public void testZipOutputStreamStoreWithAES256V2() throws IOException {
testZipOutputStream(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, AesVersion.TWO);
}
@Test
public void testZipOutputStreamDeflateWithoutEncryption() throws IOException {
testZipOutputStream(CompressionMethod.DEFLATE, false, null, null, null);
}
@Test
public void testZipOutputStreamDeflateWithoutEncryptionAndKoreanFilename() throws IOException {
List filesToAdd = new ArrayList<>();
filesToAdd.add(getTestFileFromResources("가나다.abc"));
testZipOutputStream(CompressionMethod.DEFLATE, false, null, null, null, true,
filesToAdd, CHARSET_CP_949);
}
@Test
public void testZipOutputStreamDeflateWithStandardEncryption() throws IOException {
testZipOutputStream(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, null);
}
@Test
public void testZipOutputStreamDeflateWithStandardEncryptionWhenModifiedFileTimeNotSet()
throws IOException {
testZipOutputStream(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, null, false);
}
@Test
public void testZipOutputStreamDeflateWithAES128V1() throws IOException {
testZipOutputStream(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128, AesVersion.ONE);
}
@Test
public void testZipOutputStreamDeflateWithAES128() throws IOException {
testZipOutputStream(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128, AesVersion.TWO);
}
@Test
public void testZipOutputStreamDeflateWithAES256() throws IOException {
testZipOutputStream(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, AesVersion.TWO);
}
@Test
public void testZipOutputStreamDeflateWithNullVersionUsesV2() throws IOException {
testZipOutputStream(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, null);
}
@Test
public void testZipOutputStreamThrowsExceptionWhenEntrySizeNotSetForStoreCompression() throws IOException {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("uncompressed size should be set for zip entries of compression type store");
try(ZipOutputStream zos = initializeZipOutputStream(false, InternalZipConstants.CHARSET_UTF_8)) {
for (File fileToAdd : FILES_TO_ADD) {
zipParameters.setLastModifiedFileTime(fileToAdd.lastModified());
zipParameters.setFileNameInZip(fileToAdd.getName());
zos.putNextEntry(zipParameters);
}
}
}
@Test
public void testAddCommentToEntryWithUtf8Charset() throws IOException {
testAddCommentToEntryWithCharset(StandardCharsets.UTF_8, "COMMENT_");
}
@Test
public void testAddCommentToEntryWithNullCharset() throws IOException {
testAddCommentToEntryWithCharset(null, "COMMENT_ÜÖ_");
}
@Test
public void testAddCommentToEntryWithGBKCharset() throws IOException {
testAddCommentToEntryWithCharset(Charset.forName("GBK"), "fff - 副本");
}
@Test
public void testAddCommentToZipOutputStreamWithUtf8Charset() throws IOException {
testAddCommentToZipOutputStreamWithCharset(StandardCharsets.UTF_8, "SOME_COMMENT");
}
@Test
public void testAddCommentToZipOutputStreamWithNullCharsetUsesUtf8() throws IOException {
testAddCommentToZipOutputStreamWithCharset(null, "SOME_COMMENT_WITH_NO_CHARSET");
}
@Test
public void testAddCommentToZipOutputStreamWithGBKCharset() throws IOException {
testAddCommentToZipOutputStreamWithCharset(Charset.forName("GBK"), "fff - 副本");
}
@Test
public void testAddCommentToZipOutputStreamAfterClosingThrowsException() throws IOException {
expectedException.expect(IOException.class);
expectedException.expectMessage("Stream is closed");
ZipParameters zipParameters = new ZipParameters();
ZipOutputStream zos = initializeZipOutputStream(false, InternalZipConstants.CHARSET_UTF_8);
for (File fileToAdd : FILES_TO_ADD) {
zipParameters.setLastModifiedFileTime(fileToAdd.lastModified());
zipParameters.setFileNameInZip(fileToAdd.getName());
zos.putNextEntry(zipParameters);
}
zos.close();
zos.setComment("SOME_COMMENT");
}
@Test
public void testDefaultFileAttributes() throws IOException {
List filesToAdd = new ArrayList<>(FILES_TO_ADD);
filesToAdd.add(TestUtils.getTestFileFromResources("/"));
byte[] buff = new byte[4096];
int readLen;
ZipParameters zipParameters = new ZipParameters();
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(generatedZipFile))) {
for (File fileToAdd : filesToAdd) {
if (fileToAdd.isDirectory()) {
zipParameters.setFileNameInZip(fileToAdd.getName() + "/");
zipOutputStream.putNextEntry(zipParameters);
zipOutputStream.closeEntry();
continue;
}
zipParameters.setFileNameInZip(fileToAdd.getName());
zipOutputStream.putNextEntry(zipParameters);
InputStream inputStream = new FileInputStream(fileToAdd);
while ((readLen = inputStream.read(buff)) != -1) {
zipOutputStream.write(buff, 0, readLen);
}
inputStream.close();
zipOutputStream.closeEntry();
}
}
verifyDefaultFileAttributes();
}
@Test
public void testCreatingZipWithoutClosingEntryManuallySuccessfullyClosesEntry() throws IOException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(generatedZipFile))) {
File fileToAdd = getTestFileFromResources("file_PDF_1MB.pdf");
byte[] buffer = new byte[InternalZipConstants.BUFF_SIZE];
int readLen;
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(fileToAdd.getName());
zipOutputStream.putNextEntry(zipParameters);
try (InputStream inputStream = new FileInputStream(fileToAdd)) {
while ((readLen = inputStream.read(buffer)) != -1) {
zipOutputStream.write(buffer, 0, readLen);
}
}
}
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
}
@Test
public void testCreateZipFileWithDirectoriesAndExtendedLocalFileHeaderIsSuccessful() throws IOException {
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(generatedZipFile))) {
putNextEntryAndCloseEntry(zos, "dir1/");
putNextEntryAndCloseEntry(zos, "dir2/");
}
ZipFile zipFile = new ZipFile(generatedZipFile);
List fileHeaders = zipFile.getFileHeaders();
for (FileHeader fileHeader : fileHeaders) {
assertThat(fileHeader.isDataDescriptorExists()).isFalse();
}
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 2);
}
private void testZipOutputStream(CompressionMethod compressionMethod, boolean encrypt,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength,
AesVersion aesVersion)
throws IOException {
testZipOutputStream(compressionMethod, encrypt, encryptionMethod, aesKeyStrength, aesVersion, true);
}
private void testZipOutputStream(CompressionMethod compressionMethod, boolean encrypt,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength,
AesVersion aesVersion, boolean setLastModifiedTime)
throws IOException {
testZipOutputStream(compressionMethod, encrypt, encryptionMethod, aesKeyStrength, aesVersion, setLastModifiedTime,
FILES_TO_ADD, InternalZipConstants.CHARSET_UTF_8);
}
private void testZipOutputStream(CompressionMethod compressionMethod, boolean encrypt,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength,
AesVersion aesVersion, boolean setLastModifiedTime, List filesToAdd,
Charset charset)
throws IOException {
ZipParameters zipParameters = buildZipParameters(compressionMethod, encrypt, encryptionMethod, aesKeyStrength);
zipParameters.setAesVersion(aesVersion);
byte[] buff = new byte[4096];
int readLen;
try(ZipOutputStream zos = initializeZipOutputStream(encrypt, charset)) {
for (File fileToAdd : filesToAdd) {
if (zipParameters.getCompressionMethod() == CompressionMethod.STORE) {
zipParameters.setEntrySize(fileToAdd.length());
}
if (setLastModifiedTime) {
zipParameters.setLastModifiedFileTime(fileToAdd.lastModified());
}
zipParameters.setFileNameInZip(fileToAdd.getName());
zos.putNextEntry(zipParameters);
try(InputStream inputStream = new FileInputStream(fileToAdd)) {
while ((readLen = inputStream.read(buff)) != -1) {
zos.write(buff, 0, readLen);
}
}
zos.closeEntry();
}
}
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, filesToAdd.size(), true, charset);
verifyEntries();
}
private void testAddCommentToEntryWithCharset(Charset charset, String fileCommentPrefix) throws IOException {
ZipParameters zipParameters = new ZipParameters();
byte[] buff = new byte[4096];
int readLen;
List filesToAdd = FILES_TO_ADD;
try(ZipOutputStream zos = initializeZipOutputStream(false, charset)) {
for (int i = 0; i < filesToAdd.size(); i++) {
File fileToAdd = filesToAdd.get(i);
zipParameters.setFileNameInZip(fileToAdd.getName());
if (i == 0) {
zipParameters.setFileComment(fileCommentPrefix + i);
} else {
zipParameters.setFileComment(null);
}
zos.putNextEntry(zipParameters);
try(InputStream inputStream = new FileInputStream(fileToAdd)) {
while ((readLen = inputStream.read(buff)) != -1) {
zos.write(buff, 0, readLen);
}
}
zos.closeEntry();
}
}
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, filesToAdd.size(), true, charset);
verifyEntries();
verifyFileEntryComment(fileCommentPrefix, charset);
}
private void testAddCommentToZipOutputStreamWithCharset(Charset charset, String comment) throws IOException {
ZipParameters zipParameters = new ZipParameters();
byte[] buff = new byte[4096];
int readLen;
List filesToAdd = FILES_TO_ADD;
try(ZipOutputStream zos = initializeZipOutputStream(false, charset)) {
for (int i = 0; i < filesToAdd.size(); i++) {
File fileToAdd = filesToAdd.get(i);
zipParameters.setFileNameInZip(fileToAdd.getName());
zos.putNextEntry(zipParameters);
try(InputStream inputStream = new FileInputStream(fileToAdd)) {
while ((readLen = inputStream.read(buff)) != -1) {
zos.write(buff, 0, readLen);
}
}
zos.closeEntry();
}
zos.setComment(comment);
}
verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, filesToAdd.size(), true, charset);
verifyEntries();
verifyZipComment(comment, charset);
}
private void verifyEntries() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
for (FileHeader fileHeader : zipFile.getFileHeaders()) {
byte[] generalPurposeBytes = fileHeader.getGeneralPurposeFlag();
assertThat(BitUtils.isBitSet(generalPurposeBytes[0], 3)).isTrue();
if (fileHeader.isEncrypted()
&& fileHeader.getEncryptionMethod().equals(EncryptionMethod.AES)) {
if (fileHeader.getAesExtraDataRecord().getAesVersion().equals(AesVersion.TWO)) {
assertThat(fileHeader.getCrc()).isZero();
} else if (fileHeader.getCompressedSize() > 0) {
assertThat(fileHeader.getCrc()).isNotZero();
}
}
}
}
private ZipOutputStream initializeZipOutputStream(boolean encrypt, Charset charset) throws IOException {
FileOutputStream fos = new FileOutputStream(generatedZipFile);
if (encrypt) {
return new ZipOutputStream(fos, PASSWORD, charset);
}
return new ZipOutputStream(fos, null, charset);
}
private ZipParameters buildZipParameters(CompressionMethod compressionMethod, boolean encrypt,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength) {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(compressionMethod);
zipParameters.setEncryptionMethod(encryptionMethod);
zipParameters.setAesKeyStrength(aesKeyStrength);
zipParameters.setEncryptFiles(encrypt);
return zipParameters;
}
private void verifyFileEntryComment(String commentPrefix, Charset charset) throws IOException {
ZipFile zipFile = initializeZipFileWithCharset(charset);
List fileHeaders = zipFile.getFileHeaders();
for (int i = 0; i < fileHeaders.size(); i++) {
FileHeader fileHeader = fileHeaders.get(i);
if (i == 0) {
assertThat(fileHeader.getFileComment()).isEqualTo(commentPrefix + i);
} else {
assertThat(fileHeader.getFileComment()).isNull();
}
}
}
private void verifyZipComment(String expectedComment, Charset charset) throws IOException {
ZipFile zipFile = initializeZipFileWithCharset(charset);
assertThat(zipFile.getComment()).isEqualTo(expectedComment);
}
private void verifyDefaultFileAttributes() throws ZipException {
ZipFile zipFile = new ZipFile(generatedZipFile);
List