Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
tsolomko committed Oct 22, 2022
2 parents 5419717 + c7f4665 commit 6fe73cb
Show file tree
Hide file tree
Showing 32 changed files with 879 additions and 252 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,6 @@ docs/

# Vscode launch.json generated by Swift extension
.vscode/launch.json

# API baselines generate by swift package diagnose-api-breaking-changes
api_baseline/
4 changes: 2 additions & 2 deletions .jazzy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ sourcekitten_sourcefile: docs.json
clean: false
author: Timofey Solomko
module: SWCompression
module_version: 4.8.2
module_version: 4.8.3
copyright: '© 2022 Timofey Solomko'
readme: README.md
github_url: https://github.com/tsolomko/SWCompression
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.8.2
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.8.3
theme: fullwidth

custom_categories:
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## 4.8.3

- There are now minimum deployment targets specified in Swift Package Manager manifest.
- The properties of `GzipHeader` are now `var`-properties (instead of `let`).
- GZip extra fields are now supported.
- Added `GzipHeader.ExtraField` struct.
- Added `GzipHeader.extraFields` property.
- Added a new `extraFields` argument to `GzipArchive.archive` function (with a default array empty value).
- Fixed potential crashes that could occur when processing GZip archives truncated in a header or a "footer".
- Some non-well-formed values of PAX extended header records no longer cause `TarError.wrongPaxHeaderEntry` to be thrown.
- The record values with newline characters are now fully processed.
- The record values that do not contain UTF-8 strings are now ignored.
- swcomp changes:
- The symbolic links are now extracted with the values recorded in the containers.
- The hard links are now extracted from TAR containers instead of being ignored.
- Fixed build issues on Linux and Windows.
- `benchmark` is now a command group with two commands, `run` and `show`.
- Added `-a`, `--append` option to the `benchmark run` command.
- Added `-d`, `--description` option to the `benchmark run` command.
- Added `-t`, `--preserve-timestamp` option to the `benchmark run` command.
- The file format of saved results is now more flexible and allows multi-way comparisons.
- Improved precision of time measurements in benchmarks.

## 4.8.2

- Swift 5.1 is no longer supported.
Expand Down
6 changes: 6 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import PackageDescription

let package = Package(
name: "SWCompression",
platforms: [
.macOS(.v10_13),
.iOS(.v11),
.tvOS(.v11),
.watchOS(.v4)
],
products: [
.library(
name: "SWCompression",
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ Every function or type of SWCompression's public API is documented. This documen
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.

__IMPORTANT:__ The "swcomp" command-line tool is NOT intended for general use.

## Contributing

Whether you find a bug, have a suggestion, idea, feedback or something else, please
Expand Down
2 changes: 1 addition & 1 deletion SWCompression.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = "SWCompression"
s.version = "4.8.2"
s.version = "4.8.3"
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."
Expand Down
4 changes: 2 additions & 2 deletions SWCompression.xcodeproj/SWCompression.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>4.8.2</string>
<string>4.8.3</string>
<key>CFBundleVersion</key>
<string>87</string>
<string>88</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2022 Timofey Solomko</string>
</dict>
Expand Down
4 changes: 2 additions & 2 deletions SWCompression.xcodeproj/TestSWCompression.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>4.8.2</string>
<string>4.8.3</string>
<key>CFBundleVersion</key>
<string>87</string>
<string>88</string>
</dict>
</plist>
20 changes: 16 additions & 4 deletions SWCompression.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@
06F066771FFB763400312A82 /* test8.bz2 in Resources */ = {isa = PBXBuildFile; fileRef = 06F066111FFB763300312A82 /* test8.bz2 */; };
06F276DF1F2BAB4A00E67335 /* 7zEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F276DE1F2BAB4900E67335 /* 7zEntry.swift */; };
06FEAD921F54B9CD00AD016E /* EncodingTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06FEAD911F54B9CD00AD016E /* EncodingTree.swift */; };
E6023B1B28F9B60000D6F3DC /* test4_extra_field.gz in Resources */ = {isa = PBXBuildFile; fileRef = E6023B1A28F9B60000D6F3DC /* test4_extra_field.gz */; };
E6023B1D28F9C92200D6F3DC /* GzipHeader+ExtraField.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6023B1C28F9C92200D6F3DC /* GzipHeader+ExtraField.swift */; };
E604F3C22700C75F004BD38A /* test_dict_B5.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E604F3BF2700C75F004BD38A /* test_dict_B5.lz4 */; };
E604F3C32700C75F004BD38A /* test_dict_B5_BD.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E604F3C02700C75F004BD38A /* test_dict_B5_BD.lz4 */; };
E604F3C42700C75F004BD38A /* lz4_dict in Resources */ = {isa = PBXBuildFile; fileRef = E604F3C12700C75F004BD38A /* lz4_dict */; };
Expand Down Expand Up @@ -266,6 +268,7 @@
E6791E1826FD001A003852A9 /* DataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6791E1726FD001A003852A9 /* DataError.swift */; };
E6791E1B26FD0094003852A9 /* LZ4.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6791E1A26FD0094003852A9 /* LZ4.swift */; };
E6791E3326FD05EC003852A9 /* LZ4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6791E3226FD05EC003852A9 /* LZ4Tests.swift */; };
E68DA766290420BC00259CB4 /* test_pax_record_newline.tar in Resources */ = {isa = PBXBuildFile; fileRef = E68DA765290420BC00259CB4 /* test_pax_record_newline.tar */; };
E694694327480EA6009C897A /* TarReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E694694227480EA6009C897A /* TarReader.swift */; };
E6974C5B2701AC2600E06C60 /* test_dict_B5_dictID.lz4 in Resources */ = {isa = PBXBuildFile; fileRef = E6974C5A2701AC2600E06C60 /* test_dict_B5_dictID.lz4 */; };
E69FAC922729ACD900D3C406 /* test_dos_latin_us.zip in Resources */ = {isa = PBXBuildFile; fileRef = E69FAC912729ACD900D3C406 /* test_dos_latin_us.zip */; };
Expand Down Expand Up @@ -497,6 +500,8 @@
06F276DE1F2BAB4900E67335 /* 7zEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 7zEntry.swift; sourceTree = "<group>"; };
06FEAD911F54B9CD00AD016E /* EncodingTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EncodingTree.swift; path = Sources/Common/CodingTree/EncodingTree.swift; sourceTree = SOURCE_ROOT; };
06FED40B1DD7717E0013DFB2 /* BZip2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BZip2.swift; sourceTree = "<group>"; };
E6023B1A28F9B60000D6F3DC /* test4_extra_field.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = test4_extra_field.gz; sourceTree = "<group>"; };
E6023B1C28F9C92200D6F3DC /* GzipHeader+ExtraField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GzipHeader+ExtraField.swift"; sourceTree = "<group>"; };
E604F3BF2700C75F004BD38A /* test_dict_B5.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_dict_B5.lz4; sourceTree = "<group>"; };
E604F3C02700C75F004BD38A /* test_dict_B5_BD.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_dict_B5_BD.lz4; sourceTree = "<group>"; };
E604F3C12700C75F004BD38A /* lz4_dict */ = {isa = PBXFileReference; lastKnownFileType = file; path = lz4_dict; sourceTree = "<group>"; };
Expand Down Expand Up @@ -551,6 +556,7 @@
E6791E1726FD001A003852A9 /* DataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataError.swift; sourceTree = "<group>"; };
E6791E1A26FD0094003852A9 /* LZ4.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LZ4.swift; sourceTree = "<group>"; };
E6791E3226FD05EC003852A9 /* LZ4Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LZ4Tests.swift; sourceTree = "<group>"; };
E68DA765290420BC00259CB4 /* test_pax_record_newline.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = test_pax_record_newline.tar; sourceTree = "<group>"; };
E694694227480EA6009C897A /* TarReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TarReader.swift; sourceTree = "<group>"; };
E6974C5A2701AC2600E06C60 /* test_dict_B5_dictID.lz4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_dict_B5_dictID.lz4; sourceTree = "<group>"; };
E69FAC912729ACD900D3C406 /* test_dos_latin_us.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = test_dos_latin_us.zip; sourceTree = "<group>"; };
Expand Down Expand Up @@ -714,6 +720,7 @@
children = (
063364E21DC52979007E313F /* GzipArchive.swift */,
061C062A1F0E8A1D00832F0C /* GzipHeader.swift */,
E6023B1C28F9C92200D6F3DC /* GzipHeader+ExtraField.swift */,
061C06251F0E8A0300832F0C /* GzipError.swift */,
0686A63F1FA4C18800E89C9E /* FileSystemType+Gzip.swift */,
);
Expand Down Expand Up @@ -875,6 +882,7 @@
06F065BF1FFB763300312A82 /* test2.gz */,
06F065BC1FFB763300312A82 /* test3.gz */,
06F065BB1FFB763300312A82 /* test4.gz */,
E6023B1A28F9B60000D6F3DC /* test4_extra_field.gz */,
06F065B91FFB763300312A82 /* test5.gz */,
06F065BE1FFB763300312A82 /* test6.gz */,
06F065BD1FFB763300312A82 /* test7.gz */,
Expand Down Expand Up @@ -953,6 +961,7 @@
0698B10A2104E11200A7C551 /* test_gnu_inc_format.tar */,
0698B10C2106136500A7C551 /* test_big_num_field.tar */,
0698B10E2106344200A7C551 /* test_negative_mtime.tar */,
E68DA765290420BC00259CB4 /* test_pax_record_newline.tar */,
);
path = TAR;
sourceTree = "<group>";
Expand Down Expand Up @@ -1213,6 +1222,7 @@
E652FEE027009BDD006BC312 /* test5_legacy.lz4 in Resources */,
06F066721FFB763400312A82 /* test7.bz2 in Resources */,
06F0665B1FFB763400312A82 /* test10.lzma in Resources */,
E68DA766290420BC00259CB4 /* test_pax_record_newline.tar in Resources */,
E652FEFE2700A028006BC312 /* test_B7_BD.lz4 in Resources */,
06F0663C1FFB763400312A82 /* test3.xz in Resources */,
06F066591FFB763400312A82 /* test_win.tar in Resources */,
Expand Down Expand Up @@ -1278,6 +1288,7 @@
E652FED6270091B6006BC312 /* test_skippable_frame.lz4 in Resources */,
06F0665A1FFB763400312A82 /* test11.lzma in Resources */,
E652FEE427009BDD006BC312 /* test3_legacy.lz4 in Resources */,
E6023B1B28F9B60000D6F3DC /* test4_extra_field.gz in Resources */,
06F066401FFB763400312A82 /* test_zip_bzip2.zip in Resources */,
06F066461FFB763400312A82 /* test_empty_file.zip in Resources */,
06F066331FFB763400312A82 /* random_file.zlib in Resources */,
Expand Down Expand Up @@ -1406,6 +1417,7 @@
06A9606A1F1E7E0D0078E6D1 /* 7zSubstreamInfo.swift in Sources */,
E6C4150726FE230A00F9D36F /* XxHash32.swift in Sources */,
0694A74D1F7C0DF00023BC99 /* BurrowsWheeler.swift in Sources */,
E6023B1D28F9C92200D6F3DC /* GzipHeader+ExtraField.swift in Sources */,
06CC3FDD1F8AAE8B00BD576D /* MsbBitReader+7z.swift in Sources */,
06A3933B1DE0709300182E12 /* Deflate.swift in Sources */,
06092A1A1FA4CB0300DE9FD5 /* CompressionMethod.swift in Sources */,
Expand Down Expand Up @@ -1516,7 +1528,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CURRENT_PROJECT_VERSION = 87;
CURRENT_PROJECT_VERSION = 88;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
EAGER_LINKING = YES;
Expand Down Expand Up @@ -1601,7 +1613,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CURRENT_PROJECT_VERSION = 87;
CURRENT_PROJECT_VERSION = 88;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
EAGER_LINKING = YES;
Expand Down Expand Up @@ -1666,7 +1678,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 87;
DYLIB_CURRENT_VERSION = 88;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
Expand All @@ -1693,7 +1705,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 87;
DYLIB_CURRENT_VERSION = 88;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
Expand Down
44 changes: 39 additions & 5 deletions Sources/GZip/GzipArchive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,18 @@ public class GzipArchive: Archive {

private static func processMember(_ bitReader: LsbBitReader) throws -> Member {
// Valid GZip archive must contain at least 20 bytes of data (10 for the header, 2 for an empty Deflate block,
// and 8 for checksums).
guard bitReader.bitsLeft >= 20 * 8
// and 8 for checksums). In addition, since GZip format is "byte-oriented" we should ensure that members are
// byte-aligned.
guard bitReader.isAligned && bitReader.bytesLeft >= 20
else { throw GzipError.wrongMagic }

let header = try GzipHeader(bitReader)

let memberData = try Deflate.decompress(bitReader)
bitReader.align()

guard bitReader.bytesLeft >= 8
else { throw GzipError.wrongMagic }
let crc32 = bitReader.uint32()
let isize = bitReader.uint64(fromBytes: 4)
guard UInt64(truncatingIfNeeded: memberData.count) % (UInt64(truncatingIfNeeded: 1) << 32) == isize
Expand All @@ -110,14 +113,20 @@ public class GzipArchive: Archive {
- Parameter isTextFile: Set to true, if the file which will be archived is text file or ASCII-file.
- Parameter osType: Type of the system on which this archive will be created.
- Parameter modificationTime: Last time the file was modified.
- Parameter extraFields: Any extra fields. Note that no extra field is allowed to have second byte of the extra
field (subfield) ID equal to zero. In addition, the length of a field's binary content must be less than
`UInt16.max`, while the total sum of the binary content length of all extra fields plus 4 for each field must also
not exceed `UInt16.max`. See GZip format specification for more details.

- Throws: `GzipError.cannotEncodeISOLatin1` if file name of comment cannot be encoded with ISO-Latin-1 encoding.
- Throws: `GzipError.cannotEncodeISOLatin1` if a file name or a comment cannot be encoded with ISO-Latin-1 encoding
or if the total sum of the binary content length of all extra fields plus 4 for each field exceeds `UInt16.max`.

- Returns: Resulting archive's data.
*/
public static func archive(data: Data, comment: String? = nil, fileName: String? = nil,
writeHeaderCRC: Bool = false, isTextFile: Bool = false,
osType: FileSystemType? = nil, modificationTime: Date? = nil) throws -> Data {
osType: FileSystemType? = nil, modificationTime: Date? = nil,
extraFields: [GzipHeader.ExtraField] = []) throws -> Data {
var flags: UInt8 = 0

var commentData = Data()
Expand Down Expand Up @@ -146,6 +155,10 @@ public class GzipArchive: Archive {
}
}

if !extraFields.isEmpty {
flags |= 1 << 2
}

if writeHeaderCRC {
flags |= 1 << 1
}
Expand All @@ -167,14 +180,35 @@ public class GzipArchive: Archive {
var headerBytes: [UInt8] = [
0x1f, 0x8b, // 'magic' bytes.
8, // Compression method (DEFLATE).
flags // Flags; currently no flags are set.
flags
]
for i in 0..<4 {
headerBytes.append(mtimeBytes[i])
}
headerBytes.append(2) // Extra flags; 2 means that DEFLATE used slowest algorithm.
headerBytes.append(os)

if !extraFields.isEmpty {
let xlen = extraFields.reduce(0) { $0 + 4 + $1.bytes.count }
guard xlen <= UInt16.max
else { throw GzipError.cannotEncodeISOLatin1 }
headerBytes.append((xlen & 0xFF).toUInt8())
headerBytes.append(((xlen >> 8) & 0xFF).toUInt8())

for extraField in extraFields {
headerBytes.append(extraField.si1)
headerBytes.append(extraField.si2)

let len = extraField.bytes.count
headerBytes.append((len & 0xFF).toUInt8())
headerBytes.append(((len >> 8) & 0xFF).toUInt8())

for byte in extraField.bytes {
headerBytes.append(byte)
}
}
}

var outData = Data(headerBytes)

outData.append(fileNameData)
Expand Down
29 changes: 29 additions & 0 deletions Sources/GZip/GzipHeader+ExtraField.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2022 Timofey Solomko
// Licensed under MIT License
//
// See LICENSE for license information

extension GzipHeader {

/// Represents an extra field in the header of a GZip archive.
public struct ExtraField {

/// First byte of the extra field (subfield) ID.
public let si1: UInt8

/// Second byte of the extra field (subfield) ID.
public let si2: UInt8

/// Binary content of the extra field.
public var bytes: [UInt8]

/// Initializes and extra field with the specified extra field (subfield) ID bytes and its binary content.
public init(_ si1: UInt8, _ si2: UInt8, _ bytes: [UInt8]) {
self.si1 = si1
self.si2 = si2
self.bytes = bytes
}

}

}
Loading

0 comments on commit 6fe73cb

Please sign in to comment.