Files
SWCompression/Sources/LZMA/LZMARangeDecoder.swift
Timofey Solomko 3686067e54 [LZMA] Remove LZMARangeDecoder.isCorrupted property
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.
2026-02-23 18:08:26 +08:00

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
}
}