mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
3686067e54
According to LZMA specification this property is ignored by the reference implementation. In addition, specification suggests that other LZMA decoders should also ignore it. We weren't using this property for anything anyway, so its removal does not really change anything, except for better compliance with LZMA specification. In addition, range decoder initialization error is now thrown in accordance with reference implementation.
83 lines
2.4 KiB
Swift
83 lines
2.4 KiB
Swift
// Copyright (c) 2026 Timofey Solomko
|
|
// Licensed under MIT License
|
|
//
|
|
// See LICENSE for license information
|
|
|
|
import Foundation
|
|
import BitByteData
|
|
|
|
struct LZMARangeDecoder {
|
|
|
|
private let byteReader: LittleEndianByteReader
|
|
|
|
private var range = 0xFFFFFFFF as UInt32
|
|
private var code = 0 as UInt32
|
|
|
|
var isFinishedOK: Bool {
|
|
return self.code == 0
|
|
}
|
|
|
|
init(_ byteReader: LittleEndianByteReader) throws {
|
|
// To initialize range decoder at least 5 bytes are necessary.
|
|
guard byteReader.bytesLeft >= 5
|
|
else { throw LZMAError.rangeDecoderInitError }
|
|
|
|
self.byteReader = byteReader
|
|
|
|
let byte = self.byteReader.byte()
|
|
self.code = self.byteReader.uint32().byteSwapped
|
|
guard byte == 0
|
|
else { throw LZMAError.rangeDecoderInitError }
|
|
}
|
|
|
|
init() {
|
|
self.byteReader = LittleEndianByteReader(data: Data())
|
|
}
|
|
|
|
/// `range` property cannot be smaller than `(1 << 24)`. This function keeps it bigger.
|
|
mutating func normalize() {
|
|
if self.range < LZMAConstants.topValue {
|
|
self.range <<= 8
|
|
self.code = (self.code << 8) | UInt32(byteReader.byte())
|
|
}
|
|
}
|
|
|
|
/// Decodes sequence of direct bits (binary symbols with fixed and equal probabilities).
|
|
mutating func decode(directBits: Int) -> Int {
|
|
var res: UInt32 = 0
|
|
var count = directBits
|
|
repeat {
|
|
self.range >>= 1
|
|
self.code = self.code &- self.range
|
|
let t = 0 &- (self.code >> 31)
|
|
self.code = self.code &+ (self.range & t)
|
|
|
|
self.normalize()
|
|
|
|
res <<= 1
|
|
res = res &+ (t &+ 1)
|
|
count -= 1
|
|
} while count > 0
|
|
return res.toInt()
|
|
}
|
|
|
|
/// Decodes binary symbol (bit) with predicted (estimated) probability.
|
|
mutating func decode(bitWithProb prob: inout Int) -> Int {
|
|
let bound = (self.range >> UInt32(LZMAConstants.numBitModelTotalBits)) * UInt32(prob)
|
|
let symbol: Int
|
|
if self.code < bound {
|
|
prob += ((1 << LZMAConstants.numBitModelTotalBits) - prob) >> LZMAConstants.numMoveBits
|
|
self.range = bound
|
|
symbol = 0
|
|
} else {
|
|
prob -= prob >> LZMAConstants.numMoveBits
|
|
self.code -= bound
|
|
self.range -= bound
|
|
symbol = 1
|
|
}
|
|
self.normalize()
|
|
return symbol
|
|
}
|
|
|
|
}
|