From c9115f367be2fd0d03d6314428608fdcc89bf48a Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Mon, 13 Aug 2018 11:38:42 +0300 Subject: [PATCH] [ZIP] Replace stored local header and cd entry in ZipEntryInfo with separate actually required properties --- Sources/ZIP/ZipContainer.swift | 20 ++++++++------------ Sources/ZIP/ZipEntryInfo.swift | 23 ++++++++++++++++------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Sources/ZIP/ZipContainer.swift b/Sources/ZIP/ZipContainer.swift index e7811baa..dd743c56 100644 --- a/Sources/ZIP/ZipContainer.swift +++ b/Sources/ZIP/ZipContainer.swift @@ -57,17 +57,13 @@ public class ZipContainer: Container { } private static func getEntryData(from data: Data, using info: ZipEntryInfo) throws -> (data: Data, crcError: Bool) { - let hasDataDescriptor = info.localHeader.generalPurposeBitFlags & 0x08 != 0 - - // If file has data descriptor, then some values in local header are absent. - // So we need to use values from CD entry. - var uncompSize = hasDataDescriptor ? info.cdEntry.uncompSize : info.localHeader.uncompSize - var compSize = hasDataDescriptor ? info.cdEntry.compSize : info.localHeader.compSize - var crc32 = hasDataDescriptor ? info.cdEntry.crc32 : info.localHeader.crc32 + var uncompSize = info.uncompSize + var compSize = info.compSize + var crc32 = info.crc let fileData: Data let byteReader = ByteReader(data: data) - byteReader.offset = info.localHeader.dataOffset + byteReader.offset = info.dataOffset switch info.compressionMethod { case .copy: fileData = Data(bytes: byteReader.bytes(count: uncompSize.toInt())) @@ -100,9 +96,9 @@ public class ZipContainer: Container { default: throw ZipError.compressionNotSupported } - let realCompSize = byteReader.offset - info.localHeader.dataOffset + let realCompSize = byteReader.offset - info.dataOffset - if hasDataDescriptor { + if info.hasDataDescriptor { // Now we need to parse data descriptor itself. // First, it might or might not have signature. let ddSignature = byteReader.uint32() @@ -111,7 +107,7 @@ public class ZipContainer: Container { } // Now, let's update with values from data descriptor. crc32 = byteReader.uint32() - if info.localHeader.zip64FieldsArePresent { + if info.zip64FieldsArePresent { compSize = byteReader.uint64() uncompSize = byteReader.uint64() } else { @@ -175,7 +171,7 @@ public class ZipContainer: Container { let info = try ZipEntryInfo(byteReader, endOfCD.currentDiskNumber) entries.append(info) // Move to the next Central Directory entry. - byteReader.offset = info.cdEntry.nextEntryOffset + byteReader.offset = info.nextCdEntryOffset } return entries diff --git a/Sources/ZIP/ZipEntryInfo.swift b/Sources/ZIP/ZipEntryInfo.swift index 764050a4..ed19ec32 100644 --- a/Sources/ZIP/ZipEntryInfo.swift +++ b/Sources/ZIP/ZipEntryInfo.swift @@ -102,20 +102,22 @@ public struct ZipEntryInfo: ContainerEntryInfo { /// CRC32 of entry's data. public let crc: UInt32 - let cdEntry: ZipCentralDirectoryEntry - let localHeader: ZipLocalHeader + let hasDataDescriptor: Bool + let zip64FieldsArePresent: Bool + let nextCdEntryOffset: Int + let dataOffset: Int + let compSize: UInt64 + let uncompSize: UInt64 init(_ byteReader: ByteReader, _ currentDiskNumber: UInt32) throws { - // Load and save Central Directory entry. + // Read Central Directory entry. let cdEntry = try ZipCentralDirectoryEntry(byteReader) - self.cdEntry = cdEntry // Move to the location of Local Header. byteReader.offset = cdEntry.localHeaderOffset.toInt() - // Load and save Local Header. + // Read Local Header. let localHeader = try ZipLocalHeader(byteReader) try localHeader.validate(with: cdEntry, currentDiskNumber) - self.localHeader = localHeader // If file has data descriptor, then some properties are only present in CD entry. self.hasDataDescriptor = localHeader.generalPurposeBitFlags & 0x08 != 0 @@ -172,7 +174,7 @@ public struct ZipEntryInfo: ContainerEntryInfo { } // Size - self.size = cdEntry.uncompSize.toInt() + self.size = (hasDataDescriptor ? cdEntry.uncompSize : localHeader.uncompSize).toInt() // External file attributes. self.externalFileAttributes = cdEntry.externalFileAttributes @@ -206,6 +208,13 @@ public struct ZipEntryInfo: ContainerEntryInfo { var customExtraFields = cdEntry.customExtraFields customExtraFields.append(contentsOf: localHeader.customExtraFields) self.customExtraFields = customExtraFields + + // Save some properties from CD entry and Local Header. + self.zip64FieldsArePresent = localHeader.zip64FieldsArePresent + self.nextCdEntryOffset = cdEntry.nextEntryOffset + self.dataOffset = localHeader.dataOffset + self.compSize = hasDataDescriptor ? cdEntry.compSize : localHeader.compSize + self.uncompSize = hasDataDescriptor ? cdEntry.uncompSize : localHeader.uncompSize } }