diff --git a/Sources/ZIPFoundation/Archive+ZIP64.swift b/Sources/ZIPFoundation/Archive+ZIP64.swift index 8b94b7c3..f09a5088 100644 --- a/Sources/ZIPFoundation/Archive+ZIP64.swift +++ b/Sources/ZIPFoundation/Archive+ZIP64.swift @@ -80,8 +80,9 @@ extension Archive.ZIP64EndOfCentralDirectoryRecord { self.sizeOfZIP64EndOfCentralDirectoryRecord = data.scanValue(start: 4) self.versionMadeBy = data.scanValue(start: 12) self.versionNeededToExtract = data.scanValue(start: 14) - // Version Needed to Extract: 4.5 - File uses ZIP64 format extensions - guard self.versionNeededToExtract >= Archive.Version.v45.rawValue else { return nil } + // Note: The ZIP spec recommends versionNeededToExtract >= 4.5 for ZIP64, + // but some producers (e.g. Microsoft Outlook OLM export) write valid ZIP64 + // structures with a lower version. We accept the record if the signature matches. self.numberOfDisk = data.scanValue(start: 16) self.numberOfDiskStart = data.scanValue(start: 20) self.totalNumberOfEntriesOnDisk = data.scanValue(start: 24) diff --git a/Sources/ZIPFoundation/Entry.swift b/Sources/ZIPFoundation/Entry.swift index a6370c64..e1a31a68 100644 --- a/Sources/ZIPFoundation/Entry.swift +++ b/Sources/ZIPFoundation/Entry.swift @@ -297,19 +297,22 @@ extension Entry.CentralDirectoryStructure { extension Entry.CentralDirectoryStructure { var effectiveCompressedSize: UInt64 { - if self.isZIP64, let compressedSize = self.zip64ExtendedInformation?.compressedSize, compressedSize > 0 { + if self.isZIP64, self.compressedSize == .max, + let compressedSize = self.zip64ExtendedInformation?.compressedSize { return compressedSize } return UInt64(compressedSize) } var effectiveUncompressedSize: UInt64 { - if self.isZIP64, let uncompressedSize = self.zip64ExtendedInformation?.uncompressedSize, uncompressedSize > 0 { + if self.isZIP64, self.uncompressedSize == .max, + let uncompressedSize = self.zip64ExtendedInformation?.uncompressedSize { return uncompressedSize } return UInt64(uncompressedSize) } var effectiveRelativeOffsetOfLocalHeader: UInt64 { - if self.isZIP64, let offset = self.zip64ExtendedInformation?.relativeOffsetOfLocalHeader, offset > 0 { + if self.isZIP64, self.relativeOffsetOfLocalHeader == .max, + let offset = self.zip64ExtendedInformation?.relativeOffsetOfLocalHeader { return offset } return UInt64(relativeOffsetOfLocalHeader) diff --git a/Tests/ZIPFoundationTests/ZIPFoundationArchiveTests+ZIP64.swift b/Tests/ZIPFoundationTests/ZIPFoundationArchiveTests+ZIP64.swift index 95a14dcf..3aec341a 100644 --- a/Tests/ZIPFoundationTests/ZIPFoundationArchiveTests+ZIP64.swift +++ b/Tests/ZIPFoundationTests/ZIPFoundationArchiveTests+ZIP64.swift @@ -52,17 +52,19 @@ extension ZIPFoundationTests { additionalDataProvider: {_ -> Data in return Data() }) XCTAssertNil(invalidEOCDRecord2) - let eocdRecordWithWrongVersion: [UInt8] = [0x50, 0x4b, 0x06, 0x06, 0x2c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x14, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - let invalidEOCDRecord3 = Archive.ZIP64EndOfCentralDirectoryRecord(data: Data(eocdRecordWithWrongVersion), - additionalDataProvider: {_ -> Data in - return Data() }) - XCTAssertNil(invalidEOCDRecord3) + // Some ZIP producers (e.g. Microsoft Outlook OLM export) write valid ZIP64 + // structures with versionNeededToExtract < 4.5. These should be accepted. + let eocdRecordWithLowVersion: [UInt8] = [0x50, 0x4b, 0x06, 0x06, 0x2c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + let lowVersionEOCDRecord = Archive.ZIP64EndOfCentralDirectoryRecord(data: Data(eocdRecordWithLowVersion), + additionalDataProvider: {_ -> Data in + return Data() }) + XCTAssertNotNil(lowVersionEOCDRecord) } func testArchiveZIP64EOCDLocator() {