/*
* Copyright 2010 Srikanth Reddy Lingala
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.lingala.zip4j.util;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipModel;
public class Zip4jUtil {
public static boolean isStringNotNullAndNotEmpty(String str) {
if (str == null || str.trim().length() <= 0) {
return false;
}
return true;
}
public static boolean checkOutputFolder(String path) throws ZipException {
if (!isStringNotNullAndNotEmpty(path)) {
throw new ZipException(new NullPointerException("output path is null"));
}
File file = new File(path);
if (file.exists()) {
if (!file.isDirectory()) {
throw new ZipException("output folder is not valid");
}
if (!file.canWrite()) {
throw new ZipException("no write access to output folder");
}
} else {
try {
file.mkdirs();
if (!file.isDirectory()) {
throw new ZipException("output folder is not valid");
}
if (!file.canWrite()) {
throw new ZipException("no write access to destination folder");
}
// SecurityManager manager = new SecurityManager();
// try {
// manager.checkWrite(file.getAbsolutePath());
// } catch (Exception e) {
// e.printStackTrace();
// throw new ZipException("no write access to destination folder");
// }
} catch (Exception e) {
throw new ZipException("Cannot create destination folder");
}
}
return true;
}
public static boolean checkFileReadAccess(String path) throws ZipException {
if (!isStringNotNullAndNotEmpty(path)) {
throw new ZipException("path is null");
}
if (!checkFileExists(path)) {
throw new ZipException("file does not exist: " + path);
}
try {
File file = new File(path);
return file.canRead();
} catch (Exception e) {
throw new ZipException("cannot read zip file");
}
}
public static boolean checkFileWriteAccess(String path) throws ZipException {
if (!isStringNotNullAndNotEmpty(path)) {
throw new ZipException("path is null");
}
if (!checkFileExists(path)) {
throw new ZipException("file does not exist: " + path);
}
try {
File file = new File(path);
return file.canWrite();
} catch (Exception e) {
throw new ZipException("cannot read zip file");
}
}
public static boolean checkFileExists(String path) throws ZipException {
if (!isStringNotNullAndNotEmpty(path)) {
throw new ZipException("path is null");
}
File file = new File(path);
return checkFileExists(file);
}
public static boolean checkFileExists(File file) throws ZipException {
if (file == null) {
throw new ZipException("cannot check if file exists: input file is null");
}
return file.exists();
}
public static boolean isWindows(){
String os = System.getProperty("os.name").toLowerCase();
return (os.indexOf( "win" ) >= 0);
}
public static void setFileReadOnly(File file) throws ZipException {
if (file == null) {
throw new ZipException("input file is null. cannot set read only file attribute");
}
if (file.exists()) {
file.setReadOnly();
}
}
public static void setFileHidden(File file) throws ZipException {
// if (file == null) {
// throw new ZipException("input file is null. cannot set hidden file attribute");
// }
//
// if (!isWindows()) {
// return;
// }
//
// if (file.exists()) {
// try {
// Runtime.getRuntime().exec("attrib +H \"" + file.getAbsolutePath() + "\"");
// } catch (IOException e) {
// // do nothing as this is not of a higher priority
// // add log statements here when logging is done
// }
// }
}
public static void setFileArchive(File file) throws ZipException {
// if (file == null) {
// throw new ZipException("input file is null. cannot set archive file attribute");
// }
//
// if (!isWindows()) {
// return;
// }
//
// if (file.exists()) {
// try {
// if (file.isDirectory()) {
// Runtime.getRuntime().exec("attrib +A \"" + file.getAbsolutePath() + "\"");
// } else {
// Runtime.getRuntime().exec("attrib +A \"" + file.getAbsolutePath() + "\"");
// }
//
// } catch (IOException e) {
// // do nothing as this is not of a higher priority
// // add log statements here when logging is done
// }
// }
}
public static void setFileSystemMode(File file) throws ZipException {
// if (file == null) {
// throw new ZipException("input file is null. cannot set archive file attribute");
// }
//
// if (!isWindows()) {
// return;
// }
//
// if (file.exists()) {
// try {
// Runtime.getRuntime().exec("attrib +S \"" + file.getAbsolutePath() + "\"");
// } catch (IOException e) {
// // do nothing as this is not of a higher priority
// // add log statements here when logging is done
// }
// }
}
public static long getLastModifiedFileTime(File file, TimeZone timeZone) throws ZipException {
if (file == null) {
throw new ZipException("input file is null, cannot read last modified file time");
}
if (!file.exists()) {
throw new ZipException("input file does not exist, cannot read last modified file time");
}
return file.lastModified();
}
public static String getFileNameFromFilePath(File file) throws ZipException {
if (file == null) {
throw new ZipException("input file is null, cannot get file name");
}
if (file.isDirectory()) {
return null;
}
return file.getName();
}
public static long getFileLengh(String file) throws ZipException {
if (!isStringNotNullAndNotEmpty(file)) {
throw new ZipException("invalid file name");
}
return getFileLengh(new File(file));
}
public static long getFileLengh(File file) throws ZipException {
if (file == null) {
throw new ZipException("input file is null, cannot calculate file length");
}
if (file.isDirectory()) {
return -1;
}
return file.length();
}
/**
* Converts input time from Java to DOS format
* @param time
* @return time in DOS format
*/
public static long javaToDosTime(long time) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
int year = cal.get(Calendar.YEAR);
if (year < 1980) {
return (1 << 21) | (1 << 16);
}
return (year - 1980) << 25 | (cal.get(Calendar.MONTH) + 1) << 21 |
cal.get(Calendar.DATE) << 16 | cal.get(Calendar.HOUR_OF_DAY) << 11 | cal.get(Calendar.MINUTE) << 5 |
cal.get(Calendar.SECOND) >> 1;
}
/**
* Converts time in dos format to Java format
* @param dosTime
* @return time in java format
*/
public static long dosToJavaTme(int dosTime) {
int sec = 2 * (dosTime & 0x1f);
int min = (dosTime >> 5) & 0x3f;
int hrs = (dosTime >> 11) & 0x1f;
int day = (dosTime >> 16) & 0x1f;
int mon = ((dosTime >> 21) & 0xf) - 1;
int year = ((dosTime >> 25) & 0x7f) + 1980;
Calendar cal = Calendar.getInstance();
cal.set(year, mon, day, hrs, min, sec);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime().getTime();
}
public static FileHeader getFileHeader(ZipModel zipModel, String fileName) throws ZipException {
if (zipModel == null) {
throw new ZipException("zip model is null, cannot determine file header for fileName: " + fileName);
}
if (!isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("file name is null, cannot determine file header for fileName: " + fileName);
}
FileHeader fileHeader = null;
fileHeader = getFileHeaderWithExactMatch(zipModel, fileName);
if (fileHeader == null) {
fileName = fileName.replaceAll("\\\\", "/");
fileHeader = getFileHeaderWithExactMatch(zipModel, fileName);
if (fileHeader == null) {
fileName = fileName.replaceAll("/", "\\\\");
fileHeader = getFileHeaderWithExactMatch(zipModel, fileName);
}
}
return fileHeader;
}
public static FileHeader getFileHeaderWithExactMatch(ZipModel zipModel, String fileName) throws ZipException {
if (zipModel == null) {
throw new ZipException("zip model is null, cannot determine file header with exact match for fileName: " + fileName);
}
if (!isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("file name is null, cannot determine file header with exact match for fileName: " + fileName);
}
if (zipModel.getCentralDirectory() == null) {
throw new ZipException("central directory is null, cannot determine file header with exact match for fileName: " + fileName);
}
if (zipModel.getCentralDirectory().getFileHeaders() == null) {
throw new ZipException("file Headers are null, cannot determine file header with exact match for fileName: " + fileName);
}
if (zipModel.getCentralDirectory().getFileHeaders().size() <= 0) {
return null;
}
ArrayList fileHeaders = zipModel.getCentralDirectory().getFileHeaders();
for (int i = 0; i < fileHeaders.size(); i++) {
FileHeader fileHeader = (FileHeader)fileHeaders.get(i);
String fileNameForHdr = fileHeader.getFileName();
if (!isStringNotNullAndNotEmpty(fileNameForHdr)) {
continue;
}
if (fileName.equalsIgnoreCase(fileNameForHdr)) {
return fileHeader;
}
}
return null;
}
public static int getIndexOfFileHeader(ZipModel zipModel,
FileHeader fileHeader) throws ZipException {
if (zipModel == null || fileHeader == null) {
throw new ZipException("input parameters is null, cannot determine index of file header");
}
if (zipModel.getCentralDirectory() == null) {
throw new ZipException("central directory is null, ccannot determine index of file header");
}
if (zipModel.getCentralDirectory().getFileHeaders() == null) {
throw new ZipException("file Headers are null, cannot determine index of file header");
}
if (zipModel.getCentralDirectory().getFileHeaders().size() <= 0) {
return -1;
}
String fileName = fileHeader.getFileName();
if (!isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("file name in file header is empty or null, cannot determine index of file header");
}
ArrayList fileHeaders = zipModel.getCentralDirectory().getFileHeaders();
for (int i = 0; i < fileHeaders.size(); i++) {
FileHeader fileHeaderTmp = (FileHeader)fileHeaders.get(i);
String fileNameForHdr = fileHeaderTmp.getFileName();
if (!isStringNotNullAndNotEmpty(fileNameForHdr)) {
continue;
}
if (fileName.equalsIgnoreCase(fileNameForHdr)) {
return i;
}
}
return -1;
}
public static ArrayList getFilesInDirectoryRec(File path,
boolean readHiddenFiles) throws ZipException {
if (path == null) {
throw new ZipException("input path is null, cannot read files in the directory");
}
ArrayList result = new ArrayList();
File[] filesAndDirs = path.listFiles();
List filesDirs = Arrays.asList(filesAndDirs);
if (!path.canRead()) {
return result;
}
for(int i = 0; i < filesDirs.size(); i++) {
File file = (File)filesDirs.get(i);
if (file.isHidden() && !readHiddenFiles) {
return result;
}
result.add(file);
if (file.isDirectory()) {
List deeperList = getFilesInDirectoryRec(file, readHiddenFiles);
result.addAll(deeperList);
}
}
return result;
}
public static String getZipFileNameWithoutExt(String zipFile) throws ZipException {
if (!isStringNotNullAndNotEmpty(zipFile)) {
throw new ZipException("zip file name is empty or null, cannot determine zip file name");
}
String tmpFileName = zipFile;
if (zipFile.indexOf(System.getProperty("file.separator")) >= 0) {
tmpFileName = zipFile.substring(zipFile.lastIndexOf(System.getProperty("file.separator")));
}
if (tmpFileName.indexOf(".") > 0) {
tmpFileName = tmpFileName.substring(0, tmpFileName.lastIndexOf("."));
}
return tmpFileName;
}
public static byte[] convertCharset(String str) throws ZipException {
try {
byte[] converted = null;
String charSet = detectCharSet(str);
if (charSet.equals(InternalZipConstants.CHARSET_CP850)) {
converted = str.getBytes(InternalZipConstants.CHARSET_CP850);
} else if (charSet.equals(InternalZipConstants.CHARSET_UTF8)) {
converted = str.getBytes(InternalZipConstants.CHARSET_UTF8);
} else {
converted = str.getBytes();
}
return converted;
}
catch (UnsupportedEncodingException err) {
return str.getBytes();
} catch (Exception e) {
throw new ZipException(e);
}
}
/**
* Decodes file name based on encoding. If file name is UTF 8 encoded
* returns an UTF8 encoded string, else return Cp850 encoded String. If
* appropriate charset is not supported, then returns a System default
* charset encoded String
* @param data
* @param isUTF8
* @return String
*/
public static String decodeFileName(byte[] data, boolean isUTF8) {
if (isUTF8) {
try {
return new String(data, InternalZipConstants.CHARSET_UTF8);
} catch (UnsupportedEncodingException e) {
return new String(data);
}
} else {
return getCp850EncodedString(data);
}
}
/**
* Returns a string in Cp850 encoding from the input bytes.
* If this encoding is not supported, then String with the default encoding is returned.
* @param data
* @return String
*/
public static String getCp850EncodedString(byte[] data) {
try {
String retString = new String(data, InternalZipConstants.CHARSET_CP850);
return retString;
} catch (UnsupportedEncodingException e) {
return new String(data);
}
}
/**
* Returns an absoulte path for the given file path
* @param filePath
* @return String
*/
public static String getAbsoluteFilePath(String filePath) throws ZipException {
if (!isStringNotNullAndNotEmpty(filePath)) {
throw new ZipException("filePath is null or empty, cannot get absolute file path");
}
File file = new File(filePath);
return file.getAbsolutePath();
}
/**
* Checks to see if all the elements in the arraylist match the given type
* @param sourceList - list to be checked
* @param type - type of elements to be present in the list (ex: File, String, etc)
* @return true if all elements match the given type, if not returns false
*/
public static boolean checkArrayListTypes(ArrayList sourceList, int type) throws ZipException {
if (sourceList == null) {
throw new ZipException("input arraylist is null, cannot check types");
}
if (sourceList.size() <= 0) {
return true;
}
boolean invalidFound = false;
switch (type) {
case InternalZipConstants.LIST_TYPE_FILE:
for (int i = 0; i < sourceList.size(); i++) {
if (!(sourceList.get(i) instanceof File)) {
invalidFound = true;
break;
}
}
break;
case InternalZipConstants.LIST_TYPE_STRING:
for (int i = 0; i < sourceList.size(); i++) {
if (!(sourceList.get(i) instanceof String)) {
invalidFound = true;
break;
}
}
break;
default:
break;
}
return !invalidFound;
}
/**
* Detects the encoding charset for the input string
* @param str
* @return String - charset for the String
* @throws ZipException - if input string is null. In case of any other exception
* this method returns default System charset
*/
public static String detectCharSet(String str) throws ZipException {
if (str == null) {
throw new ZipException("input string is null, cannot detect charset");
}
try {
byte[] byteString = str.getBytes(InternalZipConstants.CHARSET_CP850);
String tempString = new String(byteString, InternalZipConstants.CHARSET_CP850);
if (str.equals(tempString)) {
return InternalZipConstants.CHARSET_CP850;
}
byteString = str.getBytes(InternalZipConstants.CHARSET_UTF8);
tempString = new String(byteString, InternalZipConstants.CHARSET_UTF8);
if (str.equals(tempString)) {
return InternalZipConstants.CHARSET_UTF8;
}
return InternalZipConstants.CHARSET_DEFAULT;
} catch (UnsupportedEncodingException e) {
return InternalZipConstants.CHARSET_DEFAULT;
} catch (Exception e) {
return InternalZipConstants.CHARSET_DEFAULT;
}
}
/**
* returns the length of the string by wrapping it in a byte buffer with
* the appropriate charset of the input string and returns the limit of the
* byte buffer
* @param str
* @return length of the string
* @throws ZipException
*/
public static int getEncodedStringLength(String str) throws ZipException {
if (!isStringNotNullAndNotEmpty(str)) {
throw new ZipException("input string is null, cannot calculate encoded String length");
}
String charset = detectCharSet(str);
return getEncodedStringLength(str, charset);
}
/**
* returns the length of the string in the input encoding
* @param str
* @param charset
* @return int
* @throws ZipException
*/
public static int getEncodedStringLength(String str, String charset) throws ZipException {
if (!isStringNotNullAndNotEmpty(str)) {
throw new ZipException("input string is null, cannot calculate encoded String length");
}
if (!isStringNotNullAndNotEmpty(charset)) {
throw new ZipException("encoding is not defined, cannot calculate string length");
}
ByteBuffer byteBuffer = null;
try {
if (charset.equals(InternalZipConstants.CHARSET_CP850)) {
byteBuffer = ByteBuffer.wrap(str.getBytes(InternalZipConstants.CHARSET_CP850));
} else if (charset.equals(InternalZipConstants.CHARSET_UTF8)) {
byteBuffer = ByteBuffer.wrap(str.getBytes(InternalZipConstants.CHARSET_UTF8));
} else {
byteBuffer = ByteBuffer.wrap(str.getBytes(charset));
}
} catch (UnsupportedEncodingException e) {
byteBuffer = ByteBuffer.wrap(str.getBytes());
} catch (Exception e) {
throw new ZipException(e);
}
return byteBuffer.limit();
}
/**
* Checks if the input charset is supported
* @param charset
* @return boolean
* @throws ZipException
*/
public static boolean isSupportedCharset(String charset) throws ZipException {
if (!isStringNotNullAndNotEmpty(charset)) {
throw new ZipException("charset is null or empty, cannot check if it is supported");
}
try {
new String("a".getBytes(), charset);
return true;
} catch (UnsupportedEncodingException e) {
return false;
} catch (Exception e) {
throw new ZipException(e);
}
}
public static ArrayList getSplitZipFiles(ZipModel zipModel) throws ZipException {
if (zipModel == null) {
throw new ZipException("cannot get split zip files: zipmodel is null");
}
if (zipModel.getEndCentralDirRecord() == null) {
return null;
}
ArrayList retList = new ArrayList();
String currZipFile = zipModel.getZipFile();
String zipFileName = (new File(currZipFile)).getName();
String partFile = null;
if (!isStringNotNullAndNotEmpty(currZipFile)) {
throw new ZipException("cannot get split zip files: zipfile is null");
}
if (!zipModel.isSplitArchive()) {
retList.add(currZipFile);
return retList;
}
int numberOfThisDisk = zipModel.getEndCentralDirRecord().getNoOfThisDisk();
if (numberOfThisDisk == 0) {
retList.add(currZipFile);
return retList;
} else {
for (int i = 0; i <= numberOfThisDisk; i++) {
if (i == numberOfThisDisk) {
retList.add(zipModel.getZipFile());
} else {
String fileExt = ".z0";
if (i > 9) {
fileExt = ".z";
}
partFile = (zipFileName.indexOf(".") >= 0) ? currZipFile.substring(0, currZipFile.lastIndexOf(".")) : currZipFile;
partFile = partFile + fileExt + (i + 1);
retList.add(partFile);
}
}
}
return retList;
}
public static String getRelativeFileName(String file, String rootFolderInZip, String rootFolderPath) throws ZipException {
if (!Zip4jUtil.isStringNotNullAndNotEmpty(file)) {
throw new ZipException("input file path/name is empty, cannot calculate relative file name");
}
String fileName = null;
if (Zip4jUtil.isStringNotNullAndNotEmpty(rootFolderPath)) {
File rootFolderFile = new File(rootFolderPath);
String rootFolderFileRef = rootFolderFile.getPath();
if (!rootFolderFileRef.endsWith(InternalZipConstants.FILE_SEPARATOR)) {
rootFolderFileRef += InternalZipConstants.FILE_SEPARATOR;
}
String tmpFileName = file.substring(rootFolderFileRef.length());
if (tmpFileName.startsWith(System.getProperty("file.separator"))) {
tmpFileName = tmpFileName.substring(1);
}
File tmpFile = new File(file);
if (tmpFile.isDirectory()) {
tmpFileName = tmpFileName.replaceAll("\\\\", "/");
tmpFileName += InternalZipConstants.ZIP_FILE_SEPARATOR;
} else {
String bkFileName = tmpFileName.substring(0, tmpFileName.lastIndexOf(tmpFile.getName()));
bkFileName = bkFileName.replaceAll("\\\\", "/");
tmpFileName = bkFileName + tmpFile.getName();
}
fileName = tmpFileName;
} else {
File relFile = new File(file);
if (relFile.isDirectory()) {
fileName = relFile.getName() + InternalZipConstants.ZIP_FILE_SEPARATOR;
} else {
fileName = Zip4jUtil.getFileNameFromFilePath(new File(file));
}
}
if (Zip4jUtil.isStringNotNullAndNotEmpty(rootFolderInZip)) {
fileName = rootFolderInZip + fileName;
}
if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
throw new ZipException("Error determining file name");
}
return fileName;
}
public static long[] getAllHeaderSignatures() {
long[] allSigs = new long[11];
allSigs[0] = InternalZipConstants.LOCSIG;
allSigs[1] = InternalZipConstants.EXTSIG;
allSigs[2] = InternalZipConstants.CENSIG;
allSigs[3] = InternalZipConstants.ENDSIG;
allSigs[4] = InternalZipConstants.DIGSIG;
allSigs[5] = InternalZipConstants.ARCEXTDATREC;
allSigs[6] = InternalZipConstants.SPLITSIG;
allSigs[7] = InternalZipConstants.ZIP64ENDCENDIRLOC;
allSigs[8] = InternalZipConstants.ZIP64ENDCENDIRREC;
allSigs[9] = InternalZipConstants.EXTRAFIELDZIP64LENGTH;
allSigs[10] = InternalZipConstants.AESSIG;
return allSigs;
}
}