From 0c2f117d31fe65179d264d50a1f64d22cd90d22b Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Thu, 13 May 2021 16:05:37 +0300 Subject: [PATCH 1/9] CI: Allow linux build with Swift 5.4 to fail --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2feceae2..e47ec207 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ git: depth: 1 submodules: false jobs: + allow_failures: + # There is an issue with Swift 5.4 on Linux which fails the build. See https://bugs.swift.org/browse/SR-14594. + env: + - SWIFT_VERSION=5.4 include: # We test only building using SPM with Swift 4.2 on macos since Carthage doesn't support multiple Swift language versions. - stage: test From dd35247f18ba68b08aead3955ff90a6bed9d6f0e Mon Sep 17 00:00:00 2001 From: Eric Thorpe Date: Thu, 13 May 2021 16:15:49 +1000 Subject: [PATCH 2/9] [ZIP] Fix CP437 support on Windows (cherry picked from commit 69eb11437a99e317d2025bb8d6157ac134bd765c) --- Sources/ZIP/ByteReader+Zip.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/ZIP/ByteReader+Zip.swift b/Sources/ZIP/ByteReader+Zip.swift index 95faf57e..cd4a9637 100644 --- a/Sources/ZIP/ByteReader+Zip.swift +++ b/Sources/ZIP/ByteReader+Zip.swift @@ -21,8 +21,12 @@ extension ByteReader { return String(data: stringData, encoding: .utf8) } if String.cp437Available && !stringData.needsUtf8() { + #if os(Windows) + return String(data: stringData, encoding: String.cp437Encoding) + #else return String(data: stringData, encoding: String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(String.cp437Encoding))) + #endif } else { return String(data: stringData, encoding: .utf8) } @@ -39,6 +43,10 @@ fileprivate extension String { static let cp437Encoding: CFStringEncoding = UInt32(truncatingIfNeeded: UInt(kCFStringEncodingDOSLatinUS)) #endif static let cp437Available: Bool = CFStringIsEncodingAvailable(cp437Encoding) + #elseif os(Windows) + // "Latin-US (DOS)" CP437-2147483120 + static let cp437Encoding = String.Encoding(rawValue: 0x80000400) + static let cp437Available = String.availableStringEncodings.contains(cp437Encoding) #else static let cp437Encoding = CFStringEncoding(CFStringEncodings.dosLatinUS.rawValue) static let cp437Available = CFStringIsEncodingAvailable(cp437Encoding) From b5e98b66cde07b9dec88f3139ec165514d35b485 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Mon, 18 Jan 2021 16:00:22 +0200 Subject: [PATCH 3/9] [BZip2] Explain zero RLE in the comments (cherry picked from commit 1f7a5352a798fec9d9cad94fc3ba26215fab3b4e) --- Sources/BZip2/BZip2+Compress.swift | 8 +++++--- Sources/ZIP/ZipLocalHeader.swift | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/BZip2/BZip2+Compress.swift b/Sources/BZip2/BZip2+Compress.swift index 6222bd9a..96af5b3d 100644 --- a/Sources/BZip2/BZip2+Compress.swift +++ b/Sources/BZip2/BZip2+Compress.swift @@ -268,6 +268,9 @@ extension BZip2: CompressionAlgorithm { lengthOfZerosRun += 1 } if (byte == 0 && i == array.count - 1) || byte != 0 { + // Runs of zeros are represented using a modified binary system with two "digits", RUNA and RUNB, where + // RUNA represents 1 and RUNB represents 2 (whereas in the usual base-2 system the digits are 0 and 1). + // (We don't need a digit for zero since we can't get a run of length 0 by definition.) if lengthOfZerosRun > 0 { let digitsNumber = Int(floor(log2(Double(lengthOfZerosRun) + 1))) var remainder = lengthOfZerosRun @@ -285,16 +288,15 @@ extension BZip2: CompressionAlgorithm { } } if byte != 0 { + // We add one, because 1 is used as RUNB. let newSymbol = byte + 1 - // We add one because, 1 is used as RUNB. - // We don't add two instead, because 0 is never encountered as separate symbol, without RUNA meaning. out.append(newSymbol) if newSymbol > maxSymbol { maxSymbol = newSymbol } } } - // Add 'end of stream' symbol. + // Add the 'end of stream' symbol. out.append(maxSymbol + 1) return (out, maxSymbol) } diff --git a/Sources/ZIP/ZipLocalHeader.swift b/Sources/ZIP/ZipLocalHeader.swift index 327a3f96..e7be7086 100644 --- a/Sources/ZIP/ZipLocalHeader.swift +++ b/Sources/ZIP/ZipLocalHeader.swift @@ -75,7 +75,7 @@ struct ZipLocalHeader { case 0x0001: // Zip64 // Zip64 extra field is a special case, because it requires knowledge about local header fields, // in particular, uncompressed and compressed sizes. - // In local header both uncompressed size and compressed size fields are required. + // In the local header both uncompressed size and compressed size fields are required. self.uncompSize = byteReader.uint64() self.compSize = byteReader.uint64() self.zip64FieldsArePresent = true From d2f45d0d48212c3bd6aabe407d6ea886b87c6264 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Sat, 22 May 2021 23:32:23 +0300 Subject: [PATCH 4/9] Upgrade BBD dependency to 1.4.4 --- Cartfile | 2 +- Package.swift | 2 +- SWCompression.podspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cartfile b/Cartfile index 934643de..2068ee10 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "tsolomko/BitByteData" ~> 1.4.3 +github "tsolomko/BitByteData" ~> 1.4.4 diff --git a/Package.swift b/Package.swift index d957f93e..769ea9f1 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,7 @@ let package = Package( // .package(url: "https://github.com/jakeheis/SwiftCLI", // from: "5.2.0"), .package(url: "https://github.com/tsolomko/BitByteData", - from: "1.4.3"), + from: "1.4.4"), ], targets: [ // SWCOMP: Uncomment the lines below to build swcomp example program. diff --git a/SWCompression.podspec b/SWCompression.podspec index 719ef789..ad182ffa 100644 --- a/SWCompression.podspec +++ b/SWCompression.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.swift_versions = ["4", "5"] - s.dependency "BitByteData", "~> 1.4.3" + s.dependency "BitByteData", "~> 1.4.4" s.subspec "Deflate" do |sp| sp.source_files = "Sources/{Deflate/*,Common/*,Common/CodingTree/*}.swift" From 5f7141fd78b418f6e2ce526d2d5dea0809198f25 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Sat, 22 May 2021 23:34:31 +0300 Subject: [PATCH 5/9] Replace Int arrays in EncodingTree with a new CodingIndex struct The hope is that this will improve memory layout/management, and, consequently, improve performance (slightly). --- Sources/Common/CodingTree/EncodingTree.swift | 21 +++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Sources/Common/CodingTree/EncodingTree.swift b/Sources/Common/CodingTree/EncodingTree.swift index a0fc7f8f..5fe0a7bb 100644 --- a/Sources/Common/CodingTree/EncodingTree.swift +++ b/Sources/Common/CodingTree/EncodingTree.swift @@ -6,22 +6,29 @@ import Foundation import BitByteData +fileprivate struct CodingIndex { + + let treeCode: Int + let bitSize: Int + +} + final class EncodingTree { private let bitWriter: BitWriter - private let codingIndices: [[Int]] + private let codingIndices: [CodingIndex] init(codes: [Code], _ bitWriter: BitWriter, reverseCodes: Bool = false) { self.bitWriter = bitWriter - var codingIndices = Array(repeating: [-1, -1], count: codes.count) + var codingIndices = Array(repeating: CodingIndex(treeCode: -1, bitSize: -1), count: codes.count) for code in codes { // Codes have already been reversed. // TODO: This assumption may be only correct for Huffman codes. let treeCode = reverseCodes ? code.code : code.code.reversed(bits: code.bits) - codingIndices[code.symbol] = [treeCode, code.bits] + codingIndices[code.symbol] = CodingIndex(treeCode: treeCode, bitSize: code.bits) } self.codingIndices = codingIndices @@ -33,10 +40,10 @@ final class EncodingTree { let codingIndex = self.codingIndices[symbol] - guard codingIndex[0] > -1 + guard codingIndex.treeCode > -1 else { fatalError("Symbol is not found.") } - self.bitWriter.write(number: codingIndex[0], bitsCount: codingIndex[1]) + self.bitWriter.write(number: codingIndex.treeCode, bitsCount: codingIndex.bitSize) } func bitSize(for stats: [Int]) -> Int { @@ -45,10 +52,10 @@ final class EncodingTree { guard symbol < self.codingIndices.count else { fatalError("Symbol is not found.") } let codingIndex = self.codingIndices[symbol] - guard codingIndex[0] > -1 + guard codingIndex.treeCode > -1 else { fatalError("Symbol is not found.") } - totalSize += count * codingIndex[1] + totalSize += count * codingIndex.bitSize } return totalSize } From 73dec6720eeac98bae5283ae4e64d0331cf77ef6 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Sat, 22 May 2021 23:35:03 +0300 Subject: [PATCH 6/9] [BZip2] Combine MTF and RLE steps in compression --- Sources/BZip2/BZip2+Compress.swift | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Sources/BZip2/BZip2+Compress.swift b/Sources/BZip2/BZip2+Compress.swift index 96af5b3d..d46d764e 100644 --- a/Sources/BZip2/BZip2+Compress.swift +++ b/Sources/BZip2/BZip2+Compress.swift @@ -79,10 +79,8 @@ extension BZip2: CompressionAlgorithm { (out, pointer) = BurrowsWheeler.transform(bytes: out) let usedBytes = Set(out).sorted() - out = mtf(out, characters: usedBytes) - var maxSymbol = 0 - (out, maxSymbol) = rleOfMtf(out) + (out, maxSymbol) = mtfRle(out, characters: usedBytes) // First, we analyze data and create Huffman trees and selectors. // Then we will perform encoding itself. @@ -258,12 +256,16 @@ extension BZip2: CompressionAlgorithm { return out } - private static func rleOfMtf(_ array: [Int]) -> ([Int], Int) { + private static func mtfRle(_ array: [Int], characters: [Int]) -> ([Int], Int) { var out = [Int]() + /// Mutable copy of `characters`. + var dictionary = characters var lengthOfZerosRun = 0 var maxSymbol = 1 for i in 0.. Date: Sat, 22 May 2021 23:42:58 +0300 Subject: [PATCH 7/9] Remove markdown and swift linters config files --- .markdownlint.json | 7 ------- .swiftlint.yml | 33 --------------------------------- 2 files changed, 40 deletions(-) delete mode 100644 .markdownlint.json delete mode 100644 .swiftlint.yml diff --git a/.markdownlint.json b/.markdownlint.json deleted file mode 100644 index f520e6d4..00000000 --- a/.markdownlint.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "MD007": { "indent": 4 }, - "MD013": { "line_length": 120 }, - "MD024": false, - "MD026": { "punctuation": ".,;:!"}, - "MD029": { "style": "ordered" } -} \ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml deleted file mode 100644 index 13f4fa2f..00000000 --- a/.swiftlint.yml +++ /dev/null @@ -1,33 +0,0 @@ -excluded: - - .build/ - - Package.swift - - Carthage/ -disabled_rules: - - cyclomatic_complexity - - file_length - - for_where - - function_body_length - - identifier_name - - type_body_length -opt_in_rules: - - array_init - - block_based_kvo - - conditional_returns_on_newline - - contains_over_first_not_nil - - discouraged_direct_init - - discouraged_object_literal - - discouraged_optional_boolean - - explicit_init - - fatal_error_message - - first_where - - implicit_return - - implicitly_unwrapped_optional - - joined_default_parameter - - literal_expression_end_indentation - - operator_usage_whitespace - - pattern_matching_keywords - - redundant_nil_coalescing - - single_test_class - - sorted_first_last - - switch_case_on_newline - - trailing_closure From 8b3c524bf48e73f777485efdaa396b0ebad52897 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Sat, 22 May 2021 23:47:29 +0300 Subject: [PATCH 8/9] Upgrade version of BBD dependency for SPM 4.2 as well --- Package@swift-4.2.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package@swift-4.2.swift b/Package@swift-4.2.swift index 33ca19c7..d81037fa 100644 --- a/Package@swift-4.2.swift +++ b/Package@swift-4.2.swift @@ -13,7 +13,7 @@ let package = Package( // .package(url: "https://github.com/jakeheis/SwiftCLI", // from: "5.2.0"), .package(url: "https://github.com/tsolomko/BitByteData", - from: "1.4.3"), + from: "1.4.4"), ], targets: [ // SWCOMP: Uncomment the lines below to build swcomp example program. From 233e0c8042871d395955985e1927327b92cb593c Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Sat, 22 May 2021 23:48:27 +0300 Subject: [PATCH 9/9] Prepare for 4.5.10 release --- .jazzy.yaml | 4 ++-- CHANGELOG.md | 6 ++++++ SWCompression.podspec | 2 +- SWCompression.xcodeproj/SWCompression.plist | 4 ++-- SWCompression.xcodeproj/TestSWCompression.plist | 4 ++-- SWCompression.xcodeproj/project.pbxproj | 8 ++++---- Sources/swcomp/main.swift | 2 +- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.jazzy.yaml b/.jazzy.yaml index 2a57f2b1..2a023beb 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -3,11 +3,11 @@ sourcekitten_sourcefile: docs.json clean: true author: Timofey Solomko module: SWCompression -module_version: 4.5.9 +module_version: 4.5.10 copyright: '© 2021 Timofey Solomko' readme: README.md github_url: https://github.com/tsolomko/SWCompression -github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.5.9 +github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.5.10 theme: fullwidth custom_categories: diff --git a/CHANGELOG.md b/CHANGELOG.md index 989429ba..d28dce1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 4.5.10 + +- Fixed compilation issues on Windows (PR #22 by @trametheka). +- Performed minor optimizations to BZip2 and Deflate compression functionality. +- Increased the lowest required version of BitByteData dependency to 1.4.4. + ## 4.5.9 - Improved performance of LZMA/LZMA2 and, consequently, of XZ. diff --git a/SWCompression.podspec b/SWCompression.podspec index ad182ffa..d02424bd 100644 --- a/SWCompression.podspec +++ b/SWCompression.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "SWCompression" - s.version = "4.5.9" + s.version = "4.5.10" 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 ccfd150a..dc55faec 100644 --- a/SWCompression.xcodeproj/SWCompression.plist +++ b/SWCompression.xcodeproj/SWCompression.plist @@ -15,9 +15,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 4.5.9 + 4.5.10 CFBundleVersion - 76 + 77 NSHumanReadableCopyright Copyright © 2021 Timofey Solomko diff --git a/SWCompression.xcodeproj/TestSWCompression.plist b/SWCompression.xcodeproj/TestSWCompression.plist index fbfd44a0..1b2400fd 100644 --- a/SWCompression.xcodeproj/TestSWCompression.plist +++ b/SWCompression.xcodeproj/TestSWCompression.plist @@ -15,8 +15,8 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 4.5.9 + 4.5.10 CFBundleVersion - 76 + 77 diff --git a/SWCompression.xcodeproj/project.pbxproj b/SWCompression.xcodeproj/project.pbxproj index e445fdd4..7bcbf9eb 100644 --- a/SWCompression.xcodeproj/project.pbxproj +++ b/SWCompression.xcodeproj/project.pbxproj @@ -1258,7 +1258,7 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -1339,7 +1339,7 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; "FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = ( @@ -1400,7 +1400,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1427,7 +1427,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/Sources/swcomp/main.swift b/Sources/swcomp/main.swift index 3cf41ef9..3e8b1885 100644 --- a/Sources/swcomp/main.swift +++ b/Sources/swcomp/main.swift @@ -7,7 +7,7 @@ import Foundation import SWCompression import SwiftCLI -let cli = CLI(name: "swcomp", version: "4.5.9", +let cli = CLI(name: "swcomp", version: "4.5.10", description: """ swcomp - small command-line client for SWCompression framework. Serves as an example of SWCompression usage.