Skip to content

Commit 266da3c

Browse files
committed
Merge branch 'dev'
2 parents 622e5c7 + 917f470 commit 266da3c

12 files changed

+508
-247
lines changed

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ let package = Package(
99
],
1010
targets: [
1111
.target(name: "Zip", dependencies: ["Miniz"]),
12-
.target(name: "Miniz", path: "Sources/miniz", publicHeadersPath: ".")
12+
.target(name: "Miniz", path: "Sources/miniz", publicHeadersPath: "."),
13+
.testTarget(name: "Tests", dependencies: ["Zip"])
1314
]
1415
)

README.md

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Zip runs on macOS, Windows and Linux.
66

77
[![Swift](https://github.com/tomasf/Zip/actions/workflows/swift.yml/badge.svg)](https://github.com/tomasf/Zip/actions/workflows/swift.yml)
88

9-
![Platforms](https://img.shields.io/badge/Platforms-macOS_|_Linux_|_Windows-cc9529?logo=swift&logoColor=white)
9+
![Platforms](https://img.shields.io/badge/Platforms-macOS_%7C_Linux_%7C_Windows-47D?logo=swift&logoColor=white)
1010

1111
## Features
1212

@@ -21,26 +21,42 @@ Add the package to your project using Swift Package Manager. In your `Package.sw
2121

2222
```swift
2323
dependencies: [
24-
.package(url: "https://github.com/tomasf/Zip.git", from: "1.0.0")
24+
.package(url: "https://github.com/tomasf/Zip.git", from: "2.0.0")
2525
]
2626
```
2727

2828
## Examples
29-
### Writing to a file-based archive
29+
### Making a new memory-based archive
3030

3131
```swift
32-
import Zip
33-
34-
let archive = try FileZipArchive(forWritingTo: URL(fileURLWithPath: "example.zip"))
35-
archive.addFile(name: "hello.txt", data: Data("Hello, Zip!".utf8))
36-
try archive.finalize()
32+
let archive = ZipArchive()
33+
try archive.addFile(at: "content.json", data: jsonData)
34+
let zipData = try archive.finalize()
3735
```
3836

39-
### Reading from a memory-based archive
37+
### Reading from an existing archive in memory
4038

4139
```swift
42-
let archive = try MemoryZipArchive(data: zipData)
43-
if let data = archive.readFile(name: "hello.txt"), let text = String(data: data, encoding: .utf8) {
44-
print("File content: \(text)")
40+
let newArchive = try ZipArchive(data: zipData)
41+
42+
let data = try archive.fileContents(at: "hello.txt")
43+
if let text = String(data: data, encoding: .utf8) {
44+
print("Hello.txt contains: \(text)")
4545
}
4646
```
47+
48+
### Writing a file-based archive
49+
50+
```swift
51+
let archive = try ZipArchive(url: archiveURL)
52+
try archive.addFile(at: "hello.txt", data: Data("Hello, Zip!".utf8))
53+
try archive.finalize() // Writes Zip data to disk
54+
```
55+
56+
## Contributions
57+
58+
Contributions are welcome! If you have ideas, suggestions, or bug reports, feel free to open an issue on GitHub. Pull requests are also appreciated.
59+
60+
## License
61+
62+
This project is licensed under the MIT License. See the LICENSE file for details.

Sources/Zip/FileZipArchive.swift

Lines changed: 0 additions & 40 deletions
This file was deleted.

Sources/Zip/MemoryZipArchive.swift

Lines changed: 0 additions & 44 deletions
This file was deleted.

Sources/Zip/ZipArchive+Get.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Foundation
2+
import Miniz
3+
4+
internal extension ZipArchive {
5+
func get<P: _Pointer>(_ body: (inout mz_zip_archive) -> P?) throws(ZipError) -> P {
6+
guard let result = body(&archive) else {
7+
throw ZipError(mzError: mz_zip_get_last_error(&archive))
8+
}
9+
return result
10+
}
11+
12+
@discardableResult
13+
func get<I: BinaryInteger>(with success: Success = .positive, _ body: (inout mz_zip_archive) -> I) throws(ZipError) -> I {
14+
let result = body(&archive)
15+
16+
if result < 0 || (success == .positive && result == 0) {
17+
throw ZipError(mzError: mz_zip_get_last_error(&archive))
18+
}
19+
20+
return result
21+
}
22+
23+
enum Success {
24+
case positive
25+
case nonNegative
26+
}
27+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import Foundation
2+
import Miniz
3+
4+
public extension ZipArchive<Data> {
5+
6+
/// Creates a memory-based `ZipArchive` instance from the provided zip archive data.
7+
///
8+
/// - Parameter data: The zip archive data used to initialize the archive.
9+
/// - Throws: An error if the archive initialization fails.
10+
convenience init(data: Data) throws {
11+
self.init(archive: .init())
12+
13+
// mz_zip_writer_init_from_reader_v2 sets m_pWrite to mz_zip_heap_write_func
14+
// This means miniz takes ownership of that memory and will free it.
15+
16+
guard let input = malloc(data.count) else {
17+
throw ZipError.allocFailed
18+
}
19+
data.withUnsafeBytes {
20+
guard let pointer = $0.baseAddress else { return }
21+
memcpy(input, pointer, data.count)
22+
}
23+
24+
try get {
25+
mz_zip_reader_init_mem(&$0, input, data.count, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue))
26+
}
27+
28+
try get {
29+
mz_zip_writer_init_from_reader_v2(&$0, nil, 0)
30+
}
31+
}
32+
33+
/// Creates an empty `ZipArchive` instance.
34+
///
35+
/// This initializer sets up an empty memory-based archive,
36+
/// allowing both reading and writing of entries.
37+
convenience init() {
38+
self.init(archive: .init())
39+
40+
try! get {
41+
mz_zip_writer_init_heap_v2(&$0, 0, 0, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue))
42+
}
43+
}
44+
45+
/// Finalizes the archive and returns the resulting zip archive data.
46+
///
47+
/// This method ensures that all changes made to the archive are finalized and retrieves the
48+
/// completed archive data.
49+
///
50+
/// - Returns: The finalized zip archive data.
51+
/// - Throws: An error if finalization fails or if the resulting data is invalid.
52+
func finalize() throws -> Data {
53+
var buffer: UnsafeMutableRawPointer?
54+
var size: Int = 0
55+
56+
try get {
57+
mz_zip_writer_finalize_heap_archive(&$0, &buffer, &size)
58+
}
59+
60+
guard let buffer else {
61+
throw ZipError.invalidData
62+
}
63+
64+
mz_zip_writer_end(&archive)
65+
defer { mz_free(buffer) }
66+
return Data(bytes: buffer, count: size)
67+
}
68+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import Foundation
2+
import Miniz
3+
4+
public extension ZipArchive<URL> {
5+
/// Creates a `ZipArchive` instance for a disk-based zip archive at the specified file URL.
6+
///
7+
/// If the file does not exist, a new archive is created at the specified location.
8+
///
9+
/// - Parameter fileURL: The file URL of the zip archive to be read or created.
10+
/// - Throws: An error if the initialization fails, such as if the file cannot be read or written.
11+
convenience init(url fileURL: URL) throws {
12+
self.init(archive: .init())
13+
try fileURL.withUnsafeFileSystemRepresentation { path in
14+
do {
15+
try get { mz_zip_reader_init_file(&$0, path, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue)) }
16+
try get { mz_zip_writer_init_from_reader_v2(&$0, path, 0) }
17+
} catch ZipError.fileOpenFailed {
18+
try get { mz_zip_writer_init_file_v2(&$0, path, 0, mz_uint32(MZ_ZIP_FLAG_WRITE_ALLOW_READING.rawValue)) }
19+
}
20+
}
21+
}
22+
23+
/// Closes the zip archive without writing the central directory to disk.
24+
///
25+
/// This method ends the zip archive session without finalizing changes. Use this if you haven't
26+
/// made changes and do not need to save the archive.
27+
///
28+
/// After calling this method, the archive is no longer usable, and you must not perform additional
29+
/// operations on it.
30+
func close() {
31+
mz_zip_writer_end(&archive)
32+
}
33+
34+
/// Finalizes the zip archive and writes it to disk.
35+
///
36+
/// This method ensures all changes are saved and closes the archive. After this method is called,
37+
/// no further modifications to the archive can be made.
38+
///
39+
/// - Throws: An error if the finalization process fails.
40+
func finalize() throws {
41+
try get { mz_zip_writer_finalize_archive(&$0) }
42+
mz_zip_writer_end(&archive)
43+
}
44+
}

0 commit comments

Comments
 (0)