[ZIP] Add support for custom extra fields

This commit is contained in:
Timofey Solomko
2018-03-31 12:25:17 +03:00
parent 6ae80d98a6
commit e35ea703dc
4 changed files with 41 additions and 2 deletions
+16 -1
View File
@@ -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 }
+2
View File
@@ -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.
+7
View File
@@ -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
}
}
+16 -1
View File
@@ -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
}