func decompressSnappyStream()

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
    }