mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
Adopted DWP-BitReader split everywhere
I've also removed a most occurrences of inout keyword because DWP (and BitReader) are classes and they are already passed by reference in arguments.
This commit is contained in:
+22
-22
@@ -22,21 +22,21 @@ public class BZip2: DecompressionAlgorithm {
|
||||
*/
|
||||
public static func decompress(data: Data) throws -> Data {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .straight)
|
||||
return Data(bytes: try decompress(&pointerData))
|
||||
let bitReader = BitReader(data: data, bitOrder: .straight)
|
||||
return Data(bytes: try decompress(bitReader))
|
||||
}
|
||||
|
||||
static func decompress(_ pointerData: inout DataWithPointer) throws -> [UInt8] {
|
||||
static func decompress(_ bitReader: BitReader) throws -> [UInt8] {
|
||||
/// An array for storing output data
|
||||
var out = [UInt8]()
|
||||
|
||||
let magic = pointerData.intFromBits(count: 16)
|
||||
let magic = bitReader.intFromBits(count: 16)
|
||||
guard magic == 0x425a else { throw BZip2Error.wrongMagic }
|
||||
|
||||
let method = pointerData.intFromBits(count: 8)
|
||||
let method = bitReader.intFromBits(count: 8)
|
||||
guard method == 104 else { throw BZip2Error.wrongCompressionMethod }
|
||||
|
||||
var blockSize = pointerData.intFromBits(count: 8)
|
||||
var blockSize = bitReader.intFromBits(count: 8)
|
||||
if blockSize >= 49 && blockSize <= 57 {
|
||||
blockSize -= 48
|
||||
} else {
|
||||
@@ -45,12 +45,12 @@ public class BZip2: DecompressionAlgorithm {
|
||||
|
||||
var totalCRC: UInt32 = 0
|
||||
while true {
|
||||
let blockType: Int64 = Int64(pointerData.intFromBits(count: 48))
|
||||
// Next 32 bits are crc (which currently is not checked).
|
||||
let blockCRC32 = UInt32(truncatingBitPattern: pointerData.intFromBits(count: 32))
|
||||
let blockType: Int64 = Int64(bitReader.intFromBits(count: 48))
|
||||
|
||||
let blockCRC32 = UInt32(truncatingBitPattern: bitReader.intFromBits(count: 32))
|
||||
|
||||
if blockType == 0x314159265359 {
|
||||
let blockBytes = try decode(data: &pointerData)
|
||||
let blockBytes = try decode(bitReader)
|
||||
guard CheckSums.bzip2CRC32(blockBytes) == blockCRC32
|
||||
else { throw BZip2Error.wrongCRC(Data(bytes: out)) }
|
||||
for byte in blockBytes {
|
||||
@@ -70,19 +70,19 @@ public class BZip2: DecompressionAlgorithm {
|
||||
return out
|
||||
}
|
||||
|
||||
private static func decode(data: inout DataWithPointer) throws -> [UInt8] {
|
||||
let isRandomized = data.bit()
|
||||
private static func decode(_ bitReader: BitReader) throws -> [UInt8] {
|
||||
let isRandomized = bitReader.bit()
|
||||
guard isRandomized != 1 else { throw BZip2Error.randomizedBlock }
|
||||
|
||||
var pointer = data.intFromBits(count: 24)
|
||||
var pointer = bitReader.intFromBits(count: 24)
|
||||
|
||||
func computeUsed() -> [Bool] {
|
||||
let huffmanUsedMap = data.intFromBits(count: 16)
|
||||
let huffmanUsedMap = bitReader.intFromBits(count: 16)
|
||||
var mapMask = 1 << 15
|
||||
var used: [Bool] = []
|
||||
while mapMask > 0 {
|
||||
if huffmanUsedMap & mapMask > 0 {
|
||||
let huffmanUsedBitmap = data.intFromBits(count: 16)
|
||||
let huffmanUsedBitmap = bitReader.intFromBits(count: 16)
|
||||
var bitMask = 1 << 15
|
||||
while bitMask > 0 {
|
||||
used.append(huffmanUsedBitmap & bitMask > 0)
|
||||
@@ -100,18 +100,18 @@ public class BZip2: DecompressionAlgorithm {
|
||||
|
||||
let used = computeUsed()
|
||||
|
||||
let huffmanGroups = data.intFromBits(count: 3)
|
||||
let huffmanGroups = bitReader.intFromBits(count: 3)
|
||||
guard huffmanGroups >= 2 && huffmanGroups <= 6 else { throw BZip2Error.wrongHuffmanGroups }
|
||||
|
||||
func computeSelectorsList() throws -> [Int] {
|
||||
let selectorsUsed = data.intFromBits(count: 15)
|
||||
let selectorsUsed = bitReader.intFromBits(count: 15)
|
||||
|
||||
var mtf: [Int] = Array(0..<huffmanGroups)
|
||||
var selectorsList: [Int] = []
|
||||
|
||||
for _ in 0..<selectorsUsed {
|
||||
var c = 0
|
||||
while data.bit() > 0 {
|
||||
while bitReader.bit() > 0 {
|
||||
c += 1
|
||||
guard c < huffmanGroups else { throw BZip2Error.wrongSelector }
|
||||
}
|
||||
@@ -131,16 +131,16 @@ public class BZip2: DecompressionAlgorithm {
|
||||
func computeTables() throws -> [HuffmanTree] {
|
||||
var tables: [HuffmanTree] = []
|
||||
for _ in 0..<huffmanGroups {
|
||||
var length = data.intFromBits(count: 5)
|
||||
var length = bitReader.intFromBits(count: 5)
|
||||
var lengths: [Int] = []
|
||||
for _ in 0..<symbolsInUse {
|
||||
guard length >= 0 && length <= 20 else { throw BZip2Error.wrongHuffmanLengthCode }
|
||||
while data.bit() > 0 {
|
||||
length -= (Int(data.bit() * 2) - 1)
|
||||
while bitReader.bit() > 0 {
|
||||
length -= (Int(bitReader.bit() * 2) - 1)
|
||||
}
|
||||
lengths.append(length)
|
||||
}
|
||||
let codes = HuffmanTree(lengthsToOrder: lengths, &data)
|
||||
let codes = HuffmanTree(lengthsToOrder: lengths, bitReader)
|
||||
tables.append(codes)
|
||||
}
|
||||
|
||||
|
||||
+23
-23
@@ -57,31 +57,31 @@ public class Deflate: DecompressionAlgorithm {
|
||||
*/
|
||||
public static func decompress(data: Data) throws -> Data {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
return Data(bytes: try decompress(&pointerData))
|
||||
let bitReader = BitReader(data: data, bitOrder: .reversed)
|
||||
return Data(bytes: try decompress(bitReader))
|
||||
}
|
||||
|
||||
static func decompress(_ pointerData: inout DataWithPointer) throws -> [UInt8] {
|
||||
static func decompress(_ bitReader: BitReader) throws -> [UInt8] {
|
||||
/// An array for storing output data
|
||||
var out: [UInt8] = []
|
||||
|
||||
while true {
|
||||
/// Is this a last block?
|
||||
let isLastBit = pointerData.bit()
|
||||
let isLastBit = bitReader.bit()
|
||||
/// Type of the current block.
|
||||
let blockType = [UInt8](pointerData.bits(count: 2).reversed())
|
||||
let blockType = [UInt8](bitReader.bits(count: 2).reversed())
|
||||
|
||||
if blockType == [0, 0] { // Uncompressed block.
|
||||
pointerData.skipUntilNextByte()
|
||||
bitReader.skipUntilNextByte()
|
||||
/// Length of the uncompressed data.
|
||||
let length = pointerData.intFromBits(count: 16)
|
||||
let length = bitReader.intFromBits(count: 16)
|
||||
/// 1-complement of the length.
|
||||
let nlength = pointerData.intFromBits(count: 16)
|
||||
let nlength = bitReader.intFromBits(count: 16)
|
||||
// Check if lengths are OK (nlength should be a 1-complement of length).
|
||||
guard length & nlength == 0 else { throw DeflateError.wrongUncompressedBlockLengths }
|
||||
// Process uncompressed data into the output
|
||||
for _ in 0..<length {
|
||||
out.append(pointerData.alignedByte())
|
||||
out.append(bitReader.alignedByte())
|
||||
}
|
||||
} else if blockType == [1, 0] || blockType == [0, 1] {
|
||||
// Block with Huffman coding (either static or dynamic)
|
||||
@@ -100,28 +100,28 @@ public class Deflate: DecompressionAlgorithm {
|
||||
let staticHuffmanBootstrap = [[0, 8], [144, 9], [256, 7], [280, 8], [288, -1]]
|
||||
let staticHuffmanLengthsBootstrap = [[0, 5], [32, -1]]
|
||||
// Initialize trees from these bootstraps.
|
||||
mainLiterals = HuffmanTree(bootstrap: staticHuffmanBootstrap, &pointerData)
|
||||
mainDistances = HuffmanTree(bootstrap: staticHuffmanLengthsBootstrap, &pointerData)
|
||||
mainLiterals = HuffmanTree(bootstrap: staticHuffmanBootstrap, bitReader)
|
||||
mainDistances = HuffmanTree(bootstrap: staticHuffmanLengthsBootstrap, bitReader)
|
||||
} else { // Dynamic Huffman
|
||||
// In this case there are Huffman codes for two alphabets in data right after block header.
|
||||
// Each code defined by a sequence of code lengths (which are compressed themselves with Huffman).
|
||||
|
||||
/// Number of literals codes.
|
||||
let literals = pointerData.intFromBits(count: 5) + 257
|
||||
let literals = bitReader.intFromBits(count: 5) + 257
|
||||
/// Number of distances codes.
|
||||
let distances = pointerData.intFromBits(count: 5) + 1
|
||||
let distances = bitReader.intFromBits(count: 5) + 1
|
||||
/// Number of code lengths codes.
|
||||
let codeLengthsLength = pointerData.intFromBits(count: 4) + 4
|
||||
let codeLengthsLength = bitReader.intFromBits(count: 4) + 4
|
||||
|
||||
// Read code lengths codes.
|
||||
// Moreover, they are stored in a very specific order,
|
||||
// defined by HuffmanTree.Constants.codeLengthOrders.
|
||||
var lengthsForOrder = Array(repeating: 0, count: 19)
|
||||
for i in 0..<codeLengthsLength {
|
||||
lengthsForOrder[Constants.codeLengthOrders[i]] = pointerData.intFromBits(count: 3)
|
||||
lengthsForOrder[Constants.codeLengthOrders[i]] = bitReader.intFromBits(count: 3)
|
||||
}
|
||||
/// Huffman tree for code lengths. Each code in the main alphabets is coded with this tree.
|
||||
let dynamicCodes = HuffmanTree(lengthsToOrder: lengthsForOrder, &pointerData)
|
||||
let dynamicCodes = HuffmanTree(lengthsToOrder: lengthsForOrder, bitReader)
|
||||
|
||||
// Now we need to read codes (code lengths) for two main alphabets (trees).
|
||||
var codeLengths: [Int] = []
|
||||
@@ -140,17 +140,17 @@ public class Deflate: DecompressionAlgorithm {
|
||||
} else if symbol == 16 {
|
||||
// Copy previous code length 3 to 6 times.
|
||||
// Next two bits show how many times we need to copy.
|
||||
count = pointerData.intFromBits(count: 2) + 3
|
||||
count = bitReader.intFromBits(count: 2) + 3
|
||||
what = codeLengths.last!
|
||||
} else if symbol == 17 {
|
||||
// Repeat code length 0 for from 3 to 10 times.
|
||||
// Next three bits show how many times we need to copy.
|
||||
count = pointerData.intFromBits(count: 3) + 3
|
||||
count = bitReader.intFromBits(count: 3) + 3
|
||||
what = 0
|
||||
} else if symbol == 18 {
|
||||
// Repeat code length 0 for from 11 to 138 times.
|
||||
// Next seven bits show how many times we need to do this.
|
||||
count = pointerData.intFromBits(count: 7) + 11
|
||||
count = bitReader.intFromBits(count: 7) + 11
|
||||
what = 0
|
||||
} else {
|
||||
throw DeflateError.wrongSymbol
|
||||
@@ -163,9 +163,9 @@ public class Deflate: DecompressionAlgorithm {
|
||||
// We have read codeLengths for both trees at once.
|
||||
// Now we need to split them and make corresponding trees.
|
||||
mainLiterals = HuffmanTree(lengthsToOrder: Array(codeLengths[0..<literals]),
|
||||
&pointerData)
|
||||
bitReader)
|
||||
mainDistances = HuffmanTree(lengthsToOrder: Array(codeLengths[literals..<codeLengths.count]),
|
||||
&pointerData)
|
||||
bitReader)
|
||||
}
|
||||
|
||||
// Main loop of data decompression.
|
||||
@@ -190,7 +190,7 @@ public class Deflate: DecompressionAlgorithm {
|
||||
// Actually, nextSymbol is not a starting value of length,
|
||||
// but an index for special array of starting values.
|
||||
let length = Constants.lengthBase[nextSymbol - 257] +
|
||||
pointerData.intFromBits(count: extraLength)
|
||||
bitReader.intFromBits(count: extraLength)
|
||||
|
||||
// Then we need to get distance code.
|
||||
let distanceCode = mainDistances.findNextSymbol()
|
||||
@@ -203,7 +203,7 @@ public class Deflate: DecompressionAlgorithm {
|
||||
let extraDistance = distanceCode == 0 || distanceCode == 1 ? 0 : ((distanceCode >> 1) - 1)
|
||||
// And yes, distanceCode is not a first part of distance but rather an index for special array.
|
||||
let distance = Constants.distanceBase[distanceCode] +
|
||||
pointerData.intFromBits(count: extraDistance)
|
||||
bitReader.intFromBits(count: extraDistance)
|
||||
|
||||
// We should repeat last 'distance' amount of data.
|
||||
// The amount of times we do this is round(length / distance).
|
||||
|
||||
@@ -100,7 +100,7 @@ public extension Deflate {
|
||||
}
|
||||
|
||||
private static func encodeHuffmanBlock(_ bldCodes: [BLDCode]) throws -> [UInt8] {
|
||||
var bitWriter = BitToByteWriter(bitOrder: .reversed)
|
||||
let bitWriter = BitToByteWriter(bitOrder: .reversed)
|
||||
|
||||
// Write block header.
|
||||
// Note: For now it is only static huffman blocks.
|
||||
@@ -109,7 +109,8 @@ public extension Deflate {
|
||||
bitWriter.write(bits: [1, 0])
|
||||
|
||||
/// Empty DWP object for creating Huffman trees.
|
||||
var pointerData = DataWithPointer(data: Data(), bitOrder: .reversed)
|
||||
/// TODO: Separate reading and writing trees, and make so this pointerData is not necessary.
|
||||
let pointerData = BitReader(data: Data(), bitOrder: .reversed)
|
||||
|
||||
// Constructing Huffman trees for the case of block with preset alphabets.
|
||||
// In this case codes for literals and distances are fixed.
|
||||
@@ -117,32 +118,32 @@ public extension Deflate {
|
||||
let staticHuffmanBootstrap = [[0, 8], [144, 9], [256, 7], [280, 8], [288, -1]]
|
||||
let staticHuffmanLengthsBootstrap = [[0, 5], [32, -1]]
|
||||
/// Huffman tree for literal and length symbols/codes.
|
||||
let mainLiterals = HuffmanTree(bootstrap: staticHuffmanBootstrap, &pointerData, true)
|
||||
let mainLiterals = HuffmanTree(bootstrap: staticHuffmanBootstrap, pointerData, true)
|
||||
/// Huffman tree for backward distance symbols/codes.
|
||||
let mainDistances = HuffmanTree(bootstrap: staticHuffmanLengthsBootstrap, &pointerData, true)
|
||||
let mainDistances = HuffmanTree(bootstrap: staticHuffmanLengthsBootstrap, pointerData, true)
|
||||
|
||||
for code in bldCodes {
|
||||
switch code {
|
||||
case .byte(let byte):
|
||||
try mainLiterals.code(symbol: byte.toInt(), &bitWriter, DeflateError.symbolNotFound)
|
||||
try mainLiterals.code(symbol: byte.toInt(), bitWriter, DeflateError.symbolNotFound)
|
||||
case .lengthDistance(let length, let distance):
|
||||
let lengthSymbol = Constants.lengthCode[Int(length) - 3]
|
||||
let lengthExtraBits = Int(length) - Constants.lengthBase[lengthSymbol - 257]
|
||||
let lengthExtraBitsCount = (257 <= lengthSymbol && lengthSymbol <= 260) || lengthSymbol == 285 ?
|
||||
0 : (((lengthSymbol - 257) >> 2) - 1)
|
||||
try mainLiterals.code(symbol: lengthSymbol, &bitWriter, DeflateError.symbolNotFound)
|
||||
try mainLiterals.code(symbol: lengthSymbol, bitWriter, DeflateError.symbolNotFound)
|
||||
bitWriter.write(number: lengthExtraBits, bitsCount: lengthExtraBitsCount)
|
||||
|
||||
let distanceSymbol = ((Constants.distanceBase.index { $0 > Int(distance) }) ?? 30) - 1
|
||||
let distanceExtraBits = Int(distance) - Constants.distanceBase[distanceSymbol]
|
||||
let distanceExtraBitsCount = distanceSymbol == 0 || distanceSymbol == 1 ? 0 : ((distanceSymbol >> 1) - 1)
|
||||
try mainDistances.code(symbol: distanceSymbol, &bitWriter, DeflateError.symbolNotFound)
|
||||
try mainDistances.code(symbol: distanceSymbol, bitWriter, DeflateError.symbolNotFound)
|
||||
bitWriter.write(number: distanceExtraBits, bitsCount: distanceExtraBitsCount)
|
||||
}
|
||||
}
|
||||
|
||||
// End data symbol.
|
||||
try mainLiterals.code(symbol: 256, &bitWriter, DeflateError.symbolNotFound)
|
||||
try mainLiterals.code(symbol: 256, bitWriter, DeflateError.symbolNotFound)
|
||||
bitWriter.finish()
|
||||
|
||||
return bitWriter.buffer
|
||||
|
||||
+10
-10
@@ -38,9 +38,9 @@ public class GzipArchive: Archive {
|
||||
*/
|
||||
public static func unarchive(archive data: Data) throws -> Data {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let bitReader = BitReader(data: data, bitOrder: .reversed)
|
||||
|
||||
return try processMember(&pointerData).data
|
||||
return try processMember(bitReader).data
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,25 +62,25 @@ public class GzipArchive: Archive {
|
||||
*/
|
||||
public static func multiUnarchive(archive data: Data) throws -> [Member] {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let bitReader = BitReader(data: data, bitOrder: .reversed)
|
||||
|
||||
var result = [Member]()
|
||||
while !pointerData.isAtTheEnd {
|
||||
result.append(try processMember(&pointerData))
|
||||
while !bitReader.isAtTheEnd {
|
||||
result.append(try processMember(bitReader))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private static func processMember(_ pointerData: inout DataWithPointer) throws -> Member {
|
||||
let header = try GzipHeader(&pointerData)
|
||||
private static func processMember(_ bitReader: BitReader) throws -> Member {
|
||||
let header = try GzipHeader(bitReader)
|
||||
|
||||
let memberData = Data(bytes: try Deflate.decompress(&pointerData))
|
||||
let memberData = Data(bytes: try Deflate.decompress(bitReader))
|
||||
|
||||
let crc32 = pointerData.uint32FromAlignedBytes(count: 4)
|
||||
let crc32 = bitReader.uint32FromAlignedBytes(count: 4)
|
||||
guard CheckSums.crc32(memberData) == crc32 else { throw GzipError.wrongCRC(memberData) }
|
||||
|
||||
let isize = pointerData.intFromAlignedBytes(count: 4)
|
||||
let isize = bitReader.intFromAlignedBytes(count: 4)
|
||||
guard UInt64(memberData.count) % UInt64(1) << 32 == UInt64(isize) else { throw GzipError.wrongISize }
|
||||
|
||||
return Member(header: header, data: memberData)
|
||||
|
||||
@@ -73,11 +73,11 @@ public struct GzipHeader {
|
||||
it might not be archived with GZip at all.
|
||||
*/
|
||||
public init(archive data: Data) throws {
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
try self.init(&pointerData)
|
||||
let pointerData = DataWithPointer(data: data)
|
||||
try self.init(pointerData)
|
||||
}
|
||||
|
||||
init(_ pointerData: inout DataWithPointer) throws {
|
||||
init(_ pointerData: DataWithPointer) throws {
|
||||
// First two bytes should be correct 'magic' bytes
|
||||
let magic = pointerData.intFromAlignedBytes(count: 2)
|
||||
guard magic == 0x8b1f else { throw GzipError.wrongMagic }
|
||||
|
||||
@@ -7,7 +7,7 @@ import Foundation
|
||||
|
||||
class HuffmanTree {
|
||||
|
||||
private var pointerData: DataWithPointer
|
||||
private var bitReader: BitReader
|
||||
|
||||
private var tree: [Int]
|
||||
private let leafCount: Int
|
||||
@@ -15,9 +15,9 @@ class HuffmanTree {
|
||||
private var codingIndices: [[Int]]
|
||||
private let coding: Bool
|
||||
|
||||
init(bootstrap: [[Int]], _ pointerData: inout DataWithPointer, _ coding: Bool = false) {
|
||||
init(bootstrap: [[Int]], _ bitReader: BitReader, _ coding: Bool = false) {
|
||||
self.coding = coding
|
||||
self.pointerData = pointerData
|
||||
self.bitReader = bitReader
|
||||
|
||||
// Fills the 'lengths' array with numerous HuffmanLengths from a 'bootstrap'.
|
||||
var lengths: [[Int]] = []
|
||||
@@ -92,18 +92,18 @@ class HuffmanTree {
|
||||
}
|
||||
}
|
||||
|
||||
convenience init(lengthsToOrder: [Int], _ pointerData: inout DataWithPointer) {
|
||||
convenience init(lengthsToOrder: [Int], _ bitReader: BitReader) {
|
||||
var addedLengths = lengthsToOrder
|
||||
addedLengths.append(-1)
|
||||
let lengthsCount = addedLengths.count
|
||||
let range = Array(0...lengthsCount)
|
||||
self.init(bootstrap: (zip(range, addedLengths)).map { [$0, $1] }, &pointerData)
|
||||
self.init(bootstrap: (zip(range, addedLengths)).map { [$0, $1] }, bitReader)
|
||||
}
|
||||
|
||||
func findNextSymbol() -> Int {
|
||||
var index = 0
|
||||
while true {
|
||||
let bit = pointerData.bit()
|
||||
let bit = bitReader.bit()
|
||||
index = bit == 0 ? 2 * index + 1 : 2 * index + 2
|
||||
guard index < self.leafCount else {
|
||||
return -1
|
||||
@@ -114,7 +114,7 @@ class HuffmanTree {
|
||||
}
|
||||
}
|
||||
|
||||
func code(symbol: Int, _ bitWriter: inout BitToByteWriter, _ symbolNotFoundError: Error) throws {
|
||||
func code(symbol: Int, _ bitWriter: BitToByteWriter, _ symbolNotFoundError: Error) throws {
|
||||
precondition(self.coding, "HuffmanTree is not initalized for coding!")
|
||||
|
||||
guard symbol < self.codingIndices.count
|
||||
|
||||
+4
-4
@@ -22,9 +22,9 @@ public class LZMA: DecompressionAlgorithm {
|
||||
*/
|
||||
public static func decompress(data: Data) throws -> Data {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let pointerData = DataWithPointer(data: data)
|
||||
|
||||
return Data(bytes: try decompress(&pointerData))
|
||||
return Data(bytes: try decompress(pointerData))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,8 +32,8 @@ public class LZMA: DecompressionAlgorithm {
|
||||
and decoder should use externally specified uncompressed size.
|
||||
Used in ZIP containers with LZMA compression.
|
||||
*/
|
||||
static func decompress(_ pointerData: inout DataWithPointer, _ externalUncompressedSize: Int? = nil) throws -> [UInt8] {
|
||||
let lzmaDecoder = try LZMADecoder(&pointerData)
|
||||
static func decompress(_ pointerData: DataWithPointer, _ externalUncompressedSize: Int? = nil) throws -> [UInt8] {
|
||||
let lzmaDecoder = try LZMADecoder(pointerData)
|
||||
try lzmaDecoder.decodeLZMA(externalUncompressedSize)
|
||||
return lzmaDecoder.out
|
||||
}
|
||||
|
||||
+4
-4
@@ -22,16 +22,16 @@ public class LZMA2: DecompressionAlgorithm {
|
||||
*/
|
||||
public static func decompress(data: Data) throws -> Data {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let pointerData = DataWithPointer(data: data)
|
||||
|
||||
let dictionarySize = try LZMA2.dictionarySize(pointerData.alignedByte())
|
||||
|
||||
return Data(bytes: try LZMA2.decompress(dictionarySize, &pointerData))
|
||||
return Data(bytes: try LZMA2.decompress(dictionarySize, pointerData))
|
||||
}
|
||||
|
||||
static func decompress(_ dictionarySize: Int, _ pointerData: inout DataWithPointer) throws -> [UInt8] {
|
||||
static func decompress(_ dictionarySize: Int, _ pointerData: DataWithPointer) throws -> [UInt8] {
|
||||
// At this point lzmaDecoder will be in a VERY bad state.
|
||||
let lzmaDecoder = try LZMADecoder(&pointerData)
|
||||
let lzmaDecoder = try LZMADecoder(pointerData)
|
||||
try lzmaDecoder.decodeLZMA2(dictionarySize)
|
||||
return lzmaDecoder.out
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class LZMADecoder {
|
||||
/// If that has happened, then stateReset is true.
|
||||
private var stateReset: Bool = false
|
||||
|
||||
init(_ pointerData: inout DataWithPointer) throws {
|
||||
init(_ pointerData: DataWithPointer) throws {
|
||||
self.pointerData = pointerData
|
||||
self.alignDecoder = LZMABitTreeDecoder(numBits: LZMAConstants.numAlignBits)
|
||||
// There are two types of matches so we need two decoders for them.
|
||||
@@ -227,7 +227,7 @@ class LZMADecoder {
|
||||
}
|
||||
|
||||
// First, we need to initialize Rande Decoder.
|
||||
guard let rD = LZMARangeDecoder(&self.pointerData) else {
|
||||
guard let rD = LZMARangeDecoder(pointerData) else {
|
||||
throw LZMAError.rangeDecoderInitError
|
||||
}
|
||||
self.rangeDecoder = rD
|
||||
|
||||
@@ -17,7 +17,7 @@ class LZMARangeDecoder {
|
||||
return self.code == 0
|
||||
}
|
||||
|
||||
init?(_ pointerData: inout DataWithPointer) {
|
||||
init?(_ pointerData: DataWithPointer) {
|
||||
self.pointerData = pointerData
|
||||
|
||||
let byte = self.pointerData.alignedByte()
|
||||
@@ -31,7 +31,7 @@ class LZMARangeDecoder {
|
||||
}
|
||||
|
||||
init() {
|
||||
self.pointerData = DataWithPointer(data: Data(), bitOrder: .reversed)
|
||||
self.pointerData = DataWithPointer(data: Data())
|
||||
self.range = 0xFFFFFFFF
|
||||
self.code = 0
|
||||
self.isCorrupted = false
|
||||
|
||||
@@ -28,7 +28,7 @@ public class TarContainer: Container {
|
||||
guard data.count >= 512 else { throw TarError.tooSmallFileIsPassed }
|
||||
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let pointerData = DataWithPointer(data: data)
|
||||
|
||||
var output = [TarEntry]()
|
||||
|
||||
@@ -45,7 +45,7 @@ public class TarContainer: Container {
|
||||
} else {
|
||||
pointerData.index -= 1024
|
||||
}
|
||||
let entry = try TarEntry(&pointerData, lastGlobalExtendedHeader, lastLocalExtendedHeader,
|
||||
let entry = try TarEntry(pointerData, lastGlobalExtendedHeader, lastLocalExtendedHeader,
|
||||
longName, longLinkName)
|
||||
switch entry.type {
|
||||
case .globalExtendedHeader:
|
||||
@@ -54,11 +54,9 @@ public class TarContainer: Container {
|
||||
lastLocalExtendedHeader = String(data: entry.data(), encoding: .utf8)
|
||||
default:
|
||||
if entry.isLongName {
|
||||
longName = try DataWithPointer(data: entry.data(), bitOrder: .reversed)
|
||||
.nullEndedAsciiString(cutoff: entry.size)
|
||||
longName = try DataWithPointer(data: entry.data()).nullEndedAsciiString(cutoff: entry.size)
|
||||
} else if entry.isLongLinkName {
|
||||
longLinkName = try DataWithPointer(data: entry.data(), bitOrder: .reversed)
|
||||
.nullEndedAsciiString(cutoff: entry.size)
|
||||
longLinkName = try DataWithPointer(data: entry.data()).nullEndedAsciiString(cutoff: entry.size)
|
||||
} else {
|
||||
output.append(entry)
|
||||
lastLocalExtendedHeader = nil
|
||||
|
||||
@@ -171,7 +171,7 @@ public class TarEntry: ContainerEntry {
|
||||
private let gnuLongName: String?
|
||||
private let gnuLongLinkName: String?
|
||||
|
||||
init(_ pointerData: inout DataWithPointer, _ globalExtendedHeader: String?, _ localExtendedHeader: String?,
|
||||
init(_ pointerData: DataWithPointer, _ globalExtendedHeader: String?, _ localExtendedHeader: String?,
|
||||
_ longName: String?, _ longLinkName: String?) throws {
|
||||
if let longName = longName {
|
||||
gnuLongName = longName
|
||||
|
||||
+19
-19
@@ -27,7 +27,7 @@ public class XZArchive: Archive {
|
||||
*/
|
||||
public static func unarchive(archive data: Data) throws -> Data {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let pointerData = DataWithPointer(data: data)
|
||||
|
||||
// First, we should check footer magic bytes.
|
||||
// If they are wrong, then file cannot be 'undamaged'.
|
||||
@@ -53,7 +53,7 @@ public class XZArchive: Archive {
|
||||
// Let's now go to the start of the file.
|
||||
pointerData.index = 0
|
||||
|
||||
return try processStream(&pointerData)
|
||||
return try processStream(pointerData)
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class XZArchive: Archive {
|
||||
*/
|
||||
public static func multiUnarchive(archive data: Data) throws -> [Data] {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let pointerData = DataWithPointer(data: data)
|
||||
|
||||
// Note: for multi-stream archives we don't check footer's magic bytes,
|
||||
// because it is impossible to determine the end of each stream
|
||||
@@ -84,7 +84,7 @@ public class XZArchive: Archive {
|
||||
|
||||
var result = [Data]()
|
||||
streamLoop: while !pointerData.isAtTheEnd {
|
||||
result.append(try processStream(&pointerData))
|
||||
result.append(try processStream(pointerData))
|
||||
|
||||
guard !pointerData.isAtTheEnd else { break streamLoop }
|
||||
|
||||
@@ -114,11 +114,11 @@ public class XZArchive: Archive {
|
||||
return result
|
||||
}
|
||||
|
||||
private static func processStream(_ pointerData: inout DataWithPointer) throws -> Data {
|
||||
private static func processStream(_ pointerData: DataWithPointer) throws -> Data {
|
||||
var out: [UInt8] = []
|
||||
|
||||
// STREAM HEADER
|
||||
let streamHeader = try processStreamHeader(&pointerData)
|
||||
let streamHeader = try processStreamHeader(pointerData)
|
||||
|
||||
// BLOCKS AND INDEX
|
||||
/// Zero value of blockHeaderSize means that we encountered INDEX.
|
||||
@@ -127,10 +127,10 @@ public class XZArchive: Archive {
|
||||
while true {
|
||||
let blockHeaderSize = pointerData.alignedByte()
|
||||
if blockHeaderSize == 0 {
|
||||
indexSize = try processIndex(blockInfos, &pointerData)
|
||||
indexSize = try processIndex(blockInfos, pointerData)
|
||||
break
|
||||
} else {
|
||||
let blockInfo = try processBlock(blockHeaderSize, &pointerData)
|
||||
let blockInfo = try processBlock(blockHeaderSize, pointerData)
|
||||
out.append(contentsOf: blockInfo.blockData)
|
||||
let checkSize: Int
|
||||
switch streamHeader.checkType {
|
||||
@@ -157,12 +157,12 @@ public class XZArchive: Archive {
|
||||
}
|
||||
|
||||
// STREAM FOOTER
|
||||
try processFooter(streamHeader, indexSize, &pointerData)
|
||||
try processFooter(streamHeader, indexSize, pointerData)
|
||||
|
||||
return Data(bytes: out)
|
||||
}
|
||||
|
||||
private static func processStreamHeader(_ pointerData: inout DataWithPointer) throws -> (checkType: UInt8, flagsCRC: UInt32) {
|
||||
private static func processStreamHeader(_ pointerData: DataWithPointer) throws -> (checkType: UInt8, flagsCRC: UInt32) {
|
||||
// Check magic number.
|
||||
guard pointerData.uint64FromAlignedBytes(count: 6) == 0x005A587A37FD
|
||||
else { throw XZError.wrongMagic }
|
||||
@@ -192,7 +192,7 @@ public class XZArchive: Archive {
|
||||
}
|
||||
|
||||
private static func processBlock(_ blockHeaderSize: UInt8,
|
||||
_ pointerData: inout DataWithPointer) throws -> (blockData: [UInt8], unpaddedSize: Int, uncompressedSize: Int) {
|
||||
_ pointerData: DataWithPointer) throws -> (blockData: [UInt8], unpaddedSize: Int, uncompressedSize: Int) {
|
||||
var blockBytes: [UInt8] = []
|
||||
let blockHeaderStartIndex = pointerData.index - 1
|
||||
blockBytes.append(blockHeaderSize)
|
||||
@@ -230,7 +230,7 @@ public class XZArchive: Archive {
|
||||
blockBytes.append(contentsOf: uncompressedSizeDecodeResult.bytesProcessed)
|
||||
}
|
||||
|
||||
var filters: [(inout DataWithPointer) throws -> [UInt8]] = []
|
||||
var filters: [(DataWithPointer) throws -> [UInt8]] = []
|
||||
for _ in 0..<numberOfFilters {
|
||||
let filterIDTuple = try pointerData.multiByteDecode()
|
||||
let filterID = filterIDTuple.multiByteInteger
|
||||
@@ -245,8 +245,8 @@ public class XZArchive: Archive {
|
||||
/// In case of LZMA2 filters property is a dicitonary size.
|
||||
let filterPropeties = pointerData.alignedByte()
|
||||
blockBytes.append(filterPropeties)
|
||||
let closure = { (dwp: inout DataWithPointer) -> [UInt8] in
|
||||
try LZMA2.decompress(LZMA2.dictionarySize(filterPropeties), &dwp)
|
||||
let closure = { (dwp: DataWithPointer) -> [UInt8] in
|
||||
try LZMA2.decompress(LZMA2.dictionarySize(filterPropeties), dwp)
|
||||
}
|
||||
filters.append(closure)
|
||||
default:
|
||||
@@ -269,13 +269,13 @@ public class XZArchive: Archive {
|
||||
var intResult = pointerData
|
||||
let compressedDataStart = pointerData.index
|
||||
for filterIndex in 0..<numberOfFilters - 1 {
|
||||
var arrayResult = try filters[numberOfFilters.toInt() - filterIndex.toInt() - 1](&intResult)
|
||||
intResult = DataWithPointer(array: &arrayResult, bitOrder: intResult.bitOrder)
|
||||
var arrayResult = try filters[numberOfFilters.toInt() - filterIndex.toInt() - 1](intResult)
|
||||
intResult = DataWithPointer(array: &arrayResult)
|
||||
}
|
||||
guard compressedSize == -1 || compressedSize == pointerData.index - compressedDataStart
|
||||
else { throw XZError.wrongDataSize }
|
||||
|
||||
let out = try filters[numberOfFilters.toInt() - 1](&intResult)
|
||||
let out = try filters[numberOfFilters.toInt() - 1](intResult)
|
||||
guard uncompressedSize == -1 || uncompressedSize == out.count
|
||||
else { throw XZError.wrongDataSize }
|
||||
|
||||
@@ -294,7 +294,7 @@ public class XZArchive: Archive {
|
||||
}
|
||||
|
||||
private static func processIndex(_ blockInfos: [(unpaddedSize: Int, uncompSize: Int)],
|
||||
_ pointerData: inout DataWithPointer) throws -> Int {
|
||||
_ pointerData: DataWithPointer) throws -> Int {
|
||||
var indexBytes: [UInt8] = [0x00]
|
||||
let numberOfRecordsTuple = try pointerData.multiByteDecode()
|
||||
indexBytes.append(contentsOf: numberOfRecordsTuple.bytesProcessed)
|
||||
@@ -332,7 +332,7 @@ public class XZArchive: Archive {
|
||||
|
||||
private static func processFooter(_ streamHeader: (checkType: UInt8, flagsCRC: UInt32),
|
||||
_ indexSize: Int,
|
||||
_ pointerData: inout DataWithPointer) throws {
|
||||
_ pointerData: DataWithPointer) throws {
|
||||
let footerCRC = pointerData.uint32FromAlignedBytes(count: 4)
|
||||
let storedBackwardSize = pointerData.alignedBytes(count: 4)
|
||||
let footerStreamFlags = pointerData.alignedBytes(count: 2)
|
||||
|
||||
@@ -29,7 +29,7 @@ struct ZipCentralDirectoryEntry {
|
||||
|
||||
private(set) var modificationTimestamp: Int?
|
||||
|
||||
init(_ pointerData: inout DataWithPointer, _ currentDiskNumber: UInt32) throws {
|
||||
init(_ pointerData: DataWithPointer, _ currentDiskNumber: UInt32) throws {
|
||||
// Check signature.
|
||||
guard pointerData.uint32FromAlignedBytes(count: 4) == 0x02014b50
|
||||
else { throw ZipError.wrongSignature }
|
||||
|
||||
@@ -26,31 +26,31 @@ public class ZipContainer: Container {
|
||||
*/
|
||||
public static func open(container data: Data) throws -> [ContainerEntry] {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let bitReader = BitReader(data: data, bitOrder: .reversed)
|
||||
var entries = [ZipEntry]()
|
||||
|
||||
pointerData.index = pointerData.size - 22 // 22 is a minimum amount which could take end of CD record.
|
||||
bitReader.index = bitReader.size - 22 // 22 is a minimum amount which could take end of CD record.
|
||||
while true {
|
||||
// Check signature.
|
||||
if pointerData.uint32FromAlignedBytes(count: 4) == 0x06054b50 {
|
||||
if bitReader.uint32FromAlignedBytes(count: 4) == 0x06054b50 {
|
||||
// We found it!
|
||||
break
|
||||
}
|
||||
if pointerData.index == 0 {
|
||||
if bitReader.index == 0 {
|
||||
throw ZipError.notFoundCentralDirectoryEnd
|
||||
}
|
||||
pointerData.index -= 5
|
||||
bitReader.index -= 5
|
||||
}
|
||||
|
||||
let endOfCD = try ZipEndOfCentralDirectory(&pointerData)
|
||||
let endOfCD = try ZipEndOfCentralDirectory(bitReader)
|
||||
let cdEntries = endOfCD.cdEntries
|
||||
|
||||
// OK, now we are ready to read Central Directory itself.
|
||||
pointerData.index = Int(UInt(truncatingBitPattern: endOfCD.cdOffset))
|
||||
bitReader.index = Int(UInt(truncatingBitPattern: endOfCD.cdOffset))
|
||||
|
||||
for _ in 0..<cdEntries {
|
||||
let cdEntry = try ZipCentralDirectoryEntry(&pointerData, endOfCD.currentDiskNumber)
|
||||
entries.append(ZipEntry(cdEntry, &pointerData))
|
||||
let cdEntry = try ZipCentralDirectoryEntry(bitReader, endOfCD.currentDiskNumber)
|
||||
entries.append(ZipEntry(cdEntry, bitReader))
|
||||
}
|
||||
|
||||
return entries
|
||||
|
||||
@@ -16,7 +16,7 @@ struct ZipEndOfCentralDirectory {
|
||||
private(set) var cdSize: UInt64
|
||||
private(set) var cdOffset: UInt64
|
||||
|
||||
init(_ pointerData: inout DataWithPointer) throws {
|
||||
init(_ pointerData: DataWithPointer) throws {
|
||||
/// Indicates if Zip64 records should be present.
|
||||
var zip64RecordExists = false
|
||||
|
||||
|
||||
+19
-19
@@ -10,7 +10,7 @@ public class ZipEntry: ContainerEntry {
|
||||
|
||||
private let cdEntry: ZipCentralDirectoryEntry
|
||||
private var localHeader: ZipLocalHeader?
|
||||
private var pointerData: DataWithPointer
|
||||
private var bitReader: BitReader
|
||||
|
||||
/// Name of the file or directory.
|
||||
public var name: String {
|
||||
@@ -78,10 +78,10 @@ public class ZipEntry: ContainerEntry {
|
||||
*/
|
||||
public func data() throws -> Data {
|
||||
// Now, let's move to the location of local header.
|
||||
pointerData.index = Int(UInt32(truncatingBitPattern: self.cdEntry.offset))
|
||||
bitReader.index = Int(UInt32(truncatingBitPattern: self.cdEntry.offset))
|
||||
|
||||
if localHeader == nil {
|
||||
localHeader = try ZipLocalHeader(&pointerData)
|
||||
localHeader = try ZipLocalHeader(bitReader)
|
||||
// Check local header for consistency with Central Directory entry.
|
||||
guard localHeader!.generalPurposeBitFlags == cdEntry.generalPurposeBitFlags &&
|
||||
localHeader!.compressionMethod == cdEntry.compressionMethod &&
|
||||
@@ -103,45 +103,45 @@ public class ZipEntry: ContainerEntry {
|
||||
var crc32 = hasDataDescriptor ? cdEntry.crc32 : localHeader!.crc32
|
||||
|
||||
let fileBytes: [UInt8]
|
||||
let fileDataStart = pointerData.index
|
||||
let fileDataStart = bitReader.index
|
||||
switch localHeader!.compressionMethod {
|
||||
case 0:
|
||||
fileBytes = pointerData.alignedBytes(count: uncompSize)
|
||||
fileBytes = bitReader.alignedBytes(count: uncompSize)
|
||||
case 8:
|
||||
fileBytes = try Deflate.decompress(&pointerData)
|
||||
// Sometimes pointerData stays in not-aligned state after deflate decompression.
|
||||
fileBytes = try Deflate.decompress(bitReader)
|
||||
// Sometimes bitReader stays in not-aligned state after deflate decompression.
|
||||
// Following line ensures that this is not the case.
|
||||
pointerData.skipUntilNextByte()
|
||||
bitReader.skipUntilNextByte()
|
||||
case 12:
|
||||
#if (!SWCOMP_ZIP_POD_BUILD) || (SWCOMP_ZIP_POD_BUILD && SWCOMP_ZIP_POD_BZ2)
|
||||
fileBytes = try BZip2.decompress(&pointerData)
|
||||
fileBytes = try BZip2.decompress(bitReader)
|
||||
#else
|
||||
throw ZipError.compressionNotSupported
|
||||
#endif
|
||||
case 14:
|
||||
#if (!SWCOMP_ZIP_POD_BUILD) || (SWCOMP_ZIP_POD_BUILD && SWCOMP_ZIP_POD_LZMA)
|
||||
pointerData.index += 4 // Skipping LZMA SDK version and size of properties.
|
||||
fileBytes = try LZMA.decompress(&pointerData, uncompSize)
|
||||
bitReader.index += 4 // Skipping LZMA SDK version and size of properties.
|
||||
fileBytes = try LZMA.decompress(bitReader, uncompSize)
|
||||
#else
|
||||
throw ZipError.compressionNotSupported
|
||||
#endif
|
||||
default:
|
||||
throw ZipError.compressionNotSupported
|
||||
}
|
||||
let realCompSize = pointerData.index - fileDataStart
|
||||
let realCompSize = bitReader.index - fileDataStart
|
||||
|
||||
if hasDataDescriptor {
|
||||
// Now we need to parse data descriptor itself.
|
||||
// First, it might or might not have signature.
|
||||
let ddSignature = pointerData.uint32FromAlignedBytes(count: 4)
|
||||
let ddSignature = bitReader.uint32FromAlignedBytes(count: 4)
|
||||
if ddSignature != 0x08074b50 {
|
||||
pointerData.index -= 4
|
||||
bitReader.index -= 4
|
||||
}
|
||||
// Now, let's update from CD with values from data descriptor.
|
||||
crc32 = pointerData.uint32FromAlignedBytes(count: 4)
|
||||
crc32 = bitReader.uint32FromAlignedBytes(count: 4)
|
||||
let sizeOfSizeField: UInt32 = localHeader!.zip64FieldsArePresent ? 8 : 4
|
||||
compSize = Int(pointerData.uint32FromAlignedBytes(count: sizeOfSizeField))
|
||||
uncompSize = Int(pointerData.uint32FromAlignedBytes(count: sizeOfSizeField))
|
||||
compSize = Int(bitReader.uint32FromAlignedBytes(count: sizeOfSizeField))
|
||||
uncompSize = Int(bitReader.uint32FromAlignedBytes(count: sizeOfSizeField))
|
||||
}
|
||||
|
||||
guard compSize == realCompSize && uncompSize == fileBytes.count
|
||||
@@ -152,9 +152,9 @@ public class ZipEntry: ContainerEntry {
|
||||
return Data(bytes: fileBytes)
|
||||
}
|
||||
|
||||
init(_ cdEntry: ZipCentralDirectoryEntry, _ pointerData: inout DataWithPointer) {
|
||||
init(_ cdEntry: ZipCentralDirectoryEntry, _ bitReader: BitReader) {
|
||||
self.cdEntry = cdEntry
|
||||
self.pointerData = pointerData
|
||||
self.bitReader = bitReader
|
||||
|
||||
var attributesDict = [FileAttributeKey: Any]()
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ struct ZipLocalHeader {
|
||||
private(set) var accessTimestamp: Int?
|
||||
private(set) var creationTimestamp: Int?
|
||||
|
||||
init(_ pointerData: inout DataWithPointer) throws {
|
||||
init(_ pointerData: DataWithPointer) throws {
|
||||
// Check signature.
|
||||
guard pointerData.uint32FromAlignedBytes(count: 4) == 0x04034b50
|
||||
else { throw ZipError.wrongSignature }
|
||||
|
||||
@@ -27,13 +27,13 @@ public class ZlibArchive: Archive {
|
||||
*/
|
||||
public static func unarchive(archive data: Data) throws -> Data {
|
||||
/// Object with input data which supports convenient work with bit shifts.
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
let bitReader = BitReader(data: data, bitOrder: .reversed)
|
||||
|
||||
_ = try ZlibHeader(&pointerData)
|
||||
_ = try ZlibHeader(bitReader)
|
||||
|
||||
let out = try Deflate.decompress(&pointerData)
|
||||
let out = try Deflate.decompress(bitReader)
|
||||
|
||||
let adler32 = pointerData.intFromAlignedBytes(count: 4).reverseBytes()
|
||||
let adler32 = bitReader.intFromAlignedBytes(count: 4).reverseBytes()
|
||||
guard CheckSums.adler32(out) == adler32 else { throw ZlibError.wrongAdler32(Data(bytes: out)) }
|
||||
|
||||
return Data(bytes: out)
|
||||
|
||||
@@ -46,21 +46,21 @@ public struct ZlibHeader {
|
||||
it might not be archived with Zlib at all.
|
||||
*/
|
||||
public init(archive data: Data) throws {
|
||||
var pointerData = DataWithPointer(data: data, bitOrder: .reversed)
|
||||
try self.init(&pointerData)
|
||||
let bitReader = BitReader(data: data, bitOrder: .reversed)
|
||||
try self.init(bitReader)
|
||||
}
|
||||
|
||||
init(_ pointerData: inout DataWithPointer) throws {
|
||||
init(_ bitReader: BitReader) throws {
|
||||
// First four bits are compression method.
|
||||
// Only compression method = 8 (DEFLATE) is supported.
|
||||
let compressionMethod = pointerData.intFromBits(count: 4)
|
||||
let compressionMethod = bitReader.intFromBits(count: 4)
|
||||
guard compressionMethod == 8 else { throw ZlibError.wrongCompressionMethod }
|
||||
|
||||
self.compressionMethod = .deflate
|
||||
|
||||
// Remaining four bits indicate window size.
|
||||
// For Deflate it must not be more than 7.
|
||||
let compressionInfo = pointerData.intFromBits(count: 4)
|
||||
let compressionInfo = bitReader.intFromBits(count: 4)
|
||||
guard compressionInfo <= 7 else { throw ZlibError.wrongCompressionInfo }
|
||||
let windowSize = 1 << (compressionInfo + 8)
|
||||
|
||||
@@ -70,14 +70,14 @@ public struct ZlibHeader {
|
||||
let cmf = compressionInfo << 4 + compressionMethod
|
||||
|
||||
// Next five bits are fcheck bits which are supposed to be integrity check.
|
||||
let fcheck = pointerData.intFromBits(count: 5)
|
||||
let fcheck = bitReader.intFromBits(count: 5)
|
||||
|
||||
// Sixth bit indicate if archive contain Adler-32 checksum of preset dictionary.
|
||||
let fdict = pointerData.intFromBits(count: 1)
|
||||
let fdict = bitReader.intFromBits(count: 1)
|
||||
|
||||
// Remaining bits indicate compression level.
|
||||
guard let compressionLevel = ZlibHeader.CompressionLevel(rawValue:
|
||||
pointerData.intFromBits(count: 2)) else { throw ZlibError.wrongCompressionLevel }
|
||||
bitReader.intFromBits(count: 2)) else { throw ZlibError.wrongCompressionLevel }
|
||||
|
||||
self.compressionLevel = compressionLevel
|
||||
|
||||
@@ -87,7 +87,7 @@ public struct ZlibHeader {
|
||||
|
||||
// If preset dictionary is present 4 bytes will be skipped.
|
||||
if fdict == 1 {
|
||||
pointerData.index += 4
|
||||
bitReader.index += 4
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user