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; }
/** * @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; }
/*--[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; }