Ejemplo n.º 1
0
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();
}
Ejemplo n.º 2
0
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;
}