Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.example.zip;
- import net.lingala.zip4j.exception.ZipException;
- import net.lingala.zip4j.exception.ZipExceptionConstants;
- import net.lingala.zip4j.model.*;
- import net.lingala.zip4j.util.InternalZipConstants;
- import net.lingala.zip4j.util.Raw;
- import net.lingala.zip4j.util.Zip4jConstants;
- import net.lingala.zip4j.util.Zip4jUtil;
- import java.io.IOException;
- import java.util.ArrayList;
- /*
- This file is a derivative of HeaderReader class from zip4j-1.3.2 library.
- The original sources can be retrieved at http://www.lingala.net/zip4j/ .
- 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.
- */
- public class MemoryHeaderReader {
- private RandomAccessStream zip4jRaf = null;
- private ZipModel zipModel;
- public MemoryHeaderReader(RandomAccessStream zip4jRaf) throws ZipException {
- if (zip4jRaf == null) {
- throw new ZipException("random access file was null", ZipExceptionConstants.randomAccessFileNull);
- }
- this.zip4jRaf = zip4jRaf;
- }
- public ZipModel readAllHeaders() throws ZipException {
- zipModel = new ZipModel();
- zipModel.setEndCentralDirRecord(readEndOfCentralDirectoryRecord());
- zipModel.setCentralDirectory(readCentralDirectory());
- return zipModel;
- }
- /**
- * Reads end of central directory record
- * @return {@link EndCentralDirRecord}
- * @throws ZipException
- */
- private EndCentralDirRecord readEndOfCentralDirectoryRecord() throws ZipException {
- try {
- byte[] ebs = new byte[4];
- long pos = zip4jRaf.length() - InternalZipConstants.ENDHDR;
- EndCentralDirRecord endCentralDirRecord = new EndCentralDirRecord();
- int counter = 0;
- do {
- zip4jRaf.seek(pos--);
- counter++;
- } while ((Raw.readLeInt(zip4jRaf, ebs) != InternalZipConstants.ENDSIG) && counter <= 3000);
- if ((Raw.readIntLittleEndian(ebs, 0) != InternalZipConstants.ENDSIG)) {
- throw new ZipException("zip headers not found. probably not a zip file");
- }
- byte[] intBuff = new byte[4];
- byte[] shortBuff = new byte[2];
- //End of central record signature
- endCentralDirRecord.setSignature(InternalZipConstants.ENDSIG);
- //number of this disk
- readIntoBuff(zip4jRaf, shortBuff);
- endCentralDirRecord.setNoOfThisDisk(Raw.readShortLittleEndian(shortBuff, 0));
- //number of the disk with the start of the central directory
- readIntoBuff(zip4jRaf, shortBuff);
- endCentralDirRecord.setNoOfThisDiskStartOfCentralDir(Raw.readShortLittleEndian(shortBuff, 0));
- //total number of entries in the central directory on this disk
- readIntoBuff(zip4jRaf, shortBuff);
- endCentralDirRecord.setTotNoOfEntriesInCentralDirOnThisDisk(Raw.readShortLittleEndian(shortBuff, 0));
- //total number of entries in the central directory
- readIntoBuff(zip4jRaf, shortBuff);
- endCentralDirRecord.setTotNoOfEntriesInCentralDir(Raw.readShortLittleEndian(shortBuff, 0));
- //size of the central directory
- readIntoBuff(zip4jRaf, intBuff);
- endCentralDirRecord.setSizeOfCentralDir(Raw.readIntLittleEndian(intBuff, 0));
- //offset of start of central directory with respect to the starting disk number
- readIntoBuff(zip4jRaf, intBuff);
- byte[] longBuff = getLongByteFromIntByte(intBuff);
- endCentralDirRecord.setOffsetOfStartOfCentralDir(Raw.readLongLittleEndian(longBuff, 0));
- //.ZIP file comment length
- readIntoBuff(zip4jRaf, shortBuff);
- int commentLength = Raw.readShortLittleEndian(shortBuff, 0);
- endCentralDirRecord.setCommentLength(commentLength);
- //.ZIP file comment
- if (commentLength > 0) {
- byte[] commentBuf = new byte[commentLength];
- readIntoBuff(zip4jRaf, commentBuf);
- endCentralDirRecord.setComment(new String(commentBuf));
- endCentralDirRecord.setCommentBytes(commentBuf);
- } else {
- endCentralDirRecord.setComment(null);
- }
- int diskNumber = endCentralDirRecord.getNoOfThisDisk();
- if (diskNumber > 0) {
- zipModel.setSplitArchive(true);
- } else {
- zipModel.setSplitArchive(false);
- }
- return endCentralDirRecord;
- } catch (RuntimeException e) {
- throw new ZipException("Probably not a zip file or a corrupted zip file", e, ZipExceptionConstants.notZipFile);
- }
- }
- /**
- * Reads central directory information for the zip file
- * @return {@link CentralDirectory}
- * @throws ZipException
- */
- private CentralDirectory readCentralDirectory() throws ZipException {
- if (zipModel.getEndCentralDirRecord() == null) {
- throw new ZipException("EndCentralRecord was null, maybe a corrupt zip file");
- }
- try {
- CentralDirectory centralDirectory = new CentralDirectory();
- ArrayList fileHeaderList = new ArrayList();
- EndCentralDirRecord endCentralDirRecord = zipModel.getEndCentralDirRecord();
- long offSetStartCentralDir = endCentralDirRecord.getOffsetOfStartOfCentralDir();
- int centralDirEntryCount = endCentralDirRecord.getTotNoOfEntriesInCentralDir();
- if (zipModel.isZip64Format()) {
- offSetStartCentralDir = zipModel.getZip64EndCentralDirRecord().getOffsetStartCenDirWRTStartDiskNo();
- centralDirEntryCount = (int) zipModel.getZip64EndCentralDirRecord().getTotNoOfEntriesInCentralDir();
- }
- zip4jRaf.seek(offSetStartCentralDir);
- byte[] intBuff = new byte[4];
- byte[] shortBuff = new byte[2];
- byte[] longBuff = new byte[8];
- for (int i = 0; i < centralDirEntryCount; i++) {
- FileHeader fileHeader = new FileHeader();
- //FileHeader Signature
- readIntoBuff(zip4jRaf, intBuff);
- int signature = Raw.readIntLittleEndian(intBuff, 0);
- if (signature != InternalZipConstants.CENSIG) {
- throw new ZipException("Expected central directory entry not found (#" + (i + 1) + ")");
- }
- fileHeader.setSignature(signature);
- //version made by
- readIntoBuff(zip4jRaf, shortBuff);
- fileHeader.setVersionMadeBy(Raw.readShortLittleEndian(shortBuff, 0));
- //version needed to extract
- readIntoBuff(zip4jRaf, shortBuff);
- fileHeader.setVersionNeededToExtract(Raw.readShortLittleEndian(shortBuff, 0));
- //general purpose bit flag
- readIntoBuff(zip4jRaf, shortBuff);
- fileHeader.setFileNameUTF8Encoded((Raw.readShortLittleEndian(shortBuff, 0) & InternalZipConstants.UFT8_NAMES_FLAG) != 0);
- int firstByte = shortBuff[0];
- int result = firstByte & 1;
- if (result != 0) {
- fileHeader.setEncrypted(true);
- }
- fileHeader.setGeneralPurposeFlag((byte[]) shortBuff.clone());
- //Check if data descriptor exists for local file header
- fileHeader.setDataDescriptorExists(firstByte >> 3 == 1);
- //compression method
- readIntoBuff(zip4jRaf, shortBuff);
- fileHeader.setCompressionMethod(Raw.readShortLittleEndian(shortBuff, 0));
- //last mod file time
- readIntoBuff(zip4jRaf, intBuff);
- fileHeader.setLastModFileTime(Raw.readIntLittleEndian(intBuff, 0));
- //crc-32
- readIntoBuff(zip4jRaf, intBuff);
- fileHeader.setCrc32(Raw.readIntLittleEndian(intBuff, 0));
- fileHeader.setCrcBuff((byte[]) intBuff.clone());
- //compressed size
- readIntoBuff(zip4jRaf, intBuff);
- longBuff = getLongByteFromIntByte(intBuff);
- fileHeader.setCompressedSize(Raw.readLongLittleEndian(longBuff, 0));
- //uncompressed size
- readIntoBuff(zip4jRaf, intBuff);
- longBuff = getLongByteFromIntByte(intBuff);
- fileHeader.setUncompressedSize(Raw.readLongLittleEndian(longBuff, 0));
- //file name length
- readIntoBuff(zip4jRaf, shortBuff);
- int fileNameLength = Raw.readShortLittleEndian(shortBuff, 0);
- fileHeader.setFileNameLength(fileNameLength);
- //extra field length
- readIntoBuff(zip4jRaf, shortBuff);
- int extraFieldLength = Raw.readShortLittleEndian(shortBuff, 0);
- fileHeader.setExtraFieldLength(extraFieldLength);
- //file comment length
- readIntoBuff(zip4jRaf, shortBuff);
- int fileCommentLength = Raw.readShortLittleEndian(shortBuff, 0);
- fileHeader.setFileComment(new String(shortBuff));
- //disk number start
- readIntoBuff(zip4jRaf, shortBuff);
- fileHeader.setDiskNumberStart(Raw.readShortLittleEndian(shortBuff, 0));
- //internal file attributes
- readIntoBuff(zip4jRaf, shortBuff);
- fileHeader.setInternalFileAttr((byte[]) shortBuff.clone());
- //external file attributes
- readIntoBuff(zip4jRaf, intBuff);
- fileHeader.setExternalFileAttr((byte[]) intBuff.clone());
- //relative offset of local header
- readIntoBuff(zip4jRaf, intBuff);
- //Commented on 26.08.2010. Revert back if any issues
- //fileHeader.setOffsetLocalHeader((Raw.readIntLittleEndian(intBuff, 0) & 0xFFFFFFFFL) + zip4jRaf.getStart());
- longBuff = getLongByteFromIntByte(intBuff);
- fileHeader.setOffsetLocalHeader((Raw.readLongLittleEndian(longBuff, 0) & 0xFFFFFFFFL));
- if (fileNameLength > 0) {
- byte[] fileNameBuf = new byte[fileNameLength];
- readIntoBuff(zip4jRaf, fileNameBuf);
- // Modified after user reported an issue http://www.lingala.net/zip4j/forum/index.php?topic=2.0
- // String fileName = new String(fileNameBuf, "Cp850");
- // Modified as per http://www.lingala.net/zip4j/forum/index.php?topic=41.0
- // String fileName = Zip4jUtil.getCp850EncodedString(fileNameBuf);
- String fileName = null;
- if (Zip4jUtil.isStringNotNullAndNotEmpty(zipModel.getFileNameCharset())) {
- fileName = new String(fileNameBuf, zipModel.getFileNameCharset());
- } else {
- fileName = Zip4jUtil.decodeFileName(fileNameBuf, fileHeader.isFileNameUTF8Encoded());
- }
- if (fileName == null) {
- throw new ZipException("fileName is null when reading central directory");
- }
- if (fileName.indexOf(":" + System.getProperty("file.separator")) >= 0) {
- fileName = fileName.substring(fileName.indexOf(":" + System.getProperty("file.separator")) + 2);
- }
- fileHeader.setFileName(fileName);
- fileHeader.setDirectory(fileName.endsWith("/") || fileName.endsWith("\\"));
- } else {
- fileHeader.setFileName(null);
- }
- //Extra field
- readAndSaveExtraDataRecord(fileHeader);
- //Read Zip64 Extra data records if exists
- readAndSaveZip64ExtendedInfo(fileHeader);
- //Read AES Extra Data record if exists
- readAndSaveAESExtraDataRecord(fileHeader);
- if (fileCommentLength > 0) {
- byte[] fileCommentBuf = new byte[fileCommentLength];
- readIntoBuff(zip4jRaf, fileCommentBuf);
- fileHeader.setFileComment(new String(fileCommentBuf));
- }
- fileHeaderList.add(fileHeader);
- }
- centralDirectory.setFileHeaders(fileHeaderList);
- //Digital Signature
- DigitalSignature digitalSignature = new DigitalSignature();
- readIntoBuff(zip4jRaf, intBuff);
- int signature = Raw.readIntLittleEndian(intBuff, 0);
- if (signature != InternalZipConstants.DIGSIG) {
- return centralDirectory;
- }
- digitalSignature.setHeaderSignature(signature);
- //size of data
- readIntoBuff(zip4jRaf, shortBuff);
- int sizeOfData = Raw.readShortLittleEndian(shortBuff, 0);
- digitalSignature.setSizeOfData(sizeOfData);
- if (sizeOfData > 0) {
- byte[] sigDataBuf = new byte[sizeOfData];
- readIntoBuff(zip4jRaf, sigDataBuf);
- digitalSignature.setSignatureData(new String(sigDataBuf));
- }
- return centralDirectory;
- } catch (IOException e) {
- throw new ZipException(e);
- }
- }
- /**
- * Reads extra data record and saves it in the {@link FileHeader}
- * @param fileHeader
- * @throws ZipException
- */
- private void readAndSaveExtraDataRecord(FileHeader fileHeader) throws ZipException {
- if (fileHeader == null) {
- throw new ZipException("file header is null");
- }
- int extraFieldLength = fileHeader.getExtraFieldLength();
- if (extraFieldLength <= 0) {
- return;
- }
- fileHeader.setExtraDataRecords(readExtraDataRecords(extraFieldLength));
- }
- /**
- * Reads extra data records
- * @param extraFieldLength
- * @return ArrayList of {@link ExtraDataRecord}
- * @throws ZipException
- */
- private ArrayList readExtraDataRecords(int extraFieldLength) throws ZipException {
- if (extraFieldLength <= 0) {
- return null;
- }
- try {
- byte[] extraFieldBuf = new byte[extraFieldLength];
- zip4jRaf.read(extraFieldBuf);
- int counter = 0;
- ArrayList extraDataList = new ArrayList();
- while (counter < extraFieldLength) {
- ExtraDataRecord extraDataRecord = new ExtraDataRecord();
- int header = Raw.readShortLittleEndian(extraFieldBuf, counter);
- extraDataRecord.setHeader(header);
- counter = counter + 2;
- int sizeOfRec = Raw.readShortLittleEndian(extraFieldBuf, counter);
- if ((2 + sizeOfRec) > extraFieldLength) {
- sizeOfRec = Raw.readShortBigEndian(extraFieldBuf, counter);
- if ((2 + sizeOfRec) > extraFieldLength) {
- //If this is the case, then extra data record is corrupt
- //skip reading any further extra data records
- break;
- }
- }
- extraDataRecord.setSizeOfData(sizeOfRec);
- counter = counter + 2;
- if (sizeOfRec > 0) {
- byte[] data = new byte[sizeOfRec];
- System.arraycopy(extraFieldBuf, counter, data, 0, sizeOfRec);
- extraDataRecord.setData(data);
- }
- counter = counter + sizeOfRec;
- extraDataList.add(extraDataRecord);
- }
- if (extraDataList.size() > 0) {
- return extraDataList;
- } else {
- return null;
- }
- } catch (IOException e) {
- throw new ZipException(e);
- }
- }
- /**
- * Reads Zip64 Extended info and saves it in the {@link FileHeader}
- * @param fileHeader
- * @throws ZipException
- */
- private void readAndSaveZip64ExtendedInfo(FileHeader fileHeader) throws ZipException {
- if (fileHeader == null) {
- throw new ZipException("file header is null in reading Zip64 Extended Info");
- }
- if (fileHeader.getExtraDataRecords() == null || fileHeader.getExtraDataRecords().size() <= 0) {
- return;
- }
- Zip64ExtendedInfo zip64ExtendedInfo = readZip64ExtendedInfo(
- fileHeader.getExtraDataRecords(),
- fileHeader.getUncompressedSize(),
- fileHeader.getCompressedSize(),
- fileHeader.getOffsetLocalHeader(),
- fileHeader.getDiskNumberStart());
- if (zip64ExtendedInfo != null) {
- fileHeader.setZip64ExtendedInfo(zip64ExtendedInfo);
- if (zip64ExtendedInfo.getUnCompressedSize() != -1)
- fileHeader.setUncompressedSize(zip64ExtendedInfo.getUnCompressedSize());
- if (zip64ExtendedInfo.getCompressedSize() != -1)
- fileHeader.setCompressedSize(zip64ExtendedInfo.getCompressedSize());
- if (zip64ExtendedInfo.getOffsetLocalHeader() != -1)
- fileHeader.setOffsetLocalHeader(zip64ExtendedInfo.getOffsetLocalHeader());
- if (zip64ExtendedInfo.getDiskNumberStart() != -1)
- fileHeader.setDiskNumberStart(zip64ExtendedInfo.getDiskNumberStart());
- }
- }
- /**
- * Reads Zip64 Extended Info
- * @param extraDataRecords
- * @param unCompressedSize
- * @param compressedSize
- * @param offsetLocalHeader
- * @param diskNumberStart
- * @return {@link Zip64ExtendedInfo}
- * @throws ZipException
- */
- private Zip64ExtendedInfo readZip64ExtendedInfo(
- ArrayList extraDataRecords,
- long unCompressedSize,
- long compressedSize,
- long offsetLocalHeader,
- int diskNumberStart
- ) {
- for (int i = 0; i < extraDataRecords.size(); i++) {
- ExtraDataRecord extraDataRecord = (ExtraDataRecord) extraDataRecords.get(i);
- if (extraDataRecord == null) {
- continue;
- }
- if (extraDataRecord.getHeader() == 0x0001) {
- Zip64ExtendedInfo zip64ExtendedInfo = new Zip64ExtendedInfo();
- byte[] byteBuff = extraDataRecord.getData();
- if (extraDataRecord.getSizeOfData() <= 0) {
- break;
- }
- byte[] longByteBuff = new byte[8];
- byte[] intByteBuff = new byte[4];
- int counter = 0;
- boolean valueAdded = false;
- if (((unCompressedSize & 0xFFFF) == 0xFFFF) && counter < extraDataRecord.getSizeOfData()) {
- System.arraycopy(byteBuff, counter, longByteBuff, 0, 8);
- long val = Raw.readLongLittleEndian(longByteBuff, 0);
- zip64ExtendedInfo.setUnCompressedSize(val);
- counter += 8;
- valueAdded = true;
- }
- if (((compressedSize & 0xFFFF) == 0xFFFF) && counter < extraDataRecord.getSizeOfData()) {
- System.arraycopy(byteBuff, counter, longByteBuff, 0, 8);
- long val = Raw.readLongLittleEndian(longByteBuff, 0);
- zip64ExtendedInfo.setCompressedSize(val);
- counter += 8;
- valueAdded = true;
- }
- if (((offsetLocalHeader & 0xFFFF) == 0xFFFF) && counter < extraDataRecord.getSizeOfData()) {
- System.arraycopy(byteBuff, counter, longByteBuff, 0, 8);
- long val = Raw.readLongLittleEndian(longByteBuff, 0);
- zip64ExtendedInfo.setOffsetLocalHeader(val);
- counter += 8;
- valueAdded = true;
- }
- if (((diskNumberStart & 0xFFFF) == 0xFFFF) && counter < extraDataRecord.getSizeOfData()) {
- System.arraycopy(byteBuff, counter, intByteBuff, 0, 4);
- int val = Raw.readIntLittleEndian(intByteBuff, 0);
- zip64ExtendedInfo.setDiskNumberStart(val);
- counter += 8;
- valueAdded = true;
- }
- if (valueAdded) {
- return zip64ExtendedInfo;
- }
- break;
- }
- }
- return null;
- }
- /**
- * Reads AES Extra Data Record and saves it in the {@link FileHeader}
- * @param fileHeader
- * @throws ZipException
- */
- private void readAndSaveAESExtraDataRecord(FileHeader fileHeader) throws ZipException {
- if (fileHeader == null) {
- throw new ZipException("file header is null in reading Zip64 Extended Info");
- }
- if (fileHeader.getExtraDataRecords() == null || fileHeader.getExtraDataRecords().size() <= 0) {
- return;
- }
- AESExtraDataRecord aesExtraDataRecord = readAESExtraDataRecord(fileHeader.getExtraDataRecords());
- if (aesExtraDataRecord != null) {
- fileHeader.setAesExtraDataRecord(aesExtraDataRecord);
- fileHeader.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
- }
- }
- /**
- * Reads AES Extra Data Record
- * @param extraDataRecords
- * @return {@link AESExtraDataRecord}
- * @throws ZipException
- */
- private AESExtraDataRecord readAESExtraDataRecord(ArrayList extraDataRecords) throws ZipException {
- if (extraDataRecords == null) {
- return null;
- }
- for (int i = 0; i < extraDataRecords.size(); i++) {
- ExtraDataRecord extraDataRecord = (ExtraDataRecord) extraDataRecords.get(i);
- if (extraDataRecord == null) {
- continue;
- }
- if (extraDataRecord.getHeader() == InternalZipConstants.AESSIG) {
- if (extraDataRecord.getData() == null) {
- throw new ZipException("corrput AES extra data records");
- }
- AESExtraDataRecord aesExtraDataRecord = new AESExtraDataRecord();
- aesExtraDataRecord.setSignature(InternalZipConstants.AESSIG);
- aesExtraDataRecord.setDataSize(extraDataRecord.getSizeOfData());
- byte[] aesData = extraDataRecord.getData();
- aesExtraDataRecord.setVersionNumber(Raw.readShortLittleEndian(aesData, 0));
- byte[] vendorIDBytes = new byte[2];
- System.arraycopy(aesData, 2, vendorIDBytes, 0, 2);
- aesExtraDataRecord.setVendorID(new String(vendorIDBytes));
- aesExtraDataRecord.setAesStrength((int) (aesData[4] & 0xFF));
- aesExtraDataRecord.setCompressionMethod(Raw.readShortLittleEndian(aesData, 5));
- return aesExtraDataRecord;
- }
- }
- return null;
- }
- /**
- * Reads buf length of bytes from the input stream to buf
- * @param zip4jRaf
- * @param buf
- * @return byte array
- * @throws ZipException
- */
- private byte[] readIntoBuff(RandomAccessStream zip4jRaf, byte[] buf) throws ZipException {
- try {
- if (zip4jRaf.read(buf, 0, buf.length) != -1) {
- return buf;
- } else {
- throw new ZipException("unexpected end of file when reading short buff");
- }
- } catch (IOException e) {
- throw new ZipException("IOException when reading short buff", e);
- }
- }
- /**
- * Returns a long byte from an int byte by appending last 4 bytes as 0's
- * @param intByte
- * @return byte array
- * @throws ZipException
- */
- private byte[] getLongByteFromIntByte(byte[] intByte) throws ZipException {
- if (intByte == null) {
- throw new ZipException("input parameter is null, cannot expand to 8 bytes");
- }
- if (intByte.length != 4) {
- throw new ZipException("invalid byte length, cannot expand to 8 bytes");
- }
- byte[] longBuff = {intByte[0], intByte[1], intByte[2], intByte[3], 0, 0, 0, 0};
- return longBuff;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement