Esempio n. 1
0
qword _chm_decompress_region(chm_t *chm, 
                             uchar *buf,
                             uqword start,
                             qword len)
{
    uqword nBlock, nOffset;
    uqword nLen;
    uqword gotLen;
    uchar *ubuffer;
    
    if (len <= 0)
        return (qword)0;
    
    /* figure out what we need to read */
    nBlock = start / chm->reset_table.block_len;
    nOffset = start % chm->reset_table.block_len;
    nLen = len;
    if (nLen > (chm->reset_table.block_len - nOffset))
        nLen = chm->reset_table.block_len - nOffset;
    
    if (chm->cache_block_indices[nBlock % chm->cache_num_blocks] == nBlock    &&
        chm->cache_blocks[nBlock % chm->cache_num_blocks] != NULL)
    {
        memcpy(buf,
               chm->cache_blocks[nBlock % chm->cache_num_blocks] + nOffset,
               (unsigned int)nLen);
        return nLen;
    }
    
    /* data request not satisfied, so... start up the decompressor machine */
    if (! chm->lzx_state)
    {
        int window_size = ffs(chm->window_size) - 1;
        chm->lzx_last_block = -1;
        chm->lzx_state = LZXinit(window_size);
    }
    
    /* decompress some data */
    gotLen = _chm_decompress_block(chm, nBlock, &ubuffer);
    if (gotLen < nLen)
        nLen = gotLen;
    memcpy(buf, ubuffer+nOffset, (unsigned int)nLen);
    return nLen;
}
Esempio n. 2
0
/**
 * @name CreateNewFileFromPatch
 * Using the input @param Header and @param Patch, create a new file on @param new_file
 *
 * @param Header
 * Parsed / preprocessed patch header
 *
 * @param Patch
 * Memory buffer pointing to the patch payload
 *
 * @param new_file
 * A handle to the output file. This file will be resized
 *
 * @return STATUS_SUCCESS on success, an error code otherwise
 */
DWORD CreateNewFileFromPatch(PATCH_HEADER* Header, SAFE_READ* Patch, HANDLE new_file)
{
    SAFE_READ NewFile;
    HANDLE hMap;
    USHORT BlockSize;
    DWORD dwStatus;
    struct LZXstate* state;
    int lzxResult;

    hMap = CreateFileMappingW(new_file, NULL, PAGE_READWRITE, 0, Header->OutputSize, NULL);
    if (hMap == INVALID_HANDLE_VALUE)
        return ERROR_PATCH_NOT_AVAILABLE;

    NewFile.Root = NewFile.Ptr = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
    CloseHandle(hMap);
    NewFile.Size = Header->OutputSize;

    if (!NewFile.Root)
        return ERROR_PATCH_NOT_AVAILABLE;

    /* At this point Patch->Ptr should point to the payload */
    BlockSize = ReadUShort(Patch);

    /* This window size does not work on all files (for example, MS SQL Express 2008 setup) */
    state = LZXinit(17);
    if (state)
    {
        lzxResult = LZXdecompress(state, Patch->Ptr, NewFile.Ptr, BlockSize, NewFile.Size);
        LZXteardown(state);

        if (lzxResult == DECR_OK)
            dwStatus = STATUS_SUCCESS;
        else
            dwStatus = ERROR_PATCH_DECODE_FAILURE;
    }
    else
    {
        dwStatus = ERROR_INSUFFICIENT_BUFFER;
    }

    UnmapViewOfFile(NewFile.Root);
    return dwStatus;
}
Esempio n. 3
0
/*--[decompress_section]-------------------------------------------------------
 |
 | A somewhat tricky routine as it handles interfacing with the external
 | LZX library. There is a reason for using the ResetTable here, as
 | otherwise certain files will not be correctly handled!
 |
 | Generally --
 | I need to get the LZXC control information to get the window size.
 | This lets me initialize the LZX library.
 |
 | From there, I read the ResetTable to know the uncompressed length and
 | each "LZXReset()" point.
 |
 | Note that the LZXReset() that this routine requires is not part of the
 | standard lzx distribution. The version that works with these files is from
 | the chmlib implementation and already has been modified.
*/
int decompress_section(lit_file * litfile, char * section_name,
    U8 * pControl, int sizeControl, U8 * pContent, int sizeContent,
    U8 ** ppUncompressed, int * psizeUncompressed)
{
    char        *path;
    int         sizeRT, ofsEntry, base, dst, u;
    int         bytesRemaining, uclength, window_bytes, accum, size;
    U8          * ptr, * pRT;
    int         window_size, status;

    if ((sizeControl < 32) || (READ_U32(pControl+CONTROL_TAG) != LZXC_TAG)) {
        lit_error(ERR_R, "Invalid ControlData tag value %08lx should be %08lx!",
            (sizeControl > 8)?READ_U32(pControl+CONTROL_TAG):0,
            LZXC_TAG);
        return E_LIT_FORMAT_ERROR;
    }

    window_size = 14;
    u = READ_U32(pControl + CONTROL_WINDOW_SIZE);
    while (u) {
        u >>= 1;
        window_size++;
    }
    if ((window_size < 15) || (window_size > 21)) {
        lit_error(ERR_R, "Invalid window in ControlData - %d from %lx.",
            window_size, READ_U32(pControl+CONTROL_WINDOW_SIZE));
        return -1;
    }

    status = LZXinit(window_size);
    if (status) {
        lit_error(ERR_R, "LZXinit(%d) failed, status = %d.",
            window_size, status);
        return E_LIT_LZX_ERROR;
    }

    path = lit_i_strmerge(storage_string,section_name,"/Transform/",
      lzxcompress_guid, rt_tail, NULL);
    if (!path) {
        return E_LIT_OUT_OF_MEMORY;
    }
    status = lit_get_file(litfile, path, &pRT, &sizeRT);
    if (status) { free(path); return status;}

    free(path);
    path = NULL;

    if (sizeRT < (RESET_INTERVAL+8)) {
        lit_error(ERR_R, "Reset table is too short (%d bytes).",
            sizeRT);
        free(pRT);
        return E_LIT_FORMAT_ERROR;
    }
    if (READ_U32(pRT + RESET_UCLENGTH + 4)) {
        lit_error(ERR_R,"Reset table has 64bit value for UCLENGTH!");
        free(pRT);
        return E_LIT_64BIT_VALUE;
    }

    /* Skip first entry -- always 0! */
    ofsEntry = READ_INT32(pRT + RESET_HDRLEN) + 8;
    uclength = READ_INT32(pRT + RESET_UCLENGTH);
    accum    = READ_INT32(pRT + RESET_INTERVAL);

    ptr = malloc(uclength+1);
    /* Check for corruption */
    ptr[uclength] = 0xCC;

    if (!ptr) {
        lit_error(ERR_R, "Unable to malloc uc length (%d bytes)!",
            uclength);
        free(pRT);
        return E_LIT_OUT_OF_MEMORY;
    }
    bytesRemaining = uclength;
    window_bytes = (1 << window_size);

    base = 0;
    dst  = 0;

    while (ofsEntry  < sizeRT)
    {
        if (accum == window_bytes) {
            accum = 0;

            size = READ_INT32(pRT + ofsEntry);
            u = READ_INT32(pRT + ofsEntry + 4);
            if (u) {
                lit_error(ERR_R, "Reset table entry greater than 32 bits!");
                free(pRT); free(ptr);
                return E_LIT_64BIT_VALUE;
            }
            if (size >= sizeContent) {
                lit_error(ERR_R, "ResetTable entry out of bounds, %lx. (%d)",
                    size, ofsEntry);
                free(ptr); free(pRT); return E_LIT_FORMAT_ERROR;
            }
            status = 0;
            if (bytesRemaining >= window_bytes) {
                LZXreset();
                status = LZXdecompress(pContent + base, ptr+dst,
                    size - base, window_bytes);
                bytesRemaining -= window_bytes;
                dst += window_bytes;
                base = size;
            }
            if (status) {
                lit_error(ERR_R, "LZXdecompress failed, status = %d.",
                    status);
                free(ptr);
                free(pRT);
                return -1;
            }
        }
        accum += READ_INT32(pRT + RESET_INTERVAL);
        ofsEntry += 8;
    }
    free(pRT);
    if (bytesRemaining < window_bytes) {
        LZXreset();
        status = LZXdecompress(pContent + base, ptr + dst,
            sizeContent - base, bytesRemaining);
        bytesRemaining = 0;
    }
    if (ptr[uclength] != 0xCC)
    {
        lit_error(ERR_R,
"LZXdecompress overflowed memory. (%02x). \n"\
"This is a serious bug, please report this.\n", ptr[uclength]);

        /* Can't really free, anything may be corrupted at this point */
        return -1;
    }
    if (status) {
        lit_error(ERR_R, "LZXdecompress failed, status = %d.", status);
        free(ptr);
        return E_LIT_LZX_ERROR;
    }

    if (bytesRemaining) {
        lit_error(ERR_R, "Failed to completely decompress section! (%d left).",            bytesRemaining);
        free(ptr);
        return E_LIT_LZX_ERROR;
    }

    if (ppUncompressed) *ppUncompressed = ptr;
    else free(ptr);
    if (psizeUncompressed) *psizeUncompressed = uclength;
    return 0;
}