From 8b10dd5c0cf3734693b3dae34bbfa63b507a0e67 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Fri, 5 Jun 2026 12:56:59 +0800 Subject: [PATCH 1/3] [GZip] Add null terminator as a zero byte instead of character Fixes #66. --- Sources/GZip/GzipArchive.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Sources/GZip/GzipArchive.swift b/Sources/GZip/GzipArchive.swift index 8b09dd0a..e50292f9 100644 --- a/Sources/GZip/GzipArchive.swift +++ b/Sources/GZip/GzipArchive.swift @@ -130,29 +130,29 @@ public class GzipArchive: Archive { var flags: UInt8 = 0 var commentData = Data() - if var comment = comment { + if let comment = comment { flags |= 1 << 4 - if comment.last != "\u{00}" { - comment.append("\u{00}") - } if let data = comment.data(using: .isoLatin1) { commentData = data } else { throw GzipError.cannotEncodeISOLatin1 } + if commentData.last != 0 { + commentData.append(0) + } } var fileNameData = Data() - if var fileName = fileName { + if let fileName = fileName { flags |= 1 << 3 - if fileName.last != "\u{00}" { - fileName.append("\u{00}") - } if let data = fileName.data(using: .isoLatin1) { fileNameData = data } else { throw GzipError.cannotEncodeISOLatin1 } + if fileNameData.last != 0 { + fileNameData.append(0) + } } if !extraFields.isEmpty { From e75d4bb167527586977d4c8f94b1244f574dcf58 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Fri, 5 Jun 2026 13:51:43 +0800 Subject: [PATCH 2/3] [ZIP] Decode CP437 manually on non-Darwin platforms with Swift earlier than 6.2 Fixes #65. --- Sources/ZIP/LittleEndianByteReader+Zip.swift | 50 ++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/Sources/ZIP/LittleEndianByteReader+Zip.swift b/Sources/ZIP/LittleEndianByteReader+Zip.swift index e5f8b1da..bb97fc8e 100644 --- a/Sources/ZIP/LittleEndianByteReader+Zip.swift +++ b/Sources/ZIP/LittleEndianByteReader+Zip.swift @@ -17,7 +17,12 @@ extension LittleEndianByteReader { return String(data: stringData, encoding: .utf8) } if String.cp437Available && !stringData.needsUtf8() { - return String(data: stringData, encoding: String.cp437Encoding) + #if (os(Linux) || os(Windows)) && (compiler(<6.2)) + return stringData.decodeCp437() + #else + return String(data: stringData, encoding: String.cp437Encoding) + #endif + } else { return String(data: stringData, encoding: .utf8) } @@ -34,13 +39,52 @@ fileprivate extension String { // compatible with UTF-8, as CP437 contains codes in the 80-FF range which are not valid UTF-8 codes. // In any case, we are constrained to the implementation provided by Foundation, which currently treats them as // control characters. - static let cp437Encoding = String.Encoding(rawValue: 0x80000400) - static let cp437Available = String.availableStringEncodings.contains(cp437Encoding) + #if (os(Linux) || os(Windows)) && (compiler(<6.2)) + /// CP437 is available on all platforms where decoding is performed manually. + static let cp437Available = true + static let cp437UnicodeScalars = [0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, + 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, 0x25BA, 0x25C4, 0x2195, 0x203C, + 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, + 0x25B2, 0x25BC, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, + 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, + 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, + 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, + 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302, 0x00C7, 0x00FC, + 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, + 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, + 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, + 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, + 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, + 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, + 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, + 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, + 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, + 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0].map { UnicodeScalar($0)! } + #else + static let cp437Available = String.availableStringEncodings.contains(cp437Encoding) + static let cp437Encoding = String.Encoding(rawValue: 0x80000400) + #endif } fileprivate extension Data { + #if (os(Linux) || os(Windows)) && (compiler(<6.2)) + func decodeCp437() -> String { + var out = "" + out.unicodeScalars.append(contentsOf: self.toByteArray().map { String.cp437UnicodeScalars[$0.toInt()] }) + return out + } + #endif + func needsUtf8() -> Bool { // UTF-8 can have BOM. if self.count >= 3 { From 56267f0e14c582f991ee3cc725fbe03b09ac5e3a Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Sat, 13 Jun 2026 16:18:50 +0800 Subject: [PATCH 3/3] Prepare for 4.9.1 release --- .jazzy.yaml | 4 ++-- CHANGELOG.md | 5 +++++ SWCompression.xcodeproj/SWCompression.plist | 4 ++-- SWCompression.xcodeproj/TestSWCompression.plist | 4 ++-- SWCompression.xcodeproj/project.pbxproj | 8 ++++---- Sources/swcomp/main.swift | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.jazzy.yaml b/.jazzy.yaml index 96f38b96..8f97ec7b 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.9.0 +module_version: 4.9.1 copyright: '© 2026 Timofey Solomko' readme: README.md github_url: https://github.com/tsolomko/SWCompression -github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.9.0 +github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.9.1 theme: fullwidth custom_categories: diff --git a/CHANGELOG.md b/CHANGELOG.md index 008c23a9..617a5912 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 4.9.1 + +- Fixed an issue where `GzipError.cannotEncodeISOLatin1` is incorrectly thrown on non-Darwin platforms with Swift 6.0. +- Fixed an issue where `ZipError.wrongTextField` is incorrectly thrown on non-Darwin platforms with Swift 6.0 and 6.1. + ## 4.9.0 - Swift versions from 5.3 up to and including 5.8 are no longer supported. diff --git a/SWCompression.xcodeproj/SWCompression.plist b/SWCompression.xcodeproj/SWCompression.plist index 6f786191..01cb6f2b 100644 --- a/SWCompression.xcodeproj/SWCompression.plist +++ b/SWCompression.xcodeproj/SWCompression.plist @@ -15,9 +15,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 4.9.0 + 4.9.1 CFBundleVersion - 93 + 94 NSHumanReadableCopyright Copyright © 2026 Timofey Solomko diff --git a/SWCompression.xcodeproj/TestSWCompression.plist b/SWCompression.xcodeproj/TestSWCompression.plist index 2de87aba..65e53524 100644 --- a/SWCompression.xcodeproj/TestSWCompression.plist +++ b/SWCompression.xcodeproj/TestSWCompression.plist @@ -15,8 +15,8 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 4.9.0 + 4.9.1 CFBundleVersion - 93 + 94 diff --git a/SWCompression.xcodeproj/project.pbxproj b/SWCompression.xcodeproj/project.pbxproj index 3e3f8614..115bb45f 100644 --- a/SWCompression.xcodeproj/project.pbxproj +++ b/SWCompression.xcodeproj/project.pbxproj @@ -1566,7 +1566,7 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 93; + CURRENT_PROJECT_VERSION = 94; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; EAGER_LINKING = YES; @@ -1620,7 +1620,7 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 93; + CURRENT_PROJECT_VERSION = 94; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; EAGER_LINKING = YES; @@ -1653,7 +1653,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 93; + DYLIB_CURRENT_VERSION = 94; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist; @@ -1672,7 +1672,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 93; + DYLIB_CURRENT_VERSION = 94; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist; diff --git a/Sources/swcomp/main.swift b/Sources/swcomp/main.swift index 71edf6d1..59161f39 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.9.0" +let _SWC_VERSION = "4.9.1" let cli = CLI(name: "swcomp", version: _SWC_VERSION, description: """