Exemplo n.º 1
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;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
qword _chm_decompress_block(chm_t *h,
                            uqword block,
                            uchar **ubuffer)
{
    uchar *cbuffer = malloc(((unsigned int)h->reset_table.block_len + 6144));
    uqword cmpStart;                                    /* compressed start  */
    qword cmpLen;                                       /* compressed len    */
    int indexSlot;                                      /* cache index slot  */
    uchar *lbuffer;                                     /* local buffer ptr  */
    udword blockAlign = (udword)(block % h->reset_blkcount); /* reset intvl. aln. */
    udword i;                                           /* local loop index  */
    
    if (cbuffer == NULL)
        return -1;
    
    /* let the caching system pull its weight! */
    if (block - blockAlign <= h->lzx_last_block  &&
        block              >= h->lzx_last_block)
        blockAlign = (udword)(block - h->lzx_last_block);
    
    /* check if we need previous blocks */
    if (blockAlign != 0)
    {
        /* fetch all required previous blocks since last reset */
        for (i = blockAlign; i > 0; i--)
        {
            udword curBlockIdx = (udword)block - i;
            
            /* check if we most recently decompressed the previous block */
            if (h->lzx_last_block != curBlockIdx)
            {
                if ((curBlockIdx % h->reset_blkcount) == 0)
                {
#ifdef CHM_DEBUG
                    fprintf(stderr, "***RESET (1)***\n");
#endif
                    LZXreset(h->lzx_state);
                }
                
                indexSlot = (int)((curBlockIdx) % h->cache_num_blocks);
                if (! h->cache_blocks[indexSlot])
                    h->cache_blocks[indexSlot] = (uchar *)malloc((unsigned int)(h->reset_table.block_len));
                if (! h->cache_blocks[indexSlot])
                {
                    free(cbuffer);
                    return -1;
                }
                h->cache_block_indices[indexSlot] = curBlockIdx;
                lbuffer = h->cache_blocks[indexSlot];
                
                /* decompress the previous block */
#ifdef CHM_DEBUG
                fprintf(stderr, "Decompressing block #%4d (EXTRA)\n", curBlockIdx);
#endif
                if (!_chm_get_cmpblock_bounds(h, curBlockIdx, &cmpStart, &cmpLen) ||
                    cmpLen < 0                                                    ||
                    cmpLen > h->reset_table.block_len + 6144                      ||
                    _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen      ||
                    LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
                                  (int)h->reset_table.block_len) != DECR_OK)
                {
#ifdef CHM_DEBUG
                    fprintf(stderr, "   (DECOMPRESS FAILED!)\n");
#endif
                    free(cbuffer);
                    return (qword)0;
                }
                
                h->lzx_last_block = (int)curBlockIdx;
            }
        }
    }
    else
    {
        if ((block % h->reset_blkcount) == 0)
        {
#ifdef CHM_DEBUG
            fprintf(stderr, "***RESET (2)***\n");
#endif
            LZXreset(h->lzx_state);
        }
    }
    
    /* allocate slot in cache */
    indexSlot = (int)(block % h->cache_num_blocks);
    if (! h->cache_blocks[indexSlot])
        h->cache_blocks[indexSlot] = (uchar *)malloc(((unsigned int)h->reset_table.block_len));
    if (! h->cache_blocks[indexSlot])
    {
        free(cbuffer);
        return -1;
    }
    h->cache_block_indices[indexSlot] = block;
    lbuffer = h->cache_blocks[indexSlot];
    *ubuffer = lbuffer;
    
    /* decompress the block we actually want */
#ifdef CHM_DEBUG
    fprintf(stderr, "Decompressing block #%4d (REAL )\n", block);
#endif
    if (! _chm_get_cmpblock_bounds(h, block, &cmpStart, &cmpLen)          ||
        _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen          ||
        LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
                      (int)h->reset_table.block_len) != DECR_OK)
    {
#ifdef CHM_DEBUG
        fprintf(stderr, "   (DECOMPRESS FAILED!)\n");
#endif
        free(cbuffer);
        return (qword)0;
    }
    h->lzx_last_block = (int)block;
    
    /* XXX: modify LZX routines to return the length of the data they
     * decompressed and return that instead, for an extra sanity check.
     */
    free(cbuffer);
    return h->reset_table.block_len;
}