diff --git a/Sources/Zip/ZipArchive+OnDisk.swift b/Sources/Zip/ZipArchive+OnDisk.swift index a34ac2b..00c05e0 100644 --- a/Sources/Zip/ZipArchive+OnDisk.swift +++ b/Sources/Zip/ZipArchive+OnDisk.swift @@ -7,15 +7,20 @@ public extension ZipArchive { /// If the file does not exist, a new archive is created at the specified location. /// /// - Parameter fileURL: The file URL of the zip archive to be read or created. + /// - Parameter mode: The mode to use. The default, `Mode.readWrite`, lets you read an archive and, optionally, add new files to it. Use `Mode.overwrite` to create a new empty archive and overwrite an existing file if it exists. /// - Throws: An error if the initialization fails, such as if the file cannot be read or written. - convenience init(url fileURL: URL) throws { + convenience init(url fileURL: URL, mode: Mode = .readAdd) throws { self.init(archive: .init()) try fileURL.withUnsafeFileSystemRepresentation { path in - do { - try get { mz_zip_reader_init_file(&$0, path, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue)) } - try get { mz_zip_writer_init_from_reader_v2(&$0, path, 0) } - } catch ZipError.fileOpenFailed { - try get { mz_zip_writer_init_file_v2(&$0, path, 0, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue)) } + if mode == .readAdd { + do { + try get { mz_zip_reader_init_file(&$0, path, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue)) } + try get { mz_zip_writer_init_from_reader_v2(&$0, path, 0) } + } catch ZipError.fileOpenFailed { + try get { mz_zip_writer_init_file_v2(&$0, path, 0, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue)) } + } + } else { + try get { mz_zip_writer_init_file_v2(&$0, path, 0, 0) } } } } @@ -41,4 +46,9 @@ public extension ZipArchive { try get { mz_zip_writer_finalize_archive(&$0) } mz_zip_writer_end(&archive) } + + enum Mode { + case readAdd + case overwrite + } } diff --git a/Tests/Tests.swift b/Tests/Tests.swift index 275ca4e..3ff8a9a 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -3,6 +3,14 @@ import Testing import Foundation struct Tests { + let fileManager = FileManager() + let fileUUID = UUID() + var fileURL: URL { + fileManager.temporaryDirectory + .appendingPathComponent(fileUUID.uuidString) + .appendingPathExtension("zip") + } + let filename = "file1" let filename2 = "file2" let filename3 = "file3" @@ -64,25 +72,38 @@ struct Tests { @Test func files() throws { - let fileManager = FileManager() - - let temp = fileManager.temporaryDirectory - let url = temp.appendingPathComponent(UUID().uuidString).appendingPathExtension("zip") - - let archive = try ZipArchive(url: url) + let archive = try ZipArchive(url: fileURL) try archive.addFile(at: filename, data: data) #expect(try archive.fileContents(at: filename) == data) try archive.addFile(at: filename2, data: data2) #expect(try archive.fileContents(at: filename2) == data2) try archive.finalize() - let archive2 = try ZipArchive(url: url) + let archive2 = try ZipArchive(url: fileURL) #expect(try archive2.fileContents(at: filename) == data) try archive2.addFile(at: filename3, data: data3) #expect(try archive2.entries.count == 3) try archive2.finalize() - try? fileManager.removeItem(at: url) + try? fileManager.removeItem(at: fileURL) + } + + @Test + func overwriteFile() throws { + let archive1 = try ZipArchive(url: fileURL, mode: .overwrite) + #expect(try archive1.entries.count == 0) + try archive1.addFile(at: filename, data: data) + try archive1.finalize() + + let archive2 = try ZipArchive(url: fileURL, mode: .overwrite) + #expect(try archive2.entries.count == 0) + try archive2.addFile(at: filename, data: data2) + try archive2.finalize() + + let archive3 = try ZipArchive(url: fileURL, mode: .readAdd) + #expect(try archive3.entries.count == 1) + #expect(try archive3.fileContents(at: filename) == data2) + archive3.close() } @Test