570 lines
20 KiB
Java
570 lines
20 KiB
Java
/*
|
|
* Copyright 2010 Srikanth Reddy Lingala
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package net.lingala.zip4j.io;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.zip.CRC32;
|
|
|
|
import net.lingala.zip4j.core.HeaderWriter;
|
|
import net.lingala.zip4j.crypto.AESEncrpyter;
|
|
import net.lingala.zip4j.crypto.IEncrypter;
|
|
import net.lingala.zip4j.crypto.StandardEncrypter;
|
|
import net.lingala.zip4j.exception.ZipException;
|
|
import net.lingala.zip4j.model.AESExtraDataRecord;
|
|
import net.lingala.zip4j.model.CentralDirectory;
|
|
import net.lingala.zip4j.model.EndCentralDirRecord;
|
|
import net.lingala.zip4j.model.FileHeader;
|
|
import net.lingala.zip4j.model.LocalFileHeader;
|
|
import net.lingala.zip4j.model.ZipModel;
|
|
import net.lingala.zip4j.model.ZipParameters;
|
|
import net.lingala.zip4j.util.InternalZipConstants;
|
|
import net.lingala.zip4j.util.Raw;
|
|
import net.lingala.zip4j.util.Zip4jConstants;
|
|
import net.lingala.zip4j.util.Zip4jUtil;
|
|
|
|
public class CipherOutputStream extends BaseOutputStream {
|
|
|
|
protected OutputStream outputStream;
|
|
private File sourceFile;
|
|
protected FileHeader fileHeader;
|
|
protected LocalFileHeader localFileHeader;
|
|
private IEncrypter encrypter;
|
|
protected ZipParameters zipParameters;
|
|
protected ZipModel zipModel;
|
|
private long totalBytesWritten;
|
|
protected CRC32 crc;
|
|
private long bytesWrittenForThisFile;
|
|
private byte[] pendingBuffer;
|
|
private int pendingBufferLength;
|
|
private long totalBytesRead;
|
|
|
|
public CipherOutputStream(OutputStream outputStream, ZipModel zipModel) {
|
|
this.outputStream = outputStream;
|
|
initZipModel(zipModel);
|
|
crc = new CRC32();
|
|
this.totalBytesWritten = 0;
|
|
this.bytesWrittenForThisFile = 0;
|
|
this.pendingBuffer = new byte[InternalZipConstants.AES_BLOCK_SIZE];
|
|
this.pendingBufferLength = 0;
|
|
this.totalBytesRead = 0;
|
|
}
|
|
|
|
public void putNextEntry(File file, ZipParameters zipParameters) throws ZipException {
|
|
if (!zipParameters.isSourceExternalStream() && file == null) {
|
|
throw new ZipException("input file is null");
|
|
}
|
|
|
|
if (!zipParameters.isSourceExternalStream() && !Zip4jUtil.checkFileExists(file)) {
|
|
throw new ZipException("input file does not exist");
|
|
}
|
|
|
|
try {
|
|
sourceFile = file;
|
|
|
|
this.zipParameters = (ZipParameters)zipParameters.clone();
|
|
|
|
if (!zipParameters.isSourceExternalStream()) {
|
|
if (sourceFile.isDirectory()) {
|
|
this.zipParameters.setEncryptFiles(false);
|
|
this.zipParameters.setEncryptionMethod(-1);
|
|
this.zipParameters.setCompressionMethod(Zip4jConstants.COMP_STORE);
|
|
}
|
|
} else {
|
|
if (!Zip4jUtil.isStringNotNullAndNotEmpty(this.zipParameters.getFileNameInZip())) {
|
|
throw new ZipException("file name is empty for external stream");
|
|
}
|
|
if (this.zipParameters.getFileNameInZip().endsWith("/") ||
|
|
this.zipParameters.getFileNameInZip().endsWith("\\")) {
|
|
this.zipParameters.setEncryptFiles(false);
|
|
this.zipParameters.setEncryptionMethod(-1);
|
|
this.zipParameters.setCompressionMethod(Zip4jConstants.COMP_STORE);
|
|
}
|
|
}
|
|
|
|
createFileHeader();
|
|
createLocalFileHeader();
|
|
|
|
if (zipModel.isSplitArchive()) {
|
|
if (zipModel.getCentralDirectory() == null ||
|
|
zipModel.getCentralDirectory().getFileHeaders() == null ||
|
|
zipModel.getCentralDirectory().getFileHeaders().size() == 0) {
|
|
byte[] intByte = new byte[4];
|
|
Raw.writeIntLittleEndian(intByte, 0, (int)InternalZipConstants.SPLITSIG);
|
|
outputStream.write(intByte);
|
|
totalBytesWritten += 4;
|
|
}
|
|
}
|
|
|
|
if (this.outputStream instanceof SplitOutputStream) {
|
|
if (totalBytesWritten == 4) {
|
|
fileHeader.setOffsetLocalHeader(4);
|
|
} else {
|
|
fileHeader.setOffsetLocalHeader(((SplitOutputStream)outputStream).getFilePointer());
|
|
}
|
|
} else {
|
|
if (totalBytesWritten == 4) {
|
|
fileHeader.setOffsetLocalHeader(4);
|
|
} else {
|
|
fileHeader.setOffsetLocalHeader(totalBytesWritten);
|
|
}
|
|
}
|
|
|
|
HeaderWriter headerWriter = new HeaderWriter();
|
|
totalBytesWritten += headerWriter.writeLocalFileHeader(zipModel, localFileHeader, outputStream);
|
|
|
|
if (this.zipParameters.isEncryptFiles()) {
|
|
initEncrypter();
|
|
if (encrypter != null) {
|
|
if (zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_STANDARD) {
|
|
byte[] headerBytes = ((StandardEncrypter)encrypter).getHeaderBytes();
|
|
outputStream.write(headerBytes);
|
|
totalBytesWritten += headerBytes.length;
|
|
bytesWrittenForThisFile += headerBytes.length;
|
|
} else if (zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_AES) {
|
|
byte[] saltBytes = ((AESEncrpyter)encrypter).getSaltBytes();
|
|
byte[] passwordVerifier = ((AESEncrpyter)encrypter).getDerivedPasswordVerifier();
|
|
outputStream.write(saltBytes);
|
|
outputStream.write(passwordVerifier);
|
|
totalBytesWritten += saltBytes.length + passwordVerifier.length;
|
|
bytesWrittenForThisFile += saltBytes.length + passwordVerifier.length;
|
|
}
|
|
}
|
|
}
|
|
|
|
crc.reset();
|
|
} catch (CloneNotSupportedException e) {
|
|
throw new ZipException(e);
|
|
} catch (ZipException e) {
|
|
throw e;
|
|
} catch (Exception e) {
|
|
throw new ZipException(e);
|
|
}
|
|
}
|
|
|
|
private void initEncrypter() throws ZipException {
|
|
if (!zipParameters.isEncryptFiles()) {
|
|
encrypter = null;
|
|
return;
|
|
}
|
|
|
|
switch (zipParameters.getEncryptionMethod()) {
|
|
case Zip4jConstants.ENC_METHOD_STANDARD:
|
|
// Since we do not know the crc here, we use the modification time for encrypting.
|
|
encrypter = new StandardEncrypter(zipParameters.getPassword(), (localFileHeader.getLastModFileTime() & 0x0000ffff) << 16);
|
|
break;
|
|
case Zip4jConstants.ENC_METHOD_AES:
|
|
encrypter = new AESEncrpyter(zipParameters.getPassword(), zipParameters.getAesKeyStrength());
|
|
break;
|
|
default:
|
|
throw new ZipException("invalid encprytion method");
|
|
}
|
|
}
|
|
|
|
private void initZipModel(ZipModel zipModel) {
|
|
if (zipModel == null) {
|
|
this.zipModel = new ZipModel();
|
|
} else {
|
|
this.zipModel = zipModel;
|
|
}
|
|
|
|
if (this.zipModel.getEndCentralDirRecord() == null)
|
|
this.zipModel.setEndCentralDirRecord(new EndCentralDirRecord());
|
|
|
|
if (this.zipModel.getCentralDirectory() == null)
|
|
this.zipModel.setCentralDirectory(new CentralDirectory());
|
|
|
|
if (this.zipModel.getCentralDirectory().getFileHeaders() == null)
|
|
this.zipModel.getCentralDirectory().setFileHeaders(new ArrayList());
|
|
|
|
if (this.zipModel.getLocalFileHeaderList() == null)
|
|
this.zipModel.setLocalFileHeaderList(new ArrayList());
|
|
|
|
if (this.outputStream instanceof SplitOutputStream) {
|
|
if (((SplitOutputStream)outputStream).isSplitZipFile()) {
|
|
this.zipModel.setSplitArchive(true);
|
|
this.zipModel.setSplitLength(((SplitOutputStream)outputStream).getSplitLength());
|
|
}
|
|
}
|
|
|
|
this.zipModel.getEndCentralDirRecord().setSignature(InternalZipConstants.ENDSIG);
|
|
}
|
|
|
|
public void write(int bval) throws IOException {
|
|
byte[] b = new byte[1];
|
|
b[0] = (byte) bval;
|
|
write(b, 0, 1);
|
|
}
|
|
|
|
public void write(byte[] b) throws IOException {
|
|
if (b == null)
|
|
throw new NullPointerException();
|
|
|
|
if (b.length == 0) return;
|
|
|
|
write(b, 0, b.length);
|
|
}
|
|
|
|
public void write(byte[] b, int off, int len) throws IOException {
|
|
if (len == 0) return;
|
|
|
|
if (zipParameters.isEncryptFiles() &&
|
|
zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_AES) {
|
|
if (pendingBufferLength != 0) {
|
|
if (len >= (InternalZipConstants.AES_BLOCK_SIZE - pendingBufferLength)) {
|
|
System.arraycopy(b, off, pendingBuffer, pendingBufferLength,
|
|
(InternalZipConstants.AES_BLOCK_SIZE - pendingBufferLength));
|
|
encryptAndWrite(pendingBuffer, 0, pendingBuffer.length);
|
|
off = (InternalZipConstants.AES_BLOCK_SIZE - pendingBufferLength);
|
|
len = len - off;
|
|
pendingBufferLength = 0;
|
|
} else {
|
|
System.arraycopy(b, off, pendingBuffer, pendingBufferLength,
|
|
len);
|
|
pendingBufferLength += len;
|
|
return;
|
|
}
|
|
}
|
|
if (len != 0 && len % 16 != 0) {
|
|
System.arraycopy(b, (len + off) - (len % 16), pendingBuffer, 0, len % 16);
|
|
pendingBufferLength = len % 16;
|
|
len = len - pendingBufferLength;
|
|
}
|
|
}
|
|
if (len != 0)
|
|
encryptAndWrite(b, off, len);
|
|
}
|
|
|
|
private void encryptAndWrite(byte[] b, int off, int len) throws IOException {
|
|
if (encrypter != null) {
|
|
try {
|
|
encrypter.encryptData(b, off, len);
|
|
} catch (ZipException e) {
|
|
throw new IOException(e.getMessage());
|
|
}
|
|
}
|
|
outputStream.write(b, off, len);
|
|
totalBytesWritten += len;
|
|
bytesWrittenForThisFile += len;
|
|
}
|
|
|
|
public void closeEntry() throws IOException, ZipException {
|
|
|
|
if (this.pendingBufferLength != 0) {
|
|
encryptAndWrite(pendingBuffer, 0, pendingBufferLength);
|
|
pendingBufferLength = 0;
|
|
}
|
|
|
|
if (this.zipParameters.isEncryptFiles() &&
|
|
this.zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_AES) {
|
|
if (encrypter instanceof AESEncrpyter) {
|
|
outputStream.write(((AESEncrpyter)encrypter).getFinalMac());
|
|
bytesWrittenForThisFile += 10;
|
|
totalBytesWritten += 10;
|
|
} else {
|
|
throw new ZipException("invalid encrypter for AES encrypted file");
|
|
}
|
|
}
|
|
fileHeader.setCompressedSize(bytesWrittenForThisFile);
|
|
localFileHeader.setCompressedSize(bytesWrittenForThisFile);
|
|
|
|
if (zipParameters.isSourceExternalStream()) {
|
|
fileHeader.setUncompressedSize(totalBytesRead);
|
|
if (localFileHeader.getUncompressedSize() != totalBytesRead) {
|
|
localFileHeader.setUncompressedSize(totalBytesRead);
|
|
}
|
|
}
|
|
|
|
long crc32 = crc.getValue();
|
|
if (fileHeader.isEncrypted()) {
|
|
if (fileHeader.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_AES) {
|
|
crc32 = 0;
|
|
}
|
|
}
|
|
|
|
if (zipParameters.isEncryptFiles() &&
|
|
zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_AES) {
|
|
fileHeader.setCrc32(0);
|
|
localFileHeader.setCrc32(0);
|
|
} else {
|
|
fileHeader.setCrc32(crc32);
|
|
localFileHeader.setCrc32(crc32);
|
|
}
|
|
|
|
zipModel.getLocalFileHeaderList().add(localFileHeader);
|
|
zipModel.getCentralDirectory().getFileHeaders().add(fileHeader);
|
|
|
|
HeaderWriter headerWriter = new HeaderWriter();
|
|
totalBytesWritten += headerWriter.writeExtendedLocalHeader(localFileHeader, outputStream);
|
|
|
|
crc.reset();
|
|
bytesWrittenForThisFile = 0;
|
|
encrypter = null;
|
|
totalBytesRead = 0;
|
|
}
|
|
|
|
public void finish() throws IOException, ZipException {
|
|
zipModel.getEndCentralDirRecord().setOffsetOfStartOfCentralDir(totalBytesWritten);
|
|
|
|
HeaderWriter headerWriter = new HeaderWriter();
|
|
headerWriter.finalizeZipFile(zipModel, outputStream);
|
|
}
|
|
|
|
public void close() throws IOException {
|
|
if (outputStream != null)
|
|
outputStream.close();
|
|
}
|
|
|
|
private void createFileHeader() throws ZipException {
|
|
this.fileHeader = new FileHeader();
|
|
fileHeader.setSignature((int)InternalZipConstants.CENSIG);
|
|
fileHeader.setVersionMadeBy(20);
|
|
fileHeader.setVersionNeededToExtract(20);
|
|
if (zipParameters.isEncryptFiles() &&
|
|
zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_AES) {
|
|
fileHeader.setCompressionMethod(Zip4jConstants.ENC_METHOD_AES);
|
|
fileHeader.setAesExtraDataRecord(generateAESExtraDataRecord(zipParameters));
|
|
} else {
|
|
fileHeader.setCompressionMethod(zipParameters.getCompressionMethod());
|
|
}
|
|
if (zipParameters.isEncryptFiles()) {
|
|
fileHeader.setEncrypted(true);
|
|
fileHeader.setEncryptionMethod(zipParameters.getEncryptionMethod());
|
|
}
|
|
String fileName = null;
|
|
if (zipParameters.isSourceExternalStream()) {
|
|
fileHeader.setLastModFileTime((int) Zip4jUtil.javaToDosTime(System.currentTimeMillis()));
|
|
if (!Zip4jUtil.isStringNotNullAndNotEmpty(zipParameters.getFileNameInZip())) {
|
|
throw new ZipException("fileNameInZip is null or empty");
|
|
}
|
|
fileName = zipParameters.getFileNameInZip();
|
|
} else {
|
|
fileHeader.setLastModFileTime((int) Zip4jUtil.javaToDosTime((Zip4jUtil.getLastModifiedFileTime(
|
|
sourceFile, zipParameters.getTimeZone()))));
|
|
fileHeader.setUncompressedSize(sourceFile.length());
|
|
fileName = Zip4jUtil.getRelativeFileName(
|
|
sourceFile.getAbsolutePath(), zipParameters.getRootFolderInZip(), zipParameters.getDefaultFolderPath());
|
|
|
|
}
|
|
|
|
if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileName)) {
|
|
throw new ZipException("fileName is null or empty. unable to create file header");
|
|
}
|
|
|
|
fileHeader.setFileName(fileName);
|
|
|
|
if (Zip4jUtil.isStringNotNullAndNotEmpty(zipModel.getFileNameCharset())) {
|
|
fileHeader.setFileNameLength(Zip4jUtil.getEncodedStringLength(fileName,
|
|
zipModel.getFileNameCharset()));
|
|
} else {
|
|
fileHeader.setFileNameLength(Zip4jUtil.getEncodedStringLength(fileName));
|
|
}
|
|
|
|
if (outputStream instanceof SplitOutputStream) {
|
|
fileHeader.setDiskNumberStart(((SplitOutputStream)outputStream).getCurrSplitFileCounter());
|
|
} else {
|
|
fileHeader.setDiskNumberStart(0);
|
|
}
|
|
|
|
int fileAttrs = 0;
|
|
if (!zipParameters.isSourceExternalStream())
|
|
fileAttrs = getFileAttributes(sourceFile);
|
|
byte[] externalFileAttrs = {(byte)fileAttrs, 0, 0, 0};
|
|
fileHeader.setExternalFileAttr(externalFileAttrs);
|
|
|
|
if (zipParameters.isSourceExternalStream()) {
|
|
fileHeader.setDirectory(fileName.endsWith("/") || fileName.endsWith("\\"));
|
|
} else {
|
|
fileHeader.setDirectory(this.sourceFile.isDirectory());
|
|
}
|
|
if (fileHeader.isDirectory()) {
|
|
fileHeader.setCompressedSize(0);
|
|
fileHeader.setUncompressedSize(0);
|
|
} else {
|
|
if (!zipParameters.isSourceExternalStream()) {
|
|
long fileSize = Zip4jUtil.getFileLengh(sourceFile);
|
|
if (zipParameters.getCompressionMethod() == Zip4jConstants.COMP_STORE) {
|
|
if (zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_STANDARD) {
|
|
fileHeader.setCompressedSize(fileSize
|
|
+ InternalZipConstants.STD_DEC_HDR_SIZE);
|
|
} else if (zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_AES) {
|
|
int saltLength = 0;
|
|
switch (zipParameters.getAesKeyStrength()) {
|
|
case Zip4jConstants.AES_STRENGTH_128:
|
|
saltLength = 8;
|
|
break;
|
|
case Zip4jConstants.AES_STRENGTH_256:
|
|
saltLength = 16;
|
|
break;
|
|
default:
|
|
throw new ZipException("invalid aes key strength, cannot determine key sizes");
|
|
}
|
|
fileHeader.setCompressedSize(fileSize + saltLength
|
|
+ InternalZipConstants.AES_AUTH_LENGTH + 2); //2 is password verifier
|
|
} else {
|
|
fileHeader.setCompressedSize(0);
|
|
}
|
|
} else {
|
|
fileHeader.setCompressedSize(0);
|
|
}
|
|
fileHeader.setUncompressedSize(fileSize);
|
|
}
|
|
}
|
|
if (zipParameters.isEncryptFiles() &&
|
|
zipParameters.getEncryptionMethod() == Zip4jConstants.ENC_METHOD_STANDARD) {
|
|
fileHeader.setCrc32(zipParameters.getSourceFileCRC());
|
|
}
|
|
byte[] shortByte = new byte[2];
|
|
shortByte[0] = Raw.bitArrayToByte(generateGeneralPurposeBitArray(
|
|
fileHeader.isEncrypted(), zipParameters.getCompressionMethod()));
|
|
boolean isFileNameCharsetSet = Zip4jUtil.isStringNotNullAndNotEmpty(zipModel.getFileNameCharset());
|
|
if ((isFileNameCharsetSet &&
|
|
zipModel.getFileNameCharset().equalsIgnoreCase(InternalZipConstants.CHARSET_UTF8)) ||
|
|
(!isFileNameCharsetSet &&
|
|
Zip4jUtil.detectCharSet(fileHeader.getFileName()).equals(InternalZipConstants.CHARSET_UTF8))) {
|
|
shortByte[1] = 8;
|
|
} else {
|
|
shortByte[1] = 0;
|
|
}
|
|
fileHeader.setGeneralPurposeFlag(shortByte);
|
|
}
|
|
|
|
private void createLocalFileHeader() throws ZipException {
|
|
if (fileHeader == null) {
|
|
throw new ZipException("file header is null, cannot create local file header");
|
|
}
|
|
this.localFileHeader = new LocalFileHeader();
|
|
localFileHeader.setSignature((int)InternalZipConstants.LOCSIG);
|
|
localFileHeader.setVersionNeededToExtract(fileHeader.getVersionNeededToExtract());
|
|
localFileHeader.setCompressionMethod(fileHeader.getCompressionMethod());
|
|
localFileHeader.setLastModFileTime(fileHeader.getLastModFileTime());
|
|
localFileHeader.setUncompressedSize(fileHeader.getUncompressedSize());
|
|
localFileHeader.setFileNameLength(fileHeader.getFileNameLength());
|
|
localFileHeader.setFileName(fileHeader.getFileName());
|
|
localFileHeader.setEncrypted(fileHeader.isEncrypted());
|
|
localFileHeader.setEncryptionMethod(fileHeader.getEncryptionMethod());
|
|
localFileHeader.setAesExtraDataRecord(fileHeader.getAesExtraDataRecord());
|
|
localFileHeader.setCrc32(fileHeader.getCrc32());
|
|
localFileHeader.setCompressedSize(fileHeader.getCompressedSize());
|
|
localFileHeader.setGeneralPurposeFlag((byte[])fileHeader.getGeneralPurposeFlag().clone());
|
|
}
|
|
|
|
/**
|
|
* Checks the file attributes and returns an integer
|
|
* @param file
|
|
* @return
|
|
* @throws ZipException
|
|
*/
|
|
private int getFileAttributes(File file) throws ZipException {
|
|
if (file == null) {
|
|
throw new ZipException("input file is null, cannot get file attributes");
|
|
}
|
|
|
|
if (!file.exists()) {
|
|
return 0;
|
|
}
|
|
|
|
if (file.isDirectory()) {
|
|
if (file.isHidden()) {
|
|
return InternalZipConstants.FOLDER_MODE_HIDDEN;
|
|
} else {
|
|
return InternalZipConstants.FOLDER_MODE_NONE;
|
|
}
|
|
} else {
|
|
if (!file.canWrite() && file.isHidden()) {
|
|
return InternalZipConstants.FILE_MODE_READ_ONLY_HIDDEN;
|
|
} else if (!file.canWrite()) {
|
|
return InternalZipConstants.FILE_MODE_READ_ONLY;
|
|
} else if (file.isHidden()) {
|
|
return InternalZipConstants.FILE_MODE_HIDDEN;
|
|
} else {
|
|
return InternalZipConstants.FILE_MODE_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
private int[] generateGeneralPurposeBitArray(boolean isEncrpyted, int compressionMethod) {
|
|
|
|
int[] generalPurposeBits = new int[8];
|
|
if (isEncrpyted) {
|
|
generalPurposeBits[0] = 1;
|
|
} else {
|
|
generalPurposeBits[0] = 0;
|
|
}
|
|
|
|
if (compressionMethod == Zip4jConstants.COMP_DEFLATE) {
|
|
// Have to set flags for deflate
|
|
} else {
|
|
generalPurposeBits[1] = 0;
|
|
generalPurposeBits[2] = 0;
|
|
}
|
|
|
|
generalPurposeBits[3] = 1;
|
|
|
|
return generalPurposeBits;
|
|
}
|
|
|
|
private AESExtraDataRecord generateAESExtraDataRecord(ZipParameters parameters) throws ZipException {
|
|
|
|
if (parameters == null) {
|
|
throw new ZipException("zip parameters are null, cannot generate AES Extra Data record");
|
|
}
|
|
|
|
AESExtraDataRecord aesDataRecord = new AESExtraDataRecord();
|
|
aesDataRecord.setSignature(InternalZipConstants.AESSIG);
|
|
aesDataRecord.setDataSize(7);
|
|
aesDataRecord.setVendorID("AE");
|
|
// Always set the version number to 2 as we do not store CRC for any AES encrypted files
|
|
// only MAC is stored and as per the specification, if version number is 2, then MAC is read
|
|
// and CRC is ignored
|
|
aesDataRecord.setVersionNumber(2);
|
|
if (parameters.getAesKeyStrength() == Zip4jConstants.AES_STRENGTH_128) {
|
|
aesDataRecord.setAesStrength(Zip4jConstants.AES_STRENGTH_128);
|
|
} else if (parameters.getAesKeyStrength() == Zip4jConstants.AES_STRENGTH_256) {
|
|
aesDataRecord.setAesStrength(Zip4jConstants.AES_STRENGTH_256);
|
|
} else {
|
|
throw new ZipException("invalid AES key strength, cannot generate AES Extra data record");
|
|
}
|
|
aesDataRecord.setCompressionMethod(parameters.getCompressionMethod());
|
|
|
|
return aesDataRecord;
|
|
}
|
|
|
|
public void decrementCompressedFileSize(int value) {
|
|
if (value <= 0) return;
|
|
|
|
if (value <= this.bytesWrittenForThisFile) {
|
|
this.bytesWrittenForThisFile -= value;
|
|
}
|
|
}
|
|
|
|
protected void updateTotalBytesRead(int toUpdate) {
|
|
if (toUpdate > 0) {
|
|
totalBytesRead += toUpdate;
|
|
}
|
|
}
|
|
|
|
public void setSourceFile(File sourceFile) {
|
|
this.sourceFile = sourceFile;
|
|
}
|
|
|
|
public File getSourceFile() {
|
|
return sourceFile;
|
|
}
|
|
}
|