diff --git a/src/net/lingala/zip4j/core/ZipFile.java b/src/net/lingala/zip4j/core/ZipFile.java
index 0daba77..3473af4 100644
--- a/src/net/lingala/zip4j/core/ZipFile.java
+++ b/src/net/lingala/zip4j/core/ZipFile.java
@@ -12,8 +12,7 @@
* 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.core;
import java.io.File;
@@ -40,1002 +39,1123 @@
import net.lingala.zip4j.zip.ZipEngine;
/**
- * Base class to handle zip files. Some of the operations supported
- * in this class are:
+ * 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
+ * - 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 {
-
- private String file;
- private int mode;
- private ZipModel zipModel;
- private boolean isEncrypted;
- private ProgressMonitor progressMonitor;
- private boolean runInThread;
- private String fileNameCharset;
-
- /**
- * Creates a new Zip File Object with the given zip file path.
- * If the zip file does not exist, it is not created at this point.
- * @param zipFile
- * @throws ZipException
- */
- public ZipFile(String zipFile) throws ZipException {
- this(new File(zipFile));
- }
-
- /**
- * 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
- * @throws ZipException
- */
- public ZipFile(File zipFile) throws ZipException {
- if (zipFile == null) {
- throw new ZipException("Input zip file parameter is not null",
- ZipExceptionConstants.inputZipParamIsNull);
- }
-
- this.file = zipFile.getPath();
- this.mode = InternalZipConstants.MODE_UNZIP;
- this.progressMonitor = new ProgressMonitor();
- this.runInThread = false;
- }
-
- /**
- * Creates a zip file and adds the source file 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
- * @param sourceFile - File to be added to the zip file
- * @param parameters - parameters to create the zip file
- * @throws ZipException
- */
- public void createZipFile(File sourceFile, ZipParameters parameters) throws ZipException {
- ArrayList sourceFileList = new ArrayList();
- sourceFileList.add(sourceFile);
- createZipFile(sourceFileList, parameters, false, -1);
- }
-
- /**
- * Creates a zip file and adds the source file 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 sourceFile - File to be added to the zip file
- * @param parameters - parameters to create the zip file
- * @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 createZipFile(File sourceFile, ZipParameters parameters,
- boolean splitArchive, long splitLength) throws ZipException {
-
- ArrayList sourceFileList = new ArrayList();
- sourceFileList.add(sourceFile);
- createZipFile(sourceFileList, parameters, splitArchive, splitLength);
- }
-
- /**
- * 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
- * @param sourceFileList - File to be added to the zip file
- * @param parameters - parameters to create the zip file
- * @throws ZipException
- */
- public void createZipFile(ArrayList sourceFileList,
- ZipParameters parameters) throws ZipException {
- createZipFile(sourceFileList, parameters, false, -1);
- }
-
- /**
- * 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 sourceFileList - 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 createZipFile(ArrayList sourceFileList, ZipParameters parameters,
- boolean splitArchive, long splitLength) throws ZipException {
-
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(file)) {
- throw new ZipException("zip file path is empty");
- }
-
- if (Zip4jUtil.checkFileExists(file)) {
- throw new ZipException("zip file: " + file + " already exists. To add files to existing zip file use addFile method");
- }
-
- if (sourceFileList == null) {
- throw new ZipException("input file ArrayList is null, cannot create zip file");
- }
-
- if (!Zip4jUtil.checkArrayListTypes(sourceFileList, InternalZipConstants.LIST_TYPE_FILE)) {
- throw new ZipException("One or more elements in the input ArrayList is not of type File");
- }
-
- createNewZipModel();
- this.zipModel.setSplitArchive(splitArchive);
- this.zipModel.setSplitLength(splitLength);
- addFiles(sourceFileList, parameters);
- }
-
- /**
- * 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 createZipFileFromFolder(String folderToAdd, ZipParameters parameters,
- boolean splitArchive, long splitLength) throws ZipException {
-
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(folderToAdd)) {
- throw new ZipException("folderToAdd is empty or null, cannot create Zip File from folder");
- }
-
- createZipFileFromFolder(new File(folderToAdd), parameters, splitArchive, splitLength);
-
- }
-
- /**
- * 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 createZipFileFromFolder(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 (Zip4jUtil.checkFileExists(file)) {
- throw new ZipException("zip file: " + file + " already exists. To add files to existing zip file use addFolder method");
- }
-
- createNewZipModel();
- this.zipModel.setSplitArchive(splitArchive);
- if (splitArchive)
- this.zipModel.setSplitLength(splitLength);
-
- addFolder(folderToAdd, parameters, false);
- }
-
- /**
- * Adds input source file 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 sourceFile - File to tbe added to the zip file
- * @param parameters - zip parameters for this file
- * @throws ZipException
- */
- public void addFile(File sourceFile, ZipParameters parameters) throws ZipException {
- ArrayList sourceFileList = new ArrayList();
- sourceFileList.add(sourceFile);
- addFiles(sourceFileList, parameters);
- }
-
- /**
- * 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 sourceFileList
- * @param parameters
- * @throws ZipException
- */
- public void addFiles(ArrayList sourceFileList, ZipParameters parameters) throws ZipException {
-
- checkZipModel();
-
- if (this.zipModel == null) {
- throw new ZipException("internal error: zip model is null");
- }
-
- if (sourceFileList == null) {
- throw new ZipException("input file ArrayList is null, cannot add files");
- }
-
- if (!Zip4jUtil.checkArrayListTypes(sourceFileList, InternalZipConstants.LIST_TYPE_FILE)) {
- throw new ZipException("One or more elements in the input ArrayList is not of type File");
- }
-
- if (parameters == null) {
- throw new ZipException("input parameters are null, cannot add files to zip");
- }
-
- if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
- throw new ZipException("invalid operation - Zip4j is in busy state");
- }
-
- if (Zip4jUtil.checkFileExists(file)) {
- if (zipModel.isSplitArchive()) {
- throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
- }
- }
-
- ZipEngine zipEngine = new ZipEngine(zipModel);
- zipEngine.addFiles(sourceFileList, parameters, progressMonitor, runInThread);
- }
-
- /**
- * Adds the folder in the given path to the zip file. If zip file does not exist,
- * then a new zip file is created. If input folder path 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 path
- * @param parameters
- * @throws ZipException
- */
- public void addFolder(String path, ZipParameters parameters) throws ZipException {
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(path)) {
- throw new ZipException("input path is null or empty, cannot add folder to zip file");
- }
-
- addFolder(new File(path), parameters);
- }
-
- /**
- * 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 path
- * @param parameters
- * @throws ZipException
- */
- public void addFolder(File path, ZipParameters parameters) throws ZipException {
- if (path == null) {
- throw new ZipException("input path is null, cannot add folder to zip file");
- }
-
- if (parameters == null) {
- throw new ZipException("input parameters are null, cannot add folder to zip file");
- }
-
- addFolder(path, parameters, true);
- }
-
- /**
- * Internal method to add a folder to the zip file.
- * @param path
- * @param parameters
- * @param checkSplitArchive
- * @throws ZipException
- */
- private void addFolder(File path, ZipParameters parameters,
- boolean checkSplitArchive) throws ZipException {
-
- checkZipModel();
-
- if (this.zipModel == null) {
- throw new ZipException("internal error: zip model is null");
- }
-
- if (checkSplitArchive) {
- if (this.zipModel.isSplitArchive()) {
- throw new ZipException("This is a split archive. Zip file format does not allow updating split/spanned files");
- }
- }
-
- ZipEngine zipEngine = new ZipEngine(zipModel);
- zipEngine.addFolderToZip(path, parameters, progressMonitor, runInThread);
-
- }
-
- /**
- * Creates a new entry in the zip file and adds the content of the inputstream 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);
-
- checkZipModel();
-
- if (this.zipModel == null) {
- throw new ZipException("internal error: zip model is null");
- }
-
- if (Zip4jUtil.checkFileExists(file)) {
- if (zipModel.isSplitArchive()) {
- throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
- }
- }
-
- ZipEngine zipEngine = new ZipEngine(zipModel);
- zipEngine.addStreamToZip(inputStream, parameters);
- }
-
- /**
- * Reads the zip header information for this zip file. If the zip file
- * does not exist, then this method throws an exception.
- * Note: This method does not read local file header information
- * @throws ZipException
- */
- private void readZipInfo() throws ZipException {
-
- if (!Zip4jUtil.checkFileExists(file)) {
- throw new ZipException("zip file does not exist");
- }
-
- if (!Zip4jUtil.checkFileReadAccess(this.file)) {
- throw new ZipException("no read access for the input zip file");
- }
-
- if (this.mode != InternalZipConstants.MODE_UNZIP) {
- throw new ZipException("Invalid mode");
- }
-
- RandomAccessFile raf = null;
- try {
- raf = new RandomAccessFile(new File(file), InternalZipConstants.READ_MODE);
-
- if (zipModel == null) {
-
- HeaderReader headerReader = new HeaderReader(raf);
- zipModel = headerReader.readAllHeaders(this.fileNameCharset);
- if (zipModel != null) {
- zipModel.setZipFile(file);
- }
- }
- } catch (FileNotFoundException e) {
- throw new ZipException(e);
- } finally {
- if (raf != null) {
- try {
- raf.close();
- } catch (IOException e) {
- //ignore
- }
- }
- }
- }
-
- /**
- * 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 destPath
- * @throws ZipException
- */
- public void extractAll(String destPath) throws ZipException {
- extractAll(destPath, null);
-
- }
-
- /**
- * 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 destPath
- * @param unzipParameters
- * @throws ZipException
- */
- public void extractAll(String destPath,
- UnzipParameters unzipParameters) throws ZipException {
-
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(destPath)) {
- throw new ZipException("output path is null or invalid");
- }
-
- if (!Zip4jUtil.checkOutputFolder(destPath)) {
- 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");
- }
-
- if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
- throw new ZipException("invalid operation - Zip4j is in busy state");
- }
-
- Unzip unzip = new Unzip(zipModel);
- unzip.extractAll(unzipParameters, destPath, progressMonitor, runInThread);
-
- }
-
- /**
- * Extracts a specific file from the zip file to the destination path.
- * If destination path is invalid, then this method throws an exception.
- * @param fileHeader
- * @param destPath
- * @throws ZipException
- */
- public void extractFile(FileHeader fileHeader, String destPath) throws ZipException {
- extractFile(fileHeader, destPath, null);
- }
-
- /**
- * 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
- * @param fileHeader
- * @param destPath
- * @param unzipParameters
- * @throws ZipException
- */
- public void extractFile(FileHeader fileHeader,
- String destPath, UnzipParameters unzipParameters) throws ZipException {
- extractFile(fileHeader, destPath, unzipParameters, null);
- }
-
- /**
- * Extracts a specific file from the zip file to the destination path.
- * If destination path is invalid, then this method throws an exception.
- * @param fileHeader
- * @param destPath
- * @param unzipParameters
- * @param newFileName
- * @throws ZipException
- */
- public void extractFile(FileHeader fileHeader, String destPath,
- UnzipParameters unzipParameters, String newFileName) throws ZipException {
-
- if (fileHeader == null) {
- throw new ZipException("input file header is null, cannot extract file");
- }
-
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(destPath)) {
- throw new ZipException("destination path is empty or null, cannot extract file");
- }
-
- readZipInfo();
-
- if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
- throw new ZipException("invalid operation - Zip4j is in busy state");
- }
-
- fileHeader.extractFile(zipModel, destPath, unzipParameters, newFileName, progressMonitor, runInThread);
-
- }
-
- /**
- * 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
- *
- * Throws an exception if file header could not be found for the given file name or if
- * the destination path is invalid
- * @param fileName
- * @param destPath
- * @throws ZipException
- */
- public void extractFile(String fileName, String destPath) throws ZipException {
- extractFile(fileName, destPath, null);
- }
-
- /**
- * 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
- *
- * Throws an exception if file header could not be found for the given file name or if
- * the destination path is invalid
- * @param fileName
- * @param destPath
- * @param unzipParameters
- * @throws ZipException
- */
- public void extractFile(String fileName,
- String destPath, UnzipParameters unzipParameters) throws ZipException {
- extractFile(fileName, destPath, unzipParameters, null);
- }
-
- /**
- * 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
- *
- * Throws an exception if file header could not be found for the given file name or if
- * the destination path is invalid
- * @param fileName
- * @param destPath
- * @param unzipParameters
- * @param newFileName
- * @throws ZipException
- */
- public void extractFile(String fileName, String destPath,
- UnzipParameters unzipParameters, String newFileName) throws ZipException {
-
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
- throw new ZipException("file to extract is null or empty, cannot extract file");
- }
-
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(destPath)) {
- throw new ZipException("destination string path is empty or null, cannot extract file");
- }
-
- readZipInfo();
-
- FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, fileName);
-
- if (fileHeader == null) {
- throw new ZipException("file header not found for given file name, cannot extract file");
- }
-
- if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
- throw new ZipException("invalid operation - Zip4j is in busy state");
- }
-
- fileHeader.extractFile(zipModel, destPath, unzipParameters, newFileName, progressMonitor, runInThread);
-
- }
-
- /**
- * Sets the password for the zip file.
- * Note: For security reasons, usage of this method is discouraged. Use
- * setPassword(char[]) instead. As strings are immutable, they cannot be wiped
- * out from memory explicitly after usage. Therefore, usage of Strings to store
- * passwords is discouraged. More info here:
- * http://docs.oracle.com/javase/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx
- * @param password
- * @throws ZipException
- */
- public void setPassword(String password) throws ZipException {
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(password)) {
- throw new NullPointerException();
- }
- setPassword(password.toCharArray());
- }
-
- /**
- * Sets the password for the zip file
- * @param password
- * @throws ZipException
- */
- public void setPassword(char[] password) 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 (int i = 0; i < zipModel.getCentralDirectory().getFileHeaders().size(); i++) {
- if (zipModel.getCentralDirectory().getFileHeaders().get(i) != null) {
- if (((FileHeader)zipModel.getCentralDirectory().getFileHeaders().get(i)).isEncrypted()) {
- ((FileHeader)zipModel.getCentralDirectory().getFileHeaders().get(i)).setPassword(password);
- }
- }
- }
- }
-
- /**
- * Returns the list of file headers in the zip file. Throws an exception 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 null;
- }
- 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 (!Zip4jUtil.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 Zip4jUtil.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");
- }
-
- ArrayList fileHeaderList = zipModel.getCentralDirectory().getFileHeaders();
- for (int i = 0; i < fileHeaderList.size(); i++) {
- FileHeader fileHeader = (FileHeader)fileHeaderList.get(i);
- 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 paramters 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.
- * @param fileName
- * @throws ZipException
- */
- public void removeFile(String fileName) throws ZipException {
-
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
- throw new ZipException("file name is empty or null, cannot remove file");
- }
-
- if (zipModel == null) {
- if (Zip4jUtil.checkFileExists(file)) {
- readZipInfo();
- }
- }
-
- if (zipModel.isSplitArchive()) {
- throw new ZipException("Zip file format does not allow updating split/spanned files");
- }
-
- FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, fileName);
- if (fileHeader == null) {
- throw new ZipException("could not find file header for file: " + fileName);
- }
-
- removeFile(fileHeader);
- }
-
- /**
- * 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.
- * @param fileHeader
- * @throws ZipException
- */
- public void removeFile(FileHeader fileHeader) throws ZipException {
- if (fileHeader == null) {
- throw new ZipException("file header is null, cannot remove file");
- }
-
- if (zipModel == null) {
- if (Zip4jUtil.checkFileExists(file)) {
- readZipInfo();
- }
- }
-
- if (zipModel.isSplitArchive()) {
- throw new ZipException("Zip file format does not allow updating split/spanned files");
- }
-
- ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
- archiveMaintainer.initProgressMonitorForRemoveOp(zipModel, fileHeader, progressMonitor);
- archiveMaintainer.removeZipFile(zipModel, fileHeader, progressMonitor, runInThread);
- }
-
- /**
- * 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");
- }
-
- checkZipModel();
-
- if (this.zipModel == null) {
- throw new ZipException("zip model is null, corrupt zip file?");
- }
-
- ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
- archiveMaintainer.initProgressMonitorForMergeOp(zipModel, progressMonitor);
- archiveMaintainer.mergeSplitZipFiles(zipModel, outputZipFile, progressMonitor, runInThread);
- }
-
- /**
- * 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 (!Zip4jUtil.checkFileExists(file)) {
- throw new ZipException("zip file does not exist, cannot set comment for zip file");
- }
-
- readZipInfo();
-
- if (this.zipModel == null) {
- throw new ZipException("zipModel is null, cannot update zip file");
- }
-
- if (zipModel.getEndCentralDirRecord() == null) {
- throw new ZipException("end of central directory is null, cannot set comment");
- }
-
- ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
- archiveMaintainer.setComment(zipModel, comment);
- }
-
- /**
- * Returns the comment set for the Zip file
- * @return String
- * @throws ZipException
- */
- public String getComment() throws ZipException {
- return getComment(null);
- }
-
- /**
- * Returns the comment set for the Zip file in the input encoding
- * @param encoding
- * @return String
- * @throws ZipException
- */
- public String getComment(String encoding) throws ZipException {
- if (encoding == null) {
- if (Zip4jUtil.isSupportedCharset(InternalZipConstants.CHARSET_COMMENTS_DEFAULT)) {
- encoding = InternalZipConstants.CHARSET_COMMENTS_DEFAULT;
- } else {
- encoding = InternalZipConstants.CHARSET_DEFAULT;
- }
- }
-
- if (Zip4jUtil.checkFileExists(file)) {
- checkZipModel();
- } else {
- throw new ZipException("zip file does not exist, cannot read comment");
- }
-
- if (this.zipModel == null) {
- throw new ZipException("zip model is null, cannot read comment");
- }
-
- if (this.zipModel.getEndCentralDirRecord() == null) {
- throw new ZipException("end of central directory record is null, cannot read comment");
- }
-
- if (this.zipModel.getEndCentralDirRecord().getCommentBytes() == null ||
- this.zipModel.getEndCentralDirRecord().getCommentBytes().length <= 0) {
- return null;
- }
-
- try {
- return new String(this.zipModel.getEndCentralDirRecord().getCommentBytes(), encoding);
- } catch (UnsupportedEncodingException e) {
- throw new ZipException(e);
- }
- }
-
- /**
- * Loads the zip model if zip model is null and if zip file exists.
- * @throws ZipException
- */
- private void checkZipModel() throws ZipException {
- if (this.zipModel == null) {
- if (Zip4jUtil.checkFileExists(file)) {
- readZipInfo();
- } else {
- createNewZipModel();
- }
- }
- }
-
- /**
- * Creates a new instance of zip model
- * @throws ZipException
- */
- private void createNewZipModel() {
- zipModel = new ZipModel();
- zipModel.setZipFile(file);
- zipModel.setFileNameCharset(fileNameCharset);
- }
-
- /**
- * Zip4j will encode all the file names with the input charset. This method throws
- * an exception if the Charset is not supported
- * @param charsetName
- * @throws ZipException
- */
- public void setFileNameCharset(String charsetName) throws ZipException {
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(charsetName)) {
- throw new ZipException("null or empty charset name");
- }
-
- if (!Zip4jUtil.isSupportedCharset(charsetName)) {
- throw new ZipException("unsupported charset: " + charsetName);
- }
-
- this.fileNameCharset = charsetName;
- }
-
- /**
- * 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 ZipException {
- if (fileHeader == null) {
- throw new ZipException("FileHeader is null, cannot get InputStream");
- }
-
- checkZipModel();
-
- if (zipModel == null) {
- throw new ZipException("zip model is null, cannot get inputstream");
- }
-
- Unzip unzip = new Unzip(zipModel);
- return unzip.getInputStream(fileHeader);
- }
-
- /**
- * 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
- * @return boolean
- * @since 1.2.3
- */
- public boolean isValidZipFile() {
- try {
- readZipInfo();
- 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 ArrayList of Strings
- * @throws ZipException
- */
- public ArrayList getSplitZipFiles() throws ZipException {
- checkZipModel();
- return Zip4jUtil.getSplitZipFiles(zipModel);
- }
-
- public ProgressMonitor getProgressMonitor() {
- return progressMonitor;
- }
-
- public boolean isRunInThread() {
- return runInThread;
- }
-
- public void setRunInThread(boolean runInThread) {
- this.runInThread = runInThread;
- }
-
- /**
- * Returns the File object of the zip file
- * @return File
- */
- public File getFile() {
- return new File(this.file);
- }
+
+ private static String VERSIONE ="1.0.3";
+ private String file;
+ private int mode;
+ private ZipModel zipModel;
+ private boolean isEncrypted;
+ private ProgressMonitor progressMonitor;
+ private boolean runInThread;
+ private String fileNameCharset;
+
+ /**
+ * Creates a new Zip File Object with the given zip file path. If the zip
+ * file does not exist, it is not created at this point.
+ *
+ * @param zipFile
+ * @throws ZipException
+ */
+ public ZipFile(String zipFile) throws ZipException {
+ this(new File(zipFile));
+ }
+
+ /**
+ * 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
+ * @throws ZipException
+ */
+ public ZipFile(File zipFile) throws ZipException {
+ if (zipFile == null) {
+ throw new ZipException("Input zip file parameter is not null",
+ ZipExceptionConstants.inputZipParamIsNull);
+ }
+
+ this.file = zipFile.getPath();
+ this.mode = InternalZipConstants.MODE_UNZIP;
+ this.progressMonitor = new ProgressMonitor();
+ this.runInThread = false;
+ }
+
+ /**
+ * Creates a zip file and adds the source file 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
+ *
+ * @param sourceFile - File to be added to the zip file
+ * @param parameters - parameters to create the zip file
+ * @throws ZipException
+ */
+ public void createZipFile(File sourceFile, ZipParameters parameters) throws ZipException {
+ ArrayList sourceFileList = new ArrayList();
+ sourceFileList.add(sourceFile);
+ createZipFile(sourceFileList, parameters, false, -1);
+ }
+
+ /**
+ * Creates a zip file and adds the source file 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 sourceFile - File to be added to the zip file
+ * @param parameters - parameters to create the zip file
+ * @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 createZipFile(File sourceFile, ZipParameters parameters,
+ boolean splitArchive, long splitLength) throws ZipException {
+
+ ArrayList sourceFileList = new ArrayList();
+ sourceFileList.add(sourceFile);
+ createZipFile(sourceFileList, parameters, splitArchive, splitLength);
+ }
+
+ /**
+ * 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
+ *
+ * @param sourceFileList - File to be added to the zip file
+ * @param parameters - parameters to create the zip file
+ * @throws ZipException
+ */
+ public void createZipFile(ArrayList sourceFileList,
+ ZipParameters parameters) throws ZipException {
+ createZipFile(sourceFileList, parameters, false, -1);
+ }
+
+ /**
+ * 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 sourceFileList - 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 createZipFile(ArrayList sourceFileList, ZipParameters parameters,
+ boolean splitArchive, long splitLength) throws ZipException {
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(file)) {
+ throw new ZipException("zip file path is empty");
+ }
+
+ if (Zip4jUtil.checkFileExists(file)) {
+ throw new ZipException("zip file: " + file + " already exists. To add files to existing zip file use addFile method");
+ }
+
+ if (sourceFileList == null) {
+ throw new ZipException("input file ArrayList is null, cannot create zip file");
+ }
+
+ if (!Zip4jUtil.checkArrayListTypes(sourceFileList, InternalZipConstants.LIST_TYPE_FILE)) {
+ throw new ZipException("One or more elements in the input ArrayList is not of type File");
+ }
+
+ createNewZipModel();
+ this.zipModel.setSplitArchive(splitArchive);
+ this.zipModel.setSplitLength(splitLength);
+ addFiles(sourceFileList, parameters);
+ }
+
+ /**
+ * 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 createZipFileFromFolder(String folderToAdd, ZipParameters parameters,
+ boolean splitArchive, long splitLength) throws ZipException {
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(folderToAdd)) {
+ throw new ZipException("folderToAdd is empty or null, cannot create Zip File from folder");
+ }
+
+ createZipFileFromFolder(new File(folderToAdd), parameters, splitArchive, splitLength);
+
+ }
+
+ /**
+ * 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 createZipFileFromFolder(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 (Zip4jUtil.checkFileExists(file)) {
+ throw new ZipException("zip file: " + file + " already exists. To add files to existing zip file use addFolder method");
+ }
+
+ createNewZipModel();
+ this.zipModel.setSplitArchive(splitArchive);
+ if (splitArchive) {
+ this.zipModel.setSplitLength(splitLength);
+ }
+
+ addFolder(folderToAdd, parameters, false);
+ }
+
+ /**
+ * Creates a zip file and adds the list of source folder(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 addFolders 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 sourceFolderList - list of folders 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 createZipFileFromFolders(ArrayList sourceFolderList, ZipParameters parameters, boolean splitArchive, long splitLength) throws ZipException {
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(file)) {
+ throw new ZipException("zip file path is empty");
+ }
+
+ if (Zip4jUtil.checkFileExists(file)) {
+ throw new ZipException("zip file: " + file + " already exists. To add files to existing zip file use addFile method");
+ }
+
+ if (sourceFolderList == null) {
+ throw new ZipException("input file ArrayList is null, cannot create zip file");
+ }
+
+ if (!Zip4jUtil.checkArrayListTypes(sourceFolderList, InternalZipConstants.LIST_TYPE_FILE)) {
+ throw new ZipException("One or more elements in the input ArrayList is not of type File");
+ }
+
+ createNewZipModel();
+ this.zipModel.setSplitArchive(splitArchive);
+ this.zipModel.setSplitLength(splitLength);
+ addFolders(sourceFolderList, parameters, false);
+
+ }
+
+ /**
+ * Adds input source file 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 sourceFile - File to tbe added to the zip file
+ * @param parameters - zip parameters for this file
+ * @throws ZipException
+ */
+ public void addFile(File sourceFile, ZipParameters parameters) throws ZipException {
+ ArrayList sourceFileList = new ArrayList();
+ sourceFileList.add(sourceFile);
+ addFiles(sourceFileList, parameters);
+ }
+
+ /**
+ * 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 sourceFileList
+ * @param parameters
+ * @throws ZipException
+ */
+ public void addFiles(ArrayList sourceFileList, ZipParameters parameters) throws ZipException {
+
+ checkZipModel();
+
+ if (this.zipModel == null) {
+ throw new ZipException("internal error: zip model is null");
+ }
+
+ if (sourceFileList == null) {
+ throw new ZipException("input file ArrayList is null, cannot add files");
+ }
+
+ if (!Zip4jUtil.checkArrayListTypes(sourceFileList, InternalZipConstants.LIST_TYPE_FILE)) {
+ throw new ZipException("One or more elements in the input ArrayList is not of type File");
+ }
+
+ if (parameters == null) {
+ throw new ZipException("input parameters are null, cannot add files to zip");
+ }
+
+ if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
+ throw new ZipException("invalid operation - Zip4j is in busy state");
+ }
+
+ if (Zip4jUtil.checkFileExists(file)) {
+ if (zipModel.isSplitArchive()) {
+ throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
+ }
+ }
+
+ ZipEngine zipEngine = new ZipEngine(zipModel);
+ zipEngine.addFiles(sourceFileList, parameters, progressMonitor, runInThread);
+ }
+
+ /**
+ * Adds the folder in the given path to the zip file. If zip file does not
+ * exist, then a new zip file is created. If input folder path 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 path
+ * @param parameters
+ * @throws ZipException
+ */
+ public void addFolder(String path, ZipParameters parameters) throws ZipException {
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(path)) {
+ throw new ZipException("input path is null or empty, cannot add folder to zip file");
+ }
+
+ addFolder(new File(path), parameters);
+ }
+
+ /**
+ * 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 path
+ * @param parameters
+ * @throws ZipException
+ */
+ public void addFolder(File path, ZipParameters parameters) throws ZipException {
+ if (path == null) {
+ throw new ZipException("input path is null, cannot add folder to zip file");
+ }
+
+ if (parameters == null) {
+ throw new ZipException("input parameters are null, cannot add folder to zip file");
+ }
+
+ addFolder(path, parameters, true);
+ }
+
+ /**
+ * Internal method to add a list of folders to the zip file.
+ *
+ * @param foldersList
+ * @param parameters
+ * @param checkSplitArchive
+ * @throws ZipException
+ */
+ private void addFolders(ArrayList foldersList, ZipParameters parameters, boolean checkSplitArchive) throws ZipException {
+
+ checkZipModel();
+
+ if (this.zipModel == null) {
+ throw new ZipException("internal error: zip model is null");
+ }
+
+ if (checkSplitArchive) {
+ if (this.zipModel.isSplitArchive()) {
+ throw new ZipException("This is a split archive. Zip file format does not allow updating split/spanned files");
+ }
+ }
+
+ ZipEngine zipEngine = new ZipEngine(zipModel);
+ zipEngine.addFoldersToZip(foldersList, parameters, progressMonitor, runInThread);
+
+ }
+
+ /**
+ * Internal method to add a folder to the zip file.
+ *
+ * @param path
+ * @param parameters
+ * @param checkSplitArchive
+ * @throws ZipException
+ */
+ private void addFolder(File path, ZipParameters parameters,
+ boolean checkSplitArchive) throws ZipException {
+
+ checkZipModel();
+
+ if (this.zipModel == null) {
+ throw new ZipException("internal error: zip model is null");
+ }
+
+ if (checkSplitArchive) {
+ if (this.zipModel.isSplitArchive()) {
+ throw new ZipException("This is a split archive. Zip file format does not allow updating split/spanned files");
+ }
+ }
+
+ ZipEngine zipEngine = new ZipEngine(zipModel);
+ zipEngine.addFolderToZip(path, parameters, progressMonitor, runInThread);
+
+ }
+
+ /**
+ * Creates a new entry in the zip file and adds the content of the
+ * inputstream 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);
+
+ checkZipModel();
+
+ if (this.zipModel == null) {
+ throw new ZipException("internal error: zip model is null");
+ }
+
+ if (Zip4jUtil.checkFileExists(file)) {
+ if (zipModel.isSplitArchive()) {
+ throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
+ }
+ }
+
+ ZipEngine zipEngine = new ZipEngine(zipModel);
+ zipEngine.addStreamToZip(inputStream, parameters);
+ }
+
+ /**
+ * Reads the zip header information for this zip file. If the zip file does
+ * not exist, then this method throws an exception.
+ * Note: This method does not read local file header information
+ *
+ * @throws ZipException
+ */
+ private void readZipInfo() throws ZipException {
+
+ if (!Zip4jUtil.checkFileExists(file)) {
+ throw new ZipException("zip file does not exist");
+ }
+
+ if (!Zip4jUtil.checkFileReadAccess(this.file)) {
+ throw new ZipException("no read access for the input zip file");
+ }
+
+ if (this.mode != InternalZipConstants.MODE_UNZIP) {
+ throw new ZipException("Invalid mode");
+ }
+
+ RandomAccessFile raf = null;
+ try {
+ raf = new RandomAccessFile(new File(file), InternalZipConstants.READ_MODE);
+
+ if (zipModel == null) {
+
+ HeaderReader headerReader = new HeaderReader(raf);
+ zipModel = headerReader.readAllHeaders(this.fileNameCharset);
+ if (zipModel != null) {
+ zipModel.setZipFile(file);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ throw new ZipException(e);
+ } finally {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * 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 destPath
+ * @throws ZipException
+ */
+ public void extractAll(String destPath) throws ZipException {
+ extractAll(destPath, null);
+
+ }
+
+ /**
+ * 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 destPath
+ * @param unzipParameters
+ * @throws ZipException
+ */
+ public void extractAll(String destPath,
+ UnzipParameters unzipParameters) throws ZipException {
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(destPath)) {
+ throw new ZipException("output path is null or invalid");
+ }
+
+ if (!Zip4jUtil.checkOutputFolder(destPath)) {
+ 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");
+ }
+
+ if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
+ throw new ZipException("invalid operation - Zip4j is in busy state");
+ }
+
+ Unzip unzip = new Unzip(zipModel);
+ unzip.extractAll(unzipParameters, destPath, progressMonitor, runInThread);
+
+ }
+
+ /**
+ * Extracts a specific file from the zip file to the destination path. If
+ * destination path is invalid, then this method throws an exception.
+ *
+ * @param fileHeader
+ * @param destPath
+ * @throws ZipException
+ */
+ public void extractFile(FileHeader fileHeader, String destPath) throws ZipException {
+ extractFile(fileHeader, destPath, null);
+ }
+
+ /**
+ * 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
+ *
+ * @param fileHeader
+ * @param destPath
+ * @param unzipParameters
+ * @throws ZipException
+ */
+ public void extractFile(FileHeader fileHeader,
+ String destPath, UnzipParameters unzipParameters) throws ZipException {
+ extractFile(fileHeader, destPath, unzipParameters, null);
+ }
+
+ /**
+ * Extracts a specific file from the zip file to the destination path. If
+ * destination path is invalid, then this method throws an exception.
+ *
+ * @param fileHeader
+ * @param destPath
+ * @param unzipParameters
+ * @param newFileName
+ * @throws ZipException
+ */
+ public void extractFile(FileHeader fileHeader, String destPath,
+ UnzipParameters unzipParameters, String newFileName) throws ZipException {
+
+ if (fileHeader == null) {
+ throw new ZipException("input file header is null, cannot extract file");
+ }
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(destPath)) {
+ throw new ZipException("destination path is empty or null, cannot extract file");
+ }
+
+ readZipInfo();
+
+ if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
+ throw new ZipException("invalid operation - Zip4j is in busy state");
+ }
+
+ fileHeader.extractFile(zipModel, destPath, unzipParameters, newFileName, progressMonitor, runInThread);
+
+ }
+
+ /**
+ * 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
+ *
+ * Throws an exception if file header could not be found for the given file
+ * name or if the destination path is invalid
+ *
+ * @param fileName
+ * @param destPath
+ * @throws ZipException
+ */
+ public void extractFile(String fileName, String destPath) throws ZipException {
+ extractFile(fileName, destPath, null);
+ }
+
+ /**
+ * 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
+ *
+ * Throws an exception if file header could not be found for the given file
+ * name or if the destination path is invalid
+ *
+ * @param fileName
+ * @param destPath
+ * @param unzipParameters
+ * @throws ZipException
+ */
+ public void extractFile(String fileName,
+ String destPath, UnzipParameters unzipParameters) throws ZipException {
+ extractFile(fileName, destPath, unzipParameters, null);
+ }
+
+ /**
+ * 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
+ *
+ * Throws an exception if file header could not be found for the given file
+ * name or if the destination path is invalid
+ *
+ * @param fileName
+ * @param destPath
+ * @param unzipParameters
+ * @param newFileName
+ * @throws ZipException
+ */
+ public void extractFile(String fileName, String destPath,
+ UnzipParameters unzipParameters, String newFileName) throws ZipException {
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
+ throw new ZipException("file to extract is null or empty, cannot extract file");
+ }
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(destPath)) {
+ throw new ZipException("destination string path is empty or null, cannot extract file");
+ }
+
+ readZipInfo();
+
+ FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, fileName);
+
+ if (fileHeader == null) {
+ throw new ZipException("file header not found for given file name, cannot extract file");
+ }
+
+ if (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
+ throw new ZipException("invalid operation - Zip4j is in busy state");
+ }
+
+ fileHeader.extractFile(zipModel, destPath, unzipParameters, newFileName, progressMonitor, runInThread);
+
+ }
+
+ /**
+ * Sets the password for the zip file.
+ * Note: For security reasons, usage of this method is discouraged.
+ * Use setPassword(char[]) instead. As strings are immutable, they cannot be
+ * wiped out from memory explicitly after usage. Therefore, usage of Strings
+ * to store passwords is discouraged. More info here:
+ * http://docs.oracle.com/javase/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx
+ *
+ * @param password
+ * @throws ZipException
+ */
+ public void setPassword(String password) throws ZipException {
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(password)) {
+ throw new NullPointerException();
+ }
+ setPassword(password.toCharArray());
+ }
+
+ /**
+ * Sets the password for the zip file
+ *
+ * @param password
+ * @throws ZipException
+ */
+ public void setPassword(char[] password) 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 (int i = 0; i < zipModel.getCentralDirectory().getFileHeaders().size(); i++) {
+ if (zipModel.getCentralDirectory().getFileHeaders().get(i) != null) {
+ if (((FileHeader) zipModel.getCentralDirectory().getFileHeaders().get(i)).isEncrypted()) {
+ ((FileHeader) zipModel.getCentralDirectory().getFileHeaders().get(i)).setPassword(password);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the list of file headers in the zip file. Throws an exception 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 null;
+ }
+ 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 (!Zip4jUtil.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 Zip4jUtil.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");
+ }
+
+ ArrayList fileHeaderList = zipModel.getCentralDirectory().getFileHeaders();
+ for (int i = 0; i < fileHeaderList.size(); i++) {
+ FileHeader fileHeader = (FileHeader) fileHeaderList.get(i);
+ 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 paramters 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.
+ *
+ * @param fileName
+ * @throws ZipException
+ */
+ public void removeFile(String fileName) throws ZipException {
+
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
+ throw new ZipException("file name is empty or null, cannot remove file");
+ }
+
+ if (zipModel == null) {
+ if (Zip4jUtil.checkFileExists(file)) {
+ readZipInfo();
+ }
+ }
+
+ if (zipModel.isSplitArchive()) {
+ throw new ZipException("Zip file format does not allow updating split/spanned files");
+ }
+
+ FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, fileName);
+ if (fileHeader == null) {
+ throw new ZipException("could not find file header for file: " + fileName);
+ }
+
+ removeFile(fileHeader);
+ }
+
+ /**
+ * 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.
+ *
+ * @param fileHeader
+ * @throws ZipException
+ */
+ public void removeFile(FileHeader fileHeader) throws ZipException {
+ if (fileHeader == null) {
+ throw new ZipException("file header is null, cannot remove file");
+ }
+
+ if (zipModel == null) {
+ if (Zip4jUtil.checkFileExists(file)) {
+ readZipInfo();
+ }
+ }
+
+ if (zipModel.isSplitArchive()) {
+ throw new ZipException("Zip file format does not allow updating split/spanned files");
+ }
+
+ ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
+ archiveMaintainer.initProgressMonitorForRemoveOp(zipModel, fileHeader, progressMonitor);
+ archiveMaintainer.removeZipFile(zipModel, fileHeader, progressMonitor, runInThread);
+ }
+
+ /**
+ * 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");
+ }
+
+ checkZipModel();
+
+ if (this.zipModel == null) {
+ throw new ZipException("zip model is null, corrupt zip file?");
+ }
+
+ ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
+ archiveMaintainer.initProgressMonitorForMergeOp(zipModel, progressMonitor);
+ archiveMaintainer.mergeSplitZipFiles(zipModel, outputZipFile, progressMonitor, runInThread);
+ }
+
+ /**
+ * 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 (!Zip4jUtil.checkFileExists(file)) {
+ throw new ZipException("zip file does not exist, cannot set comment for zip file");
+ }
+
+ readZipInfo();
+
+ if (this.zipModel == null) {
+ throw new ZipException("zipModel is null, cannot update zip file");
+ }
+
+ if (zipModel.getEndCentralDirRecord() == null) {
+ throw new ZipException("end of central directory is null, cannot set comment");
+ }
+
+ ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
+ archiveMaintainer.setComment(zipModel, comment);
+ }
+
+ /**
+ * Returns the comment set for the Zip file
+ *
+ * @return String
+ * @throws ZipException
+ */
+ public String getComment() throws ZipException {
+ return getComment(null);
+ }
+
+ /**
+ * Returns the comment set for the Zip file in the input encoding
+ *
+ * @param encoding
+ * @return String
+ * @throws ZipException
+ */
+ public String getComment(String encoding) throws ZipException {
+ if (encoding == null) {
+ if (Zip4jUtil.isSupportedCharset(InternalZipConstants.CHARSET_COMMENTS_DEFAULT)) {
+ encoding = InternalZipConstants.CHARSET_COMMENTS_DEFAULT;
+ } else {
+ encoding = InternalZipConstants.CHARSET_DEFAULT;
+ }
+ }
+
+ if (Zip4jUtil.checkFileExists(file)) {
+ checkZipModel();
+ } else {
+ throw new ZipException("zip file does not exist, cannot read comment");
+ }
+
+ if (this.zipModel == null) {
+ throw new ZipException("zip model is null, cannot read comment");
+ }
+
+ if (this.zipModel.getEndCentralDirRecord() == null) {
+ throw new ZipException("end of central directory record is null, cannot read comment");
+ }
+
+ if (this.zipModel.getEndCentralDirRecord().getCommentBytes() == null
+ || this.zipModel.getEndCentralDirRecord().getCommentBytes().length <= 0) {
+ return null;
+ }
+
+ try {
+ return new String(this.zipModel.getEndCentralDirRecord().getCommentBytes(), encoding);
+ } catch (UnsupportedEncodingException e) {
+ throw new ZipException(e);
+ }
+ }
+
+ /**
+ * Loads the zip model if zip model is null and if zip file exists.
+ *
+ * @throws ZipException
+ */
+ private void checkZipModel() throws ZipException {
+ if (this.zipModel == null) {
+ if (Zip4jUtil.checkFileExists(file)) {
+ readZipInfo();
+ } else {
+ createNewZipModel();
+ }
+ }
+ }
+
+ /**
+ * Creates a new instance of zip model
+ *
+ * @throws ZipException
+ */
+ private void createNewZipModel() {
+ zipModel = new ZipModel();
+ zipModel.setZipFile(file);
+ zipModel.setFileNameCharset(fileNameCharset);
+ }
+
+ /**
+ * Zip4j will encode all the file names with the input charset. This method
+ * throws an exception if the Charset is not supported
+ *
+ * @param charsetName
+ * @throws ZipException
+ */
+ public void setFileNameCharset(String charsetName) throws ZipException {
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(charsetName)) {
+ throw new ZipException("null or empty charset name");
+ }
+
+ if (!Zip4jUtil.isSupportedCharset(charsetName)) {
+ throw new ZipException("unsupported charset: " + charsetName);
+ }
+
+ this.fileNameCharset = charsetName;
+ }
+
+ /**
+ * 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 ZipException {
+ if (fileHeader == null) {
+ throw new ZipException("FileHeader is null, cannot get InputStream");
+ }
+
+ checkZipModel();
+
+ if (zipModel == null) {
+ throw new ZipException("zip model is null, cannot get inputstream");
+ }
+
+ Unzip unzip = new Unzip(zipModel);
+ return unzip.getInputStream(fileHeader);
+ }
+
+ /**
+ * 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
+ *
+ * @return boolean
+ * @since 1.2.3
+ */
+ public boolean isValidZipFile() {
+ try {
+ readZipInfo();
+ 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 ArrayList of Strings
+ * @throws ZipException
+ */
+ public ArrayList getSplitZipFiles() throws ZipException {
+ checkZipModel();
+ return Zip4jUtil.getSplitZipFiles(zipModel);
+ }
+
+ public ProgressMonitor getProgressMonitor() {
+ return progressMonitor;
+ }
+
+ public boolean isRunInThread() {
+ return runInThread;
+ }
+
+ public void setRunInThread(boolean runInThread) {
+ this.runInThread = runInThread;
+ }
+
+ /**
+ * Returns the File object of the zip file
+ *
+ * @return File
+ */
+ public File getFile() {
+ return new File(this.file);
+ }
}
diff --git a/src/net/lingala/zip4j/io/CipherOutputStream.java b/src/net/lingala/zip4j/io/CipherOutputStream.java
index 06b1b4f..125c871 100644
--- a/src/net/lingala/zip4j/io/CipherOutputStream.java
+++ b/src/net/lingala/zip4j/io/CipherOutputStream.java
@@ -147,7 +147,6 @@ public void putNextEntry(File file, ZipParameters zipParameters) throws ZipExcep
}
}
}
-
crc.reset();
} catch (CloneNotSupportedException e) {
throw new ZipException(e);
diff --git a/src/net/lingala/zip4j/io/DeflaterOutputStream.java b/src/net/lingala/zip4j/io/DeflaterOutputStream.java
index 0e6deb9..7febdff 100644
--- a/src/net/lingala/zip4j/io/DeflaterOutputStream.java
+++ b/src/net/lingala/zip4j/io/DeflaterOutputStream.java
@@ -28,7 +28,7 @@
import net.lingala.zip4j.util.Zip4jConstants;
public class DeflaterOutputStream extends CipherOutputStream {
-
+
private byte[] buff;
protected Deflater deflater;
private boolean firstBytesRead;
@@ -41,7 +41,7 @@ public DeflaterOutputStream(OutputStream outputStream, ZipModel zipModel) {
}
public void putNextEntry(File file, ZipParameters zipParameters)
- throws ZipException {
+ throws ZipException {
super.putNextEntry(file, zipParameters);
if (zipParameters.getCompressionMethod() == Zip4jConstants.COMP_DEFLATE) {
deflater.reset();
diff --git a/src/net/lingala/zip4j/model/ZipParameters.java b/src/net/lingala/zip4j/model/ZipParameters.java
index 166be75..698d38c 100644
--- a/src/net/lingala/zip4j/model/ZipParameters.java
+++ b/src/net/lingala/zip4j/model/ZipParameters.java
@@ -12,10 +12,10 @@
* 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.TimeZone;
import net.lingala.zip4j.util.InternalZipConstants;
@@ -23,173 +23,193 @@
import net.lingala.zip4j.util.Zip4jUtil;
public class ZipParameters implements Cloneable {
-
- private int compressionMethod;
- private int compressionLevel;
- private boolean encryptFiles;
- private int encryptionMethod;
- private boolean readHiddenFiles;
- private char[] password;
- private int aesKeyStrength;
- private boolean includeRootFolder;
- private String rootFolderInZip;
- private TimeZone timeZone;
- private int sourceFileCRC;
- private String defaultFolderPath;
- private String fileNameInZip;
- private boolean isSourceExternalStream;
-
- public ZipParameters() {
- compressionMethod = Zip4jConstants.COMP_DEFLATE;
- encryptFiles = false;
- readHiddenFiles = true;
- encryptionMethod = Zip4jConstants.ENC_NO_ENCRYPTION;
- aesKeyStrength = -1;
- includeRootFolder = true;
- timeZone = TimeZone.getDefault();
- }
-
- public int getCompressionMethod() {
- return compressionMethod;
- }
-
- public void setCompressionMethod(int compressionMethod) {
- this.compressionMethod = compressionMethod;
- }
-
- public boolean isEncryptFiles() {
- return encryptFiles;
- }
-
- public void setEncryptFiles(boolean encryptFiles) {
- this.encryptFiles = encryptFiles;
- }
-
- public int getEncryptionMethod() {
- return encryptionMethod;
- }
-
- public void setEncryptionMethod(int encryptionMethod) {
- this.encryptionMethod = encryptionMethod;
- }
-
- public int getCompressionLevel() {
- return compressionLevel;
- }
-
- public void setCompressionLevel(int compressionLevel) {
- this.compressionLevel = compressionLevel;
- }
-
- public boolean isReadHiddenFiles() {
- return readHiddenFiles;
- }
-
- public void setReadHiddenFiles(boolean readHiddenFiles) {
- this.readHiddenFiles = readHiddenFiles;
- }
-
- public Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
-
- public char[] getPassword() {
- return password;
- }
-
- /**
- * Sets the password for the zip file or the file being added
- * Note: For security reasons, usage of this method is discouraged. Use
- * setPassword(char[]) instead. As strings are immutable, they cannot be wiped
- * out from memory explicitly after usage. Therefore, usage of Strings to store
- * passwords is discouraged. More info here:
- * http://docs.oracle.com/javase/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx
- * @param password
- */
- public void setPassword(String password) {
- if (password == null) return;
- setPassword(password.toCharArray());
- }
-
- public void setPassword(char[] password) {
- this.password = password;
- }
-
- public int getAesKeyStrength() {
- return aesKeyStrength;
- }
-
- public void setAesKeyStrength(int aesKeyStrength) {
- this.aesKeyStrength = aesKeyStrength;
- }
-
- public boolean isIncludeRootFolder() {
- return includeRootFolder;
- }
-
- public void setIncludeRootFolder(boolean includeRootFolder) {
- this.includeRootFolder = includeRootFolder;
- }
-
- public String getRootFolderInZip() {
- return rootFolderInZip;
- }
-
- public void setRootFolderInZip(String rootFolderInZip) {
- if (Zip4jUtil.isStringNotNullAndNotEmpty(rootFolderInZip)) {
-
- if (!rootFolderInZip.endsWith("\\") && !rootFolderInZip.endsWith("/")) {
- rootFolderInZip = rootFolderInZip + InternalZipConstants.FILE_SEPARATOR;
- }
-
- rootFolderInZip = rootFolderInZip.replaceAll("\\\\", "/");
-
+
+ private int compressionMethod;
+ private int compressionLevel;
+ private boolean encryptFiles;
+ private int encryptionMethod;
+ private boolean readHiddenFiles;
+ private char[] password;
+ private int aesKeyStrength;
+ private boolean includeRootFolder;
+ private String rootFolderInZip;
+ private TimeZone timeZone;
+ private int sourceFileCRC;
+ private String defaultFolderPath;
+ private ArrayList folderPath;
+ private String fileNameInZip;
+ private boolean isSourceExternalStream;
+
+ public ZipParameters() {
+ compressionMethod = Zip4jConstants.COMP_DEFLATE;
+ encryptFiles = false;
+ readHiddenFiles = true;
+ encryptionMethod = Zip4jConstants.ENC_NO_ENCRYPTION;
+ aesKeyStrength = -1;
+ includeRootFolder = true;
+ timeZone = TimeZone.getDefault();
+ folderPath = new ArrayList<>();
+ }
+
+ public int getCompressionMethod() {
+ return compressionMethod;
+ }
+
+ public void setCompressionMethod(int compressionMethod) {
+ this.compressionMethod = compressionMethod;
+ }
+
+ public boolean isEncryptFiles() {
+ return encryptFiles;
+ }
+
+ public void setEncryptFiles(boolean encryptFiles) {
+ this.encryptFiles = encryptFiles;
+ }
+
+ public int getEncryptionMethod() {
+ return encryptionMethod;
+ }
+
+ public void setEncryptionMethod(int encryptionMethod) {
+ this.encryptionMethod = encryptionMethod;
+ }
+
+ public int getCompressionLevel() {
+ return compressionLevel;
+ }
+
+ public void setCompressionLevel(int compressionLevel) {
+ this.compressionLevel = compressionLevel;
+ }
+
+ public boolean isReadHiddenFiles() {
+ return readHiddenFiles;
+ }
+
+ public void setReadHiddenFiles(boolean readHiddenFiles) {
+ this.readHiddenFiles = readHiddenFiles;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ public char[] getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the password for the zip file or the file being added
+ * Note: For security reasons, usage of this method is discouraged.
+ * Use setPassword(char[]) instead. As strings are immutable, they cannot be
+ * wiped out from memory explicitly after usage. Therefore, usage of Strings
+ * to store passwords is discouraged. More info here:
+ * http://docs.oracle.com/javase/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx
+ *
+ * @param password
+ */
+ public void setPassword(String password) {
+ if (password == null) {
+ return;
+ }
+ setPassword(password.toCharArray());
+ }
+
+ public void setPassword(char[] password) {
+ this.password = password;
+ }
+
+ public int getAesKeyStrength() {
+ return aesKeyStrength;
+ }
+
+ public void setAesKeyStrength(int aesKeyStrength) {
+ this.aesKeyStrength = aesKeyStrength;
+ }
+
+ public boolean isIncludeRootFolder() {
+ return includeRootFolder;
+ }
+
+ public void setIncludeRootFolder(boolean includeRootFolder) {
+ this.includeRootFolder = includeRootFolder;
+ }
+
+ public String getRootFolderInZip() {
+ return rootFolderInZip;
+ }
+
+ public void setRootFolderInZip(String rootFolderInZip) {
+ if (Zip4jUtil.isStringNotNullAndNotEmpty(rootFolderInZip)) {
+
+ if (!rootFolderInZip.endsWith("\\") && !rootFolderInZip.endsWith("/")) {
+ rootFolderInZip = rootFolderInZip + InternalZipConstants.FILE_SEPARATOR;
+ }
+
+ rootFolderInZip = rootFolderInZip.replaceAll("\\\\", "/");
+
// if (rootFolderInZip.endsWith("/")) {
// rootFolderInZip = rootFolderInZip.substring(0, rootFolderInZip.length() - 1);
// rootFolderInZip = rootFolderInZip + "\\";
// }
- }
- this.rootFolderInZip = rootFolderInZip;
- }
-
- public TimeZone getTimeZone() {
- return timeZone;
- }
-
- public void setTimeZone(TimeZone timeZone) {
- this.timeZone = timeZone;
- }
-
- public int getSourceFileCRC() {
- return sourceFileCRC;
- }
-
- public void setSourceFileCRC(int sourceFileCRC) {
- this.sourceFileCRC = sourceFileCRC;
- }
-
- public String getDefaultFolderPath() {
- return defaultFolderPath;
- }
-
- public void setDefaultFolderPath(String defaultFolderPath) {
- this.defaultFolderPath = defaultFolderPath;
- }
-
- public String getFileNameInZip() {
- return fileNameInZip;
- }
-
- public void setFileNameInZip(String fileNameInZip) {
- this.fileNameInZip = fileNameInZip;
- }
-
- public boolean isSourceExternalStream() {
- return isSourceExternalStream;
- }
-
- public void setSourceExternalStream(boolean isSourceExternalStream) {
- this.isSourceExternalStream = isSourceExternalStream;
- }
-
+ }
+ this.rootFolderInZip = rootFolderInZip;
+ }
+
+ public TimeZone getTimeZone() {
+ return timeZone;
+ }
+
+ public void setTimeZone(TimeZone timeZone) {
+ this.timeZone = timeZone;
+ }
+
+ public int getSourceFileCRC() {
+ return sourceFileCRC;
+ }
+
+ public void setSourceFileCRC(int sourceFileCRC) {
+ this.sourceFileCRC = sourceFileCRC;
+ }
+
+ public String getDefaultFolderPath() {
+ return defaultFolderPath;
+ }
+
+ public String getFolderPath(int index) {
+ if (index > folderPath.size()) {
+ return null;
+ }
+ return folderPath.get(index);
+ }
+
+ public int getFolderPathSize() {
+ return folderPath.size();
+ }
+
+ public void setDefaultFolderPath(String defaultFolderPath) {
+ this.defaultFolderPath = defaultFolderPath;
+ }
+
+ public void addFolderPath(String pathToFolder) {
+ this.folderPath.add(pathToFolder);
+ }
+
+ public String getFileNameInZip() {
+ return fileNameInZip;
+ }
+
+ public void setFileNameInZip(String fileNameInZip) {
+ this.fileNameInZip = fileNameInZip;
+ }
+
+ public boolean isSourceExternalStream() {
+ return isSourceExternalStream;
+ }
+
+ public void setSourceExternalStream(boolean isSourceExternalStream) {
+ this.isSourceExternalStream = isSourceExternalStream;
+ }
+
}
diff --git a/src/net/lingala/zip4j/zip/ZipEngine.java b/src/net/lingala/zip4j/zip/ZipEngine.java
index 067bd2a..7b49caf 100644
--- a/src/net/lingala/zip4j/zip/ZipEngine.java
+++ b/src/net/lingala/zip4j/zip/ZipEngine.java
@@ -12,8 +12,7 @@
* 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.zip;
import java.io.File;
@@ -40,446 +39,485 @@
import net.lingala.zip4j.util.Zip4jUtil;
public class ZipEngine {
-
- private ZipModel zipModel;
-
- public ZipEngine(ZipModel zipModel) throws ZipException {
-
- if (zipModel == null) {
- throw new ZipException("zip model is null in ZipEngine constructor");
- }
-
- this.zipModel = zipModel;
- }
-
- public void addFiles(final ArrayList fileList, final ZipParameters parameters,
- final ProgressMonitor progressMonitor, boolean runInThread) throws ZipException {
-
- if (fileList == null || parameters == null) {
- throw new ZipException("one of the input parameters is null when adding files");
- }
-
- if(fileList.size() <= 0) {
- throw new ZipException("no files to add");
- }
-
- progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_ADD);
- progressMonitor.setState(ProgressMonitor.STATE_BUSY);
- progressMonitor.setResult(ProgressMonitor.RESULT_WORKING);
-
- if (runInThread) {
- progressMonitor.setTotalWork(calculateTotalWork(fileList, parameters));
- progressMonitor.setFileName(((File)fileList.get(0)).getAbsolutePath());
-
- Thread thread = new Thread(InternalZipConstants.THREAD_NAME) {
- public void run() {
- try {
- initAddFiles(fileList, parameters, progressMonitor);
- } catch (ZipException e) {
- }
- }
- };
- thread.start();
-
- } else {
- initAddFiles(fileList, parameters, progressMonitor);
- }
- }
-
- private void initAddFiles(ArrayList fileList, ZipParameters parameters,
- ProgressMonitor progressMonitor) throws ZipException {
-
- if (fileList == null || parameters == null) {
- throw new ZipException("one of the input parameters is null when adding files");
- }
-
- if(fileList.size() <= 0) {
- throw new ZipException("no files to add");
- }
-
- if (zipModel.getEndCentralDirRecord() == null) {
- zipModel.setEndCentralDirRecord(createEndOfCentralDirectoryRecord());
- }
-
- ZipOutputStream outputStream = null;
- InputStream inputStream = null;
- try {
- checkParameters(parameters);
-
- removeFilesIfExists(fileList, parameters, progressMonitor);
-
- boolean isZipFileAlreadExists = Zip4jUtil.checkFileExists(zipModel.getZipFile());
-
- SplitOutputStream splitOutputStream = new SplitOutputStream(new File(zipModel.getZipFile()), zipModel.getSplitLength());
- outputStream = new ZipOutputStream(splitOutputStream, this.zipModel);
-
- if (isZipFileAlreadExists) {
- if (zipModel.getEndCentralDirRecord() == null) {
- throw new ZipException("invalid end of central directory record");
- }
- splitOutputStream.seek(zipModel.getEndCentralDirRecord().getOffsetOfStartOfCentralDir());
- }
- byte[] readBuff = new byte[InternalZipConstants.BUFF_SIZE];
- int readLen = -1;
- for (int i = 0; i < fileList.size(); i++) {
-
- if (progressMonitor.isCancelAllTasks()) {
- progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
- progressMonitor.setState(ProgressMonitor.STATE_READY);
- return;
- }
-
- ZipParameters fileParameters = (ZipParameters) parameters.clone();
-
- progressMonitor.setFileName(((File)fileList.get(i)).getAbsolutePath());
-
- if (!((File)fileList.get(i)).isDirectory()) {
- if (fileParameters.isEncryptFiles() && fileParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_STANDARD) {
- progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_CALC_CRC);
- fileParameters.setSourceFileCRC((int)CRCUtil.computeFileCRC(((File)fileList.get(i)).getAbsolutePath(), progressMonitor));
- progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_ADD);
-
- if (progressMonitor.isCancelAllTasks()) {
- progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
- progressMonitor.setState(ProgressMonitor.STATE_READY);
- return;
- }
- }
-
- if (Zip4jUtil.getFileLengh((File)fileList.get(i)) == 0) {
- fileParameters.setCompressionMethod(Zip4jConstants.COMP_STORE);
- }
- }
-
- outputStream.putNextEntry((File)fileList.get(i), fileParameters);
- if (((File)fileList.get(i)).isDirectory()) {
- outputStream.closeEntry();
- continue;
- }
-
- inputStream = new FileInputStream((File)fileList.get(i));
-
- while ((readLen = inputStream.read(readBuff)) != -1) {
- if (progressMonitor.isCancelAllTasks()) {
- progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
- progressMonitor.setState(ProgressMonitor.STATE_READY);
- return;
- }
-
- outputStream.write(readBuff, 0, readLen);
- progressMonitor.updateWorkCompleted(readLen);
- }
-
- outputStream.closeEntry();
-
- if (inputStream != null) {
- inputStream.close();
- }
- }
-
- outputStream.finish();
- progressMonitor.endProgressMonitorSuccess();
- } catch (ZipException e) {
- progressMonitor.endProgressMonitorError(e);
- throw e;
- } catch (Exception e) {
- progressMonitor.endProgressMonitorError(e);
- throw new ZipException(e);
- } finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- }
- }
-
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- public void addStreamToZip(InputStream inputStream, ZipParameters parameters) throws ZipException {
- if (inputStream == null || parameters == null) {
- throw new ZipException("one of the input parameters is null, cannot add stream to zip");
- }
-
- ZipOutputStream outputStream = null;
-
- try {
- checkParameters(parameters);
-
- boolean isZipFileAlreadExists = Zip4jUtil.checkFileExists(zipModel.getZipFile());
-
- SplitOutputStream splitOutputStream = new SplitOutputStream(new File(zipModel.getZipFile()), zipModel.getSplitLength());
- outputStream = new ZipOutputStream(splitOutputStream, this.zipModel);
-
- if (isZipFileAlreadExists) {
- if (zipModel.getEndCentralDirRecord() == null) {
- throw new ZipException("invalid end of central directory record");
- }
- splitOutputStream.seek(zipModel.getEndCentralDirRecord().getOffsetOfStartOfCentralDir());
- }
-
- byte[] readBuff = new byte[InternalZipConstants.BUFF_SIZE];
- int readLen = -1;
-
- outputStream.putNextEntry(null, parameters);
-
- if (!parameters.getFileNameInZip().endsWith("/") &&
- !parameters.getFileNameInZip().endsWith("\\")) {
- while ((readLen = inputStream.read(readBuff)) != -1) {
- outputStream.write(readBuff, 0, readLen);
- }
- }
-
- outputStream.closeEntry();
- outputStream.finish();
-
- } catch (ZipException e) {
- throw e;
- } catch (Exception e) {
- throw new ZipException(e);
- } finally {
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- //ignore
- }
- }
- }
- }
-
- public void addFolderToZip(File file, ZipParameters parameters,
- ProgressMonitor progressMonitor, boolean runInThread) throws ZipException {
- if (file == null || parameters == null) {
- throw new ZipException("one of the input parameters is null, cannot add folder to zip");
- }
-
- if (!Zip4jUtil.checkFileExists(file.getAbsolutePath())) {
- throw new ZipException("input folder does not exist");
- }
-
- if (!file.isDirectory()) {
- throw new ZipException("input file is not a folder, user addFileToZip method to add files");
- }
-
- if (!Zip4jUtil.checkFileReadAccess(file.getAbsolutePath())) {
- throw new ZipException("cannot read folder: " + file.getAbsolutePath());
- }
-
- String rootFolderPath = null;
- if (parameters.isIncludeRootFolder()) {
- if (file.getAbsolutePath() != null) {
- rootFolderPath = file.getAbsoluteFile().getParentFile() != null ? file.getAbsoluteFile().getParentFile().getAbsolutePath() : "";
- } else {
- rootFolderPath = file.getParentFile() != null ? file.getParentFile().getAbsolutePath() : "";
- }
- } else {
- rootFolderPath = file.getAbsolutePath();
- }
-
- parameters.setDefaultFolderPath(rootFolderPath);
-
- ArrayList fileList = Zip4jUtil.getFilesInDirectoryRec(file, parameters.isReadHiddenFiles());
-
- if (parameters.isIncludeRootFolder()) {
- if (fileList == null) {
- fileList = new ArrayList();
- }
- fileList.add(file);
- }
-
- addFiles(fileList, parameters, progressMonitor, runInThread);
- }
-
-
- private void checkParameters(ZipParameters parameters) throws ZipException {
-
- if (parameters == null) {
- throw new ZipException("cannot validate zip parameters");
- }
-
- if ((parameters.getCompressionMethod() != Zip4jConstants.COMP_STORE) &&
- parameters.getCompressionMethod() != Zip4jConstants.COMP_DEFLATE) {
- throw new ZipException("unsupported compression type");
- }
-
- if (parameters.getCompressionMethod() == Zip4jConstants.COMP_DEFLATE) {
- if (parameters.getCompressionLevel() < 0 && parameters.getCompressionLevel() > 9) {
- throw new ZipException("invalid compression level. compression level dor deflate should be in the range of 0-9");
- }
- }
-
- if (parameters.isEncryptFiles()) {
- if (parameters.getEncryptionMethod() != Zip4jConstants.ENC_METHOD_STANDARD &&
- parameters.getEncryptionMethod() != Zip4jConstants.ENC_METHOD_AES) {
- throw new ZipException("unsupported encryption method");
- }
-
- if (parameters.getPassword() == null || parameters.getPassword().length <= 0) {
- throw new ZipException("input password is empty or null");
- }
- } else {
- parameters.setAesKeyStrength(-1);
- parameters.setEncryptionMethod(-1);
- }
-
- }
-
- /**
- * Before adding a file to a zip file, we check if a file already exists in the zip file
- * with the same fileName (including path, if exists). If yes, then we remove this file
- * before adding the file
- *
- * Note: Relative path has to be passed as the fileName
- *
- * @param zipModel
- * @param fileName
- * @throws ZipException
- */
- private void removeFilesIfExists(ArrayList fileList, ZipParameters parameters, ProgressMonitor progressMonitor) throws ZipException {
-
- if (zipModel == null || zipModel.getCentralDirectory() == null ||
- zipModel.getCentralDirectory().getFileHeaders() == null ||
- zipModel.getCentralDirectory().getFileHeaders().size() <= 0) {
- //For a new zip file, this condition satisfies, so do nothing
- return;
- }
- RandomAccessFile outputStream = null;
-
- try {
- for (int i = 0; i < fileList.size(); i++) {
- File file = (File) fileList.get(i);
-
- String fileName = Zip4jUtil.getRelativeFileName(file.getAbsolutePath(),
- parameters.getRootFolderInZip(), parameters.getDefaultFolderPath());
-
- FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, fileName);
- if (fileHeader != null) {
-
- if (outputStream != null) {
- outputStream.close();
- outputStream = null;
- }
-
- ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
- progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_REMOVE);
- HashMap retMap = archiveMaintainer.initRemoveZipFile(zipModel,
- fileHeader, progressMonitor);
-
- if (progressMonitor.isCancelAllTasks()) {
- progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
- progressMonitor.setState(ProgressMonitor.STATE_READY);
- return;
- }
-
- progressMonitor
- .setCurrentOperation(ProgressMonitor.OPERATION_ADD);
-
- if (outputStream == null) {
- outputStream = prepareFileOutputStream();
-
- if (retMap != null) {
- if (retMap.get(InternalZipConstants.OFFSET_CENTRAL_DIR) != null) {
- long offsetCentralDir = -1;
- try {
- offsetCentralDir = Long
- .parseLong((String) retMap
- .get(InternalZipConstants.OFFSET_CENTRAL_DIR));
- } catch (NumberFormatException e) {
- throw new ZipException(
- "NumberFormatException while parsing offset central directory. " +
- "Cannot update already existing file header");
- } catch (Exception e) {
- throw new ZipException(
- "Error while parsing offset central directory. " +
- "Cannot update already existing file header");
- }
-
- if (offsetCentralDir >= 0) {
- outputStream.seek(offsetCentralDir);
- }
- }
- }
- }
- }
- }
- } catch (IOException e) {
- throw new ZipException(e);
- } finally {
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- //ignore
- }
- }
- }
- }
-
- private RandomAccessFile prepareFileOutputStream() throws ZipException {
- String outPath = zipModel.getZipFile();
- if (!Zip4jUtil.isStringNotNullAndNotEmpty(outPath)) {
- throw new ZipException("invalid output path");
- }
-
- try {
- File outFile = new File(outPath);
- if (!outFile.getParentFile().exists()) {
- outFile.getParentFile().mkdirs();
- }
- return new RandomAccessFile(outFile, InternalZipConstants.WRITE_MODE);
- } catch (FileNotFoundException e) {
- throw new ZipException(e);
- }
- }
-
- private EndCentralDirRecord createEndOfCentralDirectoryRecord() {
- EndCentralDirRecord endCentralDirRecord = new EndCentralDirRecord();
- endCentralDirRecord.setSignature(InternalZipConstants.ENDSIG);
- endCentralDirRecord.setNoOfThisDisk(0);
- endCentralDirRecord.setTotNoOfEntriesInCentralDir(0);
- endCentralDirRecord.setTotNoOfEntriesInCentralDirOnThisDisk(0);
- endCentralDirRecord.setOffsetOfStartOfCentralDir(0);
- return endCentralDirRecord;
- }
-
- private long calculateTotalWork(ArrayList fileList, ZipParameters parameters) throws ZipException {
- if (fileList == null) {
- throw new ZipException("file list is null, cannot calculate total work");
- }
-
- long totalWork = 0;
-
- for (int i = 0; i < fileList.size(); i++) {
- if(fileList.get(i) instanceof File) {
- if (((File)fileList.get(i)).exists()) {
- if (parameters.isEncryptFiles() &&
- parameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_STANDARD) {
- totalWork += (Zip4jUtil.getFileLengh((File)fileList.get(i)) * 2);
- } else {
- totalWork += Zip4jUtil.getFileLengh((File)fileList.get(i));
- }
-
- if (zipModel.getCentralDirectory() != null &&
- zipModel.getCentralDirectory().getFileHeaders() != null &&
- zipModel.getCentralDirectory().getFileHeaders().size() > 0) {
- String relativeFileName = Zip4jUtil.getRelativeFileName(
- ((File)fileList.get(i)).getAbsolutePath(), parameters.getRootFolderInZip(), parameters.getDefaultFolderPath());
- FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, relativeFileName);
- if (fileHeader != null) {
- totalWork += (Zip4jUtil.getFileLengh(new File(zipModel.getZipFile())) - fileHeader.getCompressedSize());
- }
- }
- }
- }
- }
-
- return totalWork;
- }
+
+ private ZipModel zipModel;
+
+ public ZipEngine(ZipModel zipModel) throws ZipException {
+
+ if (zipModel == null) {
+ throw new ZipException("zip model is null in ZipEngine constructor");
+ }
+
+ this.zipModel = zipModel;
+ }
+
+ public void addFiles(final ArrayList fileList, final ZipParameters parameters,
+ final ProgressMonitor progressMonitor, boolean runInThread) throws ZipException {
+
+ if (fileList == null || parameters == null) {
+ throw new ZipException("one of the input parameters is null when adding files");
+ }
+
+ if (fileList.size() <= 0) {
+ throw new ZipException("no files to add");
+ }
+
+ progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_ADD);
+ progressMonitor.setState(ProgressMonitor.STATE_BUSY);
+ progressMonitor.setResult(ProgressMonitor.RESULT_WORKING);
+
+ if (runInThread) {
+ progressMonitor.setTotalWork(calculateTotalWork(fileList, parameters));
+ progressMonitor.setFileName(((File) fileList.get(0)).getAbsolutePath());
+
+ Thread thread = new Thread(InternalZipConstants.THREAD_NAME) {
+ public void run() {
+ try {
+ initAddFiles(fileList, parameters, progressMonitor);
+ } catch (ZipException e) {
+ }
+ }
+ };
+ thread.start();
+
+ } else {
+ initAddFiles(fileList, parameters, progressMonitor);
+ }
+ }
+
+ private void initAddFiles(ArrayList fileList, ZipParameters parameters,
+ ProgressMonitor progressMonitor) throws ZipException {
+
+ if (fileList == null || parameters == null) {
+ throw new ZipException("one of the input parameters is null when adding files");
+ }
+
+ if (fileList.size() <= 0) {
+ throw new ZipException("no files to add");
+ }
+
+ if (zipModel.getEndCentralDirRecord() == null) {
+ zipModel.setEndCentralDirRecord(createEndOfCentralDirectoryRecord());
+ }
+
+ ZipOutputStream outputStream = null;
+ InputStream inputStream = null;
+ try {
+ checkParameters(parameters);
+
+ removeFilesIfExists(fileList, parameters, progressMonitor);
+
+ boolean isZipFileAlreadExists = Zip4jUtil.checkFileExists(zipModel.getZipFile());
+
+ SplitOutputStream splitOutputStream = new SplitOutputStream(new File(zipModel.getZipFile()), zipModel.getSplitLength());
+ outputStream = new ZipOutputStream(splitOutputStream, this.zipModel);
+
+ if (isZipFileAlreadExists) {
+ if (zipModel.getEndCentralDirRecord() == null) {
+ throw new ZipException("invalid end of central directory record");
+ }
+ splitOutputStream.seek(zipModel.getEndCentralDirRecord().getOffsetOfStartOfCentralDir());
+ }
+ byte[] readBuff = new byte[InternalZipConstants.BUFF_SIZE];
+ int readLen = -1;
+ for (int i = 0; i < fileList.size(); i++) {
+
+ if (progressMonitor.isCancelAllTasks()) {
+ progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
+ progressMonitor.setState(ProgressMonitor.STATE_READY);
+ return;
+ }
+
+ ZipParameters fileParameters = (ZipParameters) parameters.clone();
+
+ progressMonitor.setFileName(((File) fileList.get(i)).getAbsolutePath());
+ if (!((File) fileList.get(i)).isDirectory()) {
+ if (fileParameters.isEncryptFiles() && fileParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_STANDARD) {
+ progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_CALC_CRC);
+ fileParameters.setSourceFileCRC((int) CRCUtil.computeFileCRC(((File) fileList.get(i)).getAbsolutePath(), progressMonitor));
+ progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_ADD);
+
+ if (progressMonitor.isCancelAllTasks()) {
+ progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
+ progressMonitor.setState(ProgressMonitor.STATE_READY);
+ return;
+ }
+ }
+
+ if (Zip4jUtil.getFileLengh((File) fileList.get(i)) == 0) {
+ fileParameters.setCompressionMethod(Zip4jConstants.COMP_STORE);
+ }
+ }
+
+ String fileToProcess = ((File) fileList.get(i)).getAbsolutePath();
+
+ if (!fileToProcess.startsWith(fileParameters.getDefaultFolderPath())) {
+ for (int x = 0; x < fileParameters.getFolderPathSize(); x++) {
+ if (fileToProcess.startsWith(fileParameters.getFolderPath(x))) {
+ fileParameters.setDefaultFolderPath(fileParameters.getFolderPath(x));
+ break;
+ }
+ }
+ }
+ outputStream.putNextEntry((File) fileList.get(i), fileParameters);
+ if (((File) fileList.get(i)).isDirectory()) {
+ outputStream.closeEntry();
+ continue;
+ }
+ inputStream = new FileInputStream((File) fileList.get(i));
+
+ while ((readLen = inputStream.read(readBuff)) != -1) {
+ if (progressMonitor.isCancelAllTasks()) {
+ progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
+ progressMonitor.setState(ProgressMonitor.STATE_READY);
+ return;
+ }
+ outputStream.write(readBuff, 0, readLen);
+ progressMonitor.updateWorkCompleted(readLen);
+ }
+ outputStream.closeEntry();
+
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+
+ outputStream.finish();
+ progressMonitor.endProgressMonitorSuccess();
+ } catch (ZipException e) {
+ progressMonitor.endProgressMonitorError(e);
+ throw e;
+ } catch (Exception e) {
+ progressMonitor.endProgressMonitorError(e);
+ throw new ZipException(e);
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+ }
+
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ public void addStreamToZip(InputStream inputStream, ZipParameters parameters) throws ZipException {
+ if (inputStream == null || parameters == null) {
+ throw new ZipException("one of the input parameters is null, cannot add stream to zip");
+ }
+
+ ZipOutputStream outputStream = null;
+
+ try {
+ checkParameters(parameters);
+
+ boolean isZipFileAlreadExists = Zip4jUtil.checkFileExists(zipModel.getZipFile());
+
+ SplitOutputStream splitOutputStream = new SplitOutputStream(new File(zipModel.getZipFile()), zipModel.getSplitLength());
+ outputStream = new ZipOutputStream(splitOutputStream, this.zipModel);
+
+ if (isZipFileAlreadExists) {
+ if (zipModel.getEndCentralDirRecord() == null) {
+ throw new ZipException("invalid end of central directory record");
+ }
+ splitOutputStream.seek(zipModel.getEndCentralDirRecord().getOffsetOfStartOfCentralDir());
+ }
+
+ byte[] readBuff = new byte[InternalZipConstants.BUFF_SIZE];
+ int readLen = -1;
+
+ outputStream.putNextEntry(null, parameters);
+
+ if (!parameters.getFileNameInZip().endsWith("/")
+ && !parameters.getFileNameInZip().endsWith("\\")) {
+ while ((readLen = inputStream.read(readBuff)) != -1) {
+ outputStream.write(readBuff, 0, readLen);
+ }
+ }
+
+ outputStream.closeEntry();
+ outputStream.finish();
+
+ } catch (ZipException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ZipException(e);
+ } finally {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+ }
+
+ public void addFolderToZip(File file, ZipParameters parameters,
+ ProgressMonitor progressMonitor, boolean runInThread) throws ZipException {
+ if (file == null || parameters == null) {
+ throw new ZipException("one of the input parameters is null, cannot add folder to zip");
+ }
+
+ if (!Zip4jUtil.checkFileExists(file.getAbsolutePath())) {
+ throw new ZipException("input folder does not exist");
+ }
+
+ if (!file.isDirectory()) {
+ throw new ZipException("input file is not a folder, user addFileToZip method to add files");
+ }
+
+ if (!Zip4jUtil.checkFileReadAccess(file.getAbsolutePath())) {
+ throw new ZipException("cannot read folder: " + file.getAbsolutePath());
+ }
+
+ String rootFolderPath = null;
+ if (parameters.isIncludeRootFolder()) {
+ if (file.getAbsolutePath() != null) {
+ rootFolderPath = file.getAbsoluteFile().getParentFile() != null ? file.getAbsoluteFile().getParentFile().getAbsolutePath() : "";
+ } else {
+ rootFolderPath = file.getParentFile() != null ? file.getParentFile().getAbsolutePath() : "";
+ }
+ } else {
+ rootFolderPath = file.getAbsolutePath();
+ }
+
+ parameters.setDefaultFolderPath(rootFolderPath);
+
+ ArrayList fileList = Zip4jUtil.getFilesInDirectoryRec(file, parameters.isReadHiddenFiles());
+
+ if (parameters.isIncludeRootFolder()) {
+ if (fileList == null) {
+ fileList = new ArrayList();
+ }
+ fileList.add(file);
+ }
+
+ addFiles(fileList, parameters, progressMonitor, runInThread);
+ }
+
+ public void addFoldersToZip(ArrayList folderList, ZipParameters parameters, ProgressMonitor progressMonitor, boolean runInThread) throws ZipException {
+ if (folderList == null || parameters == null) {
+ throw new ZipException("one of the input parameters is null, cannot add folder to zip");
+ }
+
+ ArrayList totalFileList = new ArrayList();
+ for (int i = 0; i < folderList.size(); i++) {
+ File folder = folderList.get(i);
+
+ String rootFolderPath = null;
+ if (parameters.isIncludeRootFolder()) {
+ if (folder.getAbsolutePath() != null) {
+ rootFolderPath = folder.getAbsoluteFile().getParentFile() != null ? folder.getAbsoluteFile().getParentFile().getAbsolutePath() : "";
+ } else {
+ rootFolderPath = folder.getParentFile() != null ? folder.getParentFile().getAbsolutePath() : "";
+ }
+ } else {
+ rootFolderPath = folder.getAbsolutePath();
+ }
+
+ parameters.setDefaultFolderPath(rootFolderPath);
+ parameters.addFolderPath(rootFolderPath);
+ ArrayList fileList = Zip4jUtil.getFilesInDirectoryRec(folder, parameters.isReadHiddenFiles());
+
+ if (parameters.isIncludeRootFolder()) {
+ if (fileList == null) {
+ fileList = new ArrayList();
+ }
+ fileList.add(folder);
+ }
+ totalFileList.addAll(fileList);
+ }
+ addFiles(totalFileList, parameters, progressMonitor, runInThread);
+ }
+
+ private void checkParameters(ZipParameters parameters) throws ZipException {
+
+ if (parameters == null) {
+ throw new ZipException("cannot validate zip parameters");
+ }
+
+ if ((parameters.getCompressionMethod() != Zip4jConstants.COMP_STORE)
+ && parameters.getCompressionMethod() != Zip4jConstants.COMP_DEFLATE) {
+ throw new ZipException("unsupported compression type");
+ }
+
+ if (parameters.getCompressionMethod() == Zip4jConstants.COMP_DEFLATE) {
+ if (parameters.getCompressionLevel() < 0 && parameters.getCompressionLevel() > 9) {
+ throw new ZipException("invalid compression level. compression level dor deflate should be in the range of 0-9");
+ }
+ }
+
+ if (parameters.isEncryptFiles()) {
+ if (parameters.getEncryptionMethod() != Zip4jConstants.ENC_METHOD_STANDARD
+ && parameters.getEncryptionMethod() != Zip4jConstants.ENC_METHOD_AES) {
+ throw new ZipException("unsupported encryption method");
+ }
+
+ if (parameters.getPassword() == null || parameters.getPassword().length <= 0) {
+ throw new ZipException("input password is empty or null");
+ }
+ } else {
+ parameters.setAesKeyStrength(-1);
+ parameters.setEncryptionMethod(-1);
+ }
+
+ }
+
+ /**
+ * Before adding a file to a zip file, we check if a file already exists in
+ * the zip file with the same fileName (including path, if exists). If yes,
+ * then we remove this file before adding the file
+ *
+ * Note: Relative path has to be passed as the fileName
+ *
+ * @param zipModel
+ * @param fileName
+ * @throws ZipException
+ */
+ private void removeFilesIfExists(ArrayList fileList, ZipParameters parameters, ProgressMonitor progressMonitor) throws ZipException {
+
+ if (zipModel == null || zipModel.getCentralDirectory() == null
+ || zipModel.getCentralDirectory().getFileHeaders() == null
+ || zipModel.getCentralDirectory().getFileHeaders().size() <= 0) {
+ //For a new zip file, this condition satisfies, so do nothing
+ return;
+ }
+ RandomAccessFile outputStream = null;
+
+ try {
+ for (int i = 0; i < fileList.size(); i++) {
+ File file = (File) fileList.get(i);
+
+ String fileName = Zip4jUtil.getRelativeFileName(file.getAbsolutePath(),
+ parameters.getRootFolderInZip(), parameters.getDefaultFolderPath());
+
+ FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, fileName);
+ if (fileHeader != null) {
+
+ if (outputStream != null) {
+ outputStream.close();
+ outputStream = null;
+ }
+
+ ArchiveMaintainer archiveMaintainer = new ArchiveMaintainer();
+ progressMonitor.setCurrentOperation(ProgressMonitor.OPERATION_REMOVE);
+ HashMap retMap = archiveMaintainer.initRemoveZipFile(zipModel,
+ fileHeader, progressMonitor);
+
+ if (progressMonitor.isCancelAllTasks()) {
+ progressMonitor.setResult(ProgressMonitor.RESULT_CANCELLED);
+ progressMonitor.setState(ProgressMonitor.STATE_READY);
+ return;
+ }
+
+ progressMonitor
+ .setCurrentOperation(ProgressMonitor.OPERATION_ADD);
+
+ if (outputStream == null) {
+ outputStream = prepareFileOutputStream();
+
+ if (retMap != null) {
+ if (retMap.get(InternalZipConstants.OFFSET_CENTRAL_DIR) != null) {
+ long offsetCentralDir = -1;
+ try {
+ offsetCentralDir = Long
+ .parseLong((String) retMap
+ .get(InternalZipConstants.OFFSET_CENTRAL_DIR));
+ } catch (NumberFormatException e) {
+ throw new ZipException(
+ "NumberFormatException while parsing offset central directory. "
+ + "Cannot update already existing file header");
+ } catch (Exception e) {
+ throw new ZipException(
+ "Error while parsing offset central directory. "
+ + "Cannot update already existing file header");
+ }
+
+ if (offsetCentralDir >= 0) {
+ outputStream.seek(offsetCentralDir);
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new ZipException(e);
+ } finally {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+ }
+
+ private RandomAccessFile prepareFileOutputStream() throws ZipException {
+ String outPath = zipModel.getZipFile();
+ if (!Zip4jUtil.isStringNotNullAndNotEmpty(outPath)) {
+ throw new ZipException("invalid output path");
+ }
+
+ try {
+ File outFile = new File(outPath);
+ if (!outFile.getParentFile().exists()) {
+ outFile.getParentFile().mkdirs();
+ }
+ return new RandomAccessFile(outFile, InternalZipConstants.WRITE_MODE);
+ } catch (FileNotFoundException e) {
+ throw new ZipException(e);
+ }
+ }
+
+ private EndCentralDirRecord createEndOfCentralDirectoryRecord() {
+ EndCentralDirRecord endCentralDirRecord = new EndCentralDirRecord();
+ endCentralDirRecord.setSignature(InternalZipConstants.ENDSIG);
+ endCentralDirRecord.setNoOfThisDisk(0);
+ endCentralDirRecord.setTotNoOfEntriesInCentralDir(0);
+ endCentralDirRecord.setTotNoOfEntriesInCentralDirOnThisDisk(0);
+ endCentralDirRecord.setOffsetOfStartOfCentralDir(0);
+ return endCentralDirRecord;
+ }
+
+ private long calculateTotalWork(ArrayList fileList, ZipParameters parameters) throws ZipException {
+ if (fileList == null) {
+ throw new ZipException("file list is null, cannot calculate total work");
+ }
+
+ long totalWork = 0;
+
+ for (int i = 0; i < fileList.size(); i++) {
+ if (fileList.get(i) instanceof File) {
+ if (((File) fileList.get(i)).exists()) {
+ if (parameters.isEncryptFiles()
+ && parameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_STANDARD) {
+ totalWork += (Zip4jUtil.getFileLengh((File) fileList.get(i)) * 2);
+ } else {
+ totalWork += Zip4jUtil.getFileLengh((File) fileList.get(i));
+ }
+
+ if (zipModel.getCentralDirectory() != null
+ && zipModel.getCentralDirectory().getFileHeaders() != null
+ && zipModel.getCentralDirectory().getFileHeaders().size() > 0) {
+ String relativeFileName = Zip4jUtil.getRelativeFileName(
+ ((File) fileList.get(i)).getAbsolutePath(), parameters.getRootFolderInZip(), parameters.getDefaultFolderPath());
+ FileHeader fileHeader = Zip4jUtil.getFileHeader(zipModel, relativeFileName);
+ if (fileHeader != null) {
+ totalWork += (Zip4jUtil.getFileLengh(new File(zipModel.getZipFile())) - fileHeader.getCompressedSize());
+ }
+ }
+ }
+ }
+ }
+ return totalWork;
+ }
}