From ca0a1cf3bdbd0c2e90da14219341e0824f54dab7 Mon Sep 17 00:00:00 2001 From: Giuseppe Sgattoni Date: Fri, 16 Mar 2018 11:50:22 +0100 Subject: [PATCH 1/4] Added method to create a span zip file from a list of folder --- src/net/lingala/zip4j/core/ZipFile.java | 2109 ++++++++++++---------- src/net/lingala/zip4j/zip/ZipEngine.java | 920 +++++----- 2 files changed, 1590 insertions(+), 1439 deletions(-) diff --git a/src/net/lingala/zip4j/core/ZipFile.java b/src/net/lingala/zip4j/core/ZipFile.java index 0daba77..19603fb 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,1122 @@ 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:
* * */ - 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 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/zip/ZipEngine.java b/src/net/lingala/zip4j/zip/ZipEngine.java index 067bd2a..2fb7308 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,479 @@ 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); + } + } + + 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); + + 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; + } } From 2b5a8c3aa78eb01cec8f1fac35d4b859e8e99893 Mon Sep 17 00:00:00 2001 From: Giuseppe Sgattoni Date: Mon, 19 Mar 2018 16:29:35 +0100 Subject: [PATCH 2/4] restituito il progressmonitor dalla chiamata alla zipfolders --- src/net/lingala/zip4j/core/ZipFile.java | 1 + src/net/lingala/zip4j/zip/ZipEngine.java | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/net/lingala/zip4j/core/ZipFile.java b/src/net/lingala/zip4j/core/ZipFile.java index 19603fb..0e12cc5 100644 --- a/src/net/lingala/zip4j/core/ZipFile.java +++ b/src/net/lingala/zip4j/core/ZipFile.java @@ -52,6 +52,7 @@ */ public class ZipFile { + private static String VERSIONE ="1.0.0"; private String file; private int mode; private ZipModel zipModel; diff --git a/src/net/lingala/zip4j/zip/ZipEngine.java b/src/net/lingala/zip4j/zip/ZipEngine.java index 2fb7308..f307c46 100644 --- a/src/net/lingala/zip4j/zip/ZipEngine.java +++ b/src/net/lingala/zip4j/zip/ZipEngine.java @@ -23,6 +23,8 @@ import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.io.SplitOutputStream; @@ -40,6 +42,7 @@ public class ZipEngine { + private final static Logger LOGGER = Logger.getLogger(ZipEngine.class.getName()); private ZipModel zipModel; public ZipEngine(ZipModel zipModel) throws ZipException { @@ -300,6 +303,7 @@ public void addFoldersToZip(ArrayList folderList, ZipParameters parameters 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); @@ -314,9 +318,9 @@ public void addFoldersToZip(ArrayList folderList, ZipParameters parameters } else { rootFolderPath = folder.getAbsolutePath(); } - + //logger.log(Level.INFO, "**********1**" + rootFolderPath); parameters.setDefaultFolderPath(rootFolderPath); - + //logger.log(Level.INFO, "**********2**" + rootFolderPath); ArrayList fileList = Zip4jUtil.getFilesInDirectoryRec(folder, parameters.isReadHiddenFiles()); if (parameters.isIncludeRootFolder()) { From b61320bf21e1ea7232a91f36002e3d483026a7b6 Mon Sep 17 00:00:00 2001 From: Giuseppe Sgattoni Date: Tue, 20 Mar 2018 15:25:45 +0100 Subject: [PATCH 3/4] Fix gestione cartelle da zippare in posizione diversa --- src/net/lingala/zip4j/core/ZipFile.java | 2 +- .../lingala/zip4j/io/CipherOutputStream.java | 1 - .../zip4j/io/DeflaterOutputStream.java | 4 +- .../lingala/zip4j/model/ZipParameters.java | 354 +++++++++--------- src/net/lingala/zip4j/zip/ZipEngine.java | 23 +- 5 files changed, 203 insertions(+), 181 deletions(-) diff --git a/src/net/lingala/zip4j/core/ZipFile.java b/src/net/lingala/zip4j/core/ZipFile.java index 0e12cc5..3473af4 100644 --- a/src/net/lingala/zip4j/core/ZipFile.java +++ b/src/net/lingala/zip4j/core/ZipFile.java @@ -52,7 +52,7 @@ */ public class ZipFile { - private static String VERSIONE ="1.0.0"; + private static String VERSIONE ="1.0.3"; private String file; private int mode; private ZipModel zipModel; 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 f307c46..bcea59a 100644 --- a/src/net/lingala/zip4j/zip/ZipEngine.java +++ b/src/net/lingala/zip4j/zip/ZipEngine.java @@ -23,8 +23,6 @@ import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.io.SplitOutputStream; @@ -42,7 +40,6 @@ public class ZipEngine { - private final static Logger LOGGER = Logger.getLogger(ZipEngine.class.getName()); private ZipModel zipModel; public ZipEngine(ZipModel zipModel) throws ZipException { @@ -134,7 +131,6 @@ private void initAddFiles(ArrayList fileList, ZipParameters parameters, 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); @@ -152,13 +148,22 @@ private void initAddFiles(ArrayList fileList, ZipParameters parameters, 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) { @@ -167,11 +172,9 @@ private void initAddFiles(ArrayList fileList, ZipParameters parameters, progressMonitor.setState(ProgressMonitor.STATE_READY); return; } - outputStream.write(readBuff, 0, readLen); progressMonitor.updateWorkCompleted(readLen); } - outputStream.closeEntry(); if (inputStream != null) { @@ -318,9 +321,9 @@ public void addFoldersToZip(ArrayList folderList, ZipParameters parameters } else { rootFolderPath = folder.getAbsolutePath(); } - //logger.log(Level.INFO, "**********1**" + rootFolderPath); + parameters.setDefaultFolderPath(rootFolderPath); - //logger.log(Level.INFO, "**********2**" + rootFolderPath); + parameters.addFolderPath(rootFolderPath); ArrayList fileList = Zip4jUtil.getFilesInDirectoryRec(folder, parameters.isReadHiddenFiles()); if (parameters.isIncludeRootFolder()) { From 18fd351810765c955b8ecc11694d22176529c9ad Mon Sep 17 00:00:00 2001 From: Giuseppe Sgattoni Date: Tue, 20 Mar 2018 16:26:55 +0100 Subject: [PATCH 4/4] Added, in ZipParameters, a property to keep track of different rootfolders. In the ZipEngine the defaultRootFolder is checked for each file to add and eventually replaced with the correct one --- src/net/lingala/zip4j/zip/ZipEngine.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/net/lingala/zip4j/zip/ZipEngine.java b/src/net/lingala/zip4j/zip/ZipEngine.java index bcea59a..7b49caf 100644 --- a/src/net/lingala/zip4j/zip/ZipEngine.java +++ b/src/net/lingala/zip4j/zip/ZipEngine.java @@ -518,7 +518,6 @@ private long calculateTotalWork(ArrayList fileList, ZipParameters parameters) th } } } - return totalWork; } }