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

📄 chm_lib.c

📁 又一开源的解压缩chm格式文件的代码
💻 C
📖 第 1 页 / 共 4 页
字号:
                /* 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) ||                    _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                    FREEBUF(cbuffer);                    return (Int64)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);    h->cache_block_indices[indexSlot] = block;    if (! h->cache_blocks[indexSlot])        h->cache_blocks[indexSlot] = (UChar *)malloc(                                          ((unsigned int)h->reset_table.block_len));    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        FREEBUF(cbuffer);        return (Int64)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.     */    FREEBUF(cbuffer);    return h->reset_table.block_len;}/* grab a region from a compressed block */static Int64 _chm_decompress_region(struct chmFile *h,                                    UChar *buf,                                    UInt64 start,                                    Int64 len){    UInt64 nBlock, nOffset;    UInt64 nLen;    UInt64 gotLen;    UChar *ubuffer;        if (len <= 0)                return (Int64)0;    /* figure out what we need to read */    nBlock = start / h->reset_table.block_len;    nOffset = start % h->reset_table.block_len;    nLen = len;    if (nLen > (h->reset_table.block_len - nOffset))        nLen = h->reset_table.block_len - nOffset;    /* if block is cached, return data from it. */    CHM_ACQUIRE_LOCK(h->lzx_mutex);    CHM_ACQUIRE_LOCK(h->cache_mutex);    if (h->cache_block_indices[nBlock % h->cache_num_blocks] == nBlock    &&        h->cache_blocks[nBlock % h->cache_num_blocks] != NULL)    {        memcpy(buf,               h->cache_blocks[nBlock % h->cache_num_blocks] + nOffset,               (unsigned int)nLen);        CHM_RELEASE_LOCK(h->cache_mutex);        CHM_RELEASE_LOCK(h->lzx_mutex);        return nLen;    }    CHM_RELEASE_LOCK(h->cache_mutex);    /* data request not satisfied, so... start up the decompressor machine */    if (! h->lzx_state)    {        int window_size = ffs(h->window_size) - 1;        h->lzx_last_block = -1;        h->lzx_state = LZXinit(window_size);    }    /* decompress some data */    gotLen = _chm_decompress_block(h, nBlock, &ubuffer);    if (gotLen < nLen)        nLen = gotLen;    memcpy(buf, ubuffer+nOffset, (unsigned int)nLen);    CHM_RELEASE_LOCK(h->lzx_mutex);    return nLen;}/* retrieve (part of) an object */LONGINT64 chm_retrieve_object(struct chmFile *h,                               struct chmUnitInfo *ui,                               unsigned char *buf,                               LONGUINT64 addr,                               LONGINT64 len){    /* must be valid file handle */    if (h == NULL)        return (Int64)0;    /* starting address must be in correct range */    if (addr < 0  ||  addr >= ui->length)        return (Int64)0;    /* clip length */    if (addr + len > ui->length)        len = ui->length - addr;    /* if the file is uncompressed, it's simple */    if (ui->space == CHM_UNCOMPRESSED)    {        /* read data */        return _chm_fetch_bytes(h,                                buf,                                (UInt64)h->data_offset + (UInt64)ui->start + (UInt64)addr,                                len);    }    /* else if the file is compressed, it's a little trickier */    else /* ui->space == CHM_COMPRESSED */    {        Int64 swath=0, total=0;        /* if compression is not enabled for this file... */        if (! h->compression_enabled)            return total;        do {            /* swill another mouthful */            swath = _chm_decompress_region(h, buf, ui->start + addr, len);            /* if we didn't get any... */            if (swath == 0)                return total;            /* update stats */            total += swath;            len -= swath;            addr += swath;            buf += swath;        } while (len != 0);        return total;    }}/* enumerate the objects in the .chm archive */int chm_enumerate(struct chmFile *h,                  int what,                  CHM_ENUMERATOR e,                  void *context){    Int32 curPage;    /* buffer to hold whatever page we're looking at */#ifdef WIN32#ifdef _WIN32_WCE    /* RWE 6/12/2003 */    UChar *page_buf = malloc((unsigned int)h->block_len);#else    UChar *page_buf = alloca((unsigned int)h->block_len);#endif#else    UChar page_buf[h->block_len];#endif    struct chmPmglHeader header;    UChar *end;    UChar *cur;    unsigned long lenRemain;    UInt64 ui_path_len;    /* the current ui */    struct chmUnitInfo ui;    int flag;    /* starting page */    curPage = h->index_head;    /* 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 0;        }        /* figure out start and end for this page */        cur = page_buf;        lenRemain = _CHM_PMGL_LEN;        if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))        {            FREEBUF(page_buf);            return 0;        }        end = page_buf + h->block_len - (header.free_space);        /* loop over this page */        while (cur < end)        {            if (! _chm_parse_PMGL_entry(&cur, &ui))            {                FREEBUF(page_buf);                return 0;            }            /* get the length of the path */            ui_path_len = strlen(ui.path)-1;            /* check for DIRS */            if (ui.path[ui_path_len] == '/'  &&  !(what & CHM_ENUMERATE_DIRS))                continue;            /* check for FILES */            if (ui.path[ui_path_len] != '/'  &&  !(what & CHM_ENUMERATE_FILES))                continue;            /* check for NORMAL vs. META */            if (ui.path[0] == '/')            {                /* check for NORMAL vs. SPECIAL */                if (ui.path[1] == '#'  ||  ui.path[1] == '$')                    flag = CHM_ENUMERATE_SPECIAL;                else                    flag = CHM_ENUMERATE_NORMAL;            }            else                flag = CHM_ENUMERATE_META;            if (! (what & flag))                continue;            /* call the enumerator */            {                int status = (*e)(h, &ui, context);                switch (status)                {                    case CHM_ENUMERATOR_FAILURE:                        FREEBUF(page_buf);                        return 0;                    case CHM_ENUMERATOR_CONTINUE:                        break;                    case CHM_ENUMERATOR_SUCCESS:                        FREEBUF(page_buf);                        return 1;                    default:                        break;                }            }        }        /* advance to next page */        curPage = header.block_next;    }    FREEBUF(page_buf);    return 1;}int chm_enumerate_dir(struct chmFile *h,                      const char *prefix,                      int what,                      CHM_ENUMERATOR e,                      void *context){    /*     * XXX: do this efficiently (i.e. using the tree index)     */    Int32 curPage;    /* buffer to hold whatever page we're looking at */#ifdef WIN32#ifdef _WIN32_WCE    /* RWE 6/12/2003 */    UChar *page_buf = malloc((unsigned int)h->block_len);#else    UChar *page_buf = alloca((unsigned int)h->block_len);#endif#else    UChar page_buf[h->block_len];#endif    struct chmPmglHeader header;    UChar *end;    UChar *cur;    unsigned long lenRemain;    /* set to 1 once we've started */    int it_has_begun=0;    /* the current ui */    struct chmUnitInfo ui;    int flag;    UInt64 ui_path_len;    /* the length of the prefix */    char prefixRectified[CHM_MAX_PATHLEN+1];    int prefixLen;    char lastPath[CHM_MAX_PATHLEN];    int lastPathLen;    /* starting page */    curPage = h->index_head;    /* initialize pathname state */    strncpy(prefixRectified, prefix, CHM_MAX_PATHLEN);    prefixLen = strlen(prefixRectified);    if (prefixLen != 0)    {        if (prefixRectified[prefixLen-1] != '/')        {            prefixRectified[prefixLen] = '/';            prefixRectified[prefixLen+1] = '\0';            ++prefixLen;        }    }    lastPath[0] = '\0';    lastPathLen = -1;    /* 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 0;        }        /* figure out start and end for this page */        cur = page_buf;        lenRemain = _CHM_PMGL_LEN;        if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))        {            FREEBUF(page_buf);            return 0;        }        end = page_buf + h->block_len - (header.free_space);        /* loop over this page */        while (cur < end)        {            if (! _chm_parse_PMGL_entry(&cur, &ui))            {                FREEBUF(page_buf);                return 0;            }            /* check if we should start */            if (! it_has_begun)            {                if (ui.length == 0  &&  strncasecmp(ui.path, prefixRectified, prefixLen) == 0)                    it_has_begun = 1;                else                    continue;                if (ui.path[prefixLen] == '\0')                    continue;            }            /* check if we should stop */            else            {                if (strncasecmp(ui.path, prefixRectified, prefixLen) != 0)                {                    FREEBUF(page_buf);                    return 1;                }            }            /* check if we should include this path */            if (lastPathLen != -1)            {                if (strncasecmp(ui.path, lastPath, lastPathLen) == 0)                    continue;            }            strcpy(lastPath, ui.path);            lastPathLen = strlen(lastPath);            /* get the length of the path */            ui_path_len = strlen(ui.path)-1;            /* check for DIRS */            if (ui.path[ui_path_len] == '/'  &&  !(what & CHM_ENUMERATE_DIRS))                continue;            /* check for FILES */            if (ui.path[ui_path_len] != '/'  &&  !(what & CHM_ENUMERATE_FILES))                continue;            /* check for NORMAL vs. META */            if (ui.path[0] == '/')            {                /* check for NORMAL vs. SPECIAL */                if (ui.path[1] == '#'  ||  ui.path[1] == '$')                    flag = CHM_ENUMERATE_SPECIAL;                else                    flag = CHM_ENUMERATE_NORMAL;            }            else                flag = CHM_ENUMERATE_META;            if (! (what & flag))                continue;            /* call the enumerator */            {                int status = (*e)(h, &ui, context);                switch (status)                {                    case CHM_ENUMERATOR_FAILURE:                        FREEBUF(page_buf);                        return 0;                    case CHM_ENUMERATOR_CONTINUE:                        break;                    case CHM_ENUMERATOR_SUCCESS:                        FREEBUF(page_buf);                        return 1;                    default:                        break;                }            }        }        /* advance to next page */        curPage = header.block_next;    }    FREEBUF(page_buf);    return 1;}

⌨️ 快捷键说明

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