📄 chm_lib.cpp
字号:
h->cache_blocks[indexSlot] = (UChar *)malloc(
(unsigned int)(h->reset_table.block_len));
lbuffer = h->cache_blocks[indexSlot];
/* decompress the previous block */
LZXreset(h->lzx_state);
if (!_chm_get_cmpblock_bounds(h, block-i, &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)
return (Int64)0;
}
h->lzx_last_block = (int)(block - i);
}
}
else
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 */
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)
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.
*/
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. */
if (h->cache_block_indices[nBlock % h->cache_num_blocks] == (__int64)nBlock &&
h->cache_blocks[nBlock % h->cache_num_blocks] != NULL)
{
memcpy(buf,
h->cache_blocks[nBlock % h->cache_num_blocks] + nOffset,
(unsigned int)nLen);
return nLen;
}
/* 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);
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;
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 */
UChar *page_buf = (UChar*)alloca((unsigned int)h->block_len);
struct chmPmglHeader header;
UChar *end;
UChar *cur;
unsigned long lenRemain;
/* 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)
return 0;
/* figure out start and end for this page */
cur = page_buf;
lenRemain = _CHM_PMGL_LEN;
if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))
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))
return 0;
/* check for DIRS */
if (ui.length == 0 && !(what & CHM_ENUMERATE_DIRS))
continue;
/* check for FILES */
if (ui.length != 0 && !(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: return 0;
case CHM_ENUMERATOR_CONTINUE: break;
case CHM_ENUMERATOR_SUCCESS: return 1;
default: break;
}
}
}
/* advance to next page */
curPage = header.block_next;
}
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 */
UChar *page_buf = (UChar*)alloca((unsigned int)h->block_len);
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;
/* 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)
return 0;
/* figure out start and end for this page */
cur = page_buf;
lenRemain = _CHM_PMGL_LEN;
if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))
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))
return 0;
/* check if we should start */
if (! it_has_begun)
{
if (ui.length == 0 && strncmp(ui.path, prefixRectified, prefixLen) == 0)
it_has_begun = 1;
else
continue;
if (ui.path[prefixLen] == '\0')
continue;
}
/* check if we should stop */
else
{
if (strncmp(ui.path, prefixRectified, prefixLen) != 0)
return 1;
}
/* check if we should include this path */
if (lastPathLen != -1)
{
if (strncmp(ui.path, lastPath, lastPathLen) == 0)
continue;
}
strcpy(lastPath, ui.path);
lastPathLen = strlen(lastPath);
/* check for DIRS */
if (ui.length == 0 && !(what & CHM_ENUMERATE_DIRS))
continue;
/* check for FILES */
if (ui.length != 0 && !(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: return 0;
case CHM_ENUMERATOR_CONTINUE: break;
case CHM_ENUMERATOR_SUCCESS: return 1;
default: break;
}
}
}
/* advance to next page */
curPage = header.block_next;
}
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -