mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
93 lines
2.7 KiB
Swift
93 lines
2.7 KiB
Swift
//
|
|
// LZMARangeDecoder.swift
|
|
// SWCompression
|
|
//
|
|
// Created by Timofey Solomko on 23.12.16.
|
|
// Copyright © 2017 Timofey Solomko. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
final class LZMARangeDecoder {
|
|
|
|
private var pointerData: DataWithPointer
|
|
|
|
private var range: UInt32 = 0xFFFFFFFF
|
|
private var code: UInt32 = 0
|
|
private(set) var isCorrupted: Bool = false
|
|
|
|
var isFinishedOK: Bool {
|
|
return self.code == 0
|
|
}
|
|
|
|
init?(_ pointerData: inout DataWithPointer) {
|
|
self.pointerData = pointerData
|
|
|
|
let byte = self.pointerData.alignedByte()
|
|
for _ in 0..<4 {
|
|
self.code = (self.code << 8) | UInt32(self.pointerData.alignedByte())
|
|
}
|
|
if byte != 0 || self.code == self.range {
|
|
self.isCorrupted = true
|
|
return nil
|
|
}
|
|
}
|
|
|
|
init() {
|
|
self.pointerData = DataWithPointer(data: Data(), bitOrder: .reversed)
|
|
self.range = 0xFFFFFFFF
|
|
self.code = 0
|
|
self.isCorrupted = false
|
|
}
|
|
|
|
/// `range` property cannot be smaller than `(1 << 24)`. This function keeps it bigger.
|
|
func normalize() {
|
|
if self.range < UInt32(LZMAConstants.topValue) {
|
|
self.range <<= 8
|
|
self.code = (self.code << 8) | UInt32(pointerData.alignedByte())
|
|
}
|
|
}
|
|
|
|
/// Decodes sequence of direct bits (binary symbols with fixed and equal probabilities).
|
|
func decode(directBits: Int) -> Int {
|
|
var res: UInt32 = 0
|
|
var count = directBits
|
|
repeat {
|
|
self.range >>= 1
|
|
self.code = UInt32.subtractWithOverflow(self.code, self.range).0
|
|
let t = UInt32.subtractWithOverflow(0, self.code >> 31).0
|
|
self.code = UInt32.addWithOverflow(self.code, self.range & t).0
|
|
|
|
if self.code == self.range {
|
|
self.isCorrupted = true
|
|
}
|
|
|
|
self.normalize()
|
|
|
|
res <<= 1
|
|
res = UInt32.addWithOverflow(res, UInt32.addWithOverflow(t, 1).0).0
|
|
count -= 1
|
|
} while count > 0
|
|
return Int(res)
|
|
}
|
|
|
|
/// Decodes binary symbol (bit) with predicted (estimated) probability.
|
|
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
|
|
}
|
|
|
|
}
|