diff --git a/.jazzy.yaml b/.jazzy.yaml
index f556b310..05c7932a 100644
--- a/.jazzy.yaml
+++ b/.jazzy.yaml
@@ -3,11 +3,11 @@ sourcekitten_sourcefile: docs.json
clean: false
author: Timofey Solomko
module: SWCompression
-module_version: 4.8.3
+module_version: 4.8.4
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.3
+github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.8.4
theme: fullwidth
custom_categories:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1245227a..f6f8189a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 4.8.4
+
+- Fixed an issue where in some cases BZip2 compression would produce incorrect output.
+- `TarReader` methods now always return `nil` after reaching the end of a TAR container.
+
## 4.8.3
- There are now minimum deployment targets specified in Swift Package Manager manifest.
diff --git a/SWCompression.podspec b/SWCompression.podspec
index 351a2daf..b9425120 100644
--- a/SWCompression.podspec
+++ b/SWCompression.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "SWCompression"
- s.version = "4.8.3"
+ s.version = "4.8.4"
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."
diff --git a/SWCompression.xcodeproj/SWCompression.plist b/SWCompression.xcodeproj/SWCompression.plist
index 327e7b10..f167faf3 100644
--- a/SWCompression.xcodeproj/SWCompression.plist
+++ b/SWCompression.xcodeproj/SWCompression.plist
@@ -15,9 +15,9 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 4.8.3
+ 4.8.4
CFBundleVersion
- 88
+ 89
NSHumanReadableCopyright
Copyright © 2022 Timofey Solomko
diff --git a/SWCompression.xcodeproj/TestSWCompression.plist b/SWCompression.xcodeproj/TestSWCompression.plist
index f40b8805..0012bd54 100644
--- a/SWCompression.xcodeproj/TestSWCompression.plist
+++ b/SWCompression.xcodeproj/TestSWCompression.plist
@@ -15,8 +15,8 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 4.8.3
+ 4.8.4
CFBundleVersion
- 88
+ 89
diff --git a/SWCompression.xcodeproj/project.pbxproj b/SWCompression.xcodeproj/project.pbxproj
index b83aea5c..1e33abfb 100644
--- a/SWCompression.xcodeproj/project.pbxproj
+++ b/SWCompression.xcodeproj/project.pbxproj
@@ -1147,7 +1147,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
- LastUpgradeCheck = 1400;
+ LastUpgradeCheck = 1420;
ORGANIZATIONNAME = "Timofey Solomko";
TargetAttributes = {
06BE1AC71DB410F100EE0F59 = {
@@ -1528,7 +1528,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CURRENT_PROJECT_VERSION = 88;
+ CURRENT_PROJECT_VERSION = 89;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
EAGER_LINKING = YES;
@@ -1613,7 +1613,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CURRENT_PROJECT_VERSION = 88;
+ CURRENT_PROJECT_VERSION = 89;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
EAGER_LINKING = YES;
@@ -1678,7 +1678,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 88;
+ DYLIB_CURRENT_VERSION = 89;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -1705,7 +1705,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 88;
+ DYLIB_CURRENT_VERSION = 89;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
diff --git a/SWCompression.xcodeproj/xcshareddata/xcschemes/SWCompression.xcscheme b/SWCompression.xcodeproj/xcshareddata/xcschemes/SWCompression.xcscheme
index 62668c55..aea7883f 100644
--- a/SWCompression.xcodeproj/xcshareddata/xcschemes/SWCompression.xcscheme
+++ b/SWCompression.xcodeproj/xcshareddata/xcschemes/SWCompression.xcscheme
@@ -1,6 +1,6 @@
TarEntry? {
let headerData = try getData(size: 512)
@@ -94,6 +90,10 @@ public struct TarReader {
if try getData(size: 512) == Data(count: 512) {
return nil
} else {
+ // In this case we have a zero-filled block immediately followed by a non-zero-filled block which do not
+ // 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)
}
} else if headerData.count < 512 {
@@ -162,12 +162,18 @@ public struct TarReader {
private func getData(size: Int) throws -> Data {
assert(size >= 0, "TarReader.getData(size:): negative size.")
- guard size > 0
- else { return Data() }
if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
- guard let chunkData = try handle.read(upToCount: size)
- else { throw DataError.truncated }
- return chunkData
+ // 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)
diff --git a/Sources/swcomp/main.swift b/Sources/swcomp/main.swift
index e023b90b..3f617ca9 100644
--- a/Sources/swcomp/main.swift
+++ b/Sources/swcomp/main.swift
@@ -7,7 +7,7 @@ import Foundation
import SWCompression
import SwiftCLI
-let _SWC_VERSION = "4.8.3"
+let _SWC_VERSION = "4.8.4"
let cli = CLI(name: "swcomp", version: _SWC_VERSION,
description: """
diff --git a/Tests/BZip2CompressionTests.swift b/Tests/BZip2CompressionTests.swift
index b65fb87b..45218f93 100644
--- a/Tests/BZip2CompressionTests.swift
+++ b/Tests/BZip2CompressionTests.swift
@@ -84,4 +84,14 @@ class BZip2CompressionTests: XCTestCase {
try answerTest("test9")
}
+ func testBurrowsWheelerRoundtrip() throws {
+ // This test is inspired by the reported issue #38 that uncovered a mistake with a pointer variable in BWT.
+ // "1"s can be anything (except zero), but it must be the same byte value in all places.
+ // Two consecutive zeros in the middle seem to be crucial for some reason.
+ let testData = Data([0, 1, 0, 1, 0, 0, 1, 0, 1])
+ let compressedData = BZip2.compress(data: testData)
+ let redecompressedData = try BZip2.decompress(data: compressedData)
+ XCTAssertEqual(redecompressedData, testData)
+ }
+
}
diff --git a/Tests/TarReaderTests.swift b/Tests/TarReaderTests.swift
index e16e7107..ddc87d8d 100644
--- a/Tests/TarReaderTests.swift
+++ b/Tests/TarReaderTests.swift
@@ -44,7 +44,6 @@ class TarReaderTests: XCTestCase {
}
}
XCTAssertEqual(entriesCount, 1)
-
try testHandle.closeCompat()
}
@@ -104,6 +103,7 @@ class TarReaderTests: XCTestCase {
}
}
XCTAssertEqual(entriesCount, 1)
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
}
@@ -125,6 +125,7 @@ class TarReaderTests: XCTestCase {
}
}
XCTAssertEqual(entriesCount, 6)
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
}
@@ -158,6 +159,7 @@ class TarReaderTests: XCTestCase {
XCTAssertNil(entry!.info.comment)
XCTAssertEqual(entry!.data, "Hello, Windows!".data(using: .utf8))
}
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
@@ -178,6 +180,7 @@ class TarReaderTests: XCTestCase {
XCTAssertEqual(entry!.data, Data())
}
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
@@ -197,6 +200,7 @@ class TarReaderTests: XCTestCase {
XCTAssertNil(entry!.info.comment)
XCTAssertNil(entry!.data)
}
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
@@ -217,8 +221,8 @@ class TarReaderTests: XCTestCase {
XCTAssertEqual(entry!.info.permissions, Permissions(rawValue: 493))
XCTAssertNil(entry!.info.comment)
XCTAssertNil(entry!.data)
-
}
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
@@ -253,6 +257,7 @@ class TarReaderTests: XCTestCase {
XCTAssertEqual(entry!.data, answerData)
}
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
@@ -273,6 +278,7 @@ class TarReaderTests: XCTestCase {
XCTAssertEqual(entry!.data, answerData)
}
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
@@ -297,6 +303,7 @@ class TarReaderTests: XCTestCase {
}
}
XCTAssertEqual(entriesCount, 3)
+ XCTAssertNil(try reader.read())
try testHandle.closeCompat()
}
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 0b606032..46c424be 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -46,7 +46,7 @@ stages:
UTILS_PW_XCF_FLAG: '--xcf'
macosSwift57:
imageName: 'macOS-12'
- DEVELOPER_DIR: '/Applications/Xcode_14.0.1.app'
+ DEVELOPER_DIR: '/Applications/Xcode_14.2.app'
WATCHOS_ACTIONS: 'clean test'
WATCHOS_SIMULATOR: 'Apple Watch Series 6 (44mm)'
UTILS_PW_XCF_FLAG: '--xcf'
@@ -108,7 +108,7 @@ stages:
containerImage: 'swift:5.6.3-focal'
linuxSwift57:
imageName: 'ubuntu-20.04'
- containerImage: 'swift:5.7-focal'
+ containerImage: 'swift:5.7.2-focal'
pool:
vmImage: $(imageName)
container: $[ variables['containerImage'] ]
@@ -139,7 +139,7 @@ stages:
SWIFT_DEV_PATH: 'C:\Library\Swift-development\bin'
windowsSwift57:
imageName: 'windows-2019'
- SWIFT_VERSION: '5.7'
+ SWIFT_VERSION: '5.7.2'
ICU_PATH: 'C:\Program Files\swift\icu-69.1\usr\bin'
SWIFT_DEV_PATH: 'C:\Program Files\swift\runtime-development\usr\bin'
pool:
@@ -174,7 +174,7 @@ stages:
pool:
vmImage: 'macOS-12'
variables:
- DEVELOPER_DIR: '/Applications/Xcode_14.0.1.app'
+ DEVELOPER_DIR: '/Applications/Xcode_14.2.app'
steps:
- script: |
set -e -o xtrace