Skip to content

Commit

Permalink
break up LZ77.DecompressionError into subtypes, and objectify the LZ7…
Browse files Browse the repository at this point in the history
…7.MRC32 type
  • Loading branch information
tayloraswift committed Jan 30, 2024
1 parent 60f7347 commit 9567397
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 117 deletions.
36 changes: 17 additions & 19 deletions Sources/LZ77/Deflator/LZ77.Deflator.In.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,25 @@ extension LZ77.Deflator
var storage:ManagedBuffer<Void, UInt8>

private
var integral:(single:UInt32, double:UInt32)
var integral:LZ77.MRC32
}
}
extension LZ77.Deflator.In
{
init()
{
var capacity:Int = 0
var capacity:Int = 0
self.storage = .create(minimumCapacity: 0)
{
capacity = $0.capacity
return ()
}
// self.startIndex = 0
// self.endIndex = 0
self.startIndex = 4
self.endIndex = 4
self.capacity = capacity
self.startIndex = 4
self.endIndex = 4
self.capacity = capacity

self.integral = (1, 0)
self.integral = .init()
}

var count:Int
Expand Down Expand Up @@ -160,10 +159,11 @@ extension LZ77.Deflator.In
// rebase without reallocating
self.storage.withUnsafeMutablePointerToElements
{
self.integral = LZ77.MRC32.update(self.integral,
from: $0 + 4, count: self.startIndex - 4)
$0.update( from: $0 - 4 + self.startIndex, count: self.count + 4)
self.endIndex = 4 + self.count
self.integral.update(from: $0 + 4, count: self.startIndex - 4)

$0.update(from: $0 - 4 + self.startIndex, count: self.count + 4)

self.endIndex = 4 + self.count
self.startIndex = 4
}
}
Expand All @@ -181,11 +181,11 @@ extension LZ77.Deflator.In

new.withUnsafeMutablePointerToElements
{
self.integral = LZ77.MRC32.update(self.integral,
from: body + 4, count: self.startIndex - 4)
$0.update( from: body - 4 + self.startIndex, count: self.count + 4)
self.integral.update(from: body + 4, count: self.startIndex - 4)

$0.update(from: body - 4 + self.startIndex, count: self.count + 4)
}
self.endIndex = 4 + self.count
self.endIndex = 4 + self.count
self.startIndex = 4
return new
}
Expand All @@ -198,10 +198,8 @@ extension LZ77.Deflator.In
// everything still in the storage buffer has not yet been integrated
self.storage.withUnsafeMutablePointerToElements
{
let (single, double):(UInt32, UInt32) =
//LZ77.MRC32.update(self.integral, from: $0, count: self.endIndex)
LZ77.MRC32.update(self.integral, from: $0 + 4, count: self.endIndex - 4)
return double << 16 | single
self.integral.update(from: $0 + 4, count: self.endIndex - 4)
return self.integral.checksum
}
}

Expand Down
20 changes: 0 additions & 20 deletions Sources/LZ77/Inflator/LZ77.DecompressionError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,6 @@ extension LZ77
public
enum DecompressionError:Error, Equatable, Sendable
{
/// A compressed data stream had an invalid compression method code.
///
/// The compression method code should always be `8`.
case invalidStreamCompressionMethodCode(UInt8)

/// A compressed data stream specified an invalid window size.
///
/// The window size exponent should be in the range `8 ... 15`.
case invalidStreamWindowSize(exponent:Int)

/// A compressed data stream had invalid header check bits.
///
/// The header check bits should not be confused with the modular redundancy checksum,
/// which corresponds to the ``invalidStreamChecksum(declared:computed:)`` error case.
case invalidStreamHeaderCheckBits

/// A compressed data stream contains a stream dictionary, which is not allowed in a
/// compressed PNG data stream.
case unexpectedStreamDictionary

/// The modular redundancy checksum computed on the uncompressed data did not match the
/// checksum declared in the compressed data stream footer.
///
Expand Down
25 changes: 12 additions & 13 deletions Sources/LZ77/Inflator/LZ77.Inflator.Out.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,25 @@ extension LZ77.Inflator
var storage:ManagedBuffer<Void, UInt8>

private
var integral:(single:UInt32, double:UInt32)
var integral:LZ77.MRC32
}
}
extension LZ77.Inflator.Out
{
init()
{
var capacity:Int = 0
var capacity:Int = 0
self.storage = .create(minimumCapacity: 0)
{
capacity = $0.capacity
return ()
}
self.window = 0
self.startIndex = 0
self.currentIndex = 0
self.endIndex = 0
self.capacity = capacity

self.integral = (1, 0)
self.integral = .init()
}

mutating
Expand Down Expand Up @@ -163,9 +162,10 @@ extension LZ77.Inflator.Out
// rebase without reallocating
self.storage.withUnsafeMutablePointerToElements
{
self.integral = LZ77.MRC32.update(self.integral,
from: $0, count: self.startIndex)
$0.update( from: $0 + self.startIndex, count: count)
self.integral.update(from: $0, count: self.startIndex)

$0.update(from: $0 + self.startIndex, count: count)

self.currentIndex -= self.startIndex
self.endIndex -= self.startIndex
self.startIndex = 0
Expand All @@ -185,9 +185,9 @@ extension LZ77.Inflator.Out

new.withUnsafeMutablePointerToElements
{
self.integral = LZ77.MRC32.update(self.integral,
from: body, count: self.startIndex)
$0.update( from: body + self.startIndex, count: count)
self.integral.update(from: body, count: self.startIndex)

$0.update(from: body + self.startIndex, count: count)
}
self.currentIndex -= self.startIndex
self.endIndex -= self.startIndex
Expand All @@ -203,9 +203,8 @@ extension LZ77.Inflator.Out
// everything still in the storage buffer has not yet been integrated
self.storage.withUnsafeMutablePointerToElements
{
let (single, double):(UInt32, UInt32) =
LZ77.MRC32.update(self.integral, from: $0, count: self.endIndex)
return double << 16 | single
self.integral.update(from: $0, count: self.endIndex)
return self.integral.checksum
}
}
}
35 changes: 19 additions & 16 deletions Sources/LZ77/Inflator/LZ77.Inflator.Stream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ extension LZ77.Inflator.Stream
mutating
func start() throws -> Int?
{
if case .ios = self.format
if case .ios = self.format
{
return 1 << 15
}
Expand All @@ -65,26 +65,26 @@ extension LZ77.Inflator.Stream
case 8:
break
case let code:
throw LZ77.DecompressionError.invalidStreamCompressionMethodCode(code)
throw LZ77.StreamHeaderError.invalidCompressionMethod(code)
}

let exponent:Int = self.input[self.b + 4, count: 4, as: Int.self]
guard exponent < 8
else
{
throw LZ77.DecompressionError.invalidStreamWindowSize(exponent: exponent + 8)
throw LZ77.StreamHeaderError.invalidWindowSize(exponent: exponent + 8)
}

let flags:Int = self.input[self.b + 8, count: 8, as: Int.self]
guard (exponent << 12 | 8 << 8 + flags) % 31 == 0
else
{
throw LZ77.DecompressionError.invalidStreamHeaderCheckBits
throw LZ77.StreamHeaderError.invalidCheckBits
}
guard flags & 0x20 == 0
else
{
throw LZ77.DecompressionError.unexpectedStreamDictionary
throw LZ77.StreamHeaderError.unexpectedDictionary
}

self.b += 16
Expand Down Expand Up @@ -158,12 +158,13 @@ extension LZ77.Inflator.Stream
}

var lengths:[Int] = .init(repeating: 0, count: 19)
for (i, d):(Int, Int) in
zip(0 ..< codelengths, [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15])
for (i, d):(Int, Int) in zip(0 ..< codelengths,
[16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15])
{
lengths[d] = self.input[self.b + 17 + 3 * i, count: 3, as: Int.self]
}
guard let tree:LZ77.HuffmanTree<UInt8> = .validate(symbols: 0 ... 18, lengths: lengths)
guard
let tree:LZ77.HuffmanTree<UInt8> = .validate(symbols: 0 ... 18, lengths: lengths)
else
{
throw LZ77.DecompressionError.invalidHuffmanCodelengthHuffmanTable
Expand Down Expand Up @@ -226,7 +227,8 @@ extension LZ77.Inflator.Stream
continue codelengths

case 16:
guard let last:Int = self.lengths.last
guard
let last:Int = self.lengths.last
else
{
throw LZ77.DecompressionError.invalidHuffmanCodelengthSequence
Expand Down Expand Up @@ -286,12 +288,13 @@ extension LZ77.Inflator.Stream
}
#endif

guard let runliteral:LZ77.HuffmanTree<UInt16> = .validate(
symbols: 0 ... 287,
lengths: self.lengths.prefix(runliterals)),
let distance:LZ77.HuffmanTree<UInt8> = .validate(
symbols: 0 ... 31,
normalizing: self.lengths.dropFirst(runliterals))
guard
let runliteral:LZ77.HuffmanTree<UInt16> = .validate(
symbols: 0 ... 287,
lengths: self.lengths.prefix(runliterals)),
let distance:LZ77.HuffmanTree<UInt8> = .validate(
symbols: 0 ... 31,
normalizing: self.lengths.dropFirst(runliterals))
else
{
throw LZ77.DecompressionError.invalidHuffmanTable
Expand Down Expand Up @@ -449,7 +452,7 @@ extension LZ77.Inflator.Stream
print(String.init(histogram: self.statistics.symbols, size: (29, 30), pad: 4))
#endif

if case .ios = self.format
if case .ios = self.format
{
return ()
}
Expand Down
19 changes: 12 additions & 7 deletions Sources/LZ77/Inflator/LZ77.Inflator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ extension LZ77.Inflator
switch self.state
{
case .streamStart:
guard let window:Int = try self.stream.start()
guard
let window:Int = try self.stream.start()
else
{
return nil
Expand All @@ -72,8 +73,8 @@ extension LZ77.Inflator
self.state = .blockStart

case .blockStart:
guard let (final, compression):(Bool, Stream.Compression) =
try self.stream.blockStart()
guard
let (final, compression):(Bool, Stream.Compression) = try self.stream.blockStart()
else
{
return nil
Expand All @@ -99,7 +100,8 @@ extension LZ77.Inflator
#endif

case .blockTables(final: let final, runliterals: let runliterals, distances: let distances):
guard let (runliteral, distance):(LZ77.HuffmanTree<UInt16>, LZ77.HuffmanTree<UInt8>) =
guard
let (runliteral, distance):(LZ77.HuffmanTree<UInt16>, LZ77.HuffmanTree<UInt8>) =
try self.stream.blockTables(runliterals: runliterals, distances: distances)
else
{
Expand All @@ -110,23 +112,26 @@ extension LZ77.Inflator
semistatic: .init(runliteral: runliteral, distance: distance))

case .blockUncompressed(final: let final, end: let end):
guard let _:Void = try self.stream.blockUncompressed(end: end)
guard
let _:Void = try self.stream.blockUncompressed(end: end)
else
{
return nil
}
self.state = final ? .streamChecksum : .blockStart

case .blockCompressed(final: let final, semistatic: let semistatic):
guard let _:Void = try self.stream.blockCompressed(semistatic: semistatic)
guard
let _:Void = try self.stream.blockCompressed(semistatic: semistatic)
else
{
return nil
}
self.state = final ? .streamChecksum : .blockStart

case .streamChecksum:
guard let _:Void = try self.stream.checksum()
guard
let _:Void = try self.stream.checksum()
else
{
return nil
Expand Down
28 changes: 28 additions & 0 deletions Sources/LZ77/Inflator/LZ77.StreamHeaderError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
extension LZ77
{
/// Errors that can occur when decompressing a DEFLATE stream embedded in the ‘zlib’ wrapper
/// format.
public
enum StreamHeaderError:Error, Equatable
{
/// A compressed data stream had an invalid compression method code.
///
/// The compression method code should always be `8`.
case invalidCompressionMethod(UInt8)

/// A compressed data stream specified an invalid window size.
///
/// The window size exponent should be in the range `8 ... 15`.
case invalidWindowSize(exponent:Int)

/// A compressed data stream had invalid header check bits.
///
/// The header check bits should not be confused with the modular redundancy checksum,
/// which corresponds to the ``invalidStreamChecksum(declared:computed:)`` error case.
case invalidCheckBits

/// A compressed data stream contains a stream dictionary, which is not allowed in a
/// compressed PNG data stream.
case unexpectedDictionary
}
}
Loading

0 comments on commit 9567397

Please sign in to comment.