| 83 | } |
| 84 | |
| 85 | bool zlibDecompress(IStream& source, uint64_t sourceLength, IStream& dest, uint64_t decompressLength, ZlibHeaderType header) |
| 86 | { |
| 87 | if (sourceLength > source.GetLength() - source.GetPosition()) |
| 88 | throw IOException("Not Enough Data to Decompress"); |
| 89 | |
| 90 | StreamReadBuffer sourceBuf(source, sourceLength, kZlibChunkSize); |
| 91 | StreamWriteBuffer destBuf(dest, decompressLength, kZlibChunkSize); |
| 92 | |
| 93 | z_stream strm{}; |
| 94 | int ret = inflateInit2(&strm, kZlibWindowBits[static_cast<int>(header)]); |
| 95 | if (ret != Z_OK) |
| 96 | { |
| 97 | LOG_ERROR("Failed to initialise stream"); |
| 98 | return false; |
| 99 | } |
| 100 | |
| 101 | do |
| 102 | { |
| 103 | auto readBlock = sourceBuf.ReadBlock(source, kZlibMaxChunkSize); |
| 104 | strm.next_in = static_cast<const Bytef*>(readBlock.first); |
| 105 | strm.avail_in = static_cast<uInt>(readBlock.second); |
| 106 | |
| 107 | do |
| 108 | { |
| 109 | if (!destBuf) |
| 110 | { |
| 111 | LOG_ERROR("Decompressed data larger than expected"); |
| 112 | inflateEnd(&strm); |
| 113 | return false; |
| 114 | } |
| 115 | |
| 116 | auto writeBlock = destBuf.WriteBlockStart(kZlibMaxChunkSize); |
| 117 | strm.next_out = static_cast<Bytef*>(writeBlock.first); |
| 118 | strm.avail_out = static_cast<uInt>(writeBlock.second); |
| 119 | |
| 120 | ret = inflate(&strm, sourceBuf ? Z_NO_FLUSH : Z_FINISH); |
| 121 | if (ret == Z_STREAM_ERROR) |
| 122 | { |
| 123 | LOG_ERROR("Failed to decompress data"); |
| 124 | inflateEnd(&strm); |
| 125 | return false; |
| 126 | } |
| 127 | |
| 128 | destBuf.WriteBlockCommit(dest, writeBlock.second - strm.avail_out); |
| 129 | } while (strm.avail_in > 0); |
| 130 | } while (sourceBuf); |
| 131 | |
| 132 | if (destBuf) |
| 133 | { |
| 134 | LOG_ERROR("Decompressed data smaller than expected"); |
| 135 | inflateEnd(&strm); |
| 136 | return false; |
| 137 | } |
| 138 | |
| 139 | inflateEnd(&strm); |
| 140 | return true; |
| 141 | } |
| 142 |
no test coverage detected