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:
Timofey Solomko
2017-07-08 22:02:32 +03:00
parent 6eb62fc087
commit 369da20c16
20 changed files with 154 additions and 155 deletions
+22 -22
View File
@@ -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
View File
@@ -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).
+9 -8
View File
@@ -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
View File
@@ -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)
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
+4 -6
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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 }
+9 -9
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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]()
+1 -1
View File
@@ -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 }
+4 -4
View File
@@ -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)
+9 -9
View File
@@ -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
}
}