in Checkpoints/SnappyDecompression.swift [65:159]
func decompressSnappyStream(at index: inout Int) throws -> Data? {
guard index < self.count else { return nil }
let uncompressedLength = readVarint32(at: &index)
var uncompressedData = Data()
while uncompressedData.count < uncompressedLength {
// Each section starts with a tag byte, which determines whether to read a sequence of
// bytes directly into the uncompressed data (literal) or to copy a sequence of
// previously-decompressed bytes into this position. The last two bits indicate the
// class of the section, and the remaining bits encode class-specific information like
// how many offset or length bytes follow or the length of the section to copy.
let tagByte = readByte(at: &index)
let tagType = tagByte & 0b00000011
let upperBits = tagByte >> 2
switch tagType {
case 0: // Literal string of bytes.
let literalLength: Int
switch upperBits {
case 0..<60: // Literal length is encoded in the upper bits of the tag byte.
literalLength = Int(upperBits) + 1
case 60: // One-byte literal length following the tag byte.
literalLength = Int(readByte(at: &index)) + 1
case 61: // Two-byte literal length following the tag byte.
let firstByte = readByte(at: &index)
let secondByte = readByte(at: &index)
literalLength = Int(firstByte) + Int(secondByte) * 256 + 1
case 62: // Three-byte literal length following the tag byte.
let firstByte = readByte(at: &index)
let secondByte = readByte(at: &index)
let thirdByte = readByte(at: &index)
literalLength = Int(firstByte) + Int(secondByte) * 256 + Int(thirdByte) * 256
* 256 + 1
case 63: // Four-byte literal length following the tag byte.
let firstByte = readByte(at: &index)
let secondByte = readByte(at: &index)
let thirdByte = readByte(at: &index)
let fourthByte = readByte(at: &index)
literalLength = Int(firstByte) + Int(secondByte) * 256 + Int(thirdByte) * 256
* 256 + Int(fourthByte) * 256 * 256 * 256 + 1
default:
throw SnappyDecompressionError.illegalLiteralLength(upperBits: upperBits)
}
let literalData = self.readDataBlock(at: &index, size: literalLength)
uncompressedData.append(literalData)
case 1: // Copy with 1-byte offset.
let copyLength = Int(upperBits & 0b00000111) + 4
let upperOffset = (upperBits & 0b00111000) >> 3
let lowerOffset = readByte(at: &index)
let offset = Int(upperOffset) * 256 + Int(lowerOffset)
var sourceIndex = uncompressedData.count - offset
if offset < copyLength {
// Perform run-length encoding for offsets that cause reading past the end of
// the file.
let copiedBytes = copyLength - offset
let copyData = uncompressedData.readDataBlock(at: &sourceIndex, size: offset)
uncompressedData.append(copyData)
sourceIndex = uncompressedData.count - offset
let additionalData = uncompressedData.readDataBlock(
at: &sourceIndex, size: copiedBytes)
uncompressedData.append(additionalData)
} else {
let copyData = uncompressedData.readDataBlock(
at: &sourceIndex, size: copyLength)
uncompressedData.append(copyData)
}
case 2: // Copy with 2-byte offset.
let copyLength = Int(upperBits) + 1
let firstByte = readByte(at: &index)
let secondByte = readByte(at: &index)
var sourceIndex = uncompressedData.count - (Int(firstByte) + Int(secondByte) * 256)
let copyData = uncompressedData.readDataBlock(at: &sourceIndex, size: copyLength)
uncompressedData.append(copyData)
case 3: // Copy with 4-byte offset.
let copyLength = Int(upperBits) + 1
let firstByte = readByte(at: &index)
let secondByte = readByte(at: &index)
let thirdByte = readByte(at: &index)
let fourthByte = readByte(at: &index)
var sourceIndex = uncompressedData.count - (Int(firstByte) + Int(secondByte) * 256
+ Int(thirdByte) * 256 * 256 + Int(fourthByte) * 256 * 256 * 256)
let copyData = uncompressedData.readDataBlock(at: &sourceIndex, size: copyLength)
uncompressedData.append(copyData)
default:
throw SnappyDecompressionError.impossibleTagType(tagType: tagType)
}
}
if uncompressedData.count != uncompressedLength {
throw SnappyDecompressionError.uncompressedDataLengthMismatch(
target: uncompressedLength, actual: uncompressedData.count)
}
return uncompressedData
}