Skip to content

Commit

Permalink
Merge pull request #53 from dev-yong/sync-fork-repository
Browse files Browse the repository at this point in the history
Support decompression for combined compression
  • Loading branch information
1024jp authored Apr 29, 2023
2 parents 0dabd4e + 35c5903 commit f32efd3
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 47 deletions.
104 changes: 57 additions & 47 deletions Sources/Gzip/Data+Gzip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -243,61 +243,71 @@ extension Data {
return Data()
}

var stream = z_stream()
var status: Int32

status = inflateInit2_(&stream, wBits, ZLIB_VERSION, Int32(DataSize.stream))

guard status == Z_OK else {
// inflateInit2 returns:
// Z_VERSION_ERROR The zlib library version is incompatible with the version assumed by the caller.
// Z_MEM_ERROR There was not enough memory.
// Z_STREAM_ERROR A parameters are invalid.

throw GzipError(code: status, msg: stream.msg)
}

var data = Data(capacity: self.count * 2)
var totalIn: uLong = 0
var totalOut: uLong = 0

repeat {
if Int(stream.total_out) >= data.count {
data.count += self.count / 2
var stream = z_stream()
var status: Int32

status = inflateInit2_(&stream, wBits, ZLIB_VERSION, Int32(DataSize.stream))

guard status == Z_OK else {
// inflateInit2 returns:
// Z_VERSION_ERROR The zlib library version is incompatible with the version assumed by the caller.
// Z_MEM_ERROR There was not enough memory.
// Z_STREAM_ERROR A parameters are invalid.

throw GzipError(code: status, msg: stream.msg)
}

let inputCount = self.count
let outputCount = data.count

self.withUnsafeBytes { (inputPointer: UnsafeRawBufferPointer) in
stream.next_in = UnsafeMutablePointer<Bytef>(mutating: inputPointer.bindMemory(to: Bytef.self).baseAddress!).advanced(by: Int(stream.total_in))
stream.avail_in = uint(inputCount) - uInt(stream.total_in)

data.withUnsafeMutableBytes { (outputPointer: UnsafeMutableRawBufferPointer) in
stream.next_out = outputPointer.bindMemory(to: Bytef.self).baseAddress!.advanced(by: Int(stream.total_out))
stream.avail_out = uInt(outputCount) - uInt(stream.total_out)

status = inflate(&stream, Z_SYNC_FLUSH)

stream.next_out = nil

repeat {
if Int(totalOut + stream.total_out) >= data.count {
data.count += self.count / 2
}

let inputCount = self.count
let outputCount = data.count

self.withUnsafeBytes { (inputPointer: UnsafeRawBufferPointer) in
let inputStartPosition = totalIn + stream.total_in
stream.next_in = UnsafeMutablePointer<Bytef>(mutating: inputPointer.bindMemory(to: Bytef.self).baseAddress!).advanced(by: Int(inputStartPosition))
stream.avail_in = uint(inputCount) - uInt(inputStartPosition)

data.withUnsafeMutableBytes { (outputPointer: UnsafeMutableRawBufferPointer) in
let outputStartPosition = totalOut + stream.total_out
stream.next_out = outputPointer.bindMemory(to: Bytef.self).baseAddress!.advanced(by: Int(outputStartPosition))
stream.avail_out = uInt(outputCount) - uInt(outputStartPosition)

status = inflate(&stream, Z_SYNC_FLUSH)

stream.next_out = nil
}

stream.next_in = nil
}

stream.next_in = nil
} while (status == Z_OK)
totalIn += stream.total_in

guard inflateEnd(&stream) == Z_OK, status == Z_STREAM_END else {
// inflate returns:
// Z_DATA_ERROR The input data was corrupted (input stream not conforming to the zlib format or incorrect check value).
// Z_STREAM_ERROR The stream structure was inconsistent (for example if next_in or next_out was NULL).
// Z_MEM_ERROR There was not enough memory.
// Z_BUF_ERROR No progress is possible or there was not enough room in the output buffer when Z_FINISH is used.
throw GzipError(code: status, msg: stream.msg)
}

} while status == Z_OK

guard inflateEnd(&stream) == Z_OK, status == Z_STREAM_END else {
// inflate returns:
// Z_DATA_ERROR The input data was corrupted (input stream not conforming to the zlib format or incorrect check value).
// Z_STREAM_ERROR The stream structure was inconsistent (for example if next_in or next_out was NULL).
// Z_MEM_ERROR There was not enough memory.
// Z_BUF_ERROR No progress is possible or there was not enough room in the output buffer when Z_FINISH is used.

throw GzipError(code: status, msg: stream.msg)
}

data.count = Int(stream.total_out)



totalOut += stream.total_out
} while (totalIn < self.count)
data.count = Int(totalOut)

return data
}


}

Expand Down
13 changes: 13 additions & 0 deletions Tests/GzipTests/GzipTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,19 @@ final class GzipTests: XCTestCase {
XCTAssertEqual(json?.first, "{")
XCTAssertEqual(json?.last, "}")
}

func testDecompressionCompositedCompression() throws {
let firstData = try XCTUnwrap("test".data(using: .utf8)).gzipped()
let secondData = try XCTUnwrap("string".data(using: .utf8)).gzipped()

let data = firstData + secondData

let uncompressed = try data.gunzipped()

XCTAssertTrue(data.isGzipped)
XCTAssertEqual(String(data: uncompressed, encoding: .utf8), "teststring")
}

}


Expand Down

0 comments on commit f32efd3

Please sign in to comment.