bool DecompressLZOCompressedPackage(UPKReader *Package) { if (!Package->IsCompressed()) { _LogError("Package is not compressed!", "DecompressLZO"); return false; } if (!Package->IsLZOCompressed() && !Package->IsFullyCompressed()) { _LogError("Cannot decompress non-LZO compressed packages!", "DecompressLZO"); return false; } /// init lzo library int lzo_err; lzo_uint in_len; lzo_uint out_len; lzo_uint new_len; if (lzo_init() != LZO_E_OK) { _LogError("LZO library internal error: lzo_init() failed!", "DecompressLZO"); return false; } lzo_memset(in, 0, IN_LEN); std::stringstream decompressed_stream; unsigned int NumCompressedChunks = Package->Summary.NumCompressedChunks; if (Package->IsFullyCompressed()) { NumCompressedChunks = 1; } else { _LogDebug("Resetting package compression flags...", "DecompressLZO"); /// reset compression flags Package->Summary.CompressionFlags = 0; Package->Summary.PackageFlags ^= (uint32_t)UPackageFlags::Compressed; Package->Summary.NumCompressedChunks = 0; /// serialize package summary std::vector<char> sVect = Package->SerializeSummary(); decompressed_stream.write(sVect.data(), sVect.size()); } _LogDebug("Decompressing...", "DecompressLZO"); for (unsigned int i = 0; i < NumCompressedChunks; ++i) { if (Package->IsFullyCompressed()) { Package->UPKStream.seekg(0); } else { Package->UPKStream.seekg(Package->Summary.CompressedChunks[i].CompressedOffset); } _LogDebug("Decompressing chunk #" + ToString(i), "DecompressLZO"); uint32_t tag = 0; Package->UPKStream.read(reinterpret_cast<char*>(&tag), 4); if (tag != 0x9E2A83C1) { _LogError("Missing 0x9E2A83C1 signature!", "DecompressLZO"); return false; } uint32_t blockSize = 0; Package->UPKStream.read(reinterpret_cast<char*>(&blockSize), 4); if (blockSize != IN_LEN) { _LogError("Incorrect max block size!", "DecompressLZO"); return false; } std::vector<uint32_t> sizes(2); /// compressed/uncompressed pairs Package->UPKStream.read(reinterpret_cast<char*>(sizes.data()), 4 * sizes.size()); size_t dataSize = sizes[1]; /// uncompressed data chunk size unsigned numBlocks = (dataSize + blockSize - 1) / blockSize; _LogDebug("numBlocks = " + ToString(numBlocks), "DecompressLZO"); if (numBlocks < 1) { _LogError("Bad data!", "DecompressLZO"); return false; } sizes.resize((numBlocks + 1)*2); Package->UPKStream.read(reinterpret_cast<char*>(sizes.data()) + 8, 4 * sizes.size() - 8); for (unsigned i = 0; i <= numBlocks; ++i) { _LogDebug("Compressed size = " + ToString(sizes[i * 2]) + + "\tUncompressed size = " + ToString(sizes[i * 2 + 1]), "DecompressLZO"); } std::vector<unsigned char> dataChunk(dataSize); std::vector<unsigned char> compressedData(sizes[0]); Package->UPKStream.read(reinterpret_cast<char*>(compressedData.data()), compressedData.size()); size_t blockOffset = 0; size_t dataOffset = 0; for (unsigned i = 1; i <= numBlocks; ++i) { out_len = sizes[i * 2]; /// compressed size lzo_memcpy(out, compressedData.data() + blockOffset, out_len); in_len = sizes[i * 2 + 1]; /// uncompressed size new_len = in_len; lzo_err = lzo1x_decompress(out, out_len, in, &new_len, NULL); if (lzo_err == LZO_E_OK && new_len == in_len) { _LogDebug("Decompressed " + ToString(out_len) + " bytes back into " + ToString(in_len), "DecompressLZO"); } else { _LogError("LZO library internal error: decompression failed!", "DecompressLZO"); return false; } lzo_memcpy(dataChunk.data() + dataOffset, in, in_len); blockOffset += out_len; dataOffset += in_len; } decompressed_stream.write(reinterpret_cast<char*>(dataChunk.data()), dataSize); } _LogDebug("Package decompressed successfully.", "DecompressLZO"); Package->UPKStream.str(decompressed_stream.str()); return Package->ReadPackageHeader(); }
int do_file ( const char *in_name ) { int r; FILE *fp = NULL; long l; lzo_voidp wrkmem = NULL; lzo_bytep in = NULL; lzo_uint in_len; /* uncompressed length */ lzo_bytep out = NULL; lzo_uint out_len; /* compressed length */ lzo_bytep overlap = NULL; lzo_uint overhead; lzo_uint offset; lzo_uint new_len = 0; /* * Step 1: open the input file */ fp = fopen(in_name, "rb"); if (fp == NULL) { printf("%s: %s: cannot open file\n", progname, in_name); goto next_file; } fseek(fp, 0, SEEK_END); l = ftell(fp); fseek(fp, 0, SEEK_SET); if (l <= 0) { printf("%s: %s: empty file -- skipping\n", progname, in_name); goto next_file; } in_len = (lzo_uint) l; /* * Step 2: allocate compression buffers and read the file */ in = (lzo_bytep) xmalloc(in_len); out = (lzo_bytep) xmalloc(in_len + in_len / 16 + 64 + 3); wrkmem = (lzo_voidp) xmalloc(LZO1X_1_MEM_COMPRESS); in_len = (lzo_uint) lzo_fread(fp, in, in_len); fclose(fp); fp = NULL; printf("%s: %s: read %lu bytes\n", progname, in_name, (unsigned long) in_len); total_files++; total_in += (unsigned long) in_len; /* * Step 3: compress from 'in' to 'out' with LZO1X-1 */ r = lzo1x_1_compress(in,in_len,out,&out_len,wrkmem); if (r != LZO_E_OK || out_len > in_len + in_len / 16 + 64 + 3) { /* this should NEVER happen */ printf("internal error - compression failed: %d\n", r); exit(1); } printf("%-26s %8lu -> %8lu\n", "LZO1X-1:", (unsigned long) in_len, (unsigned long) out_len); /***** Step 4: overlapping compression *****/ /* * Step 4a: allocate the 'overlap' buffer for overlapping compression */ overhead = in_len > 0xbfff ? 0xbfff : in_len; overhead += in_len / 16 + 64 + 3; overlap = (lzo_bytep) xmalloc(in_len + overhead); /* * Step 4b: prepare data in 'overlap' buffer. * copy uncompressed data at the top of the overlap buffer */ /*** offset = in_len + overhead - in_len; ***/ offset = overhead; lzo_memcpy(overlap + offset, in, in_len); /* * Step 4c: do an in-place compression within the 'overlap' buffer */ r = lzo1x_1_compress(overlap+offset,in_len,overlap,&new_len,wrkmem); if (r != LZO_E_OK) { /* this should NEVER happen */ printf("overlapping compression failed: %d\n", r); exit(1); } /* * Step 4d: verify overlapping compression */ if (new_len != out_len || lzo_memcmp(out,overlap,out_len) != 0) { /* As compression is non-deterministic there can be a difference * in the representation of the compressed data (but this usually * happens very seldom). So we have to verify the overlapping * compression by doing a temporary decompression. */ lzo_uint ll = in_len; lzo_bytep tmp = (lzo_bytep) xmalloc(ll); r = lzo1x_decompress_safe(overlap, new_len, tmp, &ll, NULL); if (r != LZO_E_OK || ll != in_len || lzo_memcmp(in, tmp, ll) != 0) { /* this should NEVER happen */ printf("overlapping compression data error\n"); exit(1); } lzo_free(tmp); } printf("overlapping compression: %8lu -> %8lu overhead: %7lu\n", (unsigned long) in_len, (unsigned long) new_len, (unsigned long) overhead); lzo_free(overlap); overlap = NULL; /***** Step 5: overlapping decompression *****/ /* * Step 5a: allocate the 'overlap' buffer for in-place decompression */ if (opt_overhead == 0 || out_len >= in_len) overhead = in_len / 16 + 64 + 3; else overhead = opt_overhead; overlap = (lzo_bytep) xmalloc(in_len + overhead); /* * Step 5b: prepare data in 'overlap' buffer. * copy compressed data at the top of the overlap buffer */ offset = in_len + overhead - out_len; lzo_memcpy(overlap + offset, out, out_len); /* * Step 5c: do an in-place decompression within the 'overlap' buffer */ new_len = in_len; r = lzo1x_decompress(overlap+offset,out_len,overlap,&new_len,NULL); if (r != LZO_E_OK) { /* this may happen if overhead is too small */ printf("overlapping decompression failed: %d - increase 'opt_overhead'\n", r); exit(1); } /* * Step 5d: verify decompression */ if (new_len != in_len || lzo_memcmp(in,overlap,in_len) != 0) { /* this may happen if overhead is too small */ printf("overlapping decompression data error - increase 'opt_overhead'\n"); exit(1); } printf("overlapping decompression: %8lu -> %8lu overhead: %7lu\n", (unsigned long) out_len, (unsigned long) new_len, (unsigned long) overhead); lzo_free(overlap); overlap = NULL; next_file: lzo_free(overlap); lzo_free(wrkmem); lzo_free(out); lzo_free(in); if (fp) fclose(fp); return 0; }