From e35ea703dc5c85af3302383f2fc284a5c741b3bb Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Sun, 25 Mar 2018 13:39:21 +0300 Subject: [PATCH] [ZIP] Add support for custom extra fields --- Sources/ZIP/ZipCentralDirectoryEntry.swift | 17 ++++++++++++++++- Sources/ZIP/ZipContainer.swift | 2 ++ Sources/ZIP/ZipEntryInfo.swift | 7 +++++++ Sources/ZIP/ZipLocalHeader.swift | 17 ++++++++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Sources/ZIP/ZipCentralDirectoryEntry.swift b/Sources/ZIP/ZipCentralDirectoryEntry.swift index 355658f5..f449f4b9 100644 --- a/Sources/ZIP/ZipCentralDirectoryEntry.swift +++ b/Sources/ZIP/ZipCentralDirectoryEntry.swift @@ -39,6 +39,8 @@ struct ZipCentralDirectoryEntry { /// 0x7875 extra field. private(set) var infoZipNewUnixExtraField: InfoZipNewUnixExtraField? + let customExtraFields: [ZipExtraField] + let nextEntryOffset: Int init(_ byteReader: ByteReader) throws { @@ -78,6 +80,7 @@ struct ZipCentralDirectoryEntry { self.fileName = fileName let extraFieldStart = byteReader.offset + var customExtraFields = [ZipExtraField]() while byteReader.offset - extraFieldStart < extraFieldLength { // There are a lot of possible extra fields. let headerID = byteReader.uint16() @@ -107,9 +110,21 @@ struct ZipCentralDirectoryEntry { case 0x7875: // Info-ZIP New Unix Extra Field self.infoZipNewUnixExtraField = InfoZipNewUnixExtraField(byteReader, size, location: .centralDirectory) default: - byteReader.offset += size + let customFieldOffset = byteReader.offset + if let customExtraFieldType = ZipContainer.customExtraFields[headerID], + customExtraFieldType.id == headerID, + let customExtraField = customExtraFieldType.init(byteReader, size, location: .centralDirectory), + customExtraField.id == headerID { + customExtraFields.append(customExtraField) + guard byteReader.offset == customFieldOffset + size + else { fatalError("Custom field in Central Directory with ID=\(headerID) of" + + "type=\(customExtraFieldType) failed to read exactly \(size) bytes.") } + } else { + byteReader.offset = customFieldOffset + size + } } } + self.customExtraFields = customExtraFields guard let fileComment = byteReader.getZipStringField(fileCommentLength, useUtf8) else { throw ZipError.wrongTextField } diff --git a/Sources/ZIP/ZipContainer.swift b/Sources/ZIP/ZipContainer.swift index d2b2ed33..64072f7b 100644 --- a/Sources/ZIP/ZipContainer.swift +++ b/Sources/ZIP/ZipContainer.swift @@ -9,6 +9,8 @@ import BitByteData /// Provides functions for work with ZIP containers. public class ZipContainer: Container { + public static var customExtraFields = [UInt16: ZipExtraField.Type]() + /** Processes ZIP container and returns an array of `ZipEntry` with information and data for all entries. diff --git a/Sources/ZIP/ZipEntryInfo.swift b/Sources/ZIP/ZipEntryInfo.swift index 908ad1b3..5ebc266d 100644 --- a/Sources/ZIP/ZipEntryInfo.swift +++ b/Sources/ZIP/ZipEntryInfo.swift @@ -92,6 +92,8 @@ public struct ZipEntryInfo: ContainerEntryInfo { */ public let groupID: Int? + public let customExtraFields: [ZipExtraField] + let cdEntry: ZipCentralDirectoryEntry let localHeader: ZipLocalHeader @@ -200,6 +202,11 @@ public struct ZipEntryInfo: ContainerEntryInfo { // Owner's group ID. self.groupID = localHeader.infoZipNewUnixExtraField?.infoZipNewGid ?? localHeader.infoZipUnixExtraField?.infoZipGid.toInt() + + // Custom extra fields. + var customExtraFields = cdEntry.customExtraFields + customExtraFields.append(contentsOf: localHeader.customExtraFields) + self.customExtraFields = customExtraFields } } diff --git a/Sources/ZIP/ZipLocalHeader.swift b/Sources/ZIP/ZipLocalHeader.swift index 88a31904..a0433636 100644 --- a/Sources/ZIP/ZipLocalHeader.swift +++ b/Sources/ZIP/ZipLocalHeader.swift @@ -34,6 +34,8 @@ struct ZipLocalHeader { /// 0x7875 extra field. private(set) var infoZipNewUnixExtraField: InfoZipNewUnixExtraField? + let customExtraFields: [ZipExtraField] + let dataOffset: Int init(_ byteReader: ByteReader) throws { @@ -64,6 +66,7 @@ struct ZipLocalHeader { self.fileName = fileName let extraFieldStart = byteReader.offset + var customExtraFields = [ZipExtraField]() while byteReader.offset - extraFieldStart < extraFieldLength { // There are a lot of possible extra fields. let headerID = byteReader.uint16() @@ -85,9 +88,21 @@ struct ZipLocalHeader { case 0x7875: // Info-ZIP New Unix Extra Field self.infoZipNewUnixExtraField = InfoZipNewUnixExtraField(byteReader, size, location: .localHeader) default: - byteReader.offset += size + let customFieldOffset = byteReader.offset + if let customExtraFieldType = ZipContainer.customExtraFields[headerID], + customExtraFieldType.id == headerID, + let customExtraField = customExtraFieldType.init(byteReader, size, location: .localHeader), + customExtraField.id == headerID { + customExtraFields.append(customExtraField) + guard byteReader.offset == customFieldOffset + size + else { fatalError("Custom field in Local Header with ID=\(headerID) of" + + "type=\(customExtraFieldType) failed to read exactly \(size) bytes.") } + } else { + byteReader.offset = customFieldOffset + size + } } } + self.customExtraFields = customExtraFields self.dataOffset = byteReader.offset }