📄 chm_lib.c
字号:
/* 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 + -