[Deflate][Huffman] Filter out zero code lengths only during code construction

This should prevent crashes described in issue #57.
This commit is contained in:
Timofey Solomko
2026-03-01 20:35:21 +08:00
parent 7e6a9fd42c
commit d8c22c55da
4 changed files with 5 additions and 25 deletions
-4
View File
@@ -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 */; };
@@ -371,7 +370,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>"; };
@@ -648,7 +646,6 @@
children = (
061FCE251DBCC4BE0052F7BE /* Deflate.swift */,
06CDFC9D1F111D2600292758 /* Deflate+Compress.swift */,
06912BD11F5C8F3D0070BB60 /* Deflate+Lengths.swift */,
0631CB051F81109E00A2E0AB /* Deflate+Constants.swift */,
06CDFCA71F111D9700292758 /* DeflateError.swift */,
);
@@ -1446,7 +1443,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 */,
+1 -3
View File
@@ -12,7 +12,6 @@ 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]) -> 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
-18
View File
@@ -1,18 +0,0 @@
// Copyright (c) 2026 Timofey Solomko
// Licensed under MIT License
//
// See LICENSE for license information
// 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
}
}
+4
View File
@@ -248,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) })
}
}