From 4bb92c00d517210bc0e340dbb7bd73e562ef4838 Mon Sep 17 00:00:00 2001 From: Timofey Solomko Date: Fri, 23 Dec 2016 20:09:46 +0300 Subject: [PATCH] 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. --- Sources/LZMABitTreeDecoder.swift | 2 +- Sources/LZMADecoder.swift | 145 +++++++++++++++++-------------- Sources/LZMALenDecoder.swift | 6 +- Sources/LZMARangeDecoder.swift | 15 +++- 4 files changed, 93 insertions(+), 75 deletions(-) diff --git a/Sources/LZMABitTreeDecoder.swift b/Sources/LZMABitTreeDecoder.swift index ed57a5ec..0a17e8dd 100644 --- a/Sources/LZMABitTreeDecoder.swift +++ b/Sources/LZMABitTreeDecoder.swift @@ -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 } diff --git a/Sources/LZMADecoder.swift b/Sources/LZMADecoder.swift index 80684b0a..e28a61a5 100644 --- a/Sources/LZMADecoder.swift +++ b/Sources/LZMADecoder.swift @@ -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 - 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)") diff --git a/Sources/LZMALenDecoder.swift b/Sources/LZMALenDecoder.swift index bbe1651a..f99cb550 100644 --- a/Sources/LZMALenDecoder.swift +++ b/Sources/LZMALenDecoder.swift @@ -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)) } diff --git a/Sources/LZMARangeDecoder.swift b/Sources/LZMARangeDecoder.swift index 37f8a465..60bbb356 100644 --- a/Sources/LZMARangeDecoder.swift +++ b/Sources/LZMARangeDecoder.swift @@ -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