Skip to content

Commit b3ca1e6

Browse files
committed
1. Fix test failed on Linux 2. Minor fixes
1 parent 55c9ac5 commit b3ca1e6

14 files changed

+151
-153
lines changed

Sources/ZIPFoundation/Archive+Progress.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extension Archive {
1717
/// - Parameter entry: The entry that will be removed.
1818
/// - Returns: The number of the work units.
1919
public func totalUnitCountForRemoving(_ entry: Entry) -> Int64 {
20-
return Int64(self.offsetToStartOfCentralDirectory - Int(entry.localSize))
20+
return Int64(self.offsetToStartOfCentralDirectory - entry.localSize)
2121
}
2222

2323
func makeProgressForRemoving(_ entry: Entry) -> Progress {

Sources/ZIPFoundation/Archive+Reading.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extension Archive {
2121
/// - progress: A progress object that can be used to track or cancel the extract operation.
2222
/// - Returns: The checksum of the processed content or 0 if the `skipCRC32` flag was set to `true`.
2323
/// - Throws: An error if the destination file cannot be written or the entry contains malformed content.
24-
public func extract(_ entry: Entry, to url: URL, bufferSize: UInt32 = defaultReadChunkSize, skipCRC32: Bool = false,
24+
public func extract(_ entry: Entry, to url: URL, bufferSize: Int = defaultReadChunkSize, skipCRC32: Bool = false,
2525
progress: Progress? = nil) throws -> CRC32 {
2626
guard bufferSize > 0 else {
2727
throw ArchiveError.invalidBufferSize
@@ -75,7 +75,7 @@ extension Archive {
7575
/// - consumer: A closure that consumes contents of `Entry` as `Data` chunks.
7676
/// - Returns: The checksum of the processed content or 0 if the `skipCRC32` flag was set to `true`..
7777
/// - Throws: An error if the destination file cannot be written or the entry contains malformed content.
78-
public func extract(_ entry: Entry, bufferSize: UInt32 = defaultReadChunkSize, skipCRC32: Bool = false,
78+
public func extract(_ entry: Entry, bufferSize: Int = defaultReadChunkSize, skipCRC32: Bool = false,
7979
progress: Progress? = nil, consumer: Consumer) throws -> CRC32 {
8080
guard bufferSize > 0 else {
8181
throw ArchiveError.invalidBufferSize
@@ -111,23 +111,23 @@ extension Archive {
111111

112112
// MARK: - Helpers
113113

114-
private func readUncompressed(entry: Entry, bufferSize: UInt32, skipCRC32: Bool,
114+
private func readUncompressed(entry: Entry, bufferSize: Int, skipCRC32: Bool,
115115
progress: Progress? = nil, with consumer: Consumer) throws -> CRC32 {
116116
let size = Int(entry.centralDirectoryStructure.uncompressedSize)
117-
return try Data.consumePart(of: size, chunkSize: Int(bufferSize), skipCRC32: skipCRC32,
117+
return try Data.consumePart(of: size, chunkSize: bufferSize, skipCRC32: skipCRC32,
118118
provider: { (_, chunkSize) -> Data in
119-
return try Data.readChunk(of: Int(chunkSize), from: self.archiveFile)
119+
return try Data.readChunk(of: chunkSize, from: self.archiveFile)
120120
}, consumer: { (data) in
121121
if progress?.isCancelled == true { throw ArchiveError.cancelledOperation }
122122
try consumer(data)
123123
progress?.completedUnitCount += Int64(data.count)
124124
})
125125
}
126126

127-
private func readCompressed(entry: Entry, bufferSize: UInt32, skipCRC32: Bool,
127+
private func readCompressed(entry: Entry, bufferSize: Int, skipCRC32: Bool,
128128
progress: Progress? = nil, with consumer: Consumer) throws -> CRC32 {
129129
let size = Int(entry.centralDirectoryStructure.compressedSize)
130-
return try Data.decompress(size: size, bufferSize: Int(bufferSize), skipCRC32: skipCRC32,
130+
return try Data.decompress(size: size, bufferSize: bufferSize, skipCRC32: skipCRC32,
131131
provider: { (_, chunkSize) -> Data in
132132
return try Data.readChunk(of: chunkSize, from: self.archiveFile)
133133
}, consumer: { (data) in

Sources/ZIPFoundation/Archive+Writing.swift

Lines changed: 52 additions & 52 deletions
Large diffs are not rendered by default.

Sources/ZIPFoundation/Archive+Zip64.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@ enum ExtraFieldHeaderID: UInt16 {
1919
case zip64ExtendedInformation = 0x0001
2020
}
2121

22-
var maxUInt32 = UInt32.max
23-
var maxUInt16 = UInt16.max
24-
25-
var maxCompressedSize: UInt32 { maxUInt32 }
26-
var maxUncompressedSize: UInt32 { maxUInt32 }
27-
var maxOffsetOfLocalFileHeader: UInt32 { maxUInt32 }
28-
var maxOffsetOfCentralDirectory: UInt32 { maxUInt32 }
29-
var maxSizeOfCentralDirectory: UInt32 { maxUInt32 }
30-
var maxTotalNumberOfEntries: UInt16 { maxUInt16 }
31-
3222
extension Archive {
3323
struct Zip64EndOfCentralDirectory {
3424
let record: Zip64EndOfCentralDirectoryRecord
@@ -92,6 +82,7 @@ extension Archive.Zip64EndOfCentralDirectoryRecord {
9282
self.sizeOfZip64EndOfCentralDirectoryRecord = data.scanValue(start: 4)
9383
self.versionMadeBy = data.scanValue(start: 12)
9484
self.versionNeededToExtract = data.scanValue(start: 14)
85+
// Version Needed to Extract: 4.5 - File uses ZIP64 format extensions
9586
guard self.versionNeededToExtract >= zip64Version else { return nil }
9687
self.numberOfDisk = data.scanValue(start: 16)
9788
self.numberOfDiskStart = data.scanValue(start: 20)
@@ -152,3 +143,14 @@ extension Archive.Zip64EndOfCentralDirectoryLocator {
152143
extension Archive.Zip64EndOfCentralDirectory {
153144
var data: Data { record.data + locator.data }
154145
}
146+
147+
/// Properties that represent the maximum value of each field
148+
var maxUInt32 = UInt32.max
149+
var maxUInt16 = UInt16.max
150+
151+
var maxCompressedSize: UInt32 { maxUInt32 }
152+
var maxUncompressedSize: UInt32 { maxUInt32 }
153+
var maxOffsetOfLocalFileHeader: UInt32 { maxUInt32 }
154+
var maxOffsetOfCentralDirectory: UInt32 { maxUInt32 }
155+
var maxSizeOfCentralDirectory: UInt32 { maxUInt32 }
156+
var maxTotalNumberOfEntries: UInt16 { maxUInt16 }

Sources/ZIPFoundation/Archive.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,15 @@
1111
import Foundation
1212

1313
/// The default chunk size when reading entry data from an archive.
14-
public let defaultReadChunkSize = UInt32(16*1024)
14+
public let defaultReadChunkSize = Int(16*1024)
1515
/// The default chunk size when writing entry data to an archive.
1616
public let defaultWriteChunkSize = defaultReadChunkSize
1717
/// The default permissions for newly added entries.
1818
public let defaultFilePermissions = UInt16(0o644)
1919
public let defaultDirectoryPermissions = UInt16(0o755)
2020
let defaultPOSIXBufferSize = defaultReadChunkSize
2121
let defaultDirectoryUnitCount = Int64(1)
22-
let minDirectoryEndOffset = 22
23-
let maxDirectoryEndOffset = 66000
22+
let minEndOfCentralDirectoryOffset = 22
2423
let endOfCentralDirectoryStructSignature = 0x06054b50
2524
let localFileHeaderStructSignature = 0x04034b50
2625
let dataDescriptorStructSignature = 0x08074b50
@@ -192,8 +191,8 @@ public final class Archive: Sequence {
192191
}
193192

194193
public func makeIterator() -> AnyIterator<Entry> {
195-
let totalNumberOfEntriesInCD = Int(self.totalNumberOfEntriesInCentralDirectory)
196-
var directoryIndex = Int(self.offsetToStartOfCentralDirectory)
194+
let totalNumberOfEntriesInCD = self.totalNumberOfEntriesInCentralDirectory
195+
var directoryIndex = self.offsetToStartOfCentralDirectory
197196
var index = 0
198197
return AnyIterator {
199198
guard index < totalNumberOfEntriesInCD else { return nil }
@@ -310,10 +309,10 @@ public final class Archive: Sequence {
310309
static func scanForEndOfCentralDirectoryRecord(in file: UnsafeMutablePointer<FILE>)
311310
-> EndOfCentralDirectoryStructure? {
312311
var eocdOffset = 0
313-
var index = minDirectoryEndOffset
312+
var index = minEndOfCentralDirectoryOffset
314313
fseek(file, 0, SEEK_END)
315314
let archiveLength = ftell(file)
316-
while eocdOffset == 0 && index < maxDirectoryEndOffset && index <= archiveLength {
315+
while eocdOffset == 0 && index <= archiveLength {
317316
fseek(file, archiveLength - index, SEEK_SET)
318317
var potentialDirectoryEndTag: UInt32 = UInt32()
319318
fread(&potentialDirectoryEndTag, 1, MemoryLayout<UInt32>.size, file)

Sources/ZIPFoundation/Entry+Zip64.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ extension Entry.Zip64ExtendedInformation {
7474
defer {
7575
readOffset += MemoryLayout<T>.size
7676
}
77-
guard readOffset + field.size < data.count + 1 else {
77+
guard readOffset + field.size <= data.count else {
7878
throw Entry.EntryError.invalidDataError
7979
}
8080
return data.scanValue(start: readOffset)
@@ -98,11 +98,12 @@ extension Entry.Zip64ExtendedInformation {
9898
var offset = 0
9999
var headerID: UInt16
100100
var dataSize: UInt16
101-
while offset + 4 < data.count {
101+
let extraFieldLength = data.count
102+
while offset < extraFieldLength - 4 {
102103
headerID = data.scanValue(start: offset)
103104
dataSize = data.scanValue(start: offset + 2)
104105
let nextOffset = offset + 4 + Int(dataSize)
105-
guard nextOffset < data.count + 1 else { return nil }
106+
guard nextOffset <= extraFieldLength else { return nil }
106107
if headerID == ExtraFieldHeaderID.zip64ExtendedInformation.rawValue {
107108
return Entry.Zip64ExtendedInformation(data: data.subdata(in: offset..<nextOffset), fields: fields)
108109
}

Sources/ZIPFoundation/FileManager+ZIP.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,7 @@ extension FileManager {
232232
var fileStat = stat()
233233
lstat(entryFileSystemRepresentation, &fileStat)
234234
// `st_size` is a signed int value
235-
let fileSize = fileStat.st_size
236-
return Int(fileSize)
235+
return Int(fileStat.st_size)
237236
}
238237

239238
class func typeForItem(at url: URL) throws -> Entry.EntryType {

Tests/ZIPFoundationTests/ZIPFoundationArchieveTests+Zip64.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ extension ZIPFoundationTests {
5151
additionalDataProvider: {_ -> Data in
5252
return Data() })
5353
XCTAssertNil(invalidEOCDRecord2)
54-
// Version Needed to Extract: 4.5 - File uses ZIP64 format extensions
5554
let eocdRecordWithWrongVersion: [UInt8] = [0x50, 0x4b, 0x06, 0x06, 0x2c, 0x00, 0x00, 0x00,
5655
0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x14, 0x00,
5756
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

Tests/ZIPFoundationTests/ZIPFoundationErrorConditionTests+Zip64.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ extension ZIPFoundationTests {
1919
numberOfEntries: 0)
2020
do {
2121
_ = try archive.writeEndOfCentralDirectory(centralDirectoryStructure: makeMockCentralDirectory()!,
22-
startOfCentralDirectory: 0,
23-
startOfEndOfCentralDirectory: 0,
24-
operation: .add)
22+
startOfCentralDirectory: 0,
23+
startOfEndOfCentralDirectory: 0,
24+
operation: .add)
2525
} catch let error as Archive.ArchiveError {
2626
XCTAssertNotNil(error == .invalidSizeOfCentralDirectory)
2727
didCatchExpectedError = true
2828
} catch {
29-
XCTFail("Unexpected error while trying to add an entry exceeding maximum size.")
29+
XCTFail("Unexpected error while writing end of central directory with large central directory size.")
3030
}
3131
XCTAssert(didCatchExpectedError)
3232
}
@@ -38,14 +38,14 @@ extension ZIPFoundationTests {
3838
numberOfEntries: .max)
3939
do {
4040
_ = try archive.writeEndOfCentralDirectory(centralDirectoryStructure: makeMockCentralDirectory()!,
41-
startOfCentralDirectory: 0,
42-
startOfEndOfCentralDirectory: 0,
43-
operation: .add)
41+
startOfCentralDirectory: 0,
42+
startOfEndOfCentralDirectory: 0,
43+
operation: .add)
4444
} catch let error as Archive.ArchiveError {
4545
XCTAssertNotNil(error == .invalidNumberOfEntriesInCentralDirectory)
4646
didCatchExpectedError = true
4747
} catch {
48-
XCTFail("Unexpected error while trying to add an entry exceeding maximum size.")
48+
XCTFail("Unexpected error while writing end of central directory with large number of entries.")
4949
}
5050
XCTAssert(didCatchExpectedError)
5151
}

Tests/ZIPFoundationTests/ZIPFoundationProgressTests.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,5 +180,40 @@ extension ZIPFoundationTests {
180180
}
181181
self.wait(for: [expectation], timeout: 10.0)
182182
}
183+
184+
func testZip64ArchiveAddEntryProgress() {
185+
mockIntMaxValues()
186+
defer { resetIntMaxValues() }
187+
let archive = self.archive(for: #function, mode: .update)
188+
let assetURL = self.resourceURL(for: #function, pathExtension: "png")
189+
let progress = archive.makeProgressForAddingItem(at: assetURL)
190+
let handler: XCTKVOExpectation.Handler = { (_, _) -> Bool in
191+
if progress.fractionCompleted > 0.5 {
192+
progress.cancel()
193+
return true
194+
}
195+
return false
196+
}
197+
let cancel = self.keyValueObservingExpectation(for: progress, keyPath: #keyPath(Progress.fractionCompleted),
198+
handler: handler)
199+
let zipQueue = DispatchQueue(label: "ZIPFoundationTests")
200+
zipQueue.async {
201+
do {
202+
let relativePath = assetURL.lastPathComponent
203+
let baseURL = assetURL.deletingLastPathComponent()
204+
try archive.addEntry(with: relativePath, relativeTo: baseURL,
205+
compressionMethod: .deflate, bufferSize: 1, progress: progress)
206+
} catch let error as Archive.ArchiveError {
207+
XCTAssert(error == Archive.ArchiveError.cancelledOperation)
208+
} catch {
209+
XCTFail("Failed to add entry to uncompressed folder archive with error : \(error)")
210+
}
211+
}
212+
self.wait(for: [cancel], timeout: 20.0)
213+
zipQueue.sync {
214+
XCTAssert(progress.fractionCompleted > 0.5)
215+
// XCTAssert(archive.checkIntegrity())
216+
}
217+
}
183218
}
184219
#endif

Tests/ZIPFoundationTests/ZIPFoundationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,7 @@ extension ZIPFoundationTests {
254254
("testRemoveEntryFromArchiveWithZip64EOCD", testRemoveEntryFromArchiveWithZip64EOCD),
255255
("testRemoveZip64EntryFromArchiveWithZip64EOCD", testRemoveZip64EntryFromArchiveWithZip64EOCD),
256256
("testWriteEOCDWithTooLargeSizeOfCentralDirectory", testWriteEOCDWithTooLargeSizeOfCentralDirectory),
257-
("testWriteEOCDWithTooLargeCentralDirectoryOffset", testWriteEOCDWithTooLargeCentralDirectoryOffset),
258-
("testAddZip64EntryRollback", testAddZip64EntryRollback)
257+
("testWriteEOCDWithTooLargeCentralDirectoryOffset", testWriteEOCDWithTooLargeCentralDirectoryOffset)
259258
]
260259
}
261260

@@ -270,6 +269,7 @@ extension ZIPFoundationTests {
270269
("testReplaceCurrentArchiveWithArchiveCrossLink", testReplaceCurrentArchiveWithArchiveCrossLink),
271270
("testArchiveAddUncompressedEntryProgress", testArchiveAddUncompressedEntryProgress),
272271
("testArchiveAddCompressedEntryProgress", testArchiveAddCompressedEntryProgress),
272+
("testZip64ArchiveAddEntryProgress", testZip64ArchiveAddEntryProgress),
273273
// The below test cases test error code paths but they lead to undefined behavior and memory
274274
// corruption on non-Darwin platforms. We disable them for now.
275275
("testReadStructureErrorConditions", testReadStructureErrorConditions),

0 commit comments

Comments
 (0)