| 222 | } |
| 223 | |
| 224 | bool zstdDecompress(IStream& source, uint64_t sourceLength, IStream& dest, uint64_t decompressLength) |
| 225 | { |
| 226 | if (sourceLength > source.GetLength() - source.GetPosition()) |
| 227 | throw IOException("Not Enough Data to Decompress"); |
| 228 | |
| 229 | size_t ret; |
| 230 | StreamReadBuffer sourceBuf(source, sourceLength, ZSTD_DStreamInSize()); |
| 231 | StreamWriteBuffer destBuf(dest, decompressLength, ZSTD_DStreamOutSize()); |
| 232 | |
| 233 | const auto deleter = [](ZSTD_DCtx* ptr) { ZSTD_freeDCtx(ptr); }; |
| 234 | std::unique_ptr<ZSTD_DCtx, decltype(deleter)> ctx(ZSTD_createDCtx(), deleter); |
| 235 | if (ctx == nullptr) |
| 236 | { |
| 237 | LOG_ERROR("Failed to create zstd context"); |
| 238 | return false; |
| 239 | } |
| 240 | |
| 241 | do |
| 242 | { |
| 243 | auto readBlock = sourceBuf.ReadBlock(source); |
| 244 | ZSTD_inBuffer input = { readBlock.first, readBlock.second, 0 }; |
| 245 | |
| 246 | do |
| 247 | { |
| 248 | if (!destBuf) |
| 249 | { |
| 250 | LOG_ERROR("Decompressed data larger than expected"); |
| 251 | return false; |
| 252 | } |
| 253 | |
| 254 | auto writeBlock = destBuf.WriteBlockStart(); |
| 255 | ZSTD_outBuffer output = { writeBlock.first, writeBlock.second, 0 }; |
| 256 | |
| 257 | ret = ZSTD_decompressStream(ctx.get(), &output, &input); |
| 258 | if (ZSTD_isError(ret)) |
| 259 | { |
| 260 | LOG_ERROR("Failed to compress data with error: %s", ZSTD_getErrorName(ret)); |
| 261 | return false; |
| 262 | } |
| 263 | |
| 264 | destBuf.WriteBlockCommit(dest, output.pos); |
| 265 | } while (input.pos < input.size || (!sourceBuf && ret > 0)); |
| 266 | } while (sourceBuf); |
| 267 | |
| 268 | if (destBuf) |
| 269 | { |
| 270 | LOG_ERROR("Decompressed data smaller than expected"); |
| 271 | return false; |
| 272 | } |
| 273 | |
| 274 | return true; |
| 275 | } |
| 276 | } // namespace OpenRCT2::Compression |
no test coverage detected