ReactOS 0.4.15-dev-8135-g1bc6c90
chm_lib.c
Go to the documentation of this file.
1/***************************************************************************
2 * chm_lib.c - CHM archive manipulation routines *
3 * ------------------- *
4 * *
5 * author: Jed Wing <jedwin@ugcs.caltech.edu> *
6 * version: 0.3 *
7 * notes: These routines are meant for the manipulation of microsoft *
8 * .chm (compiled html help) files, but may likely be used *
9 * for the manipulation of any ITSS archive, if ever ITSS *
10 * archives are used for any other purpose. *
11 * *
12 * Note also that the section names are statically handled. *
13 * To be entirely correct, the section names should be read *
14 * from the section names meta-file, and then the various *
15 * content sections and the "transforms" to apply to the data *
16 * they contain should be inferred from the section name and *
17 * the meta-files referenced using that name; however, all of *
18 * the files I've been able to get my hands on appear to have *
19 * only two sections: Uncompressed and MSCompressed. *
20 * Additionally, the ITSS.DLL file included with Windows does *
21 * not appear to handle any different transforms than the *
22 * simple LZX-transform. Furthermore, the list of transforms *
23 * to apply is broken, in that only half the required space *
24 * is allocated for the list. (It appears as though the *
25 * space is allocated for ASCII strings, but the strings are *
26 * written as unicode. As a result, only the first half of *
27 * the string appears.) So this is probably not too big of *
28 * a deal, at least until CHM v4 (MS .lit files), which also *
29 * incorporate encryption, of some description. *
30 * *
31 ***************************************************************************/
32
33/***************************************************************************
34 *
35 * This library is free software; you can redistribute it and/or
36 * modify it under the terms of the GNU Lesser General Public
37 * License as published by the Free Software Foundation; either
38 * version 2.1 of the License, or (at your option) any later version.
39 *
40 * This library is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43 * Lesser General Public License for more details.
44 *
45 * You should have received a copy of the GNU Lesser General Public
46 * License along with this library; if not, write to the Free Software
47 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
48 *
49 ***************************************************************************/
50
51/***************************************************************************
52 * *
53 * Adapted for Wine by Mike McCormack *
54 * *
55 ***************************************************************************/
56
57
58#include <stdarg.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62
63#include "windef.h"
64#include "winbase.h"
65#include "winnls.h"
66
67#include "chm_lib.h"
68#include "lzx.h"
69
70#define CHM_ACQUIRE_LOCK(a) do { \
71 EnterCriticalSection(&(a)); \
72 } while(0)
73#define CHM_RELEASE_LOCK(a) do { \
74 LeaveCriticalSection(&(a)); \
75 } while(0)
76
77#define CHM_NULL_FD (INVALID_HANDLE_VALUE)
78#define CHM_CLOSE_FILE(fd) CloseHandle((fd))
79
80/*
81 * defines related to tuning
82 */
83#ifndef CHM_MAX_BLOCKS_CACHED
84#define CHM_MAX_BLOCKS_CACHED 5
85#endif
86#define CHM_PARAM_MAX_BLOCKS_CACHED 0
87
88/*
89 * architecture specific defines
90 *
91 * Note: as soon as C99 is more widespread, the below defines should
92 * probably just use the C99 sized-int types.
93 *
94 * The following settings will probably work for many platforms. The sizes
95 * don't have to be exactly correct, but the types must accommodate at least as
96 * many bits as they specify.
97 */
98
99/* i386, 32-bit, Windows */
100typedef BYTE UChar;
101typedef SHORT Int16;
103typedef LONG Int32;
104typedef DWORD UInt32;
107
108/* utilities for unmarshalling data */
109static BOOL _unmarshal_char_array(unsigned char **pData,
110 unsigned int *pLenRemain,
111 char *dest,
112 int count)
113{
114 if (count <= 0 || (unsigned int)count > *pLenRemain)
115 return FALSE;
116 memcpy(dest, (*pData), count);
117 *pData += count;
118 *pLenRemain -= count;
119 return TRUE;
120}
121
122static BOOL _unmarshal_uchar_array(unsigned char **pData,
123 unsigned int *pLenRemain,
124 unsigned char *dest,
125 int count)
126{
127 if (count <= 0 || (unsigned int)count > *pLenRemain)
128 return FALSE;
129 memcpy(dest, (*pData), count);
130 *pData += count;
131 *pLenRemain -= count;
132 return TRUE;
133}
134
135static BOOL _unmarshal_int32(unsigned char **pData,
136 unsigned int *pLenRemain,
137 Int32 *dest)
138{
139 if (4 > *pLenRemain)
140 return FALSE;
141 *dest = (*pData)[0] | (*pData)[1]<<8 | (*pData)[2]<<16 | (*pData)[3]<<24;
142 *pData += 4;
143 *pLenRemain -= 4;
144 return TRUE;
145}
146
147static BOOL _unmarshal_uint32(unsigned char **pData,
148 unsigned int *pLenRemain,
149 UInt32 *dest)
150{
151 if (4 > *pLenRemain)
152 return FALSE;
153 *dest = (*pData)[0] | (*pData)[1]<<8 | (*pData)[2]<<16 | (*pData)[3]<<24;
154 *pData += 4;
155 *pLenRemain -= 4;
156 return TRUE;
157}
158
159static BOOL _unmarshal_int64(unsigned char **pData,
160 unsigned int *pLenRemain,
161 Int64 *dest)
162{
163 Int64 temp;
164 int i;
165 if (8 > *pLenRemain)
166 return FALSE;
167 temp=0;
168 for(i=8; i>0; i--)
169 {
170 temp <<= 8;
171 temp |= (*pData)[i-1];
172 }
173 *dest = temp;
174 *pData += 8;
175 *pLenRemain -= 8;
176 return TRUE;
177}
178
179static BOOL _unmarshal_uint64(unsigned char **pData,
180 unsigned int *pLenRemain,
181 UInt64 *dest)
182{
183 UInt64 temp;
184 int i;
185 if (8 > *pLenRemain)
186 return FALSE;
187 temp=0;
188 for(i=8; i>0; i--)
189 {
190 temp <<= 8;
191 temp |= (*pData)[i-1];
192 }
193 *dest = temp;
194 *pData += 8;
195 *pLenRemain -= 8;
196 return TRUE;
197}
198
199static BOOL _unmarshal_uuid(unsigned char **pData,
200 unsigned int *pDataLen,
201 unsigned char *dest)
202{
203 return _unmarshal_uchar_array(pData, pDataLen, dest, 16);
204}
205
206/* names of sections essential to decompression */
207static const WCHAR _CHMU_RESET_TABLE[] = {
208':',':','D','a','t','a','S','p','a','c','e','/',
209 'S','t','o','r','a','g','e','/',
210 'M','S','C','o','m','p','r','e','s','s','e','d','/',
211 'T','r','a','n','s','f','o','r','m','/',
212 '{','7','F','C','2','8','9','4','0','-','9','D','3','1',
213 '-','1','1','D','0','-','9','B','2','7','-',
214 '0','0','A','0','C','9','1','E','9','C','7','C','}','/',
215 'I','n','s','t','a','n','c','e','D','a','t','a','/',
216 'R','e','s','e','t','T','a','b','l','e',0
217};
219':',':','D','a','t','a','S','p','a','c','e','/',
220 'S','t','o','r','a','g','e','/',
221 'M','S','C','o','m','p','r','e','s','s','e','d','/',
222 'C','o','n','t','r','o','l','D','a','t','a',0
223};
224static const WCHAR _CHMU_CONTENT[] = {
225':',':','D','a','t','a','S','p','a','c','e','/',
226 'S','t','o','r','a','g','e','/',
227 'M','S','C','o','m','p','r','e','s','s','e','d','/',
228 'C','o','n','t','e','n','t',0
229};
230
231/*
232 * structures local to this module
233 */
234
235/* structure of ITSF headers */
236#define _CHM_ITSF_V2_LEN (0x58)
237#define _CHM_ITSF_V3_LEN (0x60)
239{
240 char signature[4]; /* 0 (ITSF) */
241 Int32 version; /* 4 */
245 UInt32 lang_id; /* 14 */
246 UChar dir_uuid[16]; /* 18 */
247 UChar stream_uuid[16]; /* 28 */
251 UInt64 dir_len; /* 50 */
252 UInt64 data_offset; /* 58 (Not present before V3) */
253}; /* __attribute__ ((aligned (1))); */
254
255static BOOL _unmarshal_itsf_header(unsigned char **pData,
256 unsigned int *pDataLen,
257 struct chmItsfHeader *dest)
258{
259 /* we only know how to deal with the 0x58 and 0x60 byte structures */
260 if (*pDataLen != _CHM_ITSF_V2_LEN && *pDataLen != _CHM_ITSF_V3_LEN)
261 return FALSE;
262
263 /* unmarshal common fields */
264 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
265 _unmarshal_int32 (pData, pDataLen, &dest->version);
266 _unmarshal_int32 (pData, pDataLen, &dest->header_len);
267 _unmarshal_int32 (pData, pDataLen, &dest->unknown_000c);
268 _unmarshal_uint32 (pData, pDataLen, &dest->last_modified);
269 _unmarshal_uint32 (pData, pDataLen, &dest->lang_id);
270 _unmarshal_uuid (pData, pDataLen, dest->dir_uuid);
271 _unmarshal_uuid (pData, pDataLen, dest->stream_uuid);
272 _unmarshal_uint64 (pData, pDataLen, &dest->unknown_offset);
273 _unmarshal_uint64 (pData, pDataLen, &dest->unknown_len);
274 _unmarshal_uint64 (pData, pDataLen, &dest->dir_offset);
275 _unmarshal_uint64 (pData, pDataLen, &dest->dir_len);
276
277 /* error check the data */
278 /* XXX: should also check UUIDs, probably, though with a version 3 file,
279 * current MS tools do not seem to use them.
280 */
281 if (memcmp(dest->signature, "ITSF", 4) != 0)
282 return FALSE;
283 if (dest->version == 2)
284 {
285 if (dest->header_len < _CHM_ITSF_V2_LEN)
286 return FALSE;
287 }
288 else if (dest->version == 3)
289 {
290 if (dest->header_len < _CHM_ITSF_V3_LEN)
291 return FALSE;
292 }
293 else
294 return FALSE;
295
296 /* now, if we have a V3 structure, unmarshal the rest.
297 * otherwise, compute it
298 */
299 if (dest->version == 3)
300 {
301 if (*pDataLen != 0)
302 _unmarshal_uint64(pData, pDataLen, &dest->data_offset);
303 else
304 return FALSE;
305 }
306 else
307 dest->data_offset = dest->dir_offset + dest->dir_len;
308
309 return TRUE;
310}
311
312/* structure of ITSP headers */
313#define _CHM_ITSP_V1_LEN (0x54)
315{
316 char signature[4]; /* 0 (ITSP) */
317 Int32 version; /* 4 */
328 UInt32 lang_id; /* 30 */
329 UChar system_uuid[16]; /* 34 */
330 UChar unknown_0044[16]; /* 44 */
331}; /* __attribute__ ((aligned (1))); */
332
333static BOOL _unmarshal_itsp_header(unsigned char **pData,
334 unsigned int *pDataLen,
335 struct chmItspHeader *dest)
336{
337 /* we only know how to deal with a 0x54 byte structures */
338 if (*pDataLen != _CHM_ITSP_V1_LEN)
339 return FALSE;
340
341 /* unmarshal fields */
342 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
343 _unmarshal_int32 (pData, pDataLen, &dest->version);
344 _unmarshal_int32 (pData, pDataLen, &dest->header_len);
345 _unmarshal_int32 (pData, pDataLen, &dest->unknown_000c);
346 _unmarshal_uint32 (pData, pDataLen, &dest->block_len);
347 _unmarshal_int32 (pData, pDataLen, &dest->blockidx_intvl);
348 _unmarshal_int32 (pData, pDataLen, &dest->index_depth);
349 _unmarshal_int32 (pData, pDataLen, &dest->index_root);
350 _unmarshal_int32 (pData, pDataLen, &dest->index_head);
351 _unmarshal_int32 (pData, pDataLen, &dest->unknown_0024);
352 _unmarshal_uint32 (pData, pDataLen, &dest->num_blocks);
353 _unmarshal_int32 (pData, pDataLen, &dest->unknown_002c);
354 _unmarshal_uint32 (pData, pDataLen, &dest->lang_id);
355 _unmarshal_uuid (pData, pDataLen, dest->system_uuid);
356 _unmarshal_uchar_array(pData, pDataLen, dest->unknown_0044, 16);
357
358 /* error check the data */
359 if (memcmp(dest->signature, "ITSP", 4) != 0)
360 return FALSE;
361 if (dest->version != 1)
362 return FALSE;
363 if (dest->header_len != _CHM_ITSP_V1_LEN)
364 return FALSE;
365
366 return TRUE;
367}
368
369/* structure of PMGL headers */
370static const char _chm_pmgl_marker[4] = "PMGL";
371#define _CHM_PMGL_LEN (0x14)
373{
374 char signature[4]; /* 0 (PMGL) */
379}; /* __attribute__ ((aligned (1))); */
380
381static BOOL _unmarshal_pmgl_header(unsigned char **pData,
382 unsigned int *pDataLen,
383 struct chmPmglHeader *dest)
384{
385 /* we only know how to deal with a 0x14 byte structures */
386 if (*pDataLen != _CHM_PMGL_LEN)
387 return FALSE;
388
389 /* unmarshal fields */
390 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
391 _unmarshal_uint32 (pData, pDataLen, &dest->free_space);
392 _unmarshal_uint32 (pData, pDataLen, &dest->unknown_0008);
393 _unmarshal_int32 (pData, pDataLen, &dest->block_prev);
394 _unmarshal_int32 (pData, pDataLen, &dest->block_next);
395
396 /* check structure */
397 if (memcmp(dest->signature, _chm_pmgl_marker, 4) != 0)
398 return FALSE;
399
400 return TRUE;
401}
402
403/* structure of PMGI headers */
404static const char _chm_pmgi_marker[4] = "PMGI";
405#define _CHM_PMGI_LEN (0x08)
407{
408 char signature[4]; /* 0 (PMGI) */
410}; /* __attribute__ ((aligned (1))); */
411
412static BOOL _unmarshal_pmgi_header(unsigned char **pData,
413 unsigned int *pDataLen,
414 struct chmPmgiHeader *dest)
415{
416 /* we only know how to deal with a 0x8 byte structures */
417 if (*pDataLen != _CHM_PMGI_LEN)
418 return FALSE;
419
420 /* unmarshal fields */
421 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
422 _unmarshal_uint32 (pData, pDataLen, &dest->free_space);
423
424 /* check structure */
425 if (memcmp(dest->signature, _chm_pmgi_marker, 4) != 0)
426 return FALSE;
427
428 return TRUE;
429}
430
431/* structure of LZXC reset table */
432#define _CHM_LZXC_RESETTABLE_V1_LEN (0x28)
434{
442}; /* __attribute__ ((aligned (1))); */
443
445 unsigned int *pDataLen,
446 struct chmLzxcResetTable *dest)
447{
448 /* we only know how to deal with a 0x28 byte structures */
449 if (*pDataLen != _CHM_LZXC_RESETTABLE_V1_LEN)
450 return FALSE;
451
452 /* unmarshal fields */
453 _unmarshal_uint32 (pData, pDataLen, &dest->version);
454 _unmarshal_uint32 (pData, pDataLen, &dest->block_count);
455 _unmarshal_uint32 (pData, pDataLen, &dest->unknown);
456 _unmarshal_uint32 (pData, pDataLen, &dest->table_offset);
457 _unmarshal_uint64 (pData, pDataLen, &dest->uncompressed_len);
458 _unmarshal_uint64 (pData, pDataLen, &dest->compressed_len);
459 _unmarshal_uint64 (pData, pDataLen, &dest->block_len);
460
461 /* check structure */
462 if (dest->version != 2)
463 return FALSE;
464
465 return TRUE;
466}
467
468/* structure of LZXC control data block */
469#define _CHM_LZXC_MIN_LEN (0x18)
470#define _CHM_LZXC_V2_LEN (0x1c)
472{
473 UInt32 size; /* 0 */
474 char signature[4]; /* 4 (LZXC) */
480};
481
483 unsigned int *pDataLen,
484 struct chmLzxcControlData *dest)
485{
486 /* we want at least 0x18 bytes */
487 if (*pDataLen < _CHM_LZXC_MIN_LEN)
488 return FALSE;
489
490 /* unmarshal fields */
491 _unmarshal_uint32 (pData, pDataLen, &dest->size);
492 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
493 _unmarshal_uint32 (pData, pDataLen, &dest->version);
494 _unmarshal_uint32 (pData, pDataLen, &dest->resetInterval);
495 _unmarshal_uint32 (pData, pDataLen, &dest->windowSize);
496 _unmarshal_uint32 (pData, pDataLen, &dest->windowsPerReset);
497
498 if (*pDataLen >= _CHM_LZXC_V2_LEN)
499 _unmarshal_uint32 (pData, pDataLen, &dest->unknown_18);
500 else
501 dest->unknown_18 = 0;
502
503 if (dest->version == 2)
504 {
505 dest->resetInterval *= 0x8000;
506 dest->windowSize *= 0x8000;
507 }
508 if (dest->windowSize == 0 || dest->resetInterval == 0)
509 return FALSE;
510
511 /* for now, only support resetInterval a multiple of windowSize/2 */
512 if (dest->windowSize == 1)
513 return FALSE;
514 if ((dest->resetInterval % (dest->windowSize/2)) != 0)
515 return FALSE;
516
517 /* check structure */
518 if (memcmp(dest->signature, "LZXC", 4) != 0)
519 return FALSE;
520
521 return TRUE;
522}
523
524/* the structure used for chm file handles */
526{
528
532
539
544
545 /* LZX control data */
550
551 /* decompressor state */
554
555 /* cache for decompressed blocks */
559};
560
561/*
562 * utility functions local to this module
563 */
564
565/* utility function to handle differences between {pread,read}(64)? */
567 UChar *buf,
568 UInt64 os,
569 Int64 len)
570{
571 Int64 readLen=0;
572 if (h->fd == CHM_NULL_FD)
573 return readLen;
574
575 CHM_ACQUIRE_LOCK(h->mutex);
576 /* NOTE: this might be better done with CreateFileMapping, et cetera... */
577 {
578 LARGE_INTEGER old_pos, new_pos;
579 DWORD actualLen=0;
580
581 /* awkward Win32 Seek/Tell */
582 new_pos.QuadPart = 0;
583 SetFilePointerEx( h->fd, new_pos, &old_pos, FILE_CURRENT );
584 new_pos.QuadPart = os;
585 SetFilePointerEx( h->fd, new_pos, NULL, FILE_BEGIN );
586
587 /* read the data */
588 if (ReadFile(h->fd,
589 buf,
590 (DWORD)len,
591 &actualLen,
592 NULL))
593 readLen = actualLen;
594 else
595 readLen = 0;
596
597 /* restore original position */
598 SetFilePointerEx( h->fd, old_pos, NULL, FILE_BEGIN );
599 }
600 CHM_RELEASE_LOCK(h->mutex);
601 return readLen;
602}
603
604/*
605 * set a parameter on the file handle.
606 * valid parameter types:
607 * CHM_PARAM_MAX_BLOCKS_CACHED:
608 * how many decompressed blocks should be cached? A simple
609 * caching scheme is used, wherein the index of the block is
610 * used as a hash value, and hash collision results in the
611 * invalidation of the previously cached block.
612 */
613static void chm_set_param(struct chmFile *h,
614 int paramType,
615 int paramVal)
616{
617 switch (paramType)
618 {
620 CHM_ACQUIRE_LOCK(h->cache_mutex);
621 if (paramVal != h->cache_num_blocks)
622 {
623 UChar **newBlocks;
624 Int64 *newIndices;
625 int i;
626
627 /* allocate new cached blocks */
628 newBlocks = HeapAlloc(GetProcessHeap(), 0, paramVal * sizeof (UChar *));
629 newIndices = HeapAlloc(GetProcessHeap(), 0, paramVal * sizeof (UInt64));
630 for (i=0; i<paramVal; i++)
631 {
632 newBlocks[i] = NULL;
633 newIndices[i] = 0;
634 }
635
636 /* re-distribute old cached blocks */
637 if (h->cache_blocks)
638 {
639 for (i=0; i<h->cache_num_blocks; i++)
640 {
641 int newSlot = (int)(h->cache_block_indices[i] % paramVal);
642
643 if (h->cache_blocks[i])
644 {
645 /* in case of collision, destroy newcomer */
646 if (newBlocks[newSlot])
647 {
648 HeapFree(GetProcessHeap(), 0, h->cache_blocks[i]);
649 h->cache_blocks[i] = NULL;
650 }
651 else
652 {
653 newBlocks[newSlot] = h->cache_blocks[i];
654 newIndices[newSlot] =
655 h->cache_block_indices[i];
656 }
657 }
658 }
659
660 HeapFree(GetProcessHeap(), 0, h->cache_blocks);
661 HeapFree(GetProcessHeap(), 0, h->cache_block_indices);
662 }
663
664 /* now, set new values */
665 h->cache_blocks = newBlocks;
666 h->cache_block_indices = newIndices;
667 h->cache_num_blocks = paramVal;
668 }
669 CHM_RELEASE_LOCK(h->cache_mutex);
670 break;
671
672 default:
673 break;
674 }
675}
676
677/* open an ITS archive */
679{
680 unsigned char sbuffer[256];
681 unsigned int sremain;
682 unsigned char *sbufpos;
683 struct chmFile *newHandle=NULL;
684 struct chmItsfHeader itsfHeader;
685 struct chmItspHeader itspHeader;
686#if 0
687 struct chmUnitInfo uiSpan;
688#endif
689 struct chmUnitInfo uiLzxc;
690 struct chmLzxcControlData ctlData;
691
692 /* allocate handle */
693 newHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(struct chmFile));
694 newHandle->fd = CHM_NULL_FD;
695 newHandle->lzx_state = NULL;
696 newHandle->cache_blocks = NULL;
697 newHandle->cache_block_indices = NULL;
698 newHandle->cache_num_blocks = 0;
699
700 /* open file */
701 if ((newHandle->fd=CreateFileW(filename,
704 NULL,
707 NULL)) == CHM_NULL_FD)
708 {
709 HeapFree(GetProcessHeap(), 0, newHandle);
710 return NULL;
711 }
712
713 /* initialize mutexes, if needed */
714 InitializeCriticalSection(&newHandle->mutex);
715 newHandle->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.mutex");
717 newHandle->lzx_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.lzx_mutex");
719 newHandle->cache_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.cache_mutex");
720
721 /* read and verify header */
722 sremain = _CHM_ITSF_V3_LEN;
723 sbufpos = sbuffer;
724 if (_chm_fetch_bytes(newHandle, sbuffer, 0, sremain) != sremain ||
725 !_unmarshal_itsf_header(&sbufpos, &sremain, &itsfHeader))
726 {
727 chm_close(newHandle);
728 return NULL;
729 }
730
731 /* stash important values from header */
732 newHandle->dir_offset = itsfHeader.dir_offset;
733 newHandle->dir_len = itsfHeader.dir_len;
734 newHandle->data_offset = itsfHeader.data_offset;
735
736 /* now, read and verify the directory header chunk */
737 sremain = _CHM_ITSP_V1_LEN;
738 sbufpos = sbuffer;
739 if (_chm_fetch_bytes(newHandle, sbuffer,
740 itsfHeader.dir_offset, sremain) != sremain ||
741 !_unmarshal_itsp_header(&sbufpos, &sremain, &itspHeader))
742 {
743 chm_close(newHandle);
744 return NULL;
745 }
746
747 /* grab essential information from ITSP header */
748 newHandle->dir_offset += itspHeader.header_len;
749 newHandle->dir_len -= itspHeader.header_len;
750 newHandle->index_root = itspHeader.index_root;
751 newHandle->index_head = itspHeader.index_head;
752 newHandle->block_len = itspHeader.block_len;
753
754 /* if the index root is -1, this means we don't have any PMGI blocks.
755 * as a result, we must use the sole PMGL block as the index root
756 */
757 if (newHandle->index_root == -1)
758 newHandle->index_root = newHandle->index_head;
759
760 /* initialize cache */
763
764 /* By default, compression is enabled. */
765 newHandle->compression_enabled = 1;
766
767 /* prefetch most commonly needed unit infos */
770 &newHandle->rt_unit) ||
771 newHandle->rt_unit.space == CHM_COMPRESSED ||
774 &newHandle->cn_unit) ||
775 newHandle->cn_unit.space == CHM_COMPRESSED ||
778 &uiLzxc) ||
779 uiLzxc.space == CHM_COMPRESSED)
780 {
781 newHandle->compression_enabled = 0;
782 }
783
784 /* read reset table info */
785 if (newHandle->compression_enabled)
786 {
788 sbufpos = sbuffer;
789 if (chm_retrieve_object(newHandle, &newHandle->rt_unit, sbuffer,
790 0, sremain) != sremain ||
791 !_unmarshal_lzxc_reset_table(&sbufpos, &sremain,
792 &newHandle->reset_table))
793 {
794 newHandle->compression_enabled = 0;
795 }
796 }
797
798 /* read control data */
799 if (newHandle->compression_enabled)
800 {
801 sremain = (unsigned long)uiLzxc.length;
802 sbufpos = sbuffer;
803 if (chm_retrieve_object(newHandle, &uiLzxc, sbuffer,
804 0, sremain) != sremain ||
805 !_unmarshal_lzxc_control_data(&sbufpos, &sremain,
806 &ctlData))
807 {
808 newHandle->compression_enabled = 0;
809 }
810
811 newHandle->window_size = ctlData.windowSize;
812 newHandle->reset_interval = ctlData.resetInterval;
813
814/* Jed, Mon Jun 28: Experimentally, it appears that the reset block count */
815/* must be multiplied by this formerly unknown ctrl data field in */
816/* order to decompress some files. */
817#if 0
818 newHandle->reset_blkcount = newHandle->reset_interval /
819 (newHandle->window_size / 2);
820#else
821 newHandle->reset_blkcount = newHandle->reset_interval /
822 (newHandle->window_size / 2) *
823 ctlData.windowsPerReset;
824#endif
825 }
826
827 return newHandle;
828}
829
830/* Duplicate an ITS archive handle */
831struct chmFile *chm_dup(struct chmFile *oldHandle)
832{
833 struct chmFile *newHandle=NULL;
834
835 newHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(struct chmFile));
836 *newHandle = *oldHandle;
837
838 /* duplicate fd handle */
840 GetCurrentProcess(), &(newHandle->fd),
842 newHandle->lzx_state = NULL;
843 newHandle->cache_blocks = NULL;
844 newHandle->cache_block_indices = NULL;
845 newHandle->cache_num_blocks = 0;
846
847 /* initialize mutexes, if needed */
848 InitializeCriticalSection(&newHandle->mutex);
849 newHandle->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.mutex");
851 newHandle->lzx_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.lzx_mutex");
853 newHandle->cache_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.cache_mutex");
854
855 /* initialize cache */
858
859 return newHandle;
860}
861
862/* close an ITS archive */
863void chm_close(struct chmFile *h)
864{
865 if (h != NULL)
866 {
867 if (h->fd != CHM_NULL_FD)
868 CHM_CLOSE_FILE(h->fd);
869 h->fd = CHM_NULL_FD;
870
871 h->mutex.DebugInfo->Spare[0] = 0;
872 DeleteCriticalSection(&h->mutex);
873 h->lzx_mutex.DebugInfo->Spare[0] = 0;
874 DeleteCriticalSection(&h->lzx_mutex);
875 h->cache_mutex.DebugInfo->Spare[0] = 0;
876 DeleteCriticalSection(&h->cache_mutex);
877
878 if (h->lzx_state)
879 LZXteardown(h->lzx_state);
880 h->lzx_state = NULL;
881
882 if (h->cache_blocks)
883 {
884 int i;
885 for (i=0; i<h->cache_num_blocks; i++)
886 {
887 HeapFree(GetProcessHeap(), 0, h->cache_blocks[i]);
888 }
889 HeapFree(GetProcessHeap(), 0, h->cache_blocks);
890 h->cache_blocks = NULL;
891 }
892
893 HeapFree(GetProcessHeap(), 0, h->cache_block_indices);
894 h->cache_block_indices = NULL;
895
897 }
898}
899
900/*
901 * helper methods for chm_resolve_object
902 */
903
904/* skip a compressed dword */
906{
907 while (*(*pEntry)++ >= 0x80)
908 ;
909}
910
911/* skip the data from a PMGL entry */
913{
917}
918
919/* parse a compressed dword */
921{
922 UInt64 accum = 0;
923 UChar temp;
924 while ((temp=*(*pEntry)++) >= 0x80)
925 {
926 accum <<= 7;
927 accum += temp & 0x7f;
928 }
929
930 return (accum << 7) + temp;
931}
932
933/* parse a utf-8 string into an ASCII char buffer */
935{
937 path[length] = '\0';
938 *pEntry += count;
939 return !!length;
940}
941
942/* parse a PMGL entry into a chmUnitInfo struct; return 1 on success. */
944{
945 UInt64 strLen;
946
947 /* parse str len */
948 strLen = _chm_parse_cword(pEntry);
949 if (strLen > CHM_MAX_PATHLEN)
950 return FALSE;
951
952 /* parse path */
953 if (! _chm_parse_UTF8(pEntry, strLen, ui->path))
954 return FALSE;
955
956 /* parse info */
957 ui->space = (int)_chm_parse_cword(pEntry);
958 ui->start = _chm_parse_cword(pEntry);
959 ui->length = _chm_parse_cword(pEntry);
960 return TRUE;
961}
962
963/* find an exact entry in PMGL; return NULL if we fail */
964static UChar *_chm_find_in_PMGL(UChar *page_buf,
966 const WCHAR *objPath)
967{
968 /* XXX: modify this to do a binary search using the nice index structure
969 * that is provided for us.
970 */
971 struct chmPmglHeader header;
972 UInt32 hremain;
973 UChar *end;
974 UChar *cur;
975 UChar *temp;
976 UInt64 strLen;
978
979 /* figure out where to start and end */
980 cur = page_buf;
981 hremain = _CHM_PMGL_LEN;
982 if (! _unmarshal_pmgl_header(&cur, &hremain, &header))
983 return NULL;
984 end = page_buf + block_len - (header.free_space);
985
986 /* now, scan progressively */
987 while (cur < end)
988 {
989 /* grab the name */
990 temp = cur;
991 strLen = _chm_parse_cword(&cur);
992 if (! _chm_parse_UTF8(&cur, strLen, buffer))
993 return NULL;
994
995 /* check if it is the right name */
996 if (! wcsicmp(buffer, objPath))
997 return temp;
998
1000 }
1001
1002 return NULL;
1003}
1004
1005/* find which block should be searched next for the entry; -1 if no block */
1007 UInt32 block_len,
1008 const WCHAR *objPath)
1009{
1010 /* XXX: modify this to do a binary search using the nice index structure
1011 * that is provided for us
1012 */
1013 struct chmPmgiHeader header;
1014 UInt32 hremain;
1015 int page=-1;
1016 UChar *end;
1017 UChar *cur;
1018 UInt64 strLen;
1020
1021 /* figure out where to start and end */
1022 cur = page_buf;
1023 hremain = _CHM_PMGI_LEN;
1024 if (! _unmarshal_pmgi_header(&cur, &hremain, &header))
1025 return -1;
1026 end = page_buf + block_len - (header.free_space);
1027
1028 /* now, scan progressively */
1029 while (cur < end)
1030 {
1031 /* grab the name */
1032 strLen = _chm_parse_cword(&cur);
1033 if (! _chm_parse_UTF8(&cur, strLen, buffer))
1034 return -1;
1035
1036 /* check if it is the right name */
1037 if (wcsicmp(buffer, objPath) > 0)
1038 return page;
1039
1040 /* load next value for path */
1042 }
1043
1044 return page;
1045}
1046
1047/* resolve a particular object from the archive */
1049 const WCHAR *objPath,
1050 struct chmUnitInfo *ui)
1051{
1052 /*
1053 * XXX: implement caching scheme for dir pages
1054 */
1055
1056 Int32 curPage;
1057
1058 /* buffer to hold whatever page we're looking at */
1059 UChar *page_buf = HeapAlloc(GetProcessHeap(), 0, h->block_len);
1060
1061 /* starting page */
1062 curPage = h->index_root;
1063
1064 /* until we have either returned or given up */
1065 while (curPage != -1)
1066 {
1067
1068 /* try to fetch the index page */
1069 if (_chm_fetch_bytes(h, page_buf,
1070 h->dir_offset + (UInt64)curPage*h->block_len,
1071 h->block_len) != h->block_len)
1072 {
1073 HeapFree(GetProcessHeap(), 0, page_buf);
1074 return CHM_RESOLVE_FAILURE;
1075 }
1076
1077 /* now, if it is a leaf node: */
1078 if (memcmp(page_buf, _chm_pmgl_marker, 4) == 0)
1079 {
1080 /* scan block */
1081 UChar *pEntry = _chm_find_in_PMGL(page_buf,
1082 h->block_len,
1083 objPath);
1084 if (pEntry == NULL)
1085 {
1086 HeapFree(GetProcessHeap(), 0, page_buf);
1087 return CHM_RESOLVE_FAILURE;
1088 }
1089
1090 /* parse entry and return */
1092 HeapFree(GetProcessHeap(), 0, page_buf);
1093 return CHM_RESOLVE_SUCCESS;
1094 }
1095
1096 /* else, if it is a branch node: */
1097 else if (memcmp(page_buf, _chm_pmgi_marker, 4) == 0)
1098 curPage = _chm_find_in_PMGI(page_buf, h->block_len, objPath);
1099
1100 /* else, we are confused. give up. */
1101 else
1102 {
1103 HeapFree(GetProcessHeap(), 0, page_buf);
1104 return CHM_RESOLVE_FAILURE;
1105 }
1106 }
1107
1108 /* didn't find anything. fail. */
1109 HeapFree(GetProcessHeap(), 0, page_buf);
1110 return CHM_RESOLVE_FAILURE;
1111}
1112
1113/*
1114 * utility methods for dealing with compressed data
1115 */
1116
1117/* get the bounds of a compressed block. Returns FALSE on failure */
1119 UInt64 block,
1120 UInt64 *start,
1121 Int64 *len)
1122{
1123 UChar buffer[8], *dummy;
1124 UInt32 remain;
1125
1126 /* for all but the last block, use the reset table */
1127 if (block < h->reset_table.block_count-1)
1128 {
1129 /* unpack the start address */
1130 dummy = buffer;
1131 remain = 8;
1133 h->data_offset
1134 + h->rt_unit.start
1135 + h->reset_table.table_offset
1136 + block*8,
1137 remain) != remain ||
1138 !_unmarshal_uint64(&dummy, &remain, start))
1139 return FALSE;
1140
1141 /* unpack the end address */
1142 dummy = buffer;
1143 remain = 8;
1145 h->data_offset
1146 + h->rt_unit.start
1147 + h->reset_table.table_offset
1148 + block*8 + 8,
1149 remain) != remain ||
1150 !_unmarshal_int64(&dummy, &remain, len))
1151 return FALSE;
1152 }
1153
1154 /* for the last block, use the span in addition to the reset table */
1155 else
1156 {
1157 /* unpack the start address */
1158 dummy = buffer;
1159 remain = 8;
1161 h->data_offset
1162 + h->rt_unit.start
1163 + h->reset_table.table_offset
1164 + block*8,
1165 remain) != remain ||
1166 !_unmarshal_uint64(&dummy, &remain, start))
1167 return FALSE;
1168
1169 *len = h->reset_table.compressed_len;
1170 }
1171
1172 /* compute the length and absolute start address */
1173 *len -= *start;
1174 *start += h->data_offset + h->cn_unit.start;
1175
1176 return TRUE;
1177}
1178
1179/* decompress the block. must have lzx_mutex. */
1181 UInt64 block,
1182 UChar **ubuffer)
1183{
1184 UChar *cbuffer = HeapAlloc( GetProcessHeap(), 0,
1185 ((unsigned int)h->reset_table.block_len + 6144));
1186 UInt64 cmpStart; /* compressed start */
1187 Int64 cmpLen; /* compressed len */
1188 int indexSlot; /* cache index slot */
1189 UChar *lbuffer; /* local buffer ptr */
1190 UInt32 blockAlign = (UInt32)(block % h->reset_blkcount); /* reset interval align */
1191 UInt32 i; /* local loop index */
1192
1193 /* let the caching system pull its weight! */
1194 if (block - blockAlign <= h->lzx_last_block &&
1195 block >= h->lzx_last_block)
1196 blockAlign = (block - h->lzx_last_block);
1197
1198 /* check if we need previous blocks */
1199 if (blockAlign != 0)
1200 {
1201 /* fetch all required previous blocks since last reset */
1202 for (i = blockAlign; i > 0; i--)
1203 {
1204 UInt32 curBlockIdx = block - i;
1205
1206 /* check if we most recently decompressed the previous block */
1207 if (h->lzx_last_block != curBlockIdx)
1208 {
1209 if ((curBlockIdx % h->reset_blkcount) == 0)
1210 {
1211#ifdef CHM_DEBUG
1212 fprintf(stderr, "***RESET (1)***\n");
1213#endif
1214 LZXreset(h->lzx_state);
1215 }
1216
1217 indexSlot = (int)((curBlockIdx) % h->cache_num_blocks);
1218 h->cache_block_indices[indexSlot] = curBlockIdx;
1219 if (! h->cache_blocks[indexSlot])
1220 h->cache_blocks[indexSlot] =
1222 (unsigned int)(h->reset_table.block_len));
1223 lbuffer = h->cache_blocks[indexSlot];
1224
1225 /* decompress the previous block */
1226#ifdef CHM_DEBUG
1227 fprintf(stderr, "Decompressing block #%4d (EXTRA)\n", curBlockIdx);
1228#endif
1229 if (!_chm_get_cmpblock_bounds(h, curBlockIdx, &cmpStart, &cmpLen) ||
1230 _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen ||
1231 LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
1232 (int)h->reset_table.block_len) != DECR_OK)
1233 {
1234#ifdef CHM_DEBUG
1235 fprintf(stderr, " (DECOMPRESS FAILED!)\n");
1236#endif
1237 HeapFree(GetProcessHeap(), 0, cbuffer);
1238 return 0;
1239 }
1240
1241 h->lzx_last_block = (int)curBlockIdx;
1242 }
1243 }
1244 }
1245 else
1246 {
1247 if ((block % h->reset_blkcount) == 0)
1248 {
1249#ifdef CHM_DEBUG
1250 fprintf(stderr, "***RESET (2)***\n");
1251#endif
1252 LZXreset(h->lzx_state);
1253 }
1254 }
1255
1256 /* allocate slot in cache */
1257 indexSlot = (int)(block % h->cache_num_blocks);
1258 h->cache_block_indices[indexSlot] = block;
1259 if (! h->cache_blocks[indexSlot])
1260 h->cache_blocks[indexSlot] =
1261 HeapAlloc(GetProcessHeap(), 0, ((unsigned int)h->reset_table.block_len));
1262 lbuffer = h->cache_blocks[indexSlot];
1263 *ubuffer = lbuffer;
1264
1265 /* decompress the block we actually want */
1266#ifdef CHM_DEBUG
1267 fprintf(stderr, "Decompressing block #%4d (REAL )\n", block);
1268#endif
1269 if (! _chm_get_cmpblock_bounds(h, block, &cmpStart, &cmpLen) ||
1270 _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen ||
1271 LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
1272 (int)h->reset_table.block_len) != DECR_OK)
1273 {
1274#ifdef CHM_DEBUG
1275 fprintf(stderr, " (DECOMPRESS FAILED!)\n");
1276#endif
1277 HeapFree(GetProcessHeap(), 0, cbuffer);
1278 return 0;
1279 }
1280 h->lzx_last_block = (int)block;
1281
1282 /* XXX: modify LZX routines to return the length of the data they
1283 * decompressed and return that instead, for an extra sanity check.
1284 */
1285 HeapFree(GetProcessHeap(), 0, cbuffer);
1286 return h->reset_table.block_len;
1287}
1288
1289/* grab a region from a compressed block */
1291 UChar *buf,
1292 UInt64 start,
1293 Int64 len)
1294{
1295 UInt64 nBlock, nOffset;
1296 UInt64 nLen;
1297 UInt64 gotLen;
1298 UChar *ubuffer = NULL;
1299
1300 if (len <= 0)
1301 return 0;
1302
1303 /* figure out what we need to read */
1304 nBlock = start / h->reset_table.block_len;
1305 nOffset = start % h->reset_table.block_len;
1306 nLen = len;
1307 if (nLen > (h->reset_table.block_len - nOffset))
1308 nLen = h->reset_table.block_len - nOffset;
1309
1310 /* if block is cached, return data from it. */
1311 CHM_ACQUIRE_LOCK(h->lzx_mutex);
1312 CHM_ACQUIRE_LOCK(h->cache_mutex);
1313 if (h->cache_block_indices[nBlock % h->cache_num_blocks] == nBlock &&
1314 h->cache_blocks[nBlock % h->cache_num_blocks] != NULL)
1315 {
1316 memcpy(buf,
1317 h->cache_blocks[nBlock % h->cache_num_blocks] + nOffset,
1318 (unsigned int)nLen);
1319 CHM_RELEASE_LOCK(h->cache_mutex);
1320 CHM_RELEASE_LOCK(h->lzx_mutex);
1321 return nLen;
1322 }
1323 CHM_RELEASE_LOCK(h->cache_mutex);
1324
1325 /* data request not satisfied, so... start up the decompressor machine */
1326 if (! h->lzx_state)
1327 {
1328 h->lzx_last_block = -1;
1329 h->lzx_state = LZXinit(h->window_size);
1330 }
1331
1332 /* decompress some data */
1333 gotLen = _chm_decompress_block(h, nBlock, &ubuffer);
1334 if (gotLen < nLen)
1335 nLen = gotLen;
1336 memcpy(buf, ubuffer+nOffset, (unsigned int)nLen);
1337 CHM_RELEASE_LOCK(h->lzx_mutex);
1338 return nLen;
1339}
1340
1341/* retrieve (part of) an object */
1343 struct chmUnitInfo *ui,
1344 unsigned char *buf,
1346 LONGINT64 len)
1347{
1348 /* must be valid file handle */
1349 if (h == NULL)
1350 return 0;
1351
1352 /* starting address must be in correct range */
1353 if (addr >= ui->length)
1354 return 0;
1355
1356 /* clip length */
1357 if (addr + len > ui->length)
1358 len = ui->length - addr;
1359
1360 /* if the file is uncompressed, it's simple */
1361 if (ui->space == CHM_UNCOMPRESSED)
1362 {
1363 /* read data */
1364 return _chm_fetch_bytes(h,
1365 buf,
1366 h->data_offset + ui->start + addr,
1367 len);
1368 }
1369
1370 /* else if the file is compressed, it's a little trickier */
1371 else /* ui->space == CHM_COMPRESSED */
1372 {
1373 Int64 swath=0, total=0;
1374
1375 /* if compression is not enabled for this file... */
1376 if (! h->compression_enabled)
1377 return total;
1378
1379 do {
1380
1381 /* swill another mouthful */
1382 swath = _chm_decompress_region(h, buf, ui->start + addr, len);
1383
1384 /* if we didn't get any... */
1385 if (swath == 0)
1386 return total;
1387
1388 /* update stats */
1389 total += swath;
1390 len -= swath;
1391 addr += swath;
1392 buf += swath;
1393
1394 } while (len != 0);
1395
1396 return total;
1397 }
1398}
1399
1401 const WCHAR *prefix,
1402 int what,
1404 void *context)
1405{
1406 /*
1407 * XXX: do this efficiently (i.e. using the tree index)
1408 */
1409
1410 Int32 curPage;
1411
1412 /* buffer to hold whatever page we're looking at */
1413 UChar *page_buf = HeapAlloc(GetProcessHeap(), 0, h->block_len);
1414 struct chmPmglHeader header;
1415 UChar *end;
1416 UChar *cur;
1417 unsigned int lenRemain;
1418
1419 /* set to TRUE once we've started */
1420 BOOL it_has_begun = FALSE;
1421
1422 /* the current ui */
1423 struct chmUnitInfo ui;
1424 int flag;
1425 UInt64 ui_path_len;
1426
1427 /* the length of the prefix */
1428 WCHAR prefixRectified[CHM_MAX_PATHLEN+1];
1429 int prefixLen;
1430 WCHAR lastPath[CHM_MAX_PATHLEN];
1431 int lastPathLen;
1432
1433 /* starting page */
1434 curPage = h->index_head;
1435
1436 /* initialize pathname state */
1437 lstrcpynW(prefixRectified, prefix, CHM_MAX_PATHLEN);
1438 prefixLen = lstrlenW(prefixRectified);
1439 if (prefixLen != 0)
1440 {
1441 if (prefixRectified[prefixLen-1] != '/')
1442 {
1443 prefixRectified[prefixLen] = '/';
1444 prefixRectified[prefixLen+1] = '\0';
1445 ++prefixLen;
1446 }
1447 }
1448 lastPath[0] = '\0';
1449 lastPathLen = -1;
1450
1451 /* until we have either returned or given up */
1452 while (curPage != -1)
1453 {
1454
1455 /* try to fetch the index page */
1456 if (_chm_fetch_bytes(h,
1457 page_buf,
1458 h->dir_offset + (UInt64)curPage*h->block_len,
1459 h->block_len) != h->block_len)
1460 {
1461 HeapFree(GetProcessHeap(), 0, page_buf);
1462 return FALSE;
1463 }
1464
1465 /* figure out start and end for this page */
1466 cur = page_buf;
1467 lenRemain = _CHM_PMGL_LEN;
1468 if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))
1469 {
1470 HeapFree(GetProcessHeap(), 0, page_buf);
1471 return FALSE;
1472 }
1473 end = page_buf + h->block_len - (header.free_space);
1474
1475 /* loop over this page */
1476 while (cur < end)
1477 {
1478 if (! _chm_parse_PMGL_entry(&cur, &ui))
1479 {
1480 HeapFree(GetProcessHeap(), 0, page_buf);
1481 return FALSE;
1482 }
1483
1484 /* check if we should start */
1485 if (! it_has_begun)
1486 {
1487 if (ui.length == 0 && _wcsnicmp(ui.path, prefixRectified, prefixLen) == 0)
1488 it_has_begun = TRUE;
1489 else
1490 continue;
1491
1492 if (ui.path[prefixLen] == '\0')
1493 continue;
1494 }
1495
1496 /* check if we should stop */
1497 else
1498 {
1499 if (_wcsnicmp(ui.path, prefixRectified, prefixLen) != 0)
1500 {
1501 HeapFree(GetProcessHeap(), 0, page_buf);
1502 return TRUE;
1503 }
1504 }
1505
1506 /* check if we should include this path */
1507 if (lastPathLen != -1)
1508 {
1509 if (_wcsnicmp(ui.path, lastPath, lastPathLen) == 0)
1510 continue;
1511 }
1512 lstrcpyW(lastPath, ui.path);
1513 lastPathLen = lstrlenW(lastPath);
1514
1515 /* get the length of the path */
1516 ui_path_len = lstrlenW(ui.path)-1;
1517
1518 /* check for DIRS */
1519 if (ui.path[ui_path_len] == '/' && !(what & CHM_ENUMERATE_DIRS))
1520 continue;
1521
1522 /* check for FILES */
1523 if (ui.path[ui_path_len] != '/' && !(what & CHM_ENUMERATE_FILES))
1524 continue;
1525
1526 /* check for NORMAL vs. META */
1527 if (ui.path[0] == '/')
1528 {
1529
1530 /* check for NORMAL vs. SPECIAL */
1531 if (ui.path[1] == '#' || ui.path[1] == '$')
1533 else
1535 }
1536 else
1538 if (! (what & flag))
1539 continue;
1540
1541 /* call the enumerator */
1542 {
1543 int status = (*e)(h, &ui, context);
1544 switch (status)
1545 {
1547 HeapFree(GetProcessHeap(), 0, page_buf);
1548 return FALSE;
1550 break;
1552 HeapFree(GetProcessHeap(), 0, page_buf);
1553 return TRUE;
1554 default:
1555 break;
1556 }
1557 }
1558 }
1559
1560 /* advance to next page */
1561 curPage = header.block_next;
1562 }
1563
1564 HeapFree(GetProcessHeap(), 0, page_buf);
1565 return TRUE;
1566}
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define _CHM_ITSF_V2_LEN
Definition: chm_lib.c:236
static Int32 _chm_find_in_PMGI(UChar *page_buf, UInt32 block_len, const WCHAR *objPath)
Definition: chm_lib.c:1006
static const WCHAR _CHMU_LZXC_CONTROLDATA[]
Definition: chm_lib.c:218
static BOOL _unmarshal_int32(unsigned char **pData, unsigned int *pLenRemain, Int32 *dest)
Definition: chm_lib.c:135
#define CHM_RELEASE_LOCK(a)
Definition: chm_lib.c:73
static void _chm_skip_PMGL_entry_data(UChar **pEntry)
Definition: chm_lib.c:912
#define _CHM_LZXC_RESETTABLE_V1_LEN
Definition: chm_lib.c:432
static BOOL _unmarshal_uint32(unsigned char **pData, unsigned int *pLenRemain, UInt32 *dest)
Definition: chm_lib.c:147
#define CHM_ACQUIRE_LOCK(a)
Definition: chm_lib.c:70
static void chm_set_param(struct chmFile *h, int paramType, int paramVal)
Definition: chm_lib.c:613
LONGINT64 chm_retrieve_object(struct chmFile *h, struct chmUnitInfo *ui, unsigned char *buf, LONGUINT64 addr, LONGINT64 len)
Definition: chm_lib.c:1342
static BOOL _unmarshal_uuid(unsigned char **pData, unsigned int *pDataLen, unsigned char *dest)
Definition: chm_lib.c:199
#define CHM_MAX_BLOCKS_CACHED
Definition: chm_lib.c:84
int chm_resolve_object(struct chmFile *h, const WCHAR *objPath, struct chmUnitInfo *ui)
Definition: chm_lib.c:1048
static BOOL _unmarshal_pmgl_header(unsigned char **pData, unsigned int *pDataLen, struct chmPmglHeader *dest)
Definition: chm_lib.c:381
#define CHM_PARAM_MAX_BLOCKS_CACHED
Definition: chm_lib.c:86
#define CHM_CLOSE_FILE(fd)
Definition: chm_lib.c:78
static const char _chm_pmgi_marker[4]
Definition: chm_lib.c:404
static Int64 _chm_decompress_region(struct chmFile *h, UChar *buf, UInt64 start, Int64 len)
Definition: chm_lib.c:1290
USHORT UInt16
Definition: chm_lib.c:102
DWORD UInt32
Definition: chm_lib.c:104
static UChar * _chm_find_in_PMGL(UChar *page_buf, UInt32 block_len, const WCHAR *objPath)
Definition: chm_lib.c:964
static BOOL _unmarshal_itsp_header(unsigned char **pData, unsigned int *pDataLen, struct chmItspHeader *dest)
Definition: chm_lib.c:333
static BOOL _unmarshal_pmgi_header(unsigned char **pData, unsigned int *pDataLen, struct chmPmgiHeader *dest)
Definition: chm_lib.c:412
static BOOL _unmarshal_lzxc_reset_table(unsigned char **pData, unsigned int *pDataLen, struct chmLzxcResetTable *dest)
Definition: chm_lib.c:444
static BOOL _unmarshal_char_array(unsigned char **pData, unsigned int *pLenRemain, char *dest, int count)
Definition: chm_lib.c:109
static BOOL _unmarshal_uchar_array(unsigned char **pData, unsigned int *pLenRemain, unsigned char *dest, int count)
Definition: chm_lib.c:122
SHORT Int16
Definition: chm_lib.c:101
#define _CHM_ITSP_V1_LEN
Definition: chm_lib.c:313
struct chmFile * chm_dup(struct chmFile *oldHandle)
Definition: chm_lib.c:831
#define _CHM_LZXC_V2_LEN
Definition: chm_lib.c:470
static BOOL _unmarshal_int64(unsigned char **pData, unsigned int *pLenRemain, Int64 *dest)
Definition: chm_lib.c:159
static const WCHAR _CHMU_RESET_TABLE[]
Definition: chm_lib.c:207
BOOL chm_enumerate_dir(struct chmFile *h, const WCHAR *prefix, int what, CHM_ENUMERATOR e, void *context)
Definition: chm_lib.c:1400
static void _chm_skip_cword(UChar **pEntry)
Definition: chm_lib.c:905
static Int64 _chm_decompress_block(struct chmFile *h, UInt64 block, UChar **ubuffer)
Definition: chm_lib.c:1180
LONGLONG Int64
Definition: chm_lib.c:105
static BOOL _unmarshal_uint64(unsigned char **pData, unsigned int *pLenRemain, UInt64 *dest)
Definition: chm_lib.c:179
#define _CHM_LZXC_MIN_LEN
Definition: chm_lib.c:469
LONG Int32
Definition: chm_lib.c:103
static BOOL _unmarshal_lzxc_control_data(unsigned char **pData, unsigned int *pDataLen, struct chmLzxcControlData *dest)
Definition: chm_lib.c:482
static BOOL _chm_parse_UTF8(UChar **pEntry, UInt64 count, WCHAR *path)
Definition: chm_lib.c:934
BYTE UChar
Definition: chm_lib.c:100
struct chmFile * chm_openW(const WCHAR *filename)
Definition: chm_lib.c:678
#define _CHM_ITSF_V3_LEN
Definition: chm_lib.c:237
ULONGLONG UInt64
Definition: chm_lib.c:106
static const WCHAR _CHMU_CONTENT[]
Definition: chm_lib.c:224
static BOOL _unmarshal_itsf_header(unsigned char **pData, unsigned int *pDataLen, struct chmItsfHeader *dest)
Definition: chm_lib.c:255
void chm_close(struct chmFile *h)
Definition: chm_lib.c:863
#define _CHM_PMGL_LEN
Definition: chm_lib.c:371
#define CHM_NULL_FD
Definition: chm_lib.c:77
static UInt64 _chm_parse_cword(UChar **pEntry)
Definition: chm_lib.c:920
static BOOL _chm_parse_PMGL_entry(UChar **pEntry, struct chmUnitInfo *ui)
Definition: chm_lib.c:943
static BOOL _chm_get_cmpblock_bounds(struct chmFile *h, UInt64 block, UInt64 *start, Int64 *len)
Definition: chm_lib.c:1118
#define _CHM_PMGI_LEN
Definition: chm_lib.c:405
static const char _chm_pmgl_marker[4]
Definition: chm_lib.c:370
static Int64 _chm_fetch_bytes(struct chmFile *h, UChar *buf, UInt64 os, Int64 len)
Definition: chm_lib.c:566
#define CHM_COMPRESSED
Definition: chm_lib.h:60
#define CHM_ENUMERATE_NORMAL
Definition: chm_lib.h:99
#define CHM_RESOLVE_FAILURE
Definition: chm_lib.h:83
ULONGLONG LONGUINT64
Definition: chm_lib.h:53
#define CHM_ENUMERATOR_CONTINUE
Definition: chm_lib.h:106
LONGLONG LONGINT64
Definition: chm_lib.h:54
#define CHM_ENUMERATE_META
Definition: chm_lib.h:100
#define CHM_ENUMERATE_SPECIAL
Definition: chm_lib.h:101
#define CHM_RESOLVE_SUCCESS
Definition: chm_lib.h:82
#define CHM_ENUMERATE_DIRS
Definition: chm_lib.h:103
#define CHM_UNCOMPRESSED
Definition: chm_lib.h:59
#define CHM_MAX_PATHLEN
Definition: chm_lib.h:66
int(* CHM_ENUMERATOR)(struct chmFile *h, struct chmUnitInfo *ui, void *context)
Definition: chm_lib.h:96
#define CHM_ENUMERATE_FILES
Definition: chm_lib.h:102
#define CHM_ENUMERATOR_SUCCESS
Definition: chm_lib.h:107
#define CHM_ENUMERATOR_FAILURE
Definition: chm_lib.h:105
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define DECR_OK
Definition: mszip.h:79
#define GetProcessHeap()
Definition: compat.h:736
#define FILE_BEGIN
Definition: compat.h:761
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define HeapAlloc
Definition: compat.h:733
#define GetCurrentProcess()
Definition: compat.h:759
#define GENERIC_READ
Definition: compat.h:135
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CreateFileW
Definition: compat.h:741
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define lstrcpyW
Definition: compat.h:749
#define MultiByteToWideChar
Definition: compat.h:110
#define FILE_SHARE_READ
Definition: compat.h:136
#define wcsicmp
Definition: compat.h:15
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
BOOL WINAPI SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
Definition: fileinfo.c:177
BOOL WINAPI DuplicateHandle(IN HANDLE hSourceProcessHandle, IN HANDLE hSourceHandle, IN HANDLE hTargetProcessHandle, OUT LPHANDLE lpTargetHandle, IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwOptions)
Definition: handle.c:149
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
FxCollectionEntry * cur
size_t total
GLuint start
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLenum const GLvoid * addr
Definition: glext.h:9621
GLenum GLsizei len
Definition: glext.h:6722
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean flag
Definition: glfuncs.h:52
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
const char * filename
Definition: ioapi.h:137
void LZXteardown(struct LZXstate *pState)
Definition: lzx.c:209
int LZXdecompress(struct LZXstate *pState, unsigned char *inpos, unsigned char *outpos, int inlen, int outlen)
Definition: lzx.c:461
struct LZXstate * LZXinit(int wndsize)
Definition: lzx.c:172
int LZXreset(struct LZXstate *pState)
Definition: lzx.c:218
#define e
Definition: ke_i.h:82
if(dx< 0)
Definition: linetemp.h:194
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static char * dest
Definition: rtl.c:135
UINT ui
Definition: oleauto.h:49
short SHORT
Definition: pedump.c:59
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
#define long
Definition: qsort.c:33
static calc_node_t temp
Definition: rpn_ieee.c:38
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
#define CP_UTF8
Definition: nls.h:20
DWORD_PTR Spare[8/sizeof(DWORD_PTR)]
Definition: winbase.h:887
PCRITICAL_SECTION_DEBUG DebugInfo
Definition: winbase.h:894
Int64 * cache_block_indices
Definition: chm_lib.c:557
UInt32 reset_blkcount
Definition: chm_lib.c:549
UInt32 window_size
Definition: chm_lib.c:547
Int32 index_root
Definition: chm_lib.c:536
Int32 cache_num_blocks
Definition: chm_lib.c:558
UInt64 dir_offset
Definition: chm_lib.c:533
HANDLE fd
Definition: chm_lib.c:527
int lzx_last_block
Definition: chm_lib.c:553
UInt64 span
Definition: chm_lib.c:540
struct chmUnitInfo rt_unit
Definition: chm_lib.c:541
CRITICAL_SECTION cache_mutex
Definition: chm_lib.c:531
UChar ** cache_blocks
Definition: chm_lib.c:556
struct chmUnitInfo cn_unit
Definition: chm_lib.c:542
int compression_enabled
Definition: chm_lib.c:546
struct LZXstate * lzx_state
Definition: chm_lib.c:552
CRITICAL_SECTION lzx_mutex
Definition: chm_lib.c:530
Int32 index_head
Definition: chm_lib.c:537
CRITICAL_SECTION mutex
Definition: chm_lib.c:529
UInt32 reset_interval
Definition: chm_lib.c:548
UInt64 dir_len
Definition: chm_lib.c:534
UInt64 data_offset
Definition: chm_lib.c:535
UInt32 block_len
Definition: chm_lib.c:538
struct chmLzxcResetTable reset_table
Definition: chm_lib.c:543
Int32 version
Definition: chm_lib.c:241
UChar stream_uuid[16]
Definition: chm_lib.c:247
Int32 unknown_000c
Definition: chm_lib.c:243
UInt64 unknown_len
Definition: chm_lib.c:249
UInt32 last_modified
Definition: chm_lib.c:244
Int32 header_len
Definition: chm_lib.c:242
UInt64 data_offset
Definition: chm_lib.c:252
UInt32 lang_id
Definition: chm_lib.c:245
UInt64 dir_len
Definition: chm_lib.c:251
char signature[4]
Definition: chm_lib.c:240
UInt64 dir_offset
Definition: chm_lib.c:250
UChar dir_uuid[16]
Definition: chm_lib.c:246
UInt64 unknown_offset
Definition: chm_lib.c:248
Int32 unknown_000c
Definition: chm_lib.c:319
UInt32 block_len
Definition: chm_lib.c:320
char signature[4]
Definition: chm_lib.c:316
Int32 version
Definition: chm_lib.c:317
Int32 unknown_0024
Definition: chm_lib.c:325
Int32 index_depth
Definition: chm_lib.c:322
UInt32 num_blocks
Definition: chm_lib.c:326
UInt32 lang_id
Definition: chm_lib.c:328
Int32 index_head
Definition: chm_lib.c:324
UChar unknown_0044[16]
Definition: chm_lib.c:330
Int32 index_root
Definition: chm_lib.c:323
Int32 header_len
Definition: chm_lib.c:318
Int32 blockidx_intvl
Definition: chm_lib.c:321
Int32 unknown_002c
Definition: chm_lib.c:327
UChar system_uuid[16]
Definition: chm_lib.c:329
UInt32 resetInterval
Definition: chm_lib.c:476
UInt32 windowSize
Definition: chm_lib.c:477
UInt32 windowsPerReset
Definition: chm_lib.c:478
UInt32 unknown_18
Definition: chm_lib.c:479
char signature[4]
Definition: chm_lib.c:474
UInt64 compressed_len
Definition: chm_lib.c:440
UInt32 version
Definition: chm_lib.c:435
UInt32 unknown
Definition: chm_lib.c:437
UInt32 table_offset
Definition: chm_lib.c:438
UInt32 block_count
Definition: chm_lib.c:436
UInt64 block_len
Definition: chm_lib.c:441
UInt64 uncompressed_len
Definition: chm_lib.c:439
char signature[4]
Definition: chm_lib.c:408
UInt32 free_space
Definition: chm_lib.c:409
Int32 block_prev
Definition: chm_lib.c:377
UInt32 free_space
Definition: chm_lib.c:375
Int32 block_next
Definition: chm_lib.c:378
UInt32 unknown_0008
Definition: chm_lib.c:376
char signature[4]
Definition: chm_lib.c:374
LONGUINT64 length
Definition: chm_lib.h:70
int space
Definition: chm_lib.h:71
Definition: http.c:7252
Definition: module.h:576
Definition: ps.c:97
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
#define DWORD_PTR
Definition: treelist.c:76
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
int64_t LONGLONG
Definition: typedefs.h:68
uint64_t ULONGLONG
Definition: typedefs.h:67
LONGLONG QuadPart
Definition: typedefs.h:114
#define FILE_CURRENT
Definition: winbase.h:113
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define DUPLICATE_SAME_ACCESS
static unsigned int block
Definition: xmlmemory.c:101
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193