mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
Merge branch 'develop'
This commit is contained in:
+3
-48
@@ -2,9 +2,6 @@
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Custom
|
||||
Tests/temp
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
@@ -26,58 +23,16 @@ xcuserdata/
|
||||
*.xccheckout
|
||||
*.xcscmblueprint
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
.build/
|
||||
Package.pins
|
||||
|
||||
# CocoaPods
|
||||
Pods/
|
||||
|
||||
# Carthage
|
||||
# Avoid checking in source code from Carthage dependencies.
|
||||
Carthage/Checkouts
|
||||
Carthage/Build
|
||||
Cartfile.resolved
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
|
||||
# Symbolic link to swcomp executable built by SPM
|
||||
/swcomp
|
||||
|
||||
# Package.resolved, because we don't want to fix dependencies' versions
|
||||
Package.resolved
|
||||
.build/
|
||||
|
||||
# Docs generated by SourceKitten
|
||||
# Ignore docs generated by SourceKitten
|
||||
docs.json
|
||||
|
||||
# Docs generated by Jazzy
|
||||
# Ignore docs generated by Jazzy
|
||||
docs/
|
||||
|
||||
# Vscode launch.json generated by Swift extension
|
||||
.vscode/launch.json
|
||||
|
||||
# API baselines generate by swift package diagnose-api-breaking-changes
|
||||
api_baseline/
|
||||
|
||||
+3
-3
@@ -3,11 +3,11 @@ sourcekitten_sourcefile: docs.json
|
||||
clean: false
|
||||
author: Timofey Solomko
|
||||
module: SWCompression
|
||||
module_version: 4.8.7
|
||||
copyright: '© 2024 Timofey Solomko'
|
||||
module_version: 4.9.0
|
||||
copyright: '© 2026 Timofey Solomko'
|
||||
readme: README.md
|
||||
github_url: https://github.com/tsolomko/SWCompression
|
||||
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.8.7
|
||||
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.9.0
|
||||
theme: fullwidth
|
||||
|
||||
custom_categories:
|
||||
|
||||
+32
-2
@@ -1,5 +1,35 @@
|
||||
# Changelog
|
||||
|
||||
## 4.9.0
|
||||
|
||||
- Swift versions from 5.3 up to and including 5.8 are no longer supported.
|
||||
- Cocoapods and Carthage installation methods are no longer supported.
|
||||
- Enabled visionOS platform for SPM.
|
||||
- Increased minimum deployment versions for Darwin platforms: macOS from 10.13 to 14.0, iOS from 11.0 to 17.0, tvOS from
|
||||
11.0 to 17.0, and watchOS from 4.0 to 10.0.
|
||||
- Increased the lowest required version of BitByteData dependency to 2.1.
|
||||
- Added `BZip2.multiDecompress` function.
|
||||
- Improved performance of BZip2 compression and decompression.
|
||||
- Slighlty improved performance of LZMA/LZMA2 decompression.
|
||||
- Improved performance of Deflate compression and decompression.
|
||||
- Fixed potential crashes when processing truncated BZip2 archives.
|
||||
- Fixed potential crashes when processing truncated Zlib archives.
|
||||
- Fixed potential crashes when processing truncated or corrupted data compressed with Deflate.
|
||||
- Fixed incorrect parsing of LZMA dictionary sizes larger than 2<sup>24</sup>-1 in 7-Zip containers (PR #61 by @analytical-engines and @nekonya).
|
||||
- swcomp changes:
|
||||
- SPM target is now enabled only on macOS.
|
||||
- Added `-m`, `--multi-decompress` option to `bz2` command.
|
||||
- Benchmark metadatas are now printed in a standard order.
|
||||
- Benchmarking warmup iteration results are now printed and saved into a file.
|
||||
- Benchmarking raw data is now saved into a file.
|
||||
- Improved benchmarking output for multi-way comparsions.
|
||||
- Added `--print-uuid` option to `benchmark show` command.
|
||||
- Added `--metadata-only` option to `benchmark show` command.
|
||||
- Added `--self-compare` option to `benchmark show` command.
|
||||
- Added `benchmark remove-run` command.
|
||||
- Updated benchmark results file format.
|
||||
- Added `benchmark convert` command.
|
||||
|
||||
## 4.8.7
|
||||
|
||||
- Pinned BitByteData version to 2.0.4.
|
||||
@@ -7,8 +37,8 @@
|
||||
## 4.8.6
|
||||
|
||||
- Swift 5.2 is no longer supported.
|
||||
- Enable visionOS deployment target (only for Carthage users).
|
||||
- Add PrivacyInfo file.
|
||||
- Enabled visionOS deployment target (only for Carthage users).
|
||||
- Added PrivacyInfo file.
|
||||
- Fixed a documentation error in `TarEntryInfo.deviceMinorNumber`.
|
||||
|
||||
## 4.8.5
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Timofey Solomko
|
||||
Copyright (c) 2026 Timofey Solomko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+15
-18
@@ -1,15 +1,14 @@
|
||||
// swift-tools-version:5.3
|
||||
// swift-tools-version:5.9
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
var package = Package(
|
||||
name: "SWCompression",
|
||||
platforms: [
|
||||
.macOS(.v10_13),
|
||||
.iOS(.v11),
|
||||
.tvOS(.v11),
|
||||
.watchOS(.v4),
|
||||
// TODO: Enable after upgrading to Swift 5.9.
|
||||
// .visionOS(.v1)
|
||||
.macOS(.v14),
|
||||
.iOS(.v17),
|
||||
.tvOS(.v17),
|
||||
.watchOS(.v10),
|
||||
.visionOS(.v1)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
@@ -17,10 +16,7 @@ let package = Package(
|
||||
targets: ["SWCompression"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(name: "BitByteData", url: "https://github.com/tsolomko/BitByteData",
|
||||
.exact("2.0.4")),
|
||||
.package(name: "SwiftCLI", url: "https://github.com/jakeheis/SwiftCLI",
|
||||
from: "6.0.0"),
|
||||
.package(url: "https://github.com/tsolomko/BitByteData", from: "2.1.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
@@ -30,12 +26,13 @@ let package = Package(
|
||||
exclude: ["swcomp"],
|
||||
sources: ["Common", "7-Zip", "BZip2", "Deflate", "GZip", "LZ4", "LZMA", "LZMA2", "TAR", "XZ", "ZIP", "Zlib"],
|
||||
resources: [.copy("PrivacyInfo.xcprivacy")]),
|
||||
.target(
|
||||
name: "swcomp",
|
||||
dependencies: ["SWCompression", "SwiftCLI"],
|
||||
path: "Sources",
|
||||
exclude: ["Common", "7-Zip", "BZip2", "Deflate", "GZip", "LZ4", "LZMA", "LZMA2", "TAR", "XZ", "ZIP", "Zlib", "PrivacyInfo.xcprivacy"],
|
||||
sources: ["swcomp"]),
|
||||
],
|
||||
swiftLanguageVersions: [.v5]
|
||||
)
|
||||
|
||||
#if os(macOS)
|
||||
package.dependencies.append(.package(url: "https://github.com/jakeheis/SwiftCLI", from: "6.0.0"))
|
||||
package.targets.append(.executableTarget(name: "swcomp", dependencies: ["SWCompression", "SwiftCLI"], path: "Sources",
|
||||
exclude: ["Common", "7-Zip", "BZip2", "Deflate", "GZip", "LZ4", "LZMA", "LZMA2", "TAR", "XZ", "ZIP", "Zlib", "PrivacyInfo.xcprivacy"],
|
||||
sources: ["swcomp"]))
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SWCompression
|
||||
|
||||
[](https://developer.apple.com/swift/)
|
||||
[](https://developer.apple.com/swift/)
|
||||
[](https://raw.githubusercontent.com/tsolomko/SWCompression/master/LICENSE)
|
||||
[](https://dev.azure.com/tsolomko/SWCompression/_build/latest?definitionId=3&branchName=develop)
|
||||
|
||||
@@ -32,11 +32,12 @@ Also, SWCompression is _written with Swift only._
|
||||
|
||||
## Installation
|
||||
|
||||
SWCompression can be integrated into your project using Swift Package Manager, CocoaPods, or Carthage.
|
||||
SWCompression can be integrated into your project using Swift Package Manager.
|
||||
|
||||
### Swift Package Manager
|
||||
__Note:__ SWCompression versions 4.8.6 and earlier were also made available via CocoaPods or Carthage.
|
||||
|
||||
To install using SPM, add SWCompression to you package dependencies and specify it as a dependency for your target, e.g.:
|
||||
To install with Swift Package manager, add SWCompression to you package dependencies and specify it as a dependency for
|
||||
your target, e.g.:
|
||||
|
||||
```swift
|
||||
import PackageDescription
|
||||
@@ -45,7 +46,7 @@ let package = Package(
|
||||
name: "PackageName",
|
||||
dependencies: [
|
||||
.package(name: "SWCompression", url: "https://github.com/tsolomko/SWCompression.git",
|
||||
from: "4.8.0")
|
||||
from: "4.9.0")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
@@ -58,59 +59,6 @@ let package = Package(
|
||||
|
||||
More details you can find in [Swift Package Manager's Documentation](https://github.com/apple/swift-package-manager/tree/main/Documentation).
|
||||
|
||||
### CocoaPods
|
||||
|
||||
Add `pod 'SWCompression', '~> 4.8'` and `use_frameworks!` lines to your Podfile.
|
||||
|
||||
To complete installation, run `pod install`.
|
||||
|
||||
If you need only some parts of framework, you can install only them using sub-podspecs. Available subspecs:
|
||||
|
||||
- SWCompression/BZip2
|
||||
- SWCompression/Deflate
|
||||
- SWCompression/Gzip
|
||||
- SWCompression/LZMA
|
||||
- SWCompression/LZMA2
|
||||
- SWCompression/LZ4
|
||||
- SWCompression/SevenZip
|
||||
- SWCompression/TAR
|
||||
- SWCompression/XZ
|
||||
- SWCompression/Zlib
|
||||
- SWCompression/ZIP
|
||||
|
||||
#### "Optional Dependencies"
|
||||
|
||||
For both ZIP and 7-Zip there is the most commonly used compression method: Deflate and LZMA/LZMA2 correspondingly. Thus,
|
||||
SWCompression/ZIP subspec has SWCompression/Deflate subspec as a dependency and SWCompression/LZMA subspec is a
|
||||
dependency for SWCompression/SevenZip.
|
||||
|
||||
But both of these formats also support other compression methods, and some of them are implemented in SWCompression.
|
||||
For CocoaPods configurations there are some sort of 'optional dependencies' for such compression methods.
|
||||
|
||||
"Optional dependency" in this context means that SWCompression/ZIP or SWCompression/7-Zip will support a compression
|
||||
method only if a corresponding subspec is expicitly specified in your Podfile and installed.
|
||||
|
||||
List of "optional dependecies":
|
||||
|
||||
- For SWCompression/ZIP:
|
||||
- SWCompression/BZip2
|
||||
- SWCompression/LZMA
|
||||
- For SWCompression/SevenZip:
|
||||
- SWCompression/BZip2
|
||||
- SWCompression/Deflate
|
||||
- SWCompression/LZ4
|
||||
|
||||
__Note:__ If you use Swift Package Manager or Carthage you always have everything (ZIP and 7-Zip are built with Deflate,
|
||||
BZip2, LZMA/LZMA2 and LZ4 support).
|
||||
|
||||
### Carthage
|
||||
|
||||
Add to your Cartfile `github "tsolomko/SWCompression" ~> 4.8`.
|
||||
|
||||
Then you should run `carthage update --use-xcframeworks`. After that drag and drop both `SWCompression.xcframework` and
|
||||
`BitByteData.xcframework` files from from the `Carthage/Build/` directory into the "Frameworks, Libraries, and Embedded
|
||||
Content" section of your target's "General" tab in Xcode.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Example
|
||||
@@ -157,7 +105,7 @@ Every function or type of SWCompression's public API is documented. This documen
|
||||
### Sophisticated example
|
||||
|
||||
There is a small command-line program, "swcomp", which is included in this repository in "Sources/swcomp". It can be
|
||||
built using Swift Package Manager.
|
||||
built using Swift Package Manager (only available on macOS).
|
||||
|
||||
__IMPORTANT:__ The "swcomp" command-line tool is NOT intended for general use.
|
||||
|
||||
@@ -171,15 +119,11 @@ In the case of a bug, it will be especially helpful if you attach a file (archiv
|
||||
|
||||
If you'd like to contribute, please [create a pull request](https://github.com/tsolomko/SWCompression/pulls) on GitHub.
|
||||
|
||||
__Note:__ If you are considering working on SWCompression, please note that Xcode project (SWCompression.xcodeproj)
|
||||
was created manually and you shouldn't use `swift package generate-xcodeproj` command.
|
||||
|
||||
### Executing tests locally
|
||||
|
||||
If you want to run tests on your computer, you need to do a couple of additional steps after cloning the repository:
|
||||
|
||||
```bash
|
||||
./utils.py download-bbd-macos
|
||||
git submodule update --init --recursive
|
||||
cd "Tests/Test Files"
|
||||
cp gitattributes-copy .gitattributes
|
||||
@@ -187,15 +131,8 @@ git lfs pull
|
||||
git lfs checkout
|
||||
```
|
||||
|
||||
The first command will download the BitByteData dependency, which requires having Carthage installed. When using Xcode
|
||||
12 or later, you should also pass the `--xcf` option, or use the
|
||||
[xconfig workaround](https://github.com/Carthage/Carthage/blob/master/Documentation/Xcode12Workaround.md). Please note
|
||||
that when building SWCompression's Xcode project you may see ld warnings about a directory not being found. These are
|
||||
expected and harmless. Finally, you should keep in mind that support for non-xcframework method of installing
|
||||
dependencies is likely to be dropped in the future major update.
|
||||
|
||||
The remaining commands will download the files used in tests. These files are stored in a
|
||||
[separate repository](https://github.com/tsolomko/SWCompression-Test-Files), using Git LFS. There are two reasons for
|
||||
These commands will download the files used in tests which are stored in a
|
||||
[separate repository](https://github.com/tsolomko/SWCompression-Test-Files) using Git LFS. There are two reasons for
|
||||
this complicated setup. Firstly, some of these files can be quite big, and it would be unfortunate if the users of
|
||||
SWCompression had to download them during the installation. Secondly, Swift Package Manager and contemporary versions of
|
||||
Xcode don't always work well with git-lfs-enabled repositories. To prevent any potential problems test files were moved
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "SWCompression"
|
||||
s.version = "4.8.7"
|
||||
s.summary = "A framework with functions for working with compression, archives and containers."
|
||||
|
||||
s.description = "A framework with (de)compression algorithms and functions for processing various archives and containers."
|
||||
|
||||
s.homepage = "https://github.com/tsolomko/SWCompression"
|
||||
s.documentation_url = "http://tsolomko.github.io/SWCompression"
|
||||
|
||||
s.license = { :type => "MIT", :file => "LICENSE" }
|
||||
|
||||
s.author = { "Timofey Solomko" => "tsolomko@gmail.com" }
|
||||
|
||||
s.source = { :git => "https://github.com/tsolomko/SWCompression.git", :tag => "#{s.version}" }
|
||||
|
||||
s.ios.deployment_target = "11.0"
|
||||
s.osx.deployment_target = "10.13"
|
||||
s.tvos.deployment_target = "11.0"
|
||||
s.watchos.deployment_target = "4.0"
|
||||
# s.visionos.deployment_target = "1.0"
|
||||
|
||||
s.swift_versions = ["5"]
|
||||
|
||||
s.dependency "BitByteData", "~> 2.0"
|
||||
|
||||
s.subspec "Deflate" do |sp|
|
||||
sp.source_files = "Sources/{Deflate/*,Common/*,Common/CodingTree/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/Deflate" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-DSWCOMPRESSION_POD_DEFLATE" }
|
||||
end
|
||||
|
||||
s.subspec "GZip" do |sp|
|
||||
sp.dependency "SWCompression/Deflate"
|
||||
sp.resource_bundles = {"SWCompression/GZip" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.source_files = "Sources/{GZip/*,Common/*}.swift"
|
||||
end
|
||||
|
||||
s.subspec "Zlib" do |sp|
|
||||
sp.dependency "SWCompression/Deflate"
|
||||
sp.resource_bundles = {"SWCompression/Zlib" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.source_files = "Sources/{Zlib/*,Common/*}.swift"
|
||||
end
|
||||
|
||||
s.subspec "BZip2" do |sp|
|
||||
sp.source_files = "Sources/{BZip2/*,Common/*,Common/CodingTree/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/BZip2" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-DSWCOMPRESSION_POD_BZ2" }
|
||||
end
|
||||
|
||||
s.subspec "LZMA" do |sp|
|
||||
sp.source_files = "Sources/{LZMA/*,Common/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/LZMA" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-DSWCOMPRESSION_POD_LZMA" }
|
||||
end
|
||||
|
||||
s.subspec "LZMA2" do |sp|
|
||||
sp.dependency "SWCompression/LZMA"
|
||||
sp.source_files = "Sources/{LZMA2/*,Common/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/LZMA2" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
end
|
||||
|
||||
s.subspec "LZ4" do |sp|
|
||||
sp.source_files = "Sources/{LZ4/*,Common/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/LZ4" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-DSWCOMPRESSION_POD_LZ4" }
|
||||
end
|
||||
|
||||
s.subspec "XZ" do |sp|
|
||||
sp.dependency "SWCompression/LZMA2"
|
||||
sp.source_files = "Sources/{XZ/*,Common/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/XZ" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
end
|
||||
|
||||
s.subspec "ZIP" do |sp|
|
||||
sp.dependency "SWCompression/Deflate"
|
||||
sp.source_files = "Sources/{Zip/*,Common/*,Common/Container/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/ZIP" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-DSWCOMPRESSION_POD_ZIP" }
|
||||
end
|
||||
|
||||
s.subspec "TAR" do |sp|
|
||||
sp.source_files = "Sources/{TAR/*,Common/*,Common/Container/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/TAR" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
end
|
||||
|
||||
s.subspec "SevenZip" do |sp|
|
||||
sp.dependency "SWCompression/LZMA2"
|
||||
sp.source_files = "Sources/{7-Zip/*,Common/*,Common/Container/*}.swift"
|
||||
sp.resource_bundles = {"SWCompression/SevenZip" => ["Sources/PrivacyInfo.xcprivacy"]}
|
||||
sp.pod_target_xcconfig = { "OTHER_SWIFT_FLAGS" => "-DSWCOMPRESSION_POD_SEVENZIP" }
|
||||
end
|
||||
|
||||
end
|
||||
@@ -15,10 +15,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.8.7</string>
|
||||
<string>4.9.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>92</string>
|
||||
<string>93</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2024 Timofey Solomko</string>
|
||||
<string>Copyright © 2026 Timofey Solomko</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.8.7</string>
|
||||
<string>4.9.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>92</string>
|
||||
<string>93</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 60;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -64,7 +64,6 @@
|
||||
0686A6451FA4C47300E89C9E /* FileSystemType+Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0686A6441FA4C47300E89C9E /* FileSystemType+Zip.swift */; };
|
||||
068D070221368242002A6C3B /* DeltaFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 068D070121368242002A6C3B /* DeltaFilter.swift */; };
|
||||
068D070421368617002A6C3B /* test_delta_filter.7z in Resources */ = {isa = PBXBuildFile; fileRef = 068D070321368617002A6C3B /* test_delta_filter.7z */; };
|
||||
06912BD21F5C8F3D0070BB60 /* Deflate+Lengths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06912BD11F5C8F3D0070BB60 /* Deflate+Lengths.swift */; };
|
||||
0694A74D1F7C0DF00023BC99 /* BurrowsWheeler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0694A74C1F7C0DF00023BC99 /* BurrowsWheeler.swift */; };
|
||||
06955E491F65C761004D5D79 /* BZip2+Lengths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06955E481F65C761004D5D79 /* BZip2+Lengths.swift */; };
|
||||
069864CA21403CE700755D9B /* test_sha256.xz in Resources */ = {isa = PBXBuildFile; fileRef = 069864C921403CE700755D9B /* test_sha256.xz */; };
|
||||
@@ -96,7 +95,7 @@
|
||||
06BAC5941F8CFF28002443F4 /* ZipEntryInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06BAC5931F8CFF28002443F4 /* ZipEntryInfo.swift */; };
|
||||
06BB8F301E0C2C720079FB9E /* LZMA2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06BB8F2F1E0C2C720079FB9E /* LZMA2.swift */; };
|
||||
06CC3FDD1F8AAE8B00BD576D /* MsbBitReader+7z.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CC3FDC1F8AAE8B00BD576D /* MsbBitReader+7z.swift */; };
|
||||
06CC3FE21F8AAF3100BD576D /* ByteReader+XZ.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CC3FE11F8AAF3100BD576D /* ByteReader+XZ.swift */; };
|
||||
06CC3FE21F8AAF3100BD576D /* LittleEndianByteReader+XZ.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CC3FE11F8AAF3100BD576D /* LittleEndianByteReader+XZ.swift */; };
|
||||
06CDFC9E1F111D2600292758 /* Deflate+Compress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CDFC9D1F111D2600292758 /* Deflate+Compress.swift */; };
|
||||
06CDFCA31F111D6C00292758 /* BZip2Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CDFCA21F111D6C00292758 /* BZip2Error.swift */; };
|
||||
06CDFCA81F111D9700292758 /* DeflateError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CDFCA71F111D9700292758 /* DeflateError.swift */; };
|
||||
@@ -222,6 +221,7 @@
|
||||
E609D7B6271AFAA400068E79 /* test_small_dict_B5_BD.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E609D7B3271AFAA400068E79 /* test_small_dict_B5_BD.lz4 */; };
|
||||
E609D7B7271AFAA400068E79 /* test_small_dict_B5.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E609D7B4271AFAA400068E79 /* test_small_dict_B5.lz4 */; };
|
||||
E60CBA8A26AF379200A20130 /* test_only_dir_header.tar in Resources */ = {isa = PBXBuildFile; fileRef = E60CBA8926AF379200A20130 /* test_only_dir_header.tar */; };
|
||||
E61055CF2FB3546600A684F6 /* test_lzma_big_dict.7z in Resources */ = {isa = PBXBuildFile; fileRef = E61055CE2FB3546600A684F6 /* test_lzma_big_dict.7z */; };
|
||||
E631055927084D5D006EACC3 /* LZ4+Compress.swift in Sources */ = {isa = PBXBuildFile; fileRef = E631055827084D5D006EACC3 /* LZ4+Compress.swift */; };
|
||||
E6421E8F271B54C6000359B6 /* test_7z_lz4.7z in Resources */ = {isa = PBXBuildFile; fileRef = E6421E8E271B54C6000359B6 /* test_7z_lz4.7z */; };
|
||||
E644E11E2833AB2400EEFBAD /* minimal.gz in Resources */ = {isa = PBXBuildFile; fileRef = E644E11D2833AB2400EEFBAD /* minimal.gz */; };
|
||||
@@ -229,7 +229,6 @@
|
||||
E64F71BC26AAFD6A008BB308 /* Data+Tar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64F71BB26AAFD6A008BB308 /* Data+Tar.swift */; };
|
||||
E6522FB42789AF9600026B56 /* TarReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6522FB32789AF9600026B56 /* TarReaderTests.swift */; };
|
||||
E6522FB62789AFA600026B56 /* TarWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6522FB52789AFA600026B56 /* TarWriterTests.swift */; };
|
||||
E6522FBD2789C4A300026B56 /* FileHandle+CloseCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6522FBC2789C4A300026B56 /* FileHandle+CloseCompat.swift */; };
|
||||
E652D8F3263D670900FC229B /* test_nonstandard_runlength.bz2 in Resources */ = {isa = PBXBuildFile; fileRef = E652D8F2263D670900FC229B /* test_nonstandard_runlength.bz2 */; };
|
||||
E652D8F5263D678000FC229B /* test_nonstandard_runlength.answer in Resources */ = {isa = PBXBuildFile; fileRef = E652D8F4263D678000FC229B /* test_nonstandard_runlength.answer */; };
|
||||
E652FECA27007E79006BC312 /* test3.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E652FEC127007E78006BC312 /* test3.lz4 */; };
|
||||
@@ -263,6 +262,10 @@
|
||||
E652FF002700A028006BC312 /* test_B6.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E652FEF42700A028006BC312 /* test_B6.lz4 */; };
|
||||
E652FF012700A028006BC312 /* test_B5.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E652FEF52700A028006BC312 /* test_B5.lz4 */; };
|
||||
E652FF022700A028006BC312 /* test_B4.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E652FEF62700A028006BC312 /* test_B4.lz4 */; };
|
||||
E66D884E2F4F529100707F23 /* DeflateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66D884D2F4F529100707F23 /* DeflateTests.swift */; };
|
||||
E66D88612F4F53AB00707F23 /* test6.deflate in Resources */ = {isa = PBXBuildFile; fileRef = E66D885D2F4F53AB00707F23 /* test6.deflate */; };
|
||||
E66D88622F4F53AB00707F23 /* test8.deflate in Resources */ = {isa = PBXBuildFile; fileRef = E66D885E2F4F53AB00707F23 /* test8.deflate */; };
|
||||
E66D88632F4F53AB00707F23 /* test9.deflate in Resources */ = {isa = PBXBuildFile; fileRef = E66D885F2F4F53AB00707F23 /* test9.deflate */; };
|
||||
E66F36242538726E00076A6E /* test_empty.lzma in Resources */ = {isa = PBXBuildFile; fileRef = E66F36232538726E00076A6E /* test_empty.lzma */; };
|
||||
E66F362C2538E2B700076A6E /* test_empty.zlib in Resources */ = {isa = PBXBuildFile; fileRef = E66F362B2538E2B700076A6E /* test_empty.zlib */; };
|
||||
E6791E1826FD001A003852A9 /* DataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6791E1726FD001A003852A9 /* DataError.swift */; };
|
||||
@@ -276,6 +279,7 @@
|
||||
E6C057D627498F5A007C83DF /* TarWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6C057D527498F5A007C83DF /* TarWriter.swift */; };
|
||||
E6C4150726FE230A00F9D36F /* XxHash32.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6C4150626FE230A00F9D36F /* XxHash32.swift */; };
|
||||
E6D86D2F26FE35C50032CFFA /* XxHash32Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D86D2E26FE35C50032CFFA /* XxHash32Tests.swift */; };
|
||||
E6DCC9D82F30DA080042AE2E /* BitByteData in Frameworks */ = {isa = PBXBuildFile; productRef = E6DCC9D72F30DA080042AE2E /* BitByteData */; };
|
||||
E6DF9ECE2704BF14003BD91E /* test_multi_frame.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E6DF9ECD2704BF14003BD91E /* test_multi_frame.lz4 */; };
|
||||
E6E49D522BD5081D00BFC756 /* PrivacyInfo.xcprivacy in CopyFiles */ = {isa = PBXBuildFile; fileRef = E6E49D502BD507D700BFC756 /* PrivacyInfo.xcprivacy */; };
|
||||
E6EDD6A826F7767F00884532 /* test_minor_version_3.7z in Resources */ = {isa = PBXBuildFile; fileRef = E6EDD6A626F7767E00884532 /* test_minor_version_3.7z */; };
|
||||
@@ -367,7 +371,6 @@
|
||||
0686A6441FA4C47300E89C9E /* FileSystemType+Zip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileSystemType+Zip.swift"; sourceTree = "<group>"; };
|
||||
068D070121368242002A6C3B /* DeltaFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeltaFilter.swift; sourceTree = "<group>"; };
|
||||
068D070321368617002A6C3B /* test_delta_filter.7z */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_delta_filter.7z; sourceTree = "<group>"; };
|
||||
06912BD11F5C8F3D0070BB60 /* Deflate+Lengths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Deflate+Lengths.swift"; sourceTree = "<group>"; };
|
||||
0694A74C1F7C0DF00023BC99 /* BurrowsWheeler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowsWheeler.swift; sourceTree = "<group>"; };
|
||||
06955E481F65C761004D5D79 /* BZip2+Lengths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BZip2+Lengths.swift"; sourceTree = "<group>"; };
|
||||
069864C921403CE700755D9B /* test_sha256.xz */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_sha256.xz; sourceTree = "<group>"; };
|
||||
@@ -396,7 +399,7 @@
|
||||
06BB8F2F1E0C2C720079FB9E /* LZMA2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LZMA2.swift; sourceTree = "<group>"; };
|
||||
06BE1AC81DB410F100EE0F59 /* SWCompression.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SWCompression.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
06CC3FDC1F8AAE8B00BD576D /* MsbBitReader+7z.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MsbBitReader+7z.swift"; sourceTree = "<group>"; };
|
||||
06CC3FE11F8AAF3100BD576D /* ByteReader+XZ.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ByteReader+XZ.swift"; sourceTree = "<group>"; };
|
||||
06CC3FE11F8AAF3100BD576D /* LittleEndianByteReader+XZ.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LittleEndianByteReader+XZ.swift"; sourceTree = "<group>"; };
|
||||
06CDFC9D1F111D2600292758 /* Deflate+Compress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Deflate+Compress.swift"; sourceTree = "<group>"; };
|
||||
06CDFCA21F111D6C00292758 /* BZip2Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BZip2Error.swift; sourceTree = "<group>"; };
|
||||
06CDFCA71F111D9700292758 /* DeflateError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeflateError.swift; sourceTree = "<group>"; };
|
||||
@@ -523,6 +526,7 @@
|
||||
E609D7B3271AFAA400068E79 /* test_small_dict_B5_BD.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_small_dict_B5_BD.lz4; sourceTree = "<group>"; };
|
||||
E609D7B4271AFAA400068E79 /* test_small_dict_B5.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_small_dict_B5.lz4; sourceTree = "<group>"; };
|
||||
E60CBA8926AF379200A20130 /* test_only_dir_header.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = test_only_dir_header.tar; sourceTree = "<group>"; };
|
||||
E61055CE2FB3546600A684F6 /* test_lzma_big_dict.7z */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_lzma_big_dict.7z; sourceTree = "<group>"; };
|
||||
E631055827084D5D006EACC3 /* LZ4+Compress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LZ4+Compress.swift"; sourceTree = "<group>"; };
|
||||
E631055A27086132006EACC3 /* SWCompression.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = SWCompression.xctestplan; path = SWCompression.xcodeproj/SWCompression.xctestplan; sourceTree = SOURCE_ROOT; };
|
||||
E6421E8E271B54C6000359B6 /* test_7z_lz4.7z */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_7z_lz4.7z; sourceTree = "<group>"; };
|
||||
@@ -531,7 +535,6 @@
|
||||
E64F71BB26AAFD6A008BB308 /* Data+Tar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Tar.swift"; sourceTree = "<group>"; };
|
||||
E6522FB32789AF9600026B56 /* TarReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TarReaderTests.swift; sourceTree = "<group>"; };
|
||||
E6522FB52789AFA600026B56 /* TarWriterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TarWriterTests.swift; sourceTree = "<group>"; };
|
||||
E6522FBC2789C4A300026B56 /* FileHandle+CloseCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileHandle+CloseCompat.swift"; sourceTree = "<group>"; };
|
||||
E652D8F2263D670900FC229B /* test_nonstandard_runlength.bz2 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_nonstandard_runlength.bz2; sourceTree = "<group>"; };
|
||||
E652D8F4263D678000FC229B /* test_nonstandard_runlength.answer */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_nonstandard_runlength.answer; sourceTree = "<group>"; };
|
||||
E652FEC127007E78006BC312 /* test3.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test3.lz4; sourceTree = "<group>"; };
|
||||
@@ -565,6 +568,10 @@
|
||||
E652FEF42700A028006BC312 /* test_B6.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_B6.lz4; sourceTree = "<group>"; };
|
||||
E652FEF52700A028006BC312 /* test_B5.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_B5.lz4; sourceTree = "<group>"; };
|
||||
E652FEF62700A028006BC312 /* test_B4.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_B4.lz4; sourceTree = "<group>"; };
|
||||
E66D884D2F4F529100707F23 /* DeflateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeflateTests.swift; sourceTree = "<group>"; };
|
||||
E66D885D2F4F53AB00707F23 /* test6.deflate */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = test6.deflate; sourceTree = "<group>"; };
|
||||
E66D885E2F4F53AB00707F23 /* test8.deflate */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = test8.deflate; sourceTree = "<group>"; };
|
||||
E66D885F2F4F53AB00707F23 /* test9.deflate */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = test9.deflate; sourceTree = "<group>"; };
|
||||
E66F36232538726E00076A6E /* test_empty.lzma */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_empty.lzma; sourceTree = "<group>"; };
|
||||
E66F362B2538E2B700076A6E /* test_empty.zlib */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_empty.zlib; sourceTree = "<group>"; };
|
||||
E6791E1726FD001A003852A9 /* DataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataError.swift; sourceTree = "<group>"; };
|
||||
@@ -594,6 +601,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
E6DCC9D52F30DA020042AE2E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E6DCC9D82F30DA080042AE2E /* BitByteData in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -633,7 +648,6 @@
|
||||
children = (
|
||||
061FCE251DBCC4BE0052F7BE /* Deflate.swift */,
|
||||
06CDFC9D1F111D2600292758 /* Deflate+Compress.swift */,
|
||||
06912BD11F5C8F3D0070BB60 /* Deflate+Lengths.swift */,
|
||||
0631CB051F81109E00A2E0AB /* Deflate+Constants.swift */,
|
||||
06CDFCA71F111D9700292758 /* DeflateError.swift */,
|
||||
);
|
||||
@@ -676,7 +690,7 @@
|
||||
061C06201F0E89D900832F0C /* XZError.swift */,
|
||||
065146221FA8E20C007F83F4 /* XZBlock.swift */,
|
||||
0651461D1FA8E004007F83F4 /* XZStreamHeader.swift */,
|
||||
06CC3FE11F8AAF3100BD576D /* ByteReader+XZ.swift */,
|
||||
06CC3FE11F8AAF3100BD576D /* LittleEndianByteReader+XZ.swift */,
|
||||
06516B75213938B000C9823B /* Sha256.swift */,
|
||||
);
|
||||
path = XZ;
|
||||
@@ -695,9 +709,9 @@
|
||||
06BE1ABE1DB410F100EE0F59 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E6E49D502BD507D700BFC756 /* PrivacyInfo.xcprivacy */,
|
||||
06BE1ACA1DB410F100EE0F59 /* Sources */,
|
||||
06F065A01FFB763300312A82 /* Tests */,
|
||||
E6E49D502BD507D700BFC756 /* PrivacyInfo.xcprivacy */,
|
||||
E631055A27086132006EACC3 /* SWCompression.xctestplan */,
|
||||
06BE1AC91DB410F100EE0F59 /* Products */,
|
||||
);
|
||||
@@ -835,6 +849,7 @@
|
||||
06F065AC1FFB763300312A82 /* BZip2CompressionTests.swift */,
|
||||
06F065A51FFB763300312A82 /* BZip2Tests.swift */,
|
||||
06F065A21FFB763300312A82 /* DeflateCompressionTests.swift */,
|
||||
E66D884D2F4F529100707F23 /* DeflateTests.swift */,
|
||||
06F065A71FFB763300312A82 /* GzipTests.swift */,
|
||||
06F065AB1FFB763300312A82 /* LzmaTests.swift */,
|
||||
E6B18E84270884E300F9AB99 /* LZ4CompressionTests.swift */,
|
||||
@@ -844,7 +859,6 @@
|
||||
E6522FB52789AFA600026B56 /* TarWriterTests.swift */,
|
||||
06F065A61FFB763300312A82 /* TarTests.swift */,
|
||||
E6522FB32789AF9600026B56 /* TarReaderTests.swift */,
|
||||
E6522FBC2789C4A300026B56 /* FileHandle+CloseCompat.swift */,
|
||||
06F065A91FFB763300312A82 /* XzTests.swift */,
|
||||
06F065A41FFB763300312A82 /* ZipTests.swift */,
|
||||
06D42DA62067B71000C1A98B /* TestZipExtraField.swift */,
|
||||
@@ -861,6 +875,7 @@
|
||||
06F065F61FFB763300312A82 /* 7z */,
|
||||
06F065AE1FFB763300312A82 /* Answers */,
|
||||
06F066081FFB763300312A82 /* BZip2 */,
|
||||
E66D88602F4F53AB00707F23 /* Deflate */,
|
||||
06F065B81FFB763300312A82 /* GZip */,
|
||||
06F065F11FFB763300312A82 /* LZMA */,
|
||||
E6791E1F26FD04D0003852A9 /* LZ4 */,
|
||||
@@ -1033,6 +1048,7 @@
|
||||
06F066011FFB763300312A82 /* test_7z_bzip2.7z */,
|
||||
06F066021FFB763300312A82 /* test_7z_deflate.7z */,
|
||||
E6421E8E271B54C6000359B6 /* test_7z_lz4.7z */,
|
||||
E61055CE2FB3546600A684F6 /* test_lzma_big_dict.7z */,
|
||||
06F066041FFB763300312A82 /* test_empty_file.7z */,
|
||||
06F066051FFB763300312A82 /* test_empty_dir.7z */,
|
||||
06F066061FFB763300312A82 /* test_win.7z */,
|
||||
@@ -1063,6 +1079,16 @@
|
||||
path = BZip2;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E66D88602F4F53AB00707F23 /* Deflate */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E66D885D2F4F53AB00707F23 /* test6.deflate */,
|
||||
E66D885E2F4F53AB00707F23 /* test8.deflate */,
|
||||
E66D885F2F4F53AB00707F23 /* test9.deflate */,
|
||||
);
|
||||
path = Deflate;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E6791E1926FD0070003852A9 /* LZ4 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1128,10 +1154,12 @@
|
||||
buildPhases = (
|
||||
06BE1AC31DB410F100EE0F59 /* Sources */,
|
||||
E6E49D512BD5081700BFC756 /* CopyFiles */,
|
||||
E6DCC9D52F30DA020042AE2E /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
E6DCC9DA2F30DB4E0042AE2E /* PBXTargetDependency */,
|
||||
);
|
||||
name = SWCompression;
|
||||
productName = SWCompression;
|
||||
@@ -1145,7 +1173,6 @@
|
||||
06F065911FFB761600312A82 /* Sources */,
|
||||
06F065921FFB761600312A82 /* Frameworks */,
|
||||
06F065931FFB761600312A82 /* Resources */,
|
||||
062BE32F1FFBADB300343CAD /* Copy BitByteData.framework into test bundle */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -1165,7 +1192,7 @@
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 1530;
|
||||
LastUpgradeCheck = 2620;
|
||||
ORGANIZATIONNAME = "Timofey Solomko";
|
||||
TargetAttributes = {
|
||||
06BE1AC71DB410F100EE0F59 = {
|
||||
@@ -1179,7 +1206,7 @@
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 06BE1AC21DB410F100EE0F59 /* Build configuration list for PBXProject "SWCompression" */;
|
||||
compatibilityVersion = "Xcode 11.4";
|
||||
compatibilityVersion = "Xcode 15.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
@@ -1187,6 +1214,9 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = 06BE1ABE1DB410F100EE0F59;
|
||||
packageReferences = (
|
||||
E6DCC9D12F30D7610042AE2E /* XCRemoteSwiftPackageReference "BitByteData" */,
|
||||
);
|
||||
productRefGroup = 06BE1AC91DB410F100EE0F59 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -1258,6 +1288,7 @@
|
||||
06F066671FFB763400312A82 /* test2.7z in Resources */,
|
||||
062D591421248758003543BD /* test_delta_filter.xz in Resources */,
|
||||
0698B10B2104E11200A7C551 /* test_gnu_inc_format.tar in Resources */,
|
||||
E61055CF2FB3546600A684F6 /* test_lzma_big_dict.7z in Resources */,
|
||||
06F0661F1FFB763300312A82 /* test3.answer in Resources */,
|
||||
06F066281FFB763400312A82 /* test5.gz in Resources */,
|
||||
064D01AC20FD077D00CAE058 /* test_unicode_ustar.tar in Resources */,
|
||||
@@ -1345,6 +1376,9 @@
|
||||
06F066581FFB763400312A82 /* full_test.tar in Resources */,
|
||||
E6EDD6A926F7767F00884532 /* test_minor_version_4.7z in Resources */,
|
||||
E652FEFB2700A028006BC312 /* test_B1234_BD.lz4 in Resources */,
|
||||
E66D88612F4F53AB00707F23 /* test6.deflate in Resources */,
|
||||
E66D88622F4F53AB00707F23 /* test8.deflate in Resources */,
|
||||
E66D88632F4F53AB00707F23 /* test9.deflate in Resources */,
|
||||
06F0662B1FFB763400312A82 /* test3.gz in Resources */,
|
||||
E652FEF72700A028006BC312 /* test_B7.lz4 in Resources */,
|
||||
06F0664C1FFB763400312A82 /* test_pax.tar in Resources */,
|
||||
@@ -1358,25 +1392,6 @@
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
062BE32F1FFBADB300343CAD /* Copy BitByteData.framework into test bundle */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Copy BitByteData.framework into test bundle";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/bash;
|
||||
shellScript = "if [[ ${SDK_NAME} == iphone* ]]; then\n if [[ ! -d ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/ ]]; then\n mkdir -p ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n fi\n if [[ ${SDK_NAME} == iphonesimulator* ]]; then\n cp -a ${PROJECT_DIR}/Carthage/Build/BitByteData.xcframework/ios-*-simulator/BitByteData.framework ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n else\n cp -a ${PROJECT_DIR}/Carthage/Build/BitByteData.xcframework/ios-arm64*/BitByteData.framework ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n fi\nelif [[ ${SDK_NAME} == appletv* ]]; then\n if [[ ! -d ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/ ]]; then\n mkdir -p ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n fi\n if [[ ${SDK_NAME} == appletvsimulator* ]]; then\n cp -a ${PROJECT_DIR}/Carthage/Build/BitByteData.xcframework/tvos-*-simulator/BitByteData.framework ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n else\n cp -a ${PROJECT_DIR}/Carthage/Build/BitByteData.xcframework/tvos-arm64/BitByteData.framework ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n fi\nelif [[ ${SDK_NAME} == watch* ]]; then\n if [[ ! -d ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/ ]]; then\n mkdir -p ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n fi\n if [[ ${SDK_NAME} == watchsimulator* ]]; then\n cp -a ${PROJECT_DIR}/Carthage/Build/BitByteData.xcframework/watchos-*-simulator/BitByteData.framework ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n else\n cp -a ${PROJECT_DIR}/Carthage/Build/BitByteData.xcframework/watchos-arm64_32_armv7k/BitByteData.framework ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Frameworks/\n fi\nelif [[ ${SDK_NAME} == macos* ]]; then\n if [[ ! -d ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Contents/Frameworks/ ]]; then\n mkdir -p ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Contents/Frameworks/\n fi\n cp -a ${PROJECT_DIR}/Carthage/Build/BitByteData.xcframework/macos-*/BitByteData.framework ${BUILT_PRODUCTS_DIR}/TestSWCompression.xctest/Contents/Frameworks/\nfi\n\nxattr -rc ${BUILT_PRODUCTS_DIR}\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
06BE1AC31DB410F100EE0F59 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
@@ -1432,7 +1447,6 @@
|
||||
0631CB061F81109E00A2E0AB /* Deflate+Constants.swift in Sources */,
|
||||
E648151D26A889B8009261F0 /* TarHeader.swift in Sources */,
|
||||
06D95AC11F4C54E0006B46AC /* BZip2+Compress.swift in Sources */,
|
||||
06912BD21F5C8F3D0070BB60 /* Deflate+Lengths.swift in Sources */,
|
||||
06A9606A1F1E7E0D0078E6D1 /* 7zSubstreamInfo.swift in Sources */,
|
||||
E6C4150726FE230A00F9D36F /* XxHash32.swift in Sources */,
|
||||
0694A74D1F7C0DF00023BC99 /* BurrowsWheeler.swift in Sources */,
|
||||
@@ -1455,7 +1469,7 @@
|
||||
06CDFCA31F111D6C00292758 /* BZip2Error.swift in Sources */,
|
||||
06D3802E21E36190008B50C6 /* Code.swift in Sources */,
|
||||
06CFF6B22078C5A5003B8375 /* TarParser.swift in Sources */,
|
||||
06CC3FE21F8AAF3100BD576D /* ByteReader+XZ.swift in Sources */,
|
||||
06CC3FE21F8AAF3100BD576D /* LittleEndianByteReader+XZ.swift in Sources */,
|
||||
065D0ADC1F2B9D9100CE2DA8 /* 7zEntryInfo.swift in Sources */,
|
||||
06F276DF1F2BAB4A00E67335 /* 7zEntry.swift in Sources */,
|
||||
0651461E1FA8E004007F83F4 /* XZStreamHeader.swift in Sources */,
|
||||
@@ -1491,6 +1505,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E6522FB62789AFA600026B56 /* TarWriterTests.swift in Sources */,
|
||||
E66D884E2F4F529100707F23 /* DeflateTests.swift in Sources */,
|
||||
06F066151FFB763300312A82 /* ZlibTests.swift in Sources */,
|
||||
06F066141FFB763300312A82 /* DeflateCompressionTests.swift in Sources */,
|
||||
E6791E3326FD05EC003852A9 /* LZ4Tests.swift in Sources */,
|
||||
@@ -1506,7 +1521,6 @@
|
||||
E6D86D2F26FE35C50032CFFA /* XxHash32Tests.swift in Sources */,
|
||||
06F0661B1FFB763300312A82 /* XzTests.swift in Sources */,
|
||||
06F0661E1FFB763300312A82 /* BZip2CompressionTests.swift in Sources */,
|
||||
E6522FBD2789C4A300026B56 /* FileHandle+CloseCompat.swift in Sources */,
|
||||
06F066131FFB763300312A82 /* Constants.swift in Sources */,
|
||||
06F0661C1FFB763300312A82 /* SevenZipTests.swift in Sources */,
|
||||
06F066161FFB763300312A82 /* ZipTests.swift in Sources */,
|
||||
@@ -1521,6 +1535,10 @@
|
||||
target = 06BE1AC71DB410F100EE0F59 /* SWCompression */;
|
||||
targetProxy = 06F0659B1FFB761600312A82 /* PBXContainerItemProxy */;
|
||||
};
|
||||
E6DCC9DA2F30DB4E0042AE2E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
productRef = E6DCC9D92F30DB4E0042AE2E /* BitByteData */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
@@ -1548,25 +1566,13 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CURRENT_PROJECT_VERSION = 92;
|
||||
CURRENT_PROJECT_VERSION = 93;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
EAGER_LINKING = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/tvos-arm64\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=appletvsimulator*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/tvos-arm64_x86_64-simulator\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = (
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64_armv7\"",
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64\"",
|
||||
);
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = (
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64_i386_x86_64-simulator\"",
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64_x86_64-simulator\"",
|
||||
);
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=macosx*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/macos-arm64_x86_64\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=watchos*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/watchos-arm64_32_armv7k\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=watchsimulator*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/watchos-arm64_i386_x86_64-simulator\"";
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
@@ -1575,22 +1581,18 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--deep";
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
BitByteData,
|
||||
);
|
||||
SDKROOT = macosx;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos xrsimulator xros";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 11.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 17.6;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 4.0;
|
||||
XROS_DEPLOYMENT_TARGET = 1.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.6;
|
||||
XROS_DEPLOYMENT_TARGET = 1.3;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -1618,24 +1620,12 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CURRENT_PROJECT_VERSION = 92;
|
||||
CURRENT_PROJECT_VERSION = 93;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
EAGER_LINKING = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/tvos-arm64\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=appletvsimulator*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/tvos-arm64_x86_64-simulator\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = (
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64_armv7\"",
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64\"",
|
||||
);
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = (
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64_i386_x86_64-simulator\"",
|
||||
"\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/ios-arm64_x86_64-simulator\"",
|
||||
);
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=macosx*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/macos-arm64_x86_64\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=watchos*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/watchos-arm64_32_armv7k\"";
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=watchsimulator*]" = "\"$(SRCROOT)/Carthage/Build/BitByteData.xcframework/watchos-arm64_i386_x86_64-simulator\"";
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
@@ -1643,21 +1633,17 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
OTHER_CODE_SIGN_FLAGS = "--deep";
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
BitByteData,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||
SDKROOT = macosx;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos xrsimulator xros";
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 11.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 17.6;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 4.0;
|
||||
XROS_DEPLOYMENT_TARGET = 1.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.6;
|
||||
XROS_DEPLOYMENT_TARGET = 1.3;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1667,24 +1653,13 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 92;
|
||||
DYLIB_CURRENT_VERSION = 93;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@loader_path/Frameworks",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++14";
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
BitByteData,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.tsolomko.SWCompression;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -1697,24 +1672,13 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 92;
|
||||
DYLIB_CURRENT_VERSION = 93;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@loader_path/Frameworks",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++14";
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
BitByteData,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.tsolomko.SWCompression;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -1726,13 +1690,6 @@
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = NO;
|
||||
INFOPLIST_FILE = SWCompression.xcodeproj/TestSWCompression.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@loader_path/Frameworks",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.tsolomko.TestSWCompression;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@@ -1743,13 +1700,6 @@
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = NO;
|
||||
INFOPLIST_FILE = SWCompression.xcodeproj/TestSWCompression.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@loader_path/Frameworks",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.tsolomko.TestSWCompression;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@@ -1786,6 +1736,30 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
E6DCC9D12F30D7610042AE2E /* XCRemoteSwiftPackageReference "BitByteData" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/tsolomko/BitByteData";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 2.1.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
E6DCC9D72F30DA080042AE2E /* BitByteData */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E6DCC9D12F30D7610042AE2E /* XCRemoteSwiftPackageReference "BitByteData" */;
|
||||
productName = BitByteData;
|
||||
};
|
||||
E6DCC9D92F30DB4E0042AE2E /* BitByteData */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E6DCC9D12F30D7610042AE2E /* XCRemoteSwiftPackageReference "BitByteData" */;
|
||||
productName = BitByteData;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 06BE1ABF1DB410F100EE0F59 /* Project object */;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1530"
|
||||
LastUpgradeVersion = "2620"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension SevenZipCoder: Equatable {
|
||||
|
||||
static func == (lhs: SevenZipCoder, rhs: SevenZipCoder) -> Bool {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
class SevenZipCoder {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
class SevenZipCoderInfo {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Represents an error which happened while processing a 7-Zip container.
|
||||
It may indicate that either container is damaged or it might not be 7-Zip container at all.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -147,17 +147,9 @@ class SevenZipFolder {
|
||||
case .copy:
|
||||
continue
|
||||
case .deflate:
|
||||
#if (!SWCOMPRESSION_POD_SEVENZIP) || (SWCOMPRESSION_POD_SEVENZIP && SWCOMPRESSION_POD_DEFLATE)
|
||||
decodedData = try Deflate.decompress(data: decodedData)
|
||||
#else
|
||||
throw SevenZipError.compressionNotSupported
|
||||
#endif
|
||||
decodedData = try Deflate.decompress(data: decodedData)
|
||||
case .bzip2:
|
||||
#if (!SWCOMPRESSION_POD_SEVENZIP) || (SWCOMPRESSION_POD_SEVENZIP && SWCOMPRESSION_POD_BZ2)
|
||||
decodedData = try BZip2.decompress(data: decodedData)
|
||||
#else
|
||||
throw SevenZipError.compressionNotSupported
|
||||
#endif
|
||||
decodedData = try BZip2.decompress(data: decodedData)
|
||||
case .lzma2:
|
||||
// Dictionary size is stored in coder's properties.
|
||||
guard let properties = coder.properties,
|
||||
@@ -172,7 +164,7 @@ class SevenZipFolder {
|
||||
else { throw LZMAError.wrongProperties }
|
||||
|
||||
var dictionarySize = 0
|
||||
for i in 1..<4 {
|
||||
for i in 1..<5 {
|
||||
dictionarySize |= properties[i].toInt() << (8 * (i - 1))
|
||||
}
|
||||
let lzmaProperties = try LZMAProperties(lzmaByte: properties[0], dictionarySize)
|
||||
@@ -187,11 +179,7 @@ class SevenZipFolder {
|
||||
|
||||
decodedData = DeltaFilter.decode(LittleEndianByteReader(data: decodedData), (properties[0] &+ 1).toInt())
|
||||
} else if coder.id == [0x04, 0xF7, 0x11, 0x04] {
|
||||
#if (!SWCOMPRESSION_POD_SEVENZIP) || (SWCOMPRESSION_POD_SEVENZIP && SWCOMPRESSION_POD_LZ4)
|
||||
decodedData = try LZ4.decompress(data: decodedData)
|
||||
#else
|
||||
throw SevenZipError.compressionNotSupported
|
||||
#endif
|
||||
decodedData = try LZ4.decompress(data: decodedData)
|
||||
} else if coder.isEncryptionMethod {
|
||||
throw SevenZipError.encryptionNotSupported
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
class SevenZipPackInfo {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
struct SevenZipProperty {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
class SevenZipStreamInfo {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
class SevenZipSubstreamInfo {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension CompressionMethod {
|
||||
|
||||
init(_ coderID: [UInt8]) {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
extension MsbBitReader {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension BZip2 {
|
||||
|
||||
/// Represents the size of the blocks in which data is split during BZip2 compression.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -41,17 +41,18 @@ extension BZip2: CompressionAlgorithm {
|
||||
public static func compress(data: Data, blockSize: BlockSize) -> Data {
|
||||
let bitWriter = MsbBitWriter()
|
||||
// We intentionally use smaller block size for compression to account for potential data size expansion
|
||||
// after intial RLE, which seems to be not being expected by original BZip2 implementation.
|
||||
// after intial RLE, which seems to be not being expected by original BZip2 implementation.
|
||||
// In the worst case initial RLE causes expansion by a factor of 1.25, so 1000 / 1.25 = 800.
|
||||
let rawBlockSize = blockSize.sizeInKilobytes * 800
|
||||
// BZip2 Header.
|
||||
bitWriter.write(number: 0x425a, bitsCount: 16) // Magic number = 'BZ'.
|
||||
bitWriter.write(number: 0x68, bitsCount: 8) // Version = 'h'.
|
||||
bitWriter.write(unsignedNumber: 0x425a, bitsCount: 16) // Magic number = 'BZ'.
|
||||
bitWriter.write(unsignedNumber: 0x68, bitsCount: 8) // Version = 'h'.
|
||||
bitWriter.write(number: blockSize.headerByte, bitsCount: 8) // Block size.
|
||||
|
||||
var totalCRC: UInt32 = 0
|
||||
for i in stride(from: data.startIndex, to: data.endIndex, by: rawBlockSize) {
|
||||
let blockData = data[i..<min(data.endIndex, i + rawBlockSize)]
|
||||
let blockCRC = CheckSums.bzip2crc32(blockData)
|
||||
let block = data[i..<min(data.endIndex, i + rawBlockSize)].toByteArray()
|
||||
let blockCRC = CheckSums.bzip2crc32(block)
|
||||
|
||||
totalCRC = (totalCRC << 1) | (totalCRC >> 31)
|
||||
totalCRC ^= blockCRC
|
||||
@@ -60,7 +61,7 @@ extension BZip2: CompressionAlgorithm {
|
||||
bitWriter.write(bits: blockMarker) // Block magic number.
|
||||
bitWriter.write(number: blockCRC.toInt(), bitsCount: 32) // Block crc32.
|
||||
|
||||
process(block: blockData, bitWriter)
|
||||
process(block, bitWriter)
|
||||
}
|
||||
|
||||
// EOS magic number.
|
||||
@@ -72,8 +73,8 @@ extension BZip2: CompressionAlgorithm {
|
||||
return bitWriter.data
|
||||
}
|
||||
|
||||
private static func process(block data: Data, _ bitWriter: MsbBitWriter) {
|
||||
var out = initialRle(data)
|
||||
private static func process(_ block: [UInt8], _ bitWriter: MsbBitWriter) {
|
||||
var out = initialRle(block)
|
||||
|
||||
var pointer = 0
|
||||
(out, pointer) = BurrowsWheeler.transform(bytes: out)
|
||||
@@ -121,9 +122,9 @@ extension BZip2: CompressionAlgorithm {
|
||||
// Otherwise, let's create a new table and check if it gives us better results.
|
||||
// First, we calculate code lengths and codes for our current stats.
|
||||
let lengths = BZip2.lengths(from: stats)
|
||||
let codes = Code.huffmanCodes(from: lengths)
|
||||
let codes = Code.huffmanCodes(from: lengths).codes
|
||||
// Then, using these codes, we create a new Huffman tree.
|
||||
let table = EncodingTree(codes: codes.codes, bitWriter)
|
||||
let table = EncodingTree(codes, bitWriter)
|
||||
if table.bitSize(for: stats) < minimumSize {
|
||||
tables.append(table)
|
||||
tablesLengths.append(lengths.sorted { $0.symbol < $1.symbol }.map { $0.codeLength })
|
||||
@@ -147,13 +148,19 @@ extension BZip2: CompressionAlgorithm {
|
||||
|
||||
// Now, we perform encoding itself.
|
||||
// But first, we need to finish block header.
|
||||
bitWriter.write(number: 0, bitsCount: 1) // "Randomized".
|
||||
bitWriter.write(bit: 0) // "Randomized".
|
||||
bitWriter.write(number: pointer, bitsCount: 24) // Original pointer (from BWT).
|
||||
|
||||
var usedMap = Array(repeating: UInt8(0), count: 16)
|
||||
// Encode which symbols (bytes) are used in the data. All possible 256 symbols (0...255) are split into 16 "maps"
|
||||
// of 16 sequential symbols. Each map is a sequence of 16 bits where a non-zero bits indicate that used symbols.
|
||||
// If a map would consist of only zero bits, then it is omitted. This is determined in the construction of `usedMap`.
|
||||
var usedMap = Array(repeating: 0 as UInt8, count: 16)
|
||||
for usedByte in usedBytes {
|
||||
guard usedByte <= 255
|
||||
else { fatalError("Incorrect used byte.") }
|
||||
// `usedBytes` is an output of the BW transform which does not change symbols used. The input of the BW
|
||||
// transform is an output of initial RLE encoding. Since a run length value is 255 or less and the input
|
||||
// data consists of normal bytes which also have values of 255 or less, `usedByte` cannot be larger than 255
|
||||
// by construction.
|
||||
assert(usedByte <= 255, "Incorrect usedByte.")
|
||||
usedMap[usedByte / 16] = 1
|
||||
}
|
||||
bitWriter.write(bits: usedMap)
|
||||
@@ -162,7 +169,7 @@ extension BZip2: CompressionAlgorithm {
|
||||
for i in 0..<16 {
|
||||
guard usedMap[i] == 1 else { continue }
|
||||
for j in 0..<16 {
|
||||
if usedBytesIndex < usedBytes.count && i * 16 + j == usedBytes[usedBytesIndex] {
|
||||
if usedBytesIndex < usedBytes.endIndex && i * 16 + j == usedBytes[usedBytesIndex] {
|
||||
bitWriter.write(bit: 1)
|
||||
usedBytesIndex += 1
|
||||
} else {
|
||||
@@ -174,10 +181,14 @@ extension BZip2: CompressionAlgorithm {
|
||||
bitWriter.write(number: tables.count, bitsCount: 3)
|
||||
bitWriter.write(number: selectors.count, bitsCount: 15)
|
||||
|
||||
let mtfSelectors = mtf(selectors, characters: Array(0..<selectors.count))
|
||||
// Selectors are indices into `tables` list, so by construction they can only take values between 0 and
|
||||
// `tables.count - 1`. This correspondingly limits the list of characters for the MTF transform.
|
||||
let mtfSelectors = mtf(selectors, maxValue: tables.count - 1)
|
||||
for selector in mtfSelectors {
|
||||
guard selector <= 5
|
||||
else { fatalError("Incorrect selector.") }
|
||||
// The output of MTF transform are the indices into the supplied characters list. Since the length of the
|
||||
// characters list is given by `tables.count`, by construction `selector` should be between 0 and
|
||||
// `tables.count - 1`.
|
||||
assert(selector < tables.count)
|
||||
bitWriter.write(bits: Array(repeating: 1, count: selector))
|
||||
bitWriter.write(bit: 0)
|
||||
}
|
||||
@@ -185,53 +196,59 @@ extension BZip2: CompressionAlgorithm {
|
||||
// Delta bit lengths.
|
||||
for lengths in tablesLengths {
|
||||
// Starting length.
|
||||
var currentLength = lengths[0]
|
||||
bitWriter.write(number: currentLength, bitsCount: 5)
|
||||
var prevLength = lengths[0]
|
||||
bitWriter.write(number: prevLength, bitsCount: 5)
|
||||
for length in lengths {
|
||||
while currentLength != length {
|
||||
bitWriter.write(bit: 1) // Alter length.
|
||||
if currentLength > length {
|
||||
bitWriter.write(bit: 1) // Decrement length.
|
||||
currentLength -= 1
|
||||
} else {
|
||||
bitWriter.write(bit: 0) // Increment length.
|
||||
currentLength += 1
|
||||
}
|
||||
// In the worst case delta between two lengths is 19. This delta requires 19 * 2 = 38 bits to encode
|
||||
// which fits into `UInt` (at least, on modern 64-bit systems), so we can use `write(unsignedNumber:)`.
|
||||
if prevLength > length {
|
||||
// Bits: 11 -> 11_11 -> 11_11_11 -> 11_11_11_11 -> ...
|
||||
// Numbers: 3 -> 15 -> 63 -> 255 -> ...
|
||||
// https://oeis.org/A024036
|
||||
let diff = prevLength - length
|
||||
bitWriter.write(unsignedNumber: (1 << (2 * diff)) - 1, bitsCount: 2 * diff)
|
||||
} else if prevLength < length {
|
||||
// Bits: 10 -> 10_10 -> 10_10_10 -> 10_10_10_10 -> ...
|
||||
// Numbers: 2 -> 10 -> 42 -> 170 -> ...
|
||||
// https://oeis.org/A020988
|
||||
let diff = length - prevLength
|
||||
bitWriter.write(unsignedNumber: ((1 << (2 * diff)) - 1) * 2 / 3 , bitsCount: 2 * diff)
|
||||
}
|
||||
prevLength = length
|
||||
bitWriter.write(bit: 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Contents.
|
||||
var encoded = 0
|
||||
var selectorPointer = 0
|
||||
var t: EncodingTree?
|
||||
var table = tables[selectors[selectors.startIndex]]
|
||||
var selectorIndex = selectors.startIndex &+ 1
|
||||
for symbol in out {
|
||||
encoded -= 1
|
||||
if encoded <= 0 {
|
||||
encoded = 50
|
||||
if selectorPointer == selectors.count {
|
||||
fatalError("Incorrect selector.")
|
||||
} else if selectorPointer < selectors.count {
|
||||
t = tables[selectors[selectorPointer]]
|
||||
selectorPointer += 1
|
||||
}
|
||||
// New table is selected every 50 symbols.
|
||||
if encoded >= 50 {
|
||||
// Selectors were added every 50 symbols. So by construction `selectorIndex` can never exceed the
|
||||
// amount of available selectors.
|
||||
assert(selectorIndex < selectors.endIndex, "Incorrect selectorIndex.")
|
||||
table = tables[selectors[selectorIndex]]
|
||||
selectorIndex &+= 1
|
||||
encoded = 0
|
||||
}
|
||||
t?.code(symbol: symbol)
|
||||
table.code(symbol: symbol)
|
||||
encoded &+= 1
|
||||
}
|
||||
}
|
||||
|
||||
/// Initial Run Length Encoding.
|
||||
private static func initialRle(_ data: Data) -> [Int] {
|
||||
private static func initialRle(_ block: [UInt8]) -> [Int] {
|
||||
var out = [Int]()
|
||||
var index = data.startIndex
|
||||
while index < data.endIndex {
|
||||
var index = block.startIndex
|
||||
while index < block.endIndex {
|
||||
var runLength = 1
|
||||
while index + 1 < data.endIndex && data[index] == data[index + 1] && runLength < 255 {
|
||||
while index + 1 < block.endIndex && block[index] == block[index + 1] && runLength < 255 {
|
||||
runLength += 1
|
||||
index += 1
|
||||
}
|
||||
let byte = data[index].toInt()
|
||||
let byte = block[index].toInt()
|
||||
for _ in 0..<min(4, runLength) {
|
||||
out.append(byte)
|
||||
}
|
||||
@@ -243,10 +260,10 @@ extension BZip2: CompressionAlgorithm {
|
||||
return out
|
||||
}
|
||||
|
||||
private static func mtf(_ array: [Int], characters: [Int]) -> [Int] {
|
||||
/// Assumes that the characters are given by a list of integers from 0 up to and including `maxValue`.
|
||||
private static func mtf(_ array: [Int], maxValue: Int) -> [Int] {
|
||||
var out = [Int]()
|
||||
/// Mutable copy of `characters`.
|
||||
var dictionary = characters
|
||||
var dictionary = Array(0...maxValue)
|
||||
for i in 0..<array.count {
|
||||
let index = dictionary.firstIndex(of: array[i])!
|
||||
out.append(index)
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
// BZip2 specific function for generation of HuffmanLength array from stats.
|
||||
extension BZip2 {
|
||||
|
||||
|
||||
+128
-82
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -25,9 +25,32 @@ public class BZip2: DecompressionAlgorithm {
|
||||
return try decompress(bitReader)
|
||||
}
|
||||
|
||||
/**
|
||||
Decompresses one or more concatenated BZip2 archives found in `data`.
|
||||
|
||||
- Parameter data: Data that may contain one or more concatenated BZip2 archives.
|
||||
|
||||
- Throws: `BZip2Error` if an unexpected byte (bit) sequence was encountered or a checksum mismatch is detected for
|
||||
any archive. It may indicate that the input is damaged or it might not be compressed with BZip2 at all. If
|
||||
`BZip2Error.wrongCRC` is thrown, its associated value contains only the bytes decompressed for the archive that
|
||||
failed the checksum.
|
||||
|
||||
- Returns: An array of decompressed data, one element per archive, in the same order as they appear in the input.
|
||||
*/
|
||||
public static func multiDecompress(data: Data) throws -> [Data] {
|
||||
let reader = MsbBitReader(data: data)
|
||||
var result = [Data]()
|
||||
while !reader.isFinished {
|
||||
result.append(try decompress(reader))
|
||||
reader.align()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
static func decompress(_ bitReader: MsbBitReader) throws -> Data {
|
||||
// Valid BZip2 "archive" must contain at least 14 bytes of data.
|
||||
guard bitReader.bitsLeft >= 14 * 8
|
||||
// Valid BZip2 "archive" must contain at least 14 bytes of data: magic number (2 bytes), method (1 byte), and
|
||||
// block size (1 byte).
|
||||
guard bitReader.bitsLeft >= 32
|
||||
else { throw BZip2Error.wrongMagic }
|
||||
|
||||
/// An array for storing output data
|
||||
@@ -44,15 +67,18 @@ public class BZip2: DecompressionAlgorithm {
|
||||
|
||||
var totalCRC: UInt32 = 0
|
||||
while true {
|
||||
// Using `Int64` because 48 bits may not fit into `Int` on some platforms.
|
||||
// Each BZip2 block must contain block type (6 bytes) and block CRC32 (4 bytes).
|
||||
guard bitReader.bitsLeft >= 80
|
||||
else { throw BZip2Error.wrongMagic }
|
||||
// Using `UInt64` because 48 bits may not fit into `Int` on some platforms.
|
||||
let blockType = bitReader.uint64(fromBits: 48)
|
||||
|
||||
let blockCRC32 = bitReader.uint32(fromBits: 32)
|
||||
|
||||
if blockType == 0x314159265359 {
|
||||
let blockData = try decode(bitReader, blockSize)
|
||||
out.append(blockData)
|
||||
guard CheckSums.bzip2crc32(blockData) == blockCRC32
|
||||
let block = try decode(bitReader, blockSize)
|
||||
out.append(Data(block))
|
||||
guard CheckSums.bzip2crc32(block) == blockCRC32
|
||||
else { throw BZip2Error.wrongCRC(out) }
|
||||
totalCRC = (totalCRC << 1) | (totalCRC >> 31)
|
||||
totalCRC ^= blockCRC32
|
||||
@@ -68,22 +94,32 @@ public class BZip2: DecompressionAlgorithm {
|
||||
return out
|
||||
}
|
||||
|
||||
private static func decode(_ bitReader: MsbBitReader, _ blockSize: BlockSize) throws -> Data {
|
||||
private static func decode(_ bitReader: MsbBitReader, _ blockSize: BlockSize) throws -> [UInt8] {
|
||||
// Truncation checks: there is no such thing as "empty BZip2 blocks". Empty data after compression produces
|
||||
// only a "CRC32 block". As such when processing a normal BZip2 block we can assume that various BZip2
|
||||
// structures (such as table selectors or code lengths) are present, and there are at least some symbols encoded.
|
||||
|
||||
// Randomized bit, pointer (24 bits), and bitmap of used symbol blocks (16 bits) require 41 bits.
|
||||
guard bitReader.bitsLeft >= 41
|
||||
else { throw BZip2Error.wrongMagic }
|
||||
|
||||
let isRandomized = bitReader.bit()
|
||||
guard isRandomized == 0
|
||||
else { throw BZip2Error.randomizedBlock }
|
||||
|
||||
let pointer = bitReader.int(fromBits: 24)
|
||||
|
||||
// Decoding which symbols are used in Huffman tables.
|
||||
// The "list" of all possible 256 symbols is split into 16 blocks.
|
||||
// If no symbols from a block are in use, then the block is not present.
|
||||
// First, we decode which blocks are present.
|
||||
let usedBlocksBitMap = UInt16(bitReader.int(fromBits: 16))
|
||||
// Decoding which symbols are used in Huffman tables. All possible 256 symbols (0...255) are split into 16 "maps"
|
||||
// of 16 sequential symbols. Each map is a sequence of 16 bits where non-zero bits indicate used symbols. A map
|
||||
// is omitted if none of its symbols are in use. First, we decode which maps are present.
|
||||
let usedBlocksBitMap = bitReader.uint16(fromBits: 16)
|
||||
// For each non-zero bit in the bitmap there should be 16 bits of used symbols. After that there should be 3
|
||||
// bits for the number of Huffman tables and 15 bits for selectors count.
|
||||
guard bitReader.bitsLeft >= 16 * usedBlocksBitMap.nonzeroBitCount + 3 + 15
|
||||
else { throw BZip2Error.wrongMagic }
|
||||
|
||||
var blockMask = 1 << 15 as UInt16
|
||||
var usedSymbols = [UInt8]()
|
||||
// Two additional symbols are RUNA and RUNB.
|
||||
var usedSymbolsCount = 2
|
||||
while blockMask > 0 {
|
||||
if usedBlocksBitMap & blockMask > 0 {
|
||||
// Each block, if present, is a set of 16 bits which, if set, represent that the corresponding symbols
|
||||
@@ -92,7 +128,6 @@ public class BZip2: DecompressionAlgorithm {
|
||||
var symbolMask = 1 << 15 as UInt16
|
||||
while symbolMask > 0 {
|
||||
if usedSymbolsBitMask & symbolMask > 0 {
|
||||
usedSymbolsCount += 1
|
||||
usedSymbols.append(UInt8(blockMask.leadingZeroBitCount * 16 + symbolMask.leadingZeroBitCount))
|
||||
}
|
||||
symbolMask >>= 1
|
||||
@@ -100,103 +135,114 @@ public class BZip2: DecompressionAlgorithm {
|
||||
}
|
||||
blockMask >>= 1
|
||||
}
|
||||
// Two additional symbols are RUNA and RUNB.
|
||||
let usedSymbolsCount = 2 + usedSymbols.count
|
||||
|
||||
let huffmanGroups = bitReader.int(fromBits: 3)
|
||||
guard huffmanGroups >= 2 && huffmanGroups <= 6
|
||||
let huffmanTablesCount = bitReader.int(fromBits: 3)
|
||||
guard huffmanTablesCount >= 2 && huffmanTablesCount <= 6
|
||||
else { throw BZip2Error.wrongHuffmanGroups }
|
||||
|
||||
func computeSelectors() throws -> [Int] {
|
||||
let selectorsUsed = bitReader.int(fromBits: 15)
|
||||
let selectorsCount = bitReader.int(fromBits: 15)
|
||||
var mtf = Array(0..<huffmanTablesCount)
|
||||
|
||||
var mtf = Array(0..<huffmanGroups)
|
||||
var selectorsList = [Int]()
|
||||
|
||||
for _ in 0..<selectorsUsed {
|
||||
var c = 0
|
||||
while bitReader.bit() > 0 {
|
||||
c += 1
|
||||
guard c < huffmanGroups
|
||||
else { throw BZip2Error.wrongSelector }
|
||||
// It is impossible to calculate in advance how many bits encode table selectors. At minimum, if each selector
|
||||
// is encoded by a single zero bit (which means only the zeroth Huffman table is utilized), `selectorsCount`
|
||||
// bits are used. At maximum, when all symbols are encoded with the last Huffman table, each selector is given
|
||||
// by `huffmanTablesCount - 1` non-zero bits and one zero bit. This gives `huffmanTablesCount * selectorsCount`
|
||||
// bits in total.
|
||||
// Due to this unpredictability we are forced to check if there are still bits left before every read operation,
|
||||
// similarly to how bit reading is done in `DecodingTree.findNextSymbol()`.
|
||||
var selectors = [Int]()
|
||||
// Accessing `bitsLeft` property of `bitReader` incurs a lot of overhead, so we create a local copy.
|
||||
var bitsLeft = bitReader.bitsLeft
|
||||
for _ in 0..<selectorsCount {
|
||||
var c = 0
|
||||
while bitsLeft > 0 {
|
||||
let bit = bitReader.bit()
|
||||
bitsLeft -= 1
|
||||
if bit == 0 {
|
||||
break
|
||||
}
|
||||
if c >= 0 {
|
||||
let el = mtf.remove(at: c)
|
||||
mtf.insert(el, at: 0)
|
||||
}
|
||||
selectorsList.append(mtf[0])
|
||||
c += 1
|
||||
}
|
||||
|
||||
return selectorsList
|
||||
guard c < huffmanTablesCount
|
||||
else { throw BZip2Error.wrongSelector }
|
||||
let el = mtf.remove(at: c)
|
||||
mtf.insert(el, at: 0)
|
||||
selectors.append(el)
|
||||
}
|
||||
|
||||
let selectors = try computeSelectors()
|
||||
|
||||
func computeTables() throws -> [DecodingTree] {
|
||||
var tables = [DecodingTree]()
|
||||
for _ in 0..<huffmanGroups {
|
||||
var length = bitReader.int(fromBits: 5)
|
||||
var lengths = [CodeLength]()
|
||||
for i in 0..<usedSymbolsCount {
|
||||
guard length >= 0 && length <= 20
|
||||
// Similar to decoding selectors, code lengths are also encoded in unpredictable manner. As such, we check for
|
||||
// input truncation before reading every bit.
|
||||
var tables = [DecodingTree]()
|
||||
for _ in 0..<huffmanTablesCount {
|
||||
guard bitsLeft >= 5
|
||||
else { throw BZip2Error.wrongHuffmanCodeLength }
|
||||
var length = bitReader.int(fromBits: 5)
|
||||
bitsLeft -= 5
|
||||
var codeLengths = [CodeLength]()
|
||||
for i in 0..<usedSymbolsCount {
|
||||
guard length >= 0 && length <= 20
|
||||
else { throw BZip2Error.wrongHuffmanCodeLength }
|
||||
while bitsLeft > 0 {
|
||||
let bit = bitReader.bit()
|
||||
bitsLeft -= 1
|
||||
if bit == 0 {
|
||||
break
|
||||
}
|
||||
guard bitsLeft > 0
|
||||
else { throw BZip2Error.wrongHuffmanCodeLength }
|
||||
while bitReader.bit() > 0 {
|
||||
length -= (bitReader.bit().toInt() * 2 - 1)
|
||||
}
|
||||
if length > 0 {
|
||||
lengths.append(CodeLength(symbol: i, codeLength: length))
|
||||
}
|
||||
length -= (bitReader.bit().toInt() * 2 - 1)
|
||||
bitsLeft -= 1
|
||||
}
|
||||
let codes = Code.huffmanCodes(from: lengths)
|
||||
let table = DecodingTree(codes: codes.codes, maxBits: codes.maxBits, bitReader)
|
||||
tables.append(table)
|
||||
codeLengths.append(CodeLength(symbol: i, codeLength: length))
|
||||
}
|
||||
|
||||
return tables
|
||||
let codes = Code.huffmanCodes(from: codeLengths)
|
||||
let table = DecodingTree(codes, bitReader)
|
||||
tables.append(table)
|
||||
}
|
||||
|
||||
let tables = try computeTables()
|
||||
|
||||
var selectorPointer = 0
|
||||
var decoded = 0
|
||||
var table = tables[selectors[selectors.startIndex]]
|
||||
var selectorIndex = selectors.startIndex &+ 1
|
||||
var runLength = 0
|
||||
var repeatPower = 0
|
||||
var buffer: [UInt8] = []
|
||||
var currentTable: DecodingTree?
|
||||
var repeatPower = 1
|
||||
var buffer = [UInt8]()
|
||||
|
||||
while true {
|
||||
decoded -= 1
|
||||
if decoded <= 0 {
|
||||
decoded = 50
|
||||
if selectorPointer == selectors.count {
|
||||
throw BZip2Error.wrongSelector
|
||||
} else if selectorPointer < selectors.count {
|
||||
currentTable = tables[selectors[selectorPointer]]
|
||||
selectorPointer += 1
|
||||
}
|
||||
if decoded >= 50 {
|
||||
guard selectorIndex < selectorsCount
|
||||
else { throw BZip2Error.wrongSelector }
|
||||
table = tables[selectors[selectorIndex]]
|
||||
selectorIndex &+= 1
|
||||
decoded = 0
|
||||
}
|
||||
|
||||
guard let symbol = currentTable?.findNextSymbol(), symbol != -1
|
||||
let symbol = table.findNextSymbol()
|
||||
guard symbol != -1
|
||||
else { throw BZip2Error.symbolNotFound }
|
||||
decoded &+= 1
|
||||
|
||||
if symbol == 0 || symbol == 1 { // RUNA and RUNB symbols.
|
||||
if runLength == 0 {
|
||||
repeatPower = 1
|
||||
}
|
||||
runLength += repeatPower << symbol
|
||||
runLength &+= repeatPower << symbol
|
||||
repeatPower <<= 1
|
||||
continue
|
||||
} else if runLength > 0 {
|
||||
}
|
||||
if runLength > 0 {
|
||||
// There might have been a repeat run right before EOS symbol.
|
||||
for _ in 0..<runLength {
|
||||
buffer.append(usedSymbols[0])
|
||||
}
|
||||
runLength = 0
|
||||
repeatPower = 1
|
||||
}
|
||||
if symbol == usedSymbolsCount - 1 { // End of stream symbol.
|
||||
break
|
||||
} else { // Move to front inverse.
|
||||
let element = usedSymbols.remove(at: symbol - 1)
|
||||
usedSymbols.insert(element, at: 0)
|
||||
buffer.append(element)
|
||||
}
|
||||
// Move to front inverse.
|
||||
let element = usedSymbols.remove(at: symbol - 1)
|
||||
usedSymbols.insert(element, at: 0)
|
||||
buffer.append(element)
|
||||
}
|
||||
|
||||
let nt = BurrowsWheeler.reverse(bytes: buffer, pointer)
|
||||
@@ -220,7 +266,7 @@ public class BZip2: DecompressionAlgorithm {
|
||||
}
|
||||
}
|
||||
|
||||
return Data(out)
|
||||
return out
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -29,8 +29,16 @@ public enum BZip2Error: Error {
|
||||
/// Symbol wasn't found in Huffman tree.
|
||||
case symbolNotFound
|
||||
/**
|
||||
Computed checksum of uncompressed data doesn't match the value stored in archive.
|
||||
Associated value of the error contains already decompressed data.
|
||||
Computed checksum of the uncompressed data does not match the value stored in the archive.
|
||||
Associated value contains the data that were successfully decompressed up to the point where the mismatch was
|
||||
detected.
|
||||
|
||||
- When using `BZip2.decompress(data:)`: The associated value comes from a single BZip2 archive. If the mismatch
|
||||
happens at the final checksum verification, this is usually the entire decompressed output.
|
||||
|
||||
- When using `BZip2.multiDecompress(data:)`: The input may contain several concatenated BZip2 archives. The error
|
||||
is thrown for the current archive that fails the checksum. The associated value contains only the data decompressed
|
||||
for that archive. Results from earlier archives are not included and are not returned once this error is thrown.
|
||||
*/
|
||||
case wrongCRC(Data)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
enum BurrowsWheeler {
|
||||
|
||||
static func transform(bytes: [Int]) -> ([Int], Int) {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Suffix Array by Induced Sorting
|
||||
enum SuffixArray {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -27,9 +27,9 @@ enum CheckSums {
|
||||
return ~crc
|
||||
}
|
||||
|
||||
static func bzip2crc32(_ data: Data) -> UInt32 {
|
||||
static func bzip2crc32(_ block: [UInt8]) -> UInt32 {
|
||||
var crc: UInt32 = 0xFFFFFFFF
|
||||
for byte in data {
|
||||
for byte in block {
|
||||
let index = UInt32(truncatingIfNeeded: byte)
|
||||
crc = (crc << 8) ^ CheckSums.bzip2CRC32table[((crc >> 24) ^ index).toInt()]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
typealias HuffmanCodes = (codes: [Code], maxBits: Int)
|
||||
|
||||
struct Code {
|
||||
|
||||
@@ -12,8 +12,7 @@ struct Code {
|
||||
let code: Int
|
||||
let symbol: Int
|
||||
|
||||
/// `lengths` don't have to be sorted, but there must not be any 0 code lengths.
|
||||
static func huffmanCodes(from lengths: [CodeLength]) -> (codes: [Code], maxBits: Int) {
|
||||
static func huffmanCodes(from lengths: [CodeLength]) -> HuffmanCodes {
|
||||
// Sort `lengths` array to calculate canonical Huffman code.
|
||||
let sortedLengths = lengths.sorted()
|
||||
|
||||
@@ -24,8 +23,7 @@ struct Code {
|
||||
|
||||
var loopBits = -1
|
||||
var symbol = -1
|
||||
for length in sortedLengths {
|
||||
precondition(length.codeLength > 0, "Code length must not be 0 during HuffmanTree construction.")
|
||||
for length in sortedLengths where length.codeLength > 0 {
|
||||
symbol += 1
|
||||
// We sometimes need to make symbol to have length.bits bit length.
|
||||
let bits = length.codeLength
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CodeLength: Equatable {
|
||||
|
||||
let symbol: Int
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
final class DecodingTree {
|
||||
struct DecodingTree {
|
||||
|
||||
private let bitReader: BitReader
|
||||
|
||||
private let tree: [Int]
|
||||
private let leafCount: Int
|
||||
|
||||
init(codes: [Code], maxBits: Int, _ bitReader: BitReader) {
|
||||
init(_ huffmanCodes: HuffmanCodes, _ bitReader: BitReader) {
|
||||
self.bitReader = bitReader
|
||||
|
||||
// Calculate maximum amount of leaves in a tree.
|
||||
self.leafCount = 1 << (maxBits + 1)
|
||||
// Maximum amount of leaves in a binary tree with the height equal to `huffmanCodes.maxBits`.
|
||||
self.leafCount = (1 << (huffmanCodes.maxBits + 1)) - 1
|
||||
var tree = Array(repeating: -1, count: leafCount)
|
||||
|
||||
for code in codes {
|
||||
for code in huffmanCodes.codes {
|
||||
// Put code in its place in the tree.
|
||||
var treeCode = code.code
|
||||
var index = 0
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
fileprivate struct CodingIndex {
|
||||
@@ -13,13 +12,13 @@ fileprivate struct CodingIndex {
|
||||
|
||||
}
|
||||
|
||||
final class EncodingTree {
|
||||
struct EncodingTree {
|
||||
|
||||
private let bitWriter: BitWriter
|
||||
|
||||
private let codingIndices: [CodingIndex]
|
||||
|
||||
init(codes: [Code], _ bitWriter: BitWriter, reverseCodes: Bool = false) {
|
||||
init(_ codes: [Code], _ bitWriter: BitWriter, reverseCodes: Bool = false) {
|
||||
self.bitWriter = bitWriter
|
||||
|
||||
var codingIndices = Array(repeating: CodingIndex(treeCode: -1, bitSize: -1), count: codes.count)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Represents a (de)compression method.
|
||||
public enum CompressionMethod {
|
||||
/// BZip2.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Data {
|
||||
|
||||
@inlinable @inline(__always)
|
||||
func toByteArray() -> [UInt8] {
|
||||
return self.withUnsafeBytes { $0.map { $0 } }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UnsignedInteger {
|
||||
|
||||
@inlinable @inline(__always)
|
||||
@@ -32,10 +41,11 @@ extension Int {
|
||||
|
||||
/// Returns an integer with reversed order of bits.
|
||||
func reversed(bits count: Int) -> Int {
|
||||
var a = 1 << 0
|
||||
var b = 1 << (count - 1)
|
||||
// Arithmetic operations amount: 3 + 8 * ceil(count / 2)
|
||||
var a = 1
|
||||
var b = 1 << (count &- 1)
|
||||
var z = 0
|
||||
for i in Swift.stride(from: count - 1, to: -1, by: -2) {
|
||||
for i in Swift.stride(from: count &- 1, to: -1, by: -2) {
|
||||
z |= (self >> i) & a
|
||||
z |= (self << i) & b
|
||||
a <<= 1
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Represents the type of the file system on which an archive or container was created. File system determines the meaning
|
||||
of file attributes.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -30,8 +30,7 @@ extension Deflate: CompressionAlgorithm {
|
||||
// Static Huffman size is more complicated...
|
||||
let staticHuffmanBlockSize = staticHuffmanBitSize(bldCodes.stats)
|
||||
|
||||
// Since `length` of uncompressed block is 16-bit integer,
|
||||
// there is a limitation on size of uncompressed block.
|
||||
// Since `length` of uncompressed block is 16-bit integer, there is a limitation on size of uncompressed block.
|
||||
// Falling back to static Huffman encoding in case of big uncompressed block is a band-aid solution.
|
||||
if uncompBlockSize <= staticHuffmanBlockSize && uncompBlockSize <= 65535 {
|
||||
// If according to our calculations static huffman will not make output smaller than input,
|
||||
@@ -73,24 +72,13 @@ extension Deflate: CompressionAlgorithm {
|
||||
}
|
||||
|
||||
private static func createUncompressedBlock(_ data: Data) -> Data {
|
||||
let bitWriter = LsbBitWriter()
|
||||
|
||||
// Write block header.
|
||||
assert(data.count <= 65535, "Cannot create uncompressed Deflate blocks larger than 65535 bytes.")
|
||||
// Write block header, data's length and n-length. It is more efficient to avoid using LsbBitWriter.
|
||||
// Note: Only one block is supported for now.
|
||||
bitWriter.write(bit: 1)
|
||||
bitWriter.write(bits: [0, 0])
|
||||
|
||||
// Before writing lengths we need to discard remaining bits in current byte.
|
||||
bitWriter.align()
|
||||
|
||||
// Write data's length.
|
||||
bitWriter.write(number: data.count, bitsCount: 16)
|
||||
// Write data's n-length.
|
||||
bitWriter.write(number: data.count ^ (1 << 16 - 1), bitsCount: 16)
|
||||
|
||||
var out = bitWriter.data
|
||||
let nLength = data.count ^ ((1 << 16) - 1)
|
||||
var out = Data([1, UInt8(truncatingIfNeeded: data.count & 0xFF), UInt8(truncatingIfNeeded: (data.count >> 8) & 0xFF),
|
||||
UInt8(truncatingIfNeeded: nLength & 0xFF), UInt8(truncatingIfNeeded: (nLength >> 8) & 0xFF)])
|
||||
out.append(data)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -106,9 +94,9 @@ extension Deflate: CompressionAlgorithm {
|
||||
// Constructing Huffman trees for the case of block with preset alphabets.
|
||||
// In this case codes for literals and distances are fixed.
|
||||
/// Huffman tree for literal and length symbols/codes.
|
||||
let mainLiterals = EncodingTree(codes: Constants.staticHuffmanLiteralCodes, bitWriter, reverseCodes: true)
|
||||
let mainLiterals = EncodingTree(Constants.staticHuffmanLiteralCodes.codes, bitWriter, reverseCodes: true)
|
||||
/// Huffman tree for backward distance symbols/codes.
|
||||
let mainDistances = EncodingTree(codes: Constants.staticHuffmanDistanceCodes, bitWriter, reverseCodes: true)
|
||||
let mainDistances = EncodingTree(Constants.staticHuffmanDistanceCodes.codes, bitWriter, reverseCodes: true)
|
||||
|
||||
for code in bldCodes {
|
||||
switch code {
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Deflate {
|
||||
|
||||
struct Constants {
|
||||
|
||||
// Precomputed codes for the static Huffman literal and distance trees.
|
||||
static let staticHuffmanLiteralCodes =
|
||||
[Code(bits: 7, code: 0, symbol: 256), Code(bits: 7, code: 64, symbol: 257),
|
||||
static let staticHuffmanLiteralCodes: HuffmanCodes =
|
||||
([Code(bits: 7, code: 0, symbol: 256), Code(bits: 7, code: 64, symbol: 257),
|
||||
Code(bits: 7, code: 32, symbol: 258), Code(bits: 7, code: 96, symbol: 259),
|
||||
Code(bits: 7, code: 16, symbol: 260), Code(bits: 7, code: 80, symbol: 261),
|
||||
Code(bits: 7, code: 48, symbol: 262), Code(bits: 7, code: 112, symbol: 263),
|
||||
@@ -154,10 +152,10 @@ extension Deflate {
|
||||
Code(bits: 9, code: 63, symbol: 248), Code(bits: 9, code: 319, symbol: 249),
|
||||
Code(bits: 9, code: 191, symbol: 250), Code(bits: 9, code: 447, symbol: 251),
|
||||
Code(bits: 9, code: 127, symbol: 252), Code(bits: 9, code: 383, symbol: 253),
|
||||
Code(bits: 9, code: 255, symbol: 254), Code(bits: 9, code: 511, symbol: 255)]
|
||||
Code(bits: 9, code: 255, symbol: 254), Code(bits: 9, code: 511, symbol: 255)], 9)
|
||||
|
||||
static let staticHuffmanDistanceCodes =
|
||||
[Code(bits: 5, code: 0, symbol: 0), Code(bits: 5, code: 16, symbol: 1),
|
||||
static let staticHuffmanDistanceCodes: HuffmanCodes =
|
||||
([Code(bits: 5, code: 0, symbol: 0), Code(bits: 5, code: 16, symbol: 1),
|
||||
Code(bits: 5, code: 8, symbol: 2), Code(bits: 5, code: 24, symbol: 3),
|
||||
Code(bits: 5, code: 4, symbol: 4), Code(bits: 5, code: 20, symbol: 5),
|
||||
Code(bits: 5, code: 12, symbol: 6), Code(bits: 5, code: 28, symbol: 7),
|
||||
@@ -172,7 +170,7 @@ extension Deflate {
|
||||
Code(bits: 5, code: 3, symbol: 24), Code(bits: 5, code: 19, symbol: 25),
|
||||
Code(bits: 5, code: 11, symbol: 26), Code(bits: 5, code: 27, symbol: 27),
|
||||
Code(bits: 5, code: 7, symbol: 28), Code(bits: 5, code: 23, symbol: 29),
|
||||
Code(bits: 5, code: 15, symbol: 30), Code(bits: 5, code: 31, symbol: 31)]
|
||||
Code(bits: 5, code: 15, symbol: 30), Code(bits: 5, code: 31, symbol: 31)], 5)
|
||||
|
||||
static let codeLengthOrders: [Int] =
|
||||
[16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
// Deflate specific functions for generation of HuffmanLength arrays from different inputs.
|
||||
extension Deflate {
|
||||
|
||||
/// - Note: Skips zero codeLengths.
|
||||
static func lengths(from orderedCodeLengths: [Int]) -> [CodeLength] {
|
||||
var lengths = [CodeLength]()
|
||||
for (i, codeLength) in orderedCodeLengths.enumerated() where codeLength > 0 {
|
||||
lengths.append(CodeLength(symbol: i, codeLength: codeLength))
|
||||
}
|
||||
return lengths
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -77,8 +77,8 @@ public class Deflate: DecompressionAlgorithm {
|
||||
if blockType == 1 { // Static Huffman
|
||||
// In this case codes for literals and distances are fixed.
|
||||
// Initialize trees from bootstraps.
|
||||
mainLiterals = DecodingTree(codes: Constants.staticHuffmanLiteralCodes, maxBits: 9, bitReader)
|
||||
mainDistances = DecodingTree(codes: Constants.staticHuffmanDistanceCodes, maxBits: 5, bitReader)
|
||||
mainLiterals = DecodingTree(Constants.staticHuffmanLiteralCodes, bitReader)
|
||||
mainDistances = DecodingTree(Constants.staticHuffmanDistanceCodes, bitReader)
|
||||
} else { // Dynamic Huffman
|
||||
// In this case there are Huffman codes for two alphabets in data right after block header.
|
||||
// Each code defined by a sequence of code lengths (which are compressed themselves with Huffman).
|
||||
@@ -88,6 +88,11 @@ public class Deflate: DecompressionAlgorithm {
|
||||
|
||||
/// Number of literals codes.
|
||||
let literals = bitReader.int(fromBits: 5) + 257
|
||||
// According to Deflate specification maximum amount of literal/length codes is 286. However, it
|
||||
// is possible to encode a number larger than this with 5 bits. Specification seems to be silent
|
||||
// about this scenario, so we treat it as a corrupted input.
|
||||
guard literals <= 286
|
||||
else { throw DeflateError.wrongSymbol }
|
||||
/// Number of distances codes.
|
||||
let distances = bitReader.int(fromBits: 5) + 1
|
||||
/// Number of code lengths codes.
|
||||
@@ -96,68 +101,70 @@ public class Deflate: DecompressionAlgorithm {
|
||||
guard bitReader.bitsLeft >= 3 * codeLengthsCount
|
||||
else { throw DeflateError.symbolNotFound }
|
||||
|
||||
// Code lengths of the literal/length and distance Huffman trees are encoded with another Huffman
|
||||
// tree using a special alphabet. The code lengths for this latter tree are presented in a specific
|
||||
// order which is stored in `Constants.codeLengthOrders`: `codeLengthOrders[i]` is the code lengths
|
||||
// alphabet symbol at the i-th place in the sequence.
|
||||
var orderedCodeLengths = Array(repeating: 0, count: 19)
|
||||
for i in 0..<codeLengthsCount {
|
||||
orderedCodeLengths[Constants.codeLengthOrders[i]] = bitReader.int(fromBits: 3)
|
||||
}
|
||||
let dynamicCodes = Code.huffmanCodes(from: Deflate.lengths(from: orderedCodeLengths))
|
||||
/// Huffman tree for code lengths. Each code in the main alphabets is coded with this tree.
|
||||
let dynamicCodeTree = DecodingTree(codes: dynamicCodes.codes, maxBits: dynamicCodes.maxBits,
|
||||
bitReader)
|
||||
let dynamicCodeTree = DecodingTree(dynamicCodes, bitReader)
|
||||
|
||||
// Now we need to read codes (code lengths) for two main alphabets (trees).
|
||||
var codeLengths: [Int] = []
|
||||
var n = 0
|
||||
while n < (literals + distances) {
|
||||
var codeLengths = Array(repeating: 0, count: literals + distances)
|
||||
var n = codeLengths.startIndex
|
||||
while n < codeLengths.endIndex {
|
||||
// Finding next Huffman tree's symbol in data.
|
||||
let symbol = dynamicCodeTree.findNextSymbol()
|
||||
guard symbol != -1 else { throw DeflateError.symbolNotFound }
|
||||
|
||||
let count: Int
|
||||
let what: Int
|
||||
if symbol >= 0 && symbol <= 15 {
|
||||
// It is a raw code length.
|
||||
count = 1
|
||||
what = symbol
|
||||
} else if symbol == 16 {
|
||||
// Copy previous code length 3 to 6 times.
|
||||
// Next two bits show how many times we need to copy.
|
||||
codeLengths[n] = symbol
|
||||
n += 1
|
||||
} else if symbol == 16 && n > codeLengths.startIndex {
|
||||
// Copy previous code length 3 to 6 times. Next two bits show how many times we need to copy.
|
||||
// This symbol cannot be the first symbol encoding code lengths, since there is nothing to
|
||||
// copy at this point.
|
||||
guard bitReader.bitsLeft >= 2
|
||||
else { throw DeflateError.symbolNotFound }
|
||||
|
||||
count = bitReader.int(fromBits: 2) + 3
|
||||
what = codeLengths.last!
|
||||
let copyCount = bitReader.int(fromBits: 2) + 3
|
||||
guard n + copyCount <= codeLengths.endIndex
|
||||
else { throw DeflateError.wrongSymbol }
|
||||
for i in 0..<copyCount {
|
||||
codeLengths[n + i] = codeLengths[n - 1]
|
||||
}
|
||||
n += copyCount
|
||||
} else if symbol == 17 {
|
||||
// Repeat code length 0 from 3 to 10 times.
|
||||
// Next three bits show how many times we need to copy.
|
||||
// Repeat code length 0 from 3 to 10 times. Next 3 bits show how many times we need to copy.
|
||||
// Since `codeLengths` array was already preinitialized with zeros, we just have to skip
|
||||
// ahead.
|
||||
guard bitReader.bitsLeft >= 3
|
||||
else { throw DeflateError.symbolNotFound }
|
||||
|
||||
count = bitReader.int(fromBits: 3) + 3
|
||||
what = 0
|
||||
n += bitReader.int(fromBits: 3) + 3
|
||||
} else if symbol == 18 {
|
||||
// Repeat code length 0 from 11 to 138 times.
|
||||
// Next seven bits show how many times we need to do this.
|
||||
// Repeat code length 0 from 11 to 138 times. Next 7 bits show how many times we need to
|
||||
// copy. Since `codeLengths` array was already preinitialized with zeros, we just have to
|
||||
// skip ahead.
|
||||
guard bitReader.bitsLeft >= 7
|
||||
else { throw DeflateError.symbolNotFound }
|
||||
|
||||
count = bitReader.int(fromBits: 7) + 11
|
||||
what = 0
|
||||
n += bitReader.int(fromBits: 7) + 11
|
||||
} else {
|
||||
throw DeflateError.wrongSymbol
|
||||
}
|
||||
for _ in 0..<count {
|
||||
codeLengths.append(what)
|
||||
}
|
||||
n += count
|
||||
}
|
||||
// We have read codeLengths for both trees at once.
|
||||
// Now we need to split them and make corresponding trees.
|
||||
let literalCodes = Code.huffmanCodes(from: Deflate.lengths(from: Array(codeLengths[0..<literals])))
|
||||
mainLiterals = DecodingTree(codes: literalCodes.codes, maxBits: literalCodes.maxBits, bitReader)
|
||||
let distanceCodes = Code.huffmanCodes(from: Deflate.lengths(from:
|
||||
Array(codeLengths[literals..<codeLengths.count])))
|
||||
mainDistances = DecodingTree(codes: distanceCodes.codes, maxBits: distanceCodes.maxBits, bitReader)
|
||||
// Self-consistency check. Failure here can happen if at some point a zero code length was repeated
|
||||
// too many times indicating a corrupted input.
|
||||
guard n == codeLengths.endIndex
|
||||
else { throw DeflateError.wrongSymbol }
|
||||
// We have read `codeLengths` for both trees at once, so we split them and make corresponding trees.
|
||||
let literalCodes = Code.huffmanCodes(from: Deflate.lengths(from: Array(codeLengths.prefix(upTo: literals))))
|
||||
mainLiterals = DecodingTree(literalCodes, bitReader)
|
||||
let distanceCodes = Code.huffmanCodes(from: Deflate.lengths(from: Array(codeLengths.suffix(from: literals))))
|
||||
mainDistances = DecodingTree(distanceCodes, bitReader)
|
||||
}
|
||||
|
||||
// Main loop of data decompression.
|
||||
@@ -241,4 +248,8 @@ public class Deflate: DecompressionAlgorithm {
|
||||
return Data(out)
|
||||
}
|
||||
|
||||
private static func lengths(from orderedCodeLengths: [Int]) -> [CodeLength] {
|
||||
return orderedCodeLengths.enumerated().map({ CodeLength(symbol: $0, codeLength: $1) })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Represents an error which happened during Deflate compression or decompression.
|
||||
It may indicate that either the data is damaged or it might not be compressed with Deflate at all.
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension FileSystemType {
|
||||
|
||||
init(_ gzipOS: UInt8) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Represents an error which happened while processing a GZip archive.
|
||||
It may indicate that either archive is damaged or it might not be GZip archive at all.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -118,12 +118,11 @@ public struct GzipHeader {
|
||||
headerBytes.append(byte)
|
||||
}
|
||||
|
||||
// There must be least four bytes of extra fields for SI1, SI2, and 2 bytes of the length parameter
|
||||
// filled with zeros (minimal variant).
|
||||
guard reader.bytesLeft >= xlen && xlen >= 4
|
||||
else { throw GzipError.wrongMagic }
|
||||
while xlen > 0 {
|
||||
// There must be least four bytes of extra fields for SI1, SI2, and 2 bytes of the length parameter
|
||||
// filled with zeros (minimal variant).
|
||||
guard reader.bytesLeft >= xlen && xlen >= 4
|
||||
else { throw GzipError.wrongMagic }
|
||||
|
||||
let si1 = reader.byte()
|
||||
headerBytes.append(si1)
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
extension LZ4: CompressionAlgorithm {
|
||||
|
||||
|
||||
+12
-13
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -155,7 +155,7 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
}
|
||||
|
||||
// The functions below return uncompressed data and the offset to the next byte after the processed frame (even if
|
||||
// the end of the input data was reached). The offset is needed to make multiDecompress function work.
|
||||
// the end of the input data was reached). The offset is required to make multiDecompress function work.
|
||||
|
||||
private static func process(legacyFrame data: Data) throws -> (Data, Data.Index) {
|
||||
let reader = LittleEndianByteReader(data: data)
|
||||
@@ -229,11 +229,11 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
|
||||
let contentSize: Int?
|
||||
if contentSizePresent {
|
||||
// At this point valid LZ4 frame must have at least 13 bytes remaining for: content size (8 bytes), header
|
||||
// At this point a valid LZ4 frame must have at least 13 bytes remaining for content size (8 bytes), header
|
||||
// checksum (1 byte), and EndMark (4 bytes), assuming zero data blocks.
|
||||
guard reader.bytesLeft >= 13
|
||||
else { throw DataError.truncated }
|
||||
// Since Data is indexed by the Int type, the maximum size of the uncompressed data that we can decode is
|
||||
// Since Data is indexed by the Int type, the maximum size of uncompressed data that we can decode is
|
||||
// Int.max. However, LZ4 supports uncompressed data sizes up to UInt64.max, which is larger, so we check
|
||||
// for this possibility.
|
||||
let rawContentSize = reader.uint64()
|
||||
@@ -249,7 +249,7 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
// If dictionary ID is present in the frame, then we must have a dictionary to successfully decode it.
|
||||
guard dictionary != nil
|
||||
else { throw DataError.corrupted }
|
||||
// At this point valid LZ4 frame must have at least 9 bytes remaining for: dictionary ID (4 bytes), header
|
||||
// At this point a valid LZ4 frame must have at least 9 bytes remaining for dictionary ID (4 bytes), header
|
||||
// checksum (1 byte), and EndMark (4 bytes), assuming zero data blocks.
|
||||
guard reader.bytesLeft >= 9
|
||||
else { throw DataError.truncated }
|
||||
@@ -264,7 +264,7 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
}
|
||||
|
||||
if let extDictId = extDictId, let dictId = dictId {
|
||||
// If dictionary ID is present in the frame, and passed as an argument, then they must be equal.
|
||||
// If dictionary ID is present in the frame and passed as an argument, then they must be equal.
|
||||
guard extDictId == dictId
|
||||
else { throw DataError.corrupted }
|
||||
}
|
||||
@@ -278,7 +278,7 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
while true {
|
||||
guard reader.bytesLeft >= 4
|
||||
else { throw DataError.truncated }
|
||||
// Either the size of the block, or the EndMark.
|
||||
// Either the size of a block, or the EndMark.
|
||||
let blockMark = reader.uint32()
|
||||
// Check for the EndMark.
|
||||
if blockMark == 0 {
|
||||
@@ -287,8 +287,8 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
// The highest bit indicates if the block is compressed.
|
||||
let compressed = blockMark & 0x80000000 == 0
|
||||
let blockSize = (blockMark & 0x7FFFFFFF).toInt()
|
||||
// Since we don't do manual memory allocation we don't have to constraint the block size. Nevertheless, we
|
||||
// follow the reference implementation here and reject blocks with sizes greater than maximum block size.
|
||||
// Since we don't do manual memory allocation we don't have to constrain the block size. Nevertheless, we
|
||||
// follow the reference implementation here and reject blocks with sizes greater than the maximum block size.
|
||||
guard blockSize <= maxBlockSize
|
||||
else { throw DataError.corrupted }
|
||||
|
||||
@@ -350,7 +350,7 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
guard data.endIndex - reader.offset >= 1
|
||||
else { throw DataError.truncated }
|
||||
let byte = reader.byte()
|
||||
// There is no size limit on the literal count, so we need to check that it remains within Int range
|
||||
// There is no size limit on the literal count, so we have to check that it remains within Int range
|
||||
// (similar to content size considerations).
|
||||
let (newLiteralCount, overflow) = literalCount.addingReportingOverflow(byte.toInt())
|
||||
guard !overflow
|
||||
@@ -388,7 +388,7 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
guard data.endIndex - reader.offset >= 1
|
||||
else { throw DataError.truncated }
|
||||
let byte = reader.byte()
|
||||
// Again, there is no size limit on the match length, so we need to check that it remains within Int
|
||||
// Again, there is no size limit on the match length, so we have to check that it remains within Int
|
||||
// range.
|
||||
let (newMatchLength, overflow) = matchLength.addingReportingOverflow(byte.toInt())
|
||||
guard !overflow
|
||||
@@ -401,8 +401,7 @@ public enum LZ4: DecompressionAlgorithm {
|
||||
}
|
||||
|
||||
// We record the start index of the last encountered match to verify it against end-of-block restrictions.
|
||||
// Note, that this refers to the bytes that we have found a match for, and not to the bytes that we're
|
||||
// matching to.
|
||||
// This refers to the bytes that we have found a match for, and not to the bytes that we're matching to.
|
||||
lastMatchStartIndex = out.endIndex
|
||||
let matchStartIndex = out.endIndex - offset
|
||||
for i in 0..<matchLength {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Used to decode symbols that need several bits for storing.
|
||||
struct LZMABitTreeDecoder {
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
enum LZMAConstants {
|
||||
|
||||
static let topValue: UInt32 = 1 << 24
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
struct LZMADecoder {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Represents an error which happened during LZMA decompression.
|
||||
It may indicate that either data is damaged or it might not be compressed with LZMA at all.
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
struct LZMALenDecoder {
|
||||
|
||||
private var choice: Int = LZMAConstants.probInitValue
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -18,7 +18,7 @@ public struct LZMAProperties {
|
||||
public var pb: Int = 2
|
||||
|
||||
/**
|
||||
Size of the dictionary. Default value is 1 << 24.
|
||||
Size of the dictionary. Default value is `1 << 24`.
|
||||
|
||||
- Note: Dictionary size cannot be less than 4096. In case of attempt to set it to the value less than 4096 it will
|
||||
be automatically set to 4096 instead.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -12,7 +12,6 @@ struct LZMARangeDecoder {
|
||||
|
||||
private var range = 0xFFFFFFFF as UInt32
|
||||
private var code = 0 as UInt32
|
||||
private(set) var isCorrupted = false
|
||||
|
||||
var isFinishedOK: Bool {
|
||||
return self.code == 0
|
||||
@@ -27,7 +26,7 @@ struct LZMARangeDecoder {
|
||||
|
||||
let byte = self.byteReader.byte()
|
||||
self.code = self.byteReader.uint32().byteSwapped
|
||||
guard byte == 0 && self.code != self.range
|
||||
guard byte == 0
|
||||
else { throw LZMAError.rangeDecoderInitError }
|
||||
}
|
||||
|
||||
@@ -53,10 +52,6 @@ struct LZMARangeDecoder {
|
||||
let t = 0 &- (self.code >> 31)
|
||||
self.code = self.code &+ (self.range & t)
|
||||
|
||||
if self.code == self.range {
|
||||
self.isCorrupted = true
|
||||
}
|
||||
|
||||
self.normalize()
|
||||
|
||||
res <<= 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
struct LZMA2Decoder {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Represents an error which happened during LZMA2 decompression.
|
||||
It may indicate that either data is damaged or it might not be compressed with LZMA2 at all.
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension ContainerEntryType {
|
||||
|
||||
init(_ fileTypeIndicator: UInt8) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
extension LittleEndianByteReader {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
/// Provides functions for work with TAR containers.
|
||||
public class TarContainer: Container {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Represents an error which happened while processing a TAR container.
|
||||
It may indicate that either container is damaged or it might not be TAR container at all.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -6,8 +6,8 @@
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
// While it is tempting to make Provider conform to `IteratorProtocol` and `Sequence` protocols, it is in fact
|
||||
// impossible to do so, since `TarHeader.init(...)` is throwing and `IteratorProtocol.next()` cannot be throwing.
|
||||
// While it is tempting to make the parser conform to `IteratorProtocol` and `Sequence` protocols, it is in fact
|
||||
// impossible to do so, since `TarHeader.init(_)` is throwing and `IteratorProtocol.next()` cannot be throwing.
|
||||
struct TarParser {
|
||||
|
||||
enum ParsingResult {
|
||||
|
||||
+18
-44
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -23,12 +23,6 @@ import BitByteData
|
||||
try handle.close()
|
||||
```
|
||||
Note that closing the `FileHandle` remains the responsibility of the caller.
|
||||
|
||||
- Important: Due to the API availability limitations of Foundation's `FileHandle`, on certain platforms errors in
|
||||
`FileHandle` operations may result in unrecoverable runtime failures due to unhandled Objective-C exceptions (which are
|
||||
impossible to correctly handle in Swift code). As such, it is not recommended to use `TarReader` on those platforms.
|
||||
The following platforms are _unaffected_ by this issue: macOS 10.15.4+, iOS 13.4+, watchOS 6.2+, tvOS 13.4+, and any
|
||||
other platforms without Objective-C runtime.
|
||||
*/
|
||||
public struct TarReader {
|
||||
|
||||
@@ -86,7 +80,7 @@ public struct TarReader {
|
||||
return nil
|
||||
} else if headerData == Data(count: 512) {
|
||||
// EOF marker case.
|
||||
let offset = try getOffset()
|
||||
let offset = try handle.offset()
|
||||
if try getData(size: 512) == Data(count: 512) {
|
||||
return nil
|
||||
} else {
|
||||
@@ -94,7 +88,7 @@ public struct TarReader {
|
||||
// match the EOF marker signature. In practice, this indicates a malformed TAR container, since a
|
||||
// zero-filled block is not a valid TAR header (and in fact the end result is an error being thrown in
|
||||
// TarHeader initializer later down the line).
|
||||
try set(offset: offset)
|
||||
try handle.seek(toOffset: offset)
|
||||
}
|
||||
} else if headerData.count < 512 {
|
||||
throw DataError.truncated
|
||||
@@ -106,7 +100,7 @@ public struct TarReader {
|
||||
// at most 512 bytes.
|
||||
// Check, just in case, since we use blockStartIndex = -1 when creating TAR containers.
|
||||
assert(header.blockStartIndex >= 0)
|
||||
let dataStartOffset = try getOffset()
|
||||
let dataStartOffset = try handle.offset()
|
||||
|
||||
let entryData = try getData(size: header.size)
|
||||
guard entryData.count == header.size
|
||||
@@ -125,11 +119,11 @@ public struct TarReader {
|
||||
case .longName:
|
||||
longName = LittleEndianByteReader(data: entryData).tarCString(maxLength: header.size)
|
||||
}
|
||||
try set(offset: dataStartOffset + UInt64(truncatingIfNeeded: header.size.roundTo512()))
|
||||
try handle.seek(toOffset: dataStartOffset + UInt64(truncatingIfNeeded: header.size.roundTo512()))
|
||||
return try read()
|
||||
} else {
|
||||
let info = TarEntryInfo(header, lastGlobalExtendedHeader, lastLocalExtendedHeader, longName, longLinkName)
|
||||
try set(offset: dataStartOffset + UInt64(truncatingIfNeeded: header.size.roundTo512()))
|
||||
try handle.seek(toOffset: dataStartOffset + UInt64(truncatingIfNeeded: header.size.roundTo512()))
|
||||
lastLocalExtendedHeader = nil
|
||||
longName = nil
|
||||
longLinkName = nil
|
||||
@@ -144,40 +138,20 @@ public struct TarReader {
|
||||
}
|
||||
}
|
||||
|
||||
private func getOffset() throws -> UInt64 {
|
||||
if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
|
||||
return try handle.offset()
|
||||
} else {
|
||||
return handle.offsetInFile
|
||||
}
|
||||
}
|
||||
|
||||
private func set(offset: UInt64) throws {
|
||||
if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
|
||||
try handle.seek(toOffset: offset)
|
||||
} else {
|
||||
handle.seek(toFileOffset: offset)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
private func getData(size: Int) throws -> Data {
|
||||
assert(size >= 0, "TarReader.getData(size:): negative size.")
|
||||
if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
|
||||
// The documentation for FileHandle.read(upToCount:) is a bit misleading. This method does "return the data
|
||||
// obtained by reading length bytes starting at the current file pointer" even if the requested amount is
|
||||
// larger than the available data. What is not clear is when the method returns nil. Apparently, there are
|
||||
// (at least) two cases when it happens:
|
||||
// - the file pointer is at the EOF regardless of the argument value,
|
||||
// - the argument is zero.
|
||||
// It is also unclear what happens when the argument is negative (it seems that it reads everything until
|
||||
// the EOF), but the assertion above takes care of this. In any case, instead of returning nil we return
|
||||
// empty data since both of these situations logically seem equivalent for our purposes. This also allows us
|
||||
// to eliminate additional guard-check for the size parameter.
|
||||
return try handle.read(upToCount: size) ?? Data()
|
||||
} else {
|
||||
// Technically, this can throw NSException, but since it is ObjC exception we cannot handle it in Swift.
|
||||
return handle.readData(ofLength: size)
|
||||
}
|
||||
// The documentation for FileHandle.read(upToCount:) is a bit misleading. This method does "return the data
|
||||
// obtained by reading length bytes starting at the current file pointer" even if the requested amount is
|
||||
// larger than the available data. What is not clear is when the method returns nil. Apparently, there are
|
||||
// (at least) two cases when it happens:
|
||||
// - the file pointer is at the EOF regardless of the argument value,
|
||||
// - the argument is zero.
|
||||
// It is also unclear what happens when the argument is negative (it seems that it reads everything until
|
||||
// the EOF), but the assertion above takes care of this. In any case, instead of returning nil we return
|
||||
// empty data since both of these situations logically seem equivalent for our purposes. This also allows us
|
||||
// to eliminate additional guard-check for the size parameter.
|
||||
return try handle.read(upToCount: size) ?? Data()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
@@ -26,12 +26,6 @@ import Foundation
|
||||
```
|
||||
Note that `TarWriter.finalize()` must be called after finishing appending entries to the container. In addition,
|
||||
closing the `FileHandle` remains the responsibility of the caller.
|
||||
|
||||
- Important: Due to the API availability limitations of Foundation's `FileHandle`, on certain platforms errors in
|
||||
`FileHandle` operations may result in unrecoverable runtime failures due to unhandled Objective-C exceptions (which are
|
||||
impossible to correctly handle in Swift code). As such, it is not recommended to use `TarWriter` on those platforms.
|
||||
The following platforms are _unaffected_ by this issue: macOS 10.15.4+, iOS 13.4+, watchOS 6.2+, tvOS 13.4+, and any
|
||||
other platforms without Objective-C runtime.
|
||||
*/
|
||||
public struct TarWriter {
|
||||
|
||||
@@ -132,13 +126,8 @@ public struct TarWriter {
|
||||
}
|
||||
|
||||
private func write(_ data: Data) throws {
|
||||
if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
|
||||
try handle.write(contentsOf: data)
|
||||
try handle.synchronize()
|
||||
} else {
|
||||
handle.write(data)
|
||||
handle.synchronizeFile()
|
||||
}
|
||||
try handle.write(contentsOf: data)
|
||||
try handle.synchronize()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
extension LittleEndianByteReader {
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
struct XZStreamHeader {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension CompressionMethod {
|
||||
|
||||
init(_ compression: UInt16) {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2024 Timofey Solomko
|
||||
// Copyright (c) 2026 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
extension FileSystemType {
|
||||
|
||||
init(_ versionMadeBy: UInt16) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user