/* * darwin-apk © 2024 Gay Pizza Specifications * SPDX-License-Identifier: Apache-2.0 */ import Foundation import zlib struct GZipReader: ~Copyable { private static let bufferSize = 0x8000 private var zstream = z_stream() private var inputBuffer = [UInt8](repeating: 0, count: Self.bufferSize) private var outputBuffer = [UInt8](repeating: 0, count: Self.bufferSize) deinit { var zstream = self.zstream inflateEnd(&zstream) } mutating func read(inStream stream: S) throws(GZipError) -> Data { // Initialise zlib if this is the first time we're called // otherwise reset the stream in anticipation of reading the next concatenated stream var zerr = if self.zstream.state == nil { inflateInit2_(&self.zstream, 16 + MAX_WBITS, ZLIB_VERSION, Int32(MemoryLayout.size)) } else { inflateReset(&self.zstream) } guard zerr == Z_OK else { throw .zlib(zerr) } var payload = Data() repeat { if self.zstream.avail_in == 0 { // Zlib has asked for more input, fill the input buffer let read: Int do { read = try stream.read(&inputBuffer, maxLength: inputBuffer.count) } catch { throw .streamError(error) } guard read > 0 else { throw .truncatedStream } // Reset input buffer read state self.zstream.avail_in = UInt32(read) self.zstream.next_in = inputBuffer.withUnsafeMutableBufferPointer(\.baseAddress!) } // Inflate next chunk of stream self.zstream.avail_out = UInt32(outputBuffer.count) self.zstream.next_out = outputBuffer.withUnsafeMutableBufferPointer(\.baseAddress!) zerr = inflate(&self.zstream, Z_NO_FLUSH) // Copy output bytes to payload let decodedBytes = outputBuffer.count - Int(self.zstream.avail_out) payload += Data(outputBuffer[..