mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
A new attempt has been made to make an LZMADecoder initializer which can support both LZMA and LZMA2. Also lzma Constants are no longer a substruct.
This commit is contained in:
@@ -18,7 +18,7 @@ final class LZMABitTreeDecoder {
|
||||
|
||||
init(numBits: Int, _ pointerData: inout DataWithPointer) {
|
||||
self.pointerData = pointerData
|
||||
self.probs = Array(repeating: LZMADecoder.Constants.probInitValue,
|
||||
self.probs = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: 1 << numBits)
|
||||
self.numBits = numBits
|
||||
}
|
||||
|
||||
+78
-67
@@ -8,22 +8,22 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
final class LZMADecoder {
|
||||
struct LZMAConstants {
|
||||
static let topValue: Int = 1 << 24
|
||||
static let numBitModelTotalBits: Int = 11
|
||||
static let numMoveBits: Int = 5
|
||||
static let probInitValue: Int = ((1 << numBitModelTotalBits) / 2)
|
||||
static let numPosBitsMax: Int = 4
|
||||
static let numStates: Int = 12
|
||||
static let numLenToPosStates: Int = 4
|
||||
static let numAlignBits: Int = 4
|
||||
static let startPosModelIndex: Int = 4
|
||||
static let endPosModelIndex: Int = 14
|
||||
static let numFullDistances: Int = (1 << (endPosModelIndex >> 1))
|
||||
static let matchMinLen: Int = 2
|
||||
}
|
||||
|
||||
struct Constants {
|
||||
static let topValue: Int = 1 << 24
|
||||
static let numBitModelTotalBits: Int = 11
|
||||
static let numMoveBits: Int = 5
|
||||
static let probInitValue: Int = ((1 << numBitModelTotalBits) / 2)
|
||||
static let numPosBitsMax: Int = 4
|
||||
static let numStates: Int = 12
|
||||
static let numLenToPosStates: Int = 4
|
||||
static let numAlignBits: Int = 4
|
||||
static let startPosModelIndex: Int = 4
|
||||
static let endPosModelIndex: Int = 14
|
||||
static let numFullDistances: Int = (1 << (endPosModelIndex >> 1))
|
||||
static let matchMinLen: Int = 2
|
||||
}
|
||||
final class LZMADecoder {
|
||||
|
||||
private var pointerData: DataWithPointer
|
||||
|
||||
@@ -50,18 +50,18 @@ final class LZMADecoder {
|
||||
*/
|
||||
private var literalProbs: [[Int]]
|
||||
// These arrays are used to select type of match or literal.
|
||||
private var isMatch: [Int] = Array(repeating: Constants.probInitValue,
|
||||
count: Constants.numStates << Constants.numPosBitsMax)
|
||||
private var isRep: [Int] = Array(repeating: Constants.probInitValue,
|
||||
count: Constants.numStates)
|
||||
private var isRepG0: [Int] = Array(repeating: Constants.probInitValue,
|
||||
count: Constants.numStates)
|
||||
private var isRepG1: [Int] = Array(repeating: Constants.probInitValue,
|
||||
count: Constants.numStates)
|
||||
private var isRepG2: [Int] = Array(repeating: Constants.probInitValue,
|
||||
count: Constants.numStates)
|
||||
private var isRep0Long: [Int] = Array(repeating: Constants.probInitValue,
|
||||
count: Constants.numStates << Constants.numPosBitsMax)
|
||||
private var isMatch: [Int] = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: LZMAConstants.numStates << LZMAConstants.numPosBitsMax)
|
||||
private var isRep: [Int] = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: LZMAConstants.numStates)
|
||||
private var isRepG0: [Int] = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: LZMAConstants.numStates)
|
||||
private var isRepG1: [Int] = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: LZMAConstants.numStates)
|
||||
private var isRepG2: [Int] = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: LZMAConstants.numStates)
|
||||
private var isRep0Long: [Int] = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: LZMAConstants.numStates << LZMAConstants.numPosBitsMax)
|
||||
|
||||
private var posDecoders: [Int]
|
||||
|
||||
@@ -74,55 +74,66 @@ final class LZMADecoder {
|
||||
/// Is used to select exact variable from 'IsRep', 'IsRepG0', 'IsRepG1æ and 'IsRepG2' arrays.
|
||||
private var state: Int = 0
|
||||
|
||||
init(_ pointerData: inout DataWithPointer) throws {
|
||||
init(_ pointerData: inout DataWithPointer, _ initProperties: Bool = true) throws {
|
||||
self.pointerData = pointerData
|
||||
|
||||
// First byte contains lzma properties.
|
||||
var properties = pointerData.alignedByte()
|
||||
if properties >= (9 * 5 * 5) {
|
||||
throw LZMAError.WrongProperties
|
||||
if initProperties {
|
||||
var properties = pointerData.alignedByte()
|
||||
if properties >= (9 * 5 * 5) {
|
||||
throw LZMAError.WrongProperties
|
||||
}
|
||||
/// The number of literal context bits
|
||||
let lc = properties % 9
|
||||
properties /= 9
|
||||
/// The number of pos bits
|
||||
let pb = properties / 5
|
||||
/// The number of literal pos bits
|
||||
let lp = properties % 5
|
||||
var dictionarySize = pointerData.intFromAlignedBytes(count: 4)
|
||||
dictionarySize = dictionarySize < (1 << 12) ? 1 << 12 : dictionarySize
|
||||
|
||||
/// Size of uncompressed data. -1 means it is unknown.
|
||||
var uncompressedSize = pointerData.intFromAlignedBytes(count: 8)
|
||||
uncompressedSize = Double(uncompressedSize) == pow(Double(2), Double(64)) - 1 ? -1 : uncompressedSize
|
||||
|
||||
self.lc = lc
|
||||
self.lp = lp
|
||||
self.pb = pb
|
||||
self.dictionarySize = dictionarySize
|
||||
self.uncompressedSize = uncompressedSize
|
||||
} else {
|
||||
self.lc = 0
|
||||
self.lp = 0
|
||||
self.pb = 0
|
||||
self.dictionarySize = 0
|
||||
self.uncompressedSize = -1
|
||||
}
|
||||
/// The number of literal context bits
|
||||
let lc = properties % 9
|
||||
properties /= 9
|
||||
/// The number of pos bits
|
||||
let pb = properties / 5
|
||||
/// The number of literal pos bits
|
||||
let lp = properties % 5
|
||||
var dictionarySize = pointerData.intFromAlignedBytes(count: 4)
|
||||
dictionarySize = dictionarySize < (1 << 12) ? 1 << 12 : dictionarySize
|
||||
|
||||
/// Size of uncompressed data. -1 means it is unknown.
|
||||
var uncompressedSize = pointerData.intFromAlignedBytes(count: 8)
|
||||
uncompressedSize = Double(uncompressedSize) == pow(Double(2), Double(64)) - 1 ? -1 : uncompressedSize
|
||||
|
||||
self.lc = lc
|
||||
self.lp = lp
|
||||
self.pb = pb
|
||||
self.dictionarySize = dictionarySize
|
||||
self.uncompressedSize = uncompressedSize
|
||||
|
||||
|
||||
self.out = uncompressedSize == -1 ? [] : Array(repeating: 0, count: uncompressedSize)
|
||||
self.outIndex = uncompressedSize == -1 ? -1 : 0
|
||||
|
||||
self.outWindow = LZMAOutWindow(dictSize: dictionarySize)
|
||||
|
||||
guard let rD = LZMARangeDecoder(&self.pointerData) else {
|
||||
throw LZMAError.RangeDecoderInitError
|
||||
if initProperties {
|
||||
guard let rD = LZMARangeDecoder(&self.pointerData) else {
|
||||
throw LZMAError.RangeDecoderInitError
|
||||
}
|
||||
self.rangeDecoder = rD
|
||||
} else {
|
||||
self.rangeDecoder = LZMARangeDecoder()
|
||||
}
|
||||
self.rangeDecoder = rD
|
||||
|
||||
self.literalProbs = Array(repeating: Array(repeating: Constants.probInitValue,
|
||||
self.literalProbs = Array(repeating: Array(repeating: LZMAConstants.probInitValue,
|
||||
count: 0x300),
|
||||
count: 1 << (lc + lp).toInt())
|
||||
|
||||
for _ in 0..<Constants.numLenToPosStates {
|
||||
for _ in 0..<LZMAConstants.numLenToPosStates {
|
||||
self.posSlotDecoder.append(LZMABitTreeDecoder(numBits: 6, &self.pointerData))
|
||||
}
|
||||
self.alignDecoder = LZMABitTreeDecoder(numBits: Constants.numAlignBits, &self.pointerData)
|
||||
self.posDecoders = Array(repeating: Constants.probInitValue,
|
||||
count: 1 + Constants.numFullDistances - Constants.endPosModelIndex)
|
||||
self.alignDecoder = LZMABitTreeDecoder(numBits: LZMAConstants.numAlignBits, &self.pointerData)
|
||||
self.posDecoders = Array(repeating: LZMAConstants.probInitValue,
|
||||
count: 1 + LZMAConstants.numFullDistances - LZMAConstants.endPosModelIndex)
|
||||
|
||||
// There are two types of matches so we need two decoders for them.
|
||||
self.lenDecoder = LZMALenDecoder(&self.pointerData)
|
||||
@@ -146,7 +157,7 @@ final class LZMADecoder {
|
||||
|
||||
let posState = outWindow.totalPosition & ((1 << pb.toInt()) - 1)
|
||||
lzmaDiagPrint("posState: \(posState)")
|
||||
if rangeDecoder.decode(bitWithProb: &isMatch[(state << Constants.numPosBitsMax) + posState]) == 0 {
|
||||
if rangeDecoder.decode(bitWithProb: &isMatch[(state << LZMAConstants.numPosBitsMax) + posState]) == 0 {
|
||||
if uncompressedSize == 0 { throw LZMAError.ExceededUncompressedSize }
|
||||
|
||||
// DECODE LITERAL:
|
||||
@@ -207,7 +218,7 @@ final class LZMADecoder {
|
||||
if outWindow.isEmpty { throw LZMAError.WindowIsEmpty }
|
||||
if rangeDecoder.decode(bitWithProb: &isRepG0[state]) == 0 {
|
||||
// (We use last distance from 'distance history table').
|
||||
if rangeDecoder.decode(bitWithProb: &isRep0Long[(state << Constants.numPosBitsMax) + posState]) == 0 {
|
||||
if rangeDecoder.decode(bitWithProb: &isRep0Long[(state << LZMAConstants.numPosBitsMax) + posState]) == 0 {
|
||||
// SHORT REP MATCH CASE
|
||||
state = state < 7 ? 9 : 11
|
||||
lzmaDiagPrint("updatedState: \(state)")
|
||||
@@ -261,8 +272,8 @@ final class LZMADecoder {
|
||||
// DECODE DISTANCE:
|
||||
/// Is used to define context for distance decoding.
|
||||
var lenState = len
|
||||
if lenState > Constants.numLenToPosStates - 1 {
|
||||
lenState = Constants.numLenToPosStates - 1
|
||||
if lenState > LZMAConstants.numLenToPosStates - 1 {
|
||||
lenState = LZMAConstants.numLenToPosStates - 1
|
||||
}
|
||||
|
||||
lzmaDiagPrint("decodeDistance_lenState: \(lenState)")
|
||||
@@ -281,7 +292,7 @@ final class LZMADecoder {
|
||||
lzmaDiagPrint("decodeDistance_numDirectBits: \(numDirectBits)")
|
||||
var dist = ((2 | (posSlot & 1)) << numDirectBits)
|
||||
lzmaDiagPrint("decodeDistance_startDist: \(dist)")
|
||||
if posSlot < Constants.endPosModelIndex {
|
||||
if posSlot < LZMAConstants.endPosModelIndex {
|
||||
// In this case we need a sequence of bits decoded with bit tree...
|
||||
// ...(separate trees for different `posSlot` values)...
|
||||
// ...and 'Reverse' scheme to get distance value.
|
||||
@@ -292,8 +303,8 @@ final class LZMADecoder {
|
||||
lzmaDiagPrint("decodeDistance_updatedDist_0: \(dist)")
|
||||
} else {
|
||||
// Middle bits of distance are decoded as direct bits from RangeDecoder.
|
||||
dist += rangeDecoder.decode(directBits: (numDirectBits - Constants.numAlignBits))
|
||||
<< Constants.numAlignBits
|
||||
dist += rangeDecoder.decode(directBits: (numDirectBits - LZMAConstants.numAlignBits))
|
||||
<< LZMAConstants.numAlignBits
|
||||
lzmaDiagPrint("decodeDistance_updatedDist_1_1: \(dist)")
|
||||
// Low 4 bits are decoded with a bit tree decoder (called 'AlignDecoder')...
|
||||
// ...with "Reverse" scheme.
|
||||
@@ -316,7 +327,7 @@ final class LZMADecoder {
|
||||
if rep0 >= dictionarySize || !outWindow.check(distance: rep0) { throw LZMAError.NotEnoughToRepeat }
|
||||
}
|
||||
// Converting from zero-based length of the match to the real one.
|
||||
len += Constants.matchMinLen
|
||||
len += LZMAConstants.matchMinLen
|
||||
lzmaDiagPrint("finalLen: \(len)")
|
||||
if uncompressedSize > -1 && uncompressedSize < len { throw LZMAError.RepeatWillExceed }
|
||||
lzmaDiagPrint("copyMatch_at: \(rep0 + 1)")
|
||||
|
||||
@@ -12,8 +12,8 @@ final class LZMALenDecoder {
|
||||
|
||||
private var pointerData: DataWithPointer
|
||||
|
||||
private var choice: Int = LZMADecoder.Constants.probInitValue
|
||||
private var choice2: Int = LZMADecoder.Constants.probInitValue
|
||||
private var choice: Int = LZMAConstants.probInitValue
|
||||
private var choice2: Int = LZMAConstants.probInitValue
|
||||
private var lowCoder: [LZMABitTreeDecoder] = []
|
||||
private var midCoder: [LZMABitTreeDecoder] = []
|
||||
private var highCoder: LZMABitTreeDecoder
|
||||
@@ -22,7 +22,7 @@ final class LZMALenDecoder {
|
||||
self.pointerData = pointerData
|
||||
|
||||
self.highCoder = LZMABitTreeDecoder(numBits: 8, &self.pointerData)
|
||||
for _ in 0..<(1 << LZMADecoder.Constants.numPosBitsMax) {
|
||||
for _ in 0..<(1 << LZMAConstants.numPosBitsMax) {
|
||||
self.lowCoder.append(LZMABitTreeDecoder(numBits: 3, &self.pointerData))
|
||||
self.midCoder.append(LZMABitTreeDecoder(numBits: 3, &self.pointerData))
|
||||
}
|
||||
|
||||
@@ -33,9 +33,16 @@ final class LZMARangeDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
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(LZMADecoder.Constants.topValue) {
|
||||
if self.range < UInt32(LZMAConstants.topValue) {
|
||||
self.range <<= 8
|
||||
self.code = (self.code << 8) | UInt32(pointerData.alignedByte())
|
||||
}
|
||||
@@ -74,17 +81,17 @@ final class LZMARangeDecoder {
|
||||
|
||||
/// Decodes binary symbol (bit) with predicted (estimated) probability.
|
||||
func decode(bitWithProb prob: inout Int) -> Int {
|
||||
let bound = (self.range >> UInt32(LZMADecoder.Constants.numBitModelTotalBits)) * UInt32(prob)
|
||||
let bound = (self.range >> UInt32(LZMAConstants.numBitModelTotalBits)) * UInt32(prob)
|
||||
lzmaDiagPrint("decodebit")
|
||||
lzmaDiagPrint("bound: \(bound)")
|
||||
lzmaDiagPrint("probBefore: \(prob)")
|
||||
let symbol: Int
|
||||
if self.code < bound {
|
||||
prob += ((1 << LZMADecoder.Constants.numBitModelTotalBits) - prob) >> LZMADecoder.Constants.numMoveBits
|
||||
prob += ((1 << LZMAConstants.numBitModelTotalBits) - prob) >> LZMAConstants.numMoveBits
|
||||
self.range = bound
|
||||
symbol = 0
|
||||
} else {
|
||||
prob -= prob >> LZMADecoder.Constants.numMoveBits
|
||||
prob -= prob >> LZMAConstants.numMoveBits
|
||||
self.code -= bound
|
||||
self.range -= bound
|
||||
symbol = 1
|
||||
|
||||
Reference in New Issue
Block a user