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

📄 chm_lib.c

📁 又一开源的解压缩chm格式文件的代码
💻 C
📖 第 1 页 / 共 4 页
字号:
#define _CHM_PMGL_LEN (0x14)struct chmPmglHeader{    char        signature[4];           /*  0 (PMGL) */    UInt32      free_space;             /*  4 */    UInt32      unknown_0008;           /*  8 */    Int32       block_prev;             /*  c */    Int32       block_next;             /* 10 */}; /* __attribute__ ((aligned (1))); */static int _unmarshal_pmgl_header(unsigned char **pData,                                  unsigned long *pDataLen,                                  struct chmPmglHeader *dest){    /* we only know how to deal with a 0x14 byte structures */    if (*pDataLen != _CHM_PMGL_LEN)        return 0;    /* unmarshal fields */    _unmarshal_char_array(pData, pDataLen,  dest->signature, 4);    _unmarshal_uint32    (pData, pDataLen, &dest->free_space);    _unmarshal_uint32    (pData, pDataLen, &dest->unknown_0008);    _unmarshal_int32     (pData, pDataLen, &dest->block_prev);    _unmarshal_int32     (pData, pDataLen, &dest->block_next);    /* check structure */    if (memcmp(dest->signature, _chm_pmgl_marker, 4) != 0)        return 0;    return 1;}/* structure of PMGI headers */static const char _chm_pmgi_marker[4] = "PMGI";#define _CHM_PMGI_LEN (0x08)struct chmPmgiHeader{    char        signature[4];           /*  0 (PMGI) */    UInt32      free_space;             /*  4 */}; /* __attribute__ ((aligned (1))); */static int _unmarshal_pmgi_header(unsigned char **pData,                                  unsigned long *pDataLen,                                  struct chmPmgiHeader *dest){    /* we only know how to deal with a 0x8 byte structures */    if (*pDataLen != _CHM_PMGI_LEN)        return 0;    /* unmarshal fields */    _unmarshal_char_array(pData, pDataLen,  dest->signature, 4);    _unmarshal_uint32    (pData, pDataLen, &dest->free_space);    /* check structure */    if (memcmp(dest->signature, _chm_pmgi_marker, 4) != 0)        return 0;    return 1;}/* structure of LZXC reset table */#define _CHM_LZXC_RESETTABLE_V1_LEN (0x28)struct chmLzxcResetTable{    UInt32      version;    UInt32      block_count;    UInt32      unknown;    UInt32      table_offset;    UInt64      uncompressed_len;    UInt64      compressed_len;    UInt64      block_len;     }; /* __attribute__ ((aligned (1))); */static int _unmarshal_lzxc_reset_table(unsigned char **pData,                                       unsigned long *pDataLen,                                       struct chmLzxcResetTable *dest){    /* we only know how to deal with a 0x28 byte structures */    if (*pDataLen != _CHM_LZXC_RESETTABLE_V1_LEN)        return 0;    /* unmarshal fields */    _unmarshal_uint32    (pData, pDataLen, &dest->version);    _unmarshal_uint32    (pData, pDataLen, &dest->block_count);    _unmarshal_uint32    (pData, pDataLen, &dest->unknown);    _unmarshal_uint32    (pData, pDataLen, &dest->table_offset);    _unmarshal_uint64    (pData, pDataLen, &dest->uncompressed_len);    _unmarshal_uint64    (pData, pDataLen, &dest->compressed_len);    _unmarshal_uint64    (pData, pDataLen, &dest->block_len);    /* check structure */    if (dest->version != 2)        return 0;    return 1;}/* structure of LZXC control data block */#define _CHM_LZXC_MIN_LEN (0x18)#define _CHM_LZXC_V2_LEN (0x1c)struct chmLzxcControlData{    UInt32      size;                   /*  0        */    char        signature[4];           /*  4 (LZXC) */    UInt32      version;                /*  8        */    UInt32      resetInterval;          /*  c        */    UInt32      windowSize;             /* 10        */    UInt32      windowsPerReset;        /* 14        */    UInt32      unknown_18;             /* 18        */};static int _unmarshal_lzxc_control_data(unsigned char **pData,                                        unsigned long *pDataLen,                                        struct chmLzxcControlData *dest){    /* we want at least 0x18 bytes */    if (*pDataLen < _CHM_LZXC_MIN_LEN)        return 0;    /* unmarshal fields */    _unmarshal_uint32    (pData, pDataLen, &dest->size);    _unmarshal_char_array(pData, pDataLen,  dest->signature, 4);    _unmarshal_uint32    (pData, pDataLen, &dest->version);    _unmarshal_uint32    (pData, pDataLen, &dest->resetInterval);    _unmarshal_uint32    (pData, pDataLen, &dest->windowSize);    _unmarshal_uint32    (pData, pDataLen, &dest->windowsPerReset);    if (*pDataLen >= _CHM_LZXC_V2_LEN)        _unmarshal_uint32    (pData, pDataLen, &dest->unknown_18);    else        dest->unknown_18 = 0;    if (dest->version == 2)    {        dest->resetInterval *= 0x8000;        dest->windowSize *= 0x8000;    }    if (dest->windowSize == 0  ||  dest->resetInterval == 0)        return 0;    /* for now, only support resetInterval a multiple of windowSize/2 */    if (dest->windowSize == 1)        return 0;    if ((dest->resetInterval % (dest->windowSize/2)) != 0)        return 0;    /* check structure */    if (memcmp(dest->signature, "LZXC", 4) != 0)        return 0;    return 1;}/* the structure used for chm file handles */struct chmFile{#ifdef WIN32    HANDLE              fd;#else    int                 fd;#endif#ifdef CHM_MT#ifdef WIN32    CRITICAL_SECTION    mutex;    CRITICAL_SECTION    lzx_mutex;    CRITICAL_SECTION    cache_mutex;#else    pthread_mutex_t     mutex;    pthread_mutex_t     lzx_mutex;    pthread_mutex_t     cache_mutex;#endif#endif    UInt64              dir_offset;    UInt64              dir_len;        UInt64              data_offset;    Int32               index_root;    Int32               index_head;    UInt32              block_len;         UInt64              span;    struct chmUnitInfo  rt_unit;    struct chmUnitInfo  cn_unit;    struct chmLzxcResetTable reset_table;    /* LZX control data */    int                 compression_enabled;    UInt32              window_size;    UInt32              reset_interval;    UInt32              reset_blkcount;    /* decompressor state */    struct LZXstate    *lzx_state;    int                 lzx_last_block;    /* cache for decompressed blocks */    UChar             **cache_blocks;    Int64              *cache_block_indices;    Int32               cache_num_blocks;};/* * utility functions local to this module *//* utility function to handle differences between {pread,read}(64)? */static Int64 _chm_fetch_bytes(struct chmFile *h,                              UChar *buf,                              UInt64 os,                              Int64 len){    Int64 readLen=0, oldOs=0;    if (h->fd  ==  CHM_NULL_FD)        return readLen;    CHM_ACQUIRE_LOCK(h->mutex);#ifdef CHM_USE_WIN32IO    /* NOTE: this might be better done with CreateFileMapping, et cetera... */    {        DWORD origOffsetLo=0, origOffsetHi=0;        DWORD offsetLo, offsetHi;        DWORD actualLen=0;        /* awkward Win32 Seek/Tell */        offsetLo = (unsigned long)(os & 0xffffffffL);        offsetHi = (unsigned long)((os >> 32) & 0xffffffffL);        origOffsetLo = SetFilePointer(h->fd, 0, &origOffsetHi, FILE_CURRENT);        offsetLo = SetFilePointer(h->fd, offsetLo, &offsetHi, FILE_BEGIN);        /* read the data */        if (ReadFile(h->fd,                     buf,                     (DWORD)len,                     &actualLen,                     NULL) == TRUE)            readLen = actualLen;        else            readLen = 0;        /* restore original position */        SetFilePointer(h->fd, origOffsetLo, &origOffsetHi, FILE_BEGIN);    }#else#ifdef CHM_USE_PREAD#ifdef CHM_USE_IO64    readLen = pread64(h->fd, buf, (long)len, os);#else    readLen = pread(h->fd, buf, (long)len, (unsigned long)os);#endif#else#ifdef CHM_USE_IO64    oldOs = lseek64(h->fd, 0, SEEK_CUR);    lseek64(h->fd, os, SEEK_SET);    readLen = read(h->fd, buf, len);    lseek64(h->fd, oldOs, SEEK_SET);#else    oldOs = lseek(h->fd, 0, SEEK_CUR);    lseek(h->fd, (long)os, SEEK_SET);    readLen = read(h->fd, buf, len);    lseek(h->fd, (long)oldOs, SEEK_SET);#endif#endif#endif    CHM_RELEASE_LOCK(h->mutex);    return readLen;}/* open an ITS archive */#ifdef PPC_BSTR/* RWE 6/12/2003 */struct chmFile *chm_open(BSTR filename)#elsestruct chmFile *chm_open(const char *filename)#endif{    unsigned char               sbuffer[256];    unsigned long               sremain;    unsigned char              *sbufpos;    struct chmFile             *newHandle=NULL;    struct chmItsfHeader        itsfHeader;    struct chmItspHeader        itspHeader;    struct chmUnitInfo          uiSpan;    struct chmUnitInfo          uiLzxc;    struct chmLzxcControlData   ctlData;    /* allocate handle */    newHandle = (struct chmFile *)malloc(sizeof(struct chmFile));    newHandle->fd = CHM_NULL_FD;    newHandle->lzx_state = NULL;    newHandle->cache_blocks = NULL;    newHandle->cache_block_indices = NULL;    newHandle->cache_num_blocks = 0;    /* open file */#ifdef WIN32#ifdef PPC_BSTR    if ((newHandle->fd=CreateFile(filename,				  GENERIC_READ,                                  FILE_SHARE_READ,				  NULL,				  OPEN_EXISTING,				  FILE_ATTRIBUTE_NORMAL,				  NULL)) == CHM_NULL_FD)    {        free(newHandle);        return NULL;    }#else    if ((newHandle->fd=CreateFileA(filename,                                   GENERIC_READ,                                   0,                                   NULL,                                   OPEN_EXISTING,                                   FILE_ATTRIBUTE_NORMAL,                                   NULL)) == CHM_NULL_FD)    {        free(newHandle);        return NULL;    }#endif#else    if ((newHandle->fd=open(filename, O_RDONLY)) == CHM_NULL_FD)    {        free(newHandle);        return NULL;    }#endif    /* initialize mutexes, if needed */#ifdef CHM_MT#ifdef WIN32    InitializeCriticalSection(&newHandle->mutex);    InitializeCriticalSection(&newHandle->lzx_mutex);    InitializeCriticalSection(&newHandle->cache_mutex);#else    pthread_mutex_init(&newHandle->mutex, NULL);    pthread_mutex_init(&newHandle->lzx_mutex, NULL);    pthread_mutex_init(&newHandle->cache_mutex, NULL);#endif#endif    /* read and verify header */    sremain = _CHM_ITSF_V3_LEN;    sbufpos = sbuffer;    if (_chm_fetch_bytes(newHandle, sbuffer, (UInt64)0, sremain) != sremain    ||        !_unmarshal_itsf_header(&sbufpos, &sremain, &itsfHeader))    {        chm_close(newHandle);        return NULL;    }    /* stash important values from header */    newHandle->dir_offset  = itsfHeader.dir_offset;    newHandle->dir_len     = itsfHeader.dir_len;    newHandle->data_offset = itsfHeader.data_offset;    /* now, read and verify the directory header chunk */    sremain = _CHM_ITSP_V1_LEN;    sbufpos = sbuffer;    if (_chm_fetch_bytes(newHandle, sbuffer,                         (UInt64)itsfHeader.dir_offset, sremain) != sremain       ||        !_unmarshal_itsp_header(&sbufpos, &sremain, &itspHeader))    {        chm_close(newHandle);        return NULL;    }    /* grab essential information from ITSP header */    newHandle->dir_offset += itspHeader.header_len;    newHandle->dir_len    -= itspHeader.header_len;    newHandle->index_root  = itspHeader.index_root;    newHandle->index_head  = itspHeader.index_head;    newHandle->block_len   = itspHeader.block_len;    /* if the index root is -1, this means we don't have any PMGI blocks.     * as a result, we must use the sole PMGL block as the index root     */    if (newHandle->index_root == -1)        newHandle->index_root = newHandle->index_head;    /* By default, compression is enabled. */    newHandle->compression_enabled = 1;/* Jed, Sun Jun 27: 'span' doesn't seem to be used anywhere?! */#if 0    /* fetch span */    if (CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,                                                  _CHMU_SPANINFO,                                                  &uiSpan)                ||        uiSpan.space == CHM_COMPRESSED)    {        chm_close(newHandle);        return NULL;    }    /* N.B.: we've already checked that uiSpan is in the uncompressed section,     *       so this should not require attempting to decompress, which may     *       rely on having a valid "span"     */    sremain = 8;    sbufpos = sbuffer;    if (chm_retrieve_object(newHandle, &uiSpan, sbuffer,                            0, sremain) != sremain                        ||        !_unmarshal_uint64(&sbufpos, &sremain, &newHandle->span))    {        chm_close(newHandle);        return NULL;    }#endif    /* prefetch most commonly needed unit infos */    if (CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,                                                  _CHMU_RESET_TABLE,                                                  &newHandle->rt_unit)    ||        newHandle->rt_unit.space == CHM_COMPRESSED                        ||        CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,                                                  _CHMU_CONTENT,                                                  &newHandle->cn_unit)    ||        newHandle->cn_unit.space == CHM_COMPRESSED                        ||        CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,                                                  _CHMU_LZXC_CONTROLDATA,                                                  &uiLzxc)                ||        uiLzxc.space == CHM_COMPRESSED)    {        newHandle->compression_enabled = 0;    }    /* read reset table info */    if (newHandle->compression_enabled)    {        sremain = _CHM_LZXC_RESETTABLE_V1_LEN;        sbufpos = sbuffer;        if (chm_retrieve_object(newHandle, &newHandle->rt_unit, sbuffer,                                0, sremain) != sremain                        ||            !_unmarshal_lzxc_reset_table(&sbufpos, &sremain,                                         &newHandle->reset_table))        {            newHandle->compression_enabled = 0;        }    }    /* read control data */    if (newHandle->compression_enabled)    {        sremain = (unsigned long)uiLzxc.length;        sbufpos = sbuffer;        if (chm_retrieve_object(newHandle, &uiLzxc, sbuffer,                                0, sremain) != sremain                       ||            !_unmarshal_lzxc_control_data(&sbufpos, &sremain,                                          &ctlData))        {            newHandle->compression_enabled = 0;        }        newHandle->window_size = ctlData.windowSize;        newHandle->reset_interval = ctlData.resetInterval;/* Jed, Mon Jun 28: Experimentally, it appears that the reset block count *//*       must be multiplied by this formerly unknown ctrl data field in   *//*       order to decompress some files.                                  */#if 0        newHandle->reset_blkcount = newHandle->reset_interval /                    (newHandle->window_size / 2);#else        newHandle->reset_blkcount = newHandle->reset_interval    /                                    (newHandle->window_size / 2) *                                    ctlData.windowsPerReset;#endif    }    /* initialize cache */    chm_set_param(newHandle, CHM_PARAM_MAX_BLOCKS_CACHED,

⌨️ 快捷键说明

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