⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chm_lib.c

📁 又一开源的解压缩chm格式文件的代码
💻 C
📖 第 1 页 / 共 4 页
字号:
                  CHM_MAX_BLOCKS_CACHED);    return newHandle;}/* close an ITS archive */void chm_close(struct chmFile *h){    if (h != NULL)    {        if (h->fd != CHM_NULL_FD)            CHM_CLOSE_FILE(h->fd);        h->fd = CHM_NULL_FD;#ifdef CHM_MT#ifdef WIN32        DeleteCriticalSection(&h->mutex);        DeleteCriticalSection(&h->lzx_mutex);        DeleteCriticalSection(&h->cache_mutex);#else        pthread_mutex_destroy(&h->mutex);        pthread_mutex_destroy(&h->lzx_mutex);        pthread_mutex_destroy(&h->cache_mutex);#endif#endif        if (h->lzx_state)            LZXteardown(h->lzx_state);        h->lzx_state = NULL;        if (h->cache_blocks)        {            int i;            for (i=0; i<h->cache_num_blocks; i++)            {                if (h->cache_blocks[i])                    free(h->cache_blocks[i]);            }            free(h->cache_blocks);            h->cache_blocks = NULL;        }        if (h->cache_block_indices)            free(h->cache_block_indices);        h->cache_block_indices = NULL;        free(h);    }}/* * set a parameter on the file handle. * valid parameter types: *          CHM_PARAM_MAX_BLOCKS_CACHED: *                 how many decompressed blocks should be cached?  A simple *                 caching scheme is used, wherein the index of the block is *                 used as a hash value, and hash collision results in the *                 invalidation of the previously cached block. */void chm_set_param(struct chmFile *h,                   int paramType,                   int paramVal){    switch (paramType)    {        case CHM_PARAM_MAX_BLOCKS_CACHED:            CHM_ACQUIRE_LOCK(h->cache_mutex);            if (paramVal != h->cache_num_blocks)            {                UChar **newBlocks;                UInt64 *newIndices;                int     i;                /* allocate new cached blocks */                newBlocks = (UChar **)malloc(paramVal * sizeof (UChar *));                newIndices = (UInt64 *)malloc(paramVal * sizeof (UInt64));                for (i=0; i<paramVal; i++)                {                    newBlocks[i] = NULL;                    newIndices[i] = 0;                }                /* re-distribute old cached blocks */                if (h->cache_blocks)                {                    for (i=0; i<h->cache_num_blocks; i++)                    {                        int newSlot = (int)(h->cache_block_indices[i] % paramVal);                        if (h->cache_blocks[i])                        {                            /* in case of collision, destroy newcomer */                            if (newBlocks[newSlot])                            {                                free(h->cache_blocks[i]);                                h->cache_blocks[i] = NULL;                            }                            else                            {                                newBlocks[newSlot] = h->cache_blocks[i];                                newIndices[newSlot] =                                            h->cache_block_indices[i];                            }                        }                    }                    free(h->cache_blocks);                    free(h->cache_block_indices);                }                /* now, set new values */                h->cache_blocks = newBlocks;                h->cache_block_indices = newIndices;                h->cache_num_blocks = paramVal;            }            CHM_RELEASE_LOCK(h->cache_mutex);            break;        default:            break;    }}/* * helper methods for chm_resolve_object *//* skip a compressed dword */static void _chm_skip_cword(UChar **pEntry){    while (*(*pEntry)++ >= 0x80)        ;}/* skip the data from a PMGL entry */static void _chm_skip_PMGL_entry_data(UChar **pEntry){    _chm_skip_cword(pEntry);    _chm_skip_cword(pEntry);    _chm_skip_cword(pEntry);}/* parse a compressed dword */static UInt64 _chm_parse_cword(UChar **pEntry){    UInt64 accum = 0;    UChar temp;    while ((temp=*(*pEntry)++) >= 0x80)    {        accum <<= 7;        accum += temp & 0x7f;    }    return (accum << 7) + temp;}/* parse a utf-8 string into an ASCII char buffer */static int _chm_parse_UTF8(UChar **pEntry, UInt64 count, char *path){    /* XXX: implement UTF-8 support, including a real mapping onto     *      ISO-8859-1?  probably there is a library to do this?  As is     *      immediately apparent from the below code, I'm presently not doing     *      any special handling for files in which none of the strings contain     *      UTF-8 multi-byte characters.     */    while (count != 0)    {        *path++ = (char)(*(*pEntry)++);        --count;    }    *path = '\0';    return 1;}/* parse a PMGL entry into a chmUnitInfo struct; return 1 on success. */static int _chm_parse_PMGL_entry(UChar **pEntry, struct chmUnitInfo *ui){    UInt64 strLen;    /* parse str len */    strLen = _chm_parse_cword(pEntry);    if (strLen > CHM_MAX_PATHLEN)        return 0;    /* parse path */    if (! _chm_parse_UTF8(pEntry, strLen, ui->path))        return 0;    /* parse info */    ui->space  = (int)_chm_parse_cword(pEntry);    ui->start  = _chm_parse_cword(pEntry);    ui->length = _chm_parse_cword(pEntry);    return 1;}/* find an exact entry in PMGL; return NULL if we fail */static UChar *_chm_find_in_PMGL(UChar *page_buf,                         UInt32 block_len,                         const char *objPath){    /* XXX: modify this to do a binary search using the nice index structure     *      that is provided for us.     */    struct chmPmglHeader header;    UInt32 hremain;    UChar *end;    UChar *cur;    UChar *temp;    UInt64 strLen;    char buffer[CHM_MAX_PATHLEN+1];    /* figure out where to start and end */    cur = page_buf;    hremain = _CHM_PMGL_LEN;    if (! _unmarshal_pmgl_header(&cur, &hremain, &header))        return NULL;    end = page_buf + block_len - (header.free_space);    /* now, scan progressively */    while (cur < end)    {        /* grab the name */        temp = cur;        strLen = _chm_parse_cword(&cur);        if (! _chm_parse_UTF8(&cur, strLen, buffer))            return NULL;        /* check if it is the right name */        if (! strcasecmp(buffer, objPath))            return temp;        _chm_skip_PMGL_entry_data(&cur);    }    return NULL;}/* find which block should be searched next for the entry; -1 if no block */static Int32 _chm_find_in_PMGI(UChar *page_buf,                        UInt32 block_len,                        const char *objPath){    /* XXX: modify this to do a binary search using the nice index structure     *      that is provided for us     */    struct chmPmgiHeader header;    UInt32 hremain;    int page=-1;    UChar *end;    UChar *cur;    UInt64 strLen;    char buffer[CHM_MAX_PATHLEN+1];    /* figure out where to start and end */    cur = page_buf;    hremain = _CHM_PMGI_LEN;    if (! _unmarshal_pmgi_header(&cur, &hremain, &header))        return -1;    end = page_buf + block_len - (header.free_space);    /* now, scan progressively */    while (cur < end)    {        /* grab the name */        strLen = _chm_parse_cword(&cur);        if (! _chm_parse_UTF8(&cur, strLen, buffer))            return -1;        /* check if it is the right name */        if (strcasecmp(buffer, objPath) > 0)            return page;        /* load next value for path */        page = (int)_chm_parse_cword(&cur);    }    return page;}/* resolve a particular object from the archive */int chm_resolve_object(struct chmFile *h,                       const char *objPath,                       struct chmUnitInfo *ui){    /*     * XXX: implement caching scheme for dir pages     */    Int32 curPage;    /* buffer to hold whatever page we're looking at */#ifdef WIN32#ifdef _WIN32_WCE    /* RWE 6/12/2003 */    UChar *page_buf = malloc(h->block_len);#else    UChar *page_buf = alloca(h->block_len);#endif#else    UChar page_buf[h->block_len];#endif    /* starting page */    curPage = h->index_root;    /* until we have either returned or given up */    while (curPage != -1)    {        /* try to fetch the index page */        if (_chm_fetch_bytes(h, page_buf,                             (UInt64)h->dir_offset + (UInt64)curPage*h->block_len,                             h->block_len) != h->block_len)	{	    FREEBUF(page_buf);            return CHM_RESOLVE_FAILURE;	}        /* now, if it is a leaf node: */        if (memcmp(page_buf, _chm_pmgl_marker, 4) == 0)        {            /* scan block */            UChar *pEntry = _chm_find_in_PMGL(page_buf,                                              h->block_len,                                              objPath);            if (pEntry == NULL)            {                FREEBUF(page_buf);                return CHM_RESOLVE_FAILURE;            }            /* parse entry and return */            _chm_parse_PMGL_entry(&pEntry, ui);            FREEBUF(page_buf);            return CHM_RESOLVE_SUCCESS;        }        /* else, if it is a branch node: */        else if (memcmp(page_buf, _chm_pmgi_marker, 4) == 0)            curPage = _chm_find_in_PMGI(page_buf, h->block_len, objPath);        /* else, we are confused.  give up. */        else        {            FREEBUF(page_buf);            return CHM_RESOLVE_FAILURE;        }    }    /* didn't find anything.  fail. */    FREEBUF(page_buf);    return CHM_RESOLVE_FAILURE;}/* * utility methods for dealing with compressed data *//* get the bounds of a compressed block.  return 0 on failure */static int _chm_get_cmpblock_bounds(struct chmFile *h,                             UInt64 block,                             UInt64 *start,                             Int64 *len){    UChar buffer[8], *dummy;    UInt32 remain;    /* for all but the last block, use the reset table */    if (block < h->reset_table.block_count-1)    {        /* unpack the start address */        dummy = buffer;        remain = 8;        if (_chm_fetch_bytes(h, buffer,                             (UInt64)h->data_offset                                + (UInt64)h->rt_unit.start                                + (UInt64)h->reset_table.table_offset                                + (UInt64)block*8,                             remain) != remain                            ||            !_unmarshal_uint64(&dummy, &remain, start))            return 0;        /* unpack the end address */        dummy = buffer;        remain = 8;        if (_chm_fetch_bytes(h, buffer,                         (UInt64)h->data_offset                                + (UInt64)h->rt_unit.start                                + (UInt64)h->reset_table.table_offset                                + (UInt64)block*8 + 8,                         remain) != remain                                ||            !_unmarshal_int64(&dummy, &remain, len))            return 0;    }    /* for the last block, use the span in addition to the reset table */    else    {        /* unpack the start address */        dummy = buffer;        remain = 8;        if (_chm_fetch_bytes(h, buffer,                             (UInt64)h->data_offset                                + (UInt64)h->rt_unit.start                                + (UInt64)h->reset_table.table_offset                                + (UInt64)block*8,                             remain) != remain                            ||            !_unmarshal_uint64(&dummy, &remain, start))            return 0;        *len = h->reset_table.compressed_len;    }    /* compute the length and absolute start address */    *len -= *start;    *start += h->data_offset + h->cn_unit.start;    return 1;}/* decompress the block.  must have lzx_mutex. */static Int64 _chm_decompress_block(struct chmFile *h,                                   UInt64 block,                                   UChar **ubuffer){#ifdef WIN32#ifdef _WIN32_WCE    /* RWE 6/12/2003 */    UChar *cbuffer = malloc(((unsigned int)h->reset_table.block_len + 6144));#else    UChar *cbuffer = alloca(((unsigned int)h->reset_table.block_len + 6144));#endif#else    UChar cbuffer[h->reset_table.block_len + 6144];     /* compressed buffer */#endif    UInt64 cmpStart;                                    /* compressed start  */    Int64 cmpLen;                                       /* compressed len    */    int indexSlot;                                      /* cache index slot  */    UChar *lbuffer;                                     /* local buffer ptr  */    UInt32 blockAlign = (UInt32)(block % h->reset_blkcount); /* reset intvl. aln. */    UInt32 i;                                           /* local loop index  */    /* let the caching system pull its weight! */    if (block - blockAlign <= h->lzx_last_block  &&        block              >= h->lzx_last_block)        blockAlign = (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--)        {            UInt32 curBlockIdx = 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);                h->cache_block_indices[indexSlot] = curBlockIdx;                if (! h->cache_blocks[indexSlot])                    h->cache_blocks[indexSlot] = (UChar *)malloc(                                                                 (unsigned int)(h->reset_table.block_len));                lbuffer = h->cache_blocks[indexSlot];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -