ReactOS 0.4.17-dev-966-gf06eace
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/*
207 * structures local to this module
208 */
209
210/* structure of ITSF headers */
211#define _CHM_ITSF_V2_LEN (0x58)
212#define _CHM_ITSF_V3_LEN (0x60)
214{
215 char signature[4]; /* 0 (ITSF) */
216 Int32 version; /* 4 */
220 UInt32 lang_id; /* 14 */
221 UChar dir_uuid[16]; /* 18 */
222 UChar stream_uuid[16]; /* 28 */
226 UInt64 dir_len; /* 50 */
227 UInt64 data_offset; /* 58 (Not present before V3) */
228}; /* __attribute__ ((aligned (1))); */
229
230static BOOL _unmarshal_itsf_header(unsigned char **pData,
231 unsigned int *pDataLen,
232 struct chmItsfHeader *dest)
233{
234 /* we only know how to deal with the 0x58 and 0x60 byte structures */
235 if (*pDataLen != _CHM_ITSF_V2_LEN && *pDataLen != _CHM_ITSF_V3_LEN)
236 return FALSE;
237
238 /* unmarshal common fields */
239 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
240 _unmarshal_int32 (pData, pDataLen, &dest->version);
241 _unmarshal_int32 (pData, pDataLen, &dest->header_len);
242 _unmarshal_int32 (pData, pDataLen, &dest->unknown_000c);
243 _unmarshal_uint32 (pData, pDataLen, &dest->last_modified);
244 _unmarshal_uint32 (pData, pDataLen, &dest->lang_id);
245 _unmarshal_uuid (pData, pDataLen, dest->dir_uuid);
246 _unmarshal_uuid (pData, pDataLen, dest->stream_uuid);
247 _unmarshal_uint64 (pData, pDataLen, &dest->unknown_offset);
248 _unmarshal_uint64 (pData, pDataLen, &dest->unknown_len);
249 _unmarshal_uint64 (pData, pDataLen, &dest->dir_offset);
250 _unmarshal_uint64 (pData, pDataLen, &dest->dir_len);
251
252 /* error check the data */
253 /* XXX: should also check UUIDs, probably, though with a version 3 file,
254 * current MS tools do not seem to use them.
255 */
256 if (memcmp(dest->signature, "ITSF", 4) != 0)
257 return FALSE;
258 if (dest->version == 2)
259 {
260 if (dest->header_len < _CHM_ITSF_V2_LEN)
261 return FALSE;
262 }
263 else if (dest->version == 3)
264 {
265 if (dest->header_len < _CHM_ITSF_V3_LEN)
266 return FALSE;
267 }
268 else
269 return FALSE;
270
271 /* now, if we have a V3 structure, unmarshal the rest.
272 * otherwise, compute it
273 */
274 if (dest->version == 3)
275 {
276 if (*pDataLen != 0)
277 _unmarshal_uint64(pData, pDataLen, &dest->data_offset);
278 else
279 return FALSE;
280 }
281 else
282 dest->data_offset = dest->dir_offset + dest->dir_len;
283
284 return TRUE;
285}
286
287/* structure of ITSP headers */
288#define _CHM_ITSP_V1_LEN (0x54)
290{
291 char signature[4]; /* 0 (ITSP) */
292 Int32 version; /* 4 */
303 UInt32 lang_id; /* 30 */
304 UChar system_uuid[16]; /* 34 */
305 UChar unknown_0044[16]; /* 44 */
306}; /* __attribute__ ((aligned (1))); */
307
308static BOOL _unmarshal_itsp_header(unsigned char **pData,
309 unsigned int *pDataLen,
310 struct chmItspHeader *dest)
311{
312 /* we only know how to deal with a 0x54 byte structures */
313 if (*pDataLen != _CHM_ITSP_V1_LEN)
314 return FALSE;
315
316 /* unmarshal fields */
317 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
318 _unmarshal_int32 (pData, pDataLen, &dest->version);
319 _unmarshal_int32 (pData, pDataLen, &dest->header_len);
320 _unmarshal_int32 (pData, pDataLen, &dest->unknown_000c);
321 _unmarshal_uint32 (pData, pDataLen, &dest->block_len);
322 _unmarshal_int32 (pData, pDataLen, &dest->blockidx_intvl);
323 _unmarshal_int32 (pData, pDataLen, &dest->index_depth);
324 _unmarshal_int32 (pData, pDataLen, &dest->index_root);
325 _unmarshal_int32 (pData, pDataLen, &dest->index_head);
326 _unmarshal_int32 (pData, pDataLen, &dest->unknown_0024);
327 _unmarshal_uint32 (pData, pDataLen, &dest->num_blocks);
328 _unmarshal_int32 (pData, pDataLen, &dest->unknown_002c);
329 _unmarshal_uint32 (pData, pDataLen, &dest->lang_id);
330 _unmarshal_uuid (pData, pDataLen, dest->system_uuid);
331 _unmarshal_uchar_array(pData, pDataLen, dest->unknown_0044, 16);
332
333 /* error check the data */
334 if (memcmp(dest->signature, "ITSP", 4) != 0)
335 return FALSE;
336 if (dest->version != 1)
337 return FALSE;
338 if (dest->header_len != _CHM_ITSP_V1_LEN)
339 return FALSE;
340
341 return TRUE;
342}
343
344/* structure of PMGL headers */
345static const char _chm_pmgl_marker[4] = "PMGL";
346#define _CHM_PMGL_LEN (0x14)
348{
349 char signature[4]; /* 0 (PMGL) */
354}; /* __attribute__ ((aligned (1))); */
355
356static BOOL _unmarshal_pmgl_header(unsigned char **pData,
357 unsigned int *pDataLen,
358 struct chmPmglHeader *dest)
359{
360 /* we only know how to deal with a 0x14 byte structures */
361 if (*pDataLen != _CHM_PMGL_LEN)
362 return FALSE;
363
364 /* unmarshal fields */
365 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
366 _unmarshal_uint32 (pData, pDataLen, &dest->free_space);
367 _unmarshal_uint32 (pData, pDataLen, &dest->unknown_0008);
368 _unmarshal_int32 (pData, pDataLen, &dest->block_prev);
369 _unmarshal_int32 (pData, pDataLen, &dest->block_next);
370
371 /* check structure */
372 if (memcmp(dest->signature, _chm_pmgl_marker, 4) != 0)
373 return FALSE;
374
375 return TRUE;
376}
377
378/* structure of PMGI headers */
379static const char _chm_pmgi_marker[4] = "PMGI";
380#define _CHM_PMGI_LEN (0x08)
382{
383 char signature[4]; /* 0 (PMGI) */
385}; /* __attribute__ ((aligned (1))); */
386
387static BOOL _unmarshal_pmgi_header(unsigned char **pData,
388 unsigned int *pDataLen,
389 struct chmPmgiHeader *dest)
390{
391 /* we only know how to deal with a 0x8 byte structures */
392 if (*pDataLen != _CHM_PMGI_LEN)
393 return FALSE;
394
395 /* unmarshal fields */
396 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
397 _unmarshal_uint32 (pData, pDataLen, &dest->free_space);
398
399 /* check structure */
400 if (memcmp(dest->signature, _chm_pmgi_marker, 4) != 0)
401 return FALSE;
402
403 return TRUE;
404}
405
406/* structure of LZXC reset table */
407#define _CHM_LZXC_RESETTABLE_V1_LEN (0x28)
409{
417}; /* __attribute__ ((aligned (1))); */
418
420 unsigned int *pDataLen,
421 struct chmLzxcResetTable *dest)
422{
423 /* we only know how to deal with a 0x28 byte structures */
424 if (*pDataLen != _CHM_LZXC_RESETTABLE_V1_LEN)
425 return FALSE;
426
427 /* unmarshal fields */
428 _unmarshal_uint32 (pData, pDataLen, &dest->version);
429 _unmarshal_uint32 (pData, pDataLen, &dest->block_count);
430 _unmarshal_uint32 (pData, pDataLen, &dest->unknown);
431 _unmarshal_uint32 (pData, pDataLen, &dest->table_offset);
432 _unmarshal_uint64 (pData, pDataLen, &dest->uncompressed_len);
433 _unmarshal_uint64 (pData, pDataLen, &dest->compressed_len);
434 _unmarshal_uint64 (pData, pDataLen, &dest->block_len);
435
436 /* check structure */
437 if (dest->version != 2)
438 return FALSE;
439
440 return TRUE;
441}
442
443/* structure of LZXC control data block */
444#define _CHM_LZXC_MIN_LEN (0x18)
445#define _CHM_LZXC_V2_LEN (0x1c)
447{
448 UInt32 size; /* 0 */
449 char signature[4]; /* 4 (LZXC) */
455};
456
458 unsigned int *pDataLen,
459 struct chmLzxcControlData *dest)
460{
461 /* we want at least 0x18 bytes */
462 if (*pDataLen < _CHM_LZXC_MIN_LEN)
463 return FALSE;
464
465 /* unmarshal fields */
466 _unmarshal_uint32 (pData, pDataLen, &dest->size);
467 _unmarshal_char_array(pData, pDataLen, dest->signature, 4);
468 _unmarshal_uint32 (pData, pDataLen, &dest->version);
469 _unmarshal_uint32 (pData, pDataLen, &dest->resetInterval);
470 _unmarshal_uint32 (pData, pDataLen, &dest->windowSize);
471 _unmarshal_uint32 (pData, pDataLen, &dest->windowsPerReset);
472
473 if (*pDataLen >= _CHM_LZXC_V2_LEN)
474 _unmarshal_uint32 (pData, pDataLen, &dest->unknown_18);
475 else
476 dest->unknown_18 = 0;
477
478 if (dest->version == 2)
479 {
480 dest->resetInterval *= 0x8000;
481 dest->windowSize *= 0x8000;
482 }
483 if (dest->windowSize == 0 || dest->resetInterval == 0)
484 return FALSE;
485
486 /* for now, only support resetInterval a multiple of windowSize/2 */
487 if (dest->windowSize == 1)
488 return FALSE;
489 if ((dest->resetInterval % (dest->windowSize/2)) != 0)
490 return FALSE;
491
492 /* check structure */
493 if (memcmp(dest->signature, "LZXC", 4) != 0)
494 return FALSE;
495
496 return TRUE;
497}
498
499/* the structure used for chm file handles */
501{
503
507
514
519
520 /* LZX control data */
525
526 /* decompressor state */
529
530 /* cache for decompressed blocks */
534};
535
536/*
537 * utility functions local to this module
538 */
539
540/* utility function to handle differences between {pread,read}(64)? */
542 UChar *buf,
543 UInt64 os,
544 Int64 len)
545{
546 Int64 readLen=0;
547 if (h->fd == CHM_NULL_FD)
548 return readLen;
549
550 CHM_ACQUIRE_LOCK(h->mutex);
551 /* NOTE: this might be better done with CreateFileMapping, et cetera... */
552 {
553 LARGE_INTEGER old_pos, new_pos;
554 DWORD actualLen=0;
555
556 /* awkward Win32 Seek/Tell */
557 new_pos.QuadPart = 0;
558 SetFilePointerEx( h->fd, new_pos, &old_pos, FILE_CURRENT );
559 new_pos.QuadPart = os;
560 SetFilePointerEx( h->fd, new_pos, NULL, FILE_BEGIN );
561
562 /* read the data */
563 if (ReadFile(h->fd,
564 buf,
565 (DWORD)len,
566 &actualLen,
567 NULL))
568 readLen = actualLen;
569 else
570 readLen = 0;
571
572 /* restore original position */
573 SetFilePointerEx( h->fd, old_pos, NULL, FILE_BEGIN );
574 }
575 CHM_RELEASE_LOCK(h->mutex);
576 return readLen;
577}
578
579/*
580 * set a parameter on the file handle.
581 * valid parameter types:
582 * CHM_PARAM_MAX_BLOCKS_CACHED:
583 * how many decompressed blocks should be cached? A simple
584 * caching scheme is used, wherein the index of the block is
585 * used as a hash value, and hash collision results in the
586 * invalidation of the previously cached block.
587 */
588static void chm_set_param(struct chmFile *h,
589 int paramType,
590 int paramVal)
591{
592 switch (paramType)
593 {
595 CHM_ACQUIRE_LOCK(h->cache_mutex);
596 if (paramVal != h->cache_num_blocks)
597 {
598 UChar **newBlocks;
599 Int64 *newIndices;
600 int i;
601
602 /* allocate new cached blocks */
603 newBlocks = HeapAlloc(GetProcessHeap(), 0, paramVal * sizeof (UChar *));
604 newIndices = HeapAlloc(GetProcessHeap(), 0, paramVal * sizeof (UInt64));
605 for (i=0; i<paramVal; i++)
606 {
607 newBlocks[i] = NULL;
608 newIndices[i] = 0;
609 }
610
611 /* re-distribute old cached blocks */
612 if (h->cache_blocks)
613 {
614 for (i=0; i<h->cache_num_blocks; i++)
615 {
616 int newSlot = (int)(h->cache_block_indices[i] % paramVal);
617
618 if (h->cache_blocks[i])
619 {
620 /* in case of collision, destroy newcomer */
621 if (newBlocks[newSlot])
622 {
623 HeapFree(GetProcessHeap(), 0, h->cache_blocks[i]);
624 h->cache_blocks[i] = NULL;
625 }
626 else
627 {
628 newBlocks[newSlot] = h->cache_blocks[i];
629 newIndices[newSlot] =
630 h->cache_block_indices[i];
631 }
632 }
633 }
634
635 HeapFree(GetProcessHeap(), 0, h->cache_blocks);
636 HeapFree(GetProcessHeap(), 0, h->cache_block_indices);
637 }
638
639 /* now, set new values */
640 h->cache_blocks = newBlocks;
641 h->cache_block_indices = newIndices;
642 h->cache_num_blocks = paramVal;
643 }
644 CHM_RELEASE_LOCK(h->cache_mutex);
645 break;
646
647 default:
648 break;
649 }
650}
651
652/* open an ITS archive */
654{
655 unsigned char sbuffer[256];
656 unsigned int sremain;
657 unsigned char *sbufpos;
658 struct chmFile *newHandle=NULL;
659 struct chmItsfHeader itsfHeader;
660 struct chmItspHeader itspHeader;
661#if 0
662 struct chmUnitInfo uiSpan;
663#endif
664 struct chmUnitInfo uiLzxc;
665 struct chmLzxcControlData ctlData;
666
667 /* allocate handle */
668 newHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(struct chmFile));
669 newHandle->fd = CHM_NULL_FD;
670 newHandle->lzx_state = NULL;
671 newHandle->cache_blocks = NULL;
672 newHandle->cache_block_indices = NULL;
673 newHandle->cache_num_blocks = 0;
674
675 /* open file */
676 if ((newHandle->fd=CreateFileW(filename,
679 NULL,
682 NULL)) == CHM_NULL_FD)
683 {
684 HeapFree(GetProcessHeap(), 0, newHandle);
685 return NULL;
686 }
687
688 /* initialize mutexes, if needed */
690 newHandle->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.mutex");
692 newHandle->lzx_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.lzx_mutex");
694 newHandle->cache_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.cache_mutex");
695
696 /* read and verify header */
697 sremain = _CHM_ITSF_V3_LEN;
698 sbufpos = sbuffer;
699 if (_chm_fetch_bytes(newHandle, sbuffer, 0, sremain) != sremain ||
700 !_unmarshal_itsf_header(&sbufpos, &sremain, &itsfHeader))
701 {
702 chm_close(newHandle);
703 return NULL;
704 }
705
706 /* stash important values from header */
707 newHandle->dir_offset = itsfHeader.dir_offset;
708 newHandle->dir_len = itsfHeader.dir_len;
709 newHandle->data_offset = itsfHeader.data_offset;
710
711 /* now, read and verify the directory header chunk */
712 sremain = _CHM_ITSP_V1_LEN;
713 sbufpos = sbuffer;
714 if (_chm_fetch_bytes(newHandle, sbuffer,
715 itsfHeader.dir_offset, sremain) != sremain ||
716 !_unmarshal_itsp_header(&sbufpos, &sremain, &itspHeader))
717 {
718 chm_close(newHandle);
719 return NULL;
720 }
721
722 /* grab essential information from ITSP header */
723 newHandle->dir_offset += itspHeader.header_len;
724 newHandle->dir_len -= itspHeader.header_len;
725 newHandle->index_root = itspHeader.index_root;
726 newHandle->index_head = itspHeader.index_head;
727 newHandle->block_len = itspHeader.block_len;
728
729 /* if the index root is -1, this means we don't have any PMGI blocks.
730 * as a result, we must use the sole PMGL block as the index root
731 */
732 if (newHandle->index_root == -1)
733 newHandle->index_root = newHandle->index_head;
734
735 /* initialize cache */
738
739 /* By default, compression is enabled. */
740 newHandle->compression_enabled = 1;
741
742 /* prefetch most commonly needed unit infos */
744 L"::DataSpace/Storage/MSCompressed/Transform/"
745 "{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/"
746 "InstanceData/ResetTable",
747 &newHandle->rt_unit) ||
748 newHandle->rt_unit.space == CHM_COMPRESSED ||
750 L"::DataSpace/Storage/MSCompressed/Content",
751 &newHandle->cn_unit) ||
752 newHandle->cn_unit.space == CHM_COMPRESSED ||
754 L"::DataSpace/Storage/MSCompressed/ControlData",
755 &uiLzxc) ||
756 uiLzxc.space == CHM_COMPRESSED)
757 {
758 newHandle->compression_enabled = 0;
759 }
760
761 /* read reset table info */
762 if (newHandle->compression_enabled)
763 {
765 sbufpos = sbuffer;
766 if (chm_retrieve_object(newHandle, &newHandle->rt_unit, sbuffer,
767 0, sremain) != sremain ||
768 !_unmarshal_lzxc_reset_table(&sbufpos, &sremain,
769 &newHandle->reset_table))
770 {
771 newHandle->compression_enabled = 0;
772 }
773 }
774
775 /* read control data */
776 if (newHandle->compression_enabled)
777 {
778 sremain = (unsigned long)uiLzxc.length;
779 sbufpos = sbuffer;
780 if (chm_retrieve_object(newHandle, &uiLzxc, sbuffer,
781 0, sremain) != sremain ||
782 !_unmarshal_lzxc_control_data(&sbufpos, &sremain,
783 &ctlData))
784 {
785 newHandle->compression_enabled = 0;
786 }
787 else
788 {
789 newHandle->window_size = ctlData.windowSize;
790 newHandle->reset_interval = ctlData.resetInterval;
791/* Jed, Mon Jun 28: Experimentally, it appears that the reset block count */
792/* must be multiplied by this formerly unknown ctrl data field in */
793/* order to decompress some files. */
794 newHandle->reset_blkcount = newHandle->reset_interval / (newHandle->window_size / 2) *
795 ctlData.windowsPerReset;
796 }
797 }
798
799 return newHandle;
800}
801
802/* Duplicate an ITS archive handle */
803struct chmFile *chm_dup(struct chmFile *oldHandle)
804{
805 struct chmFile *newHandle=NULL;
806
807 newHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(struct chmFile));
808 *newHandle = *oldHandle;
809
810 /* duplicate fd handle */
812 GetCurrentProcess(), &(newHandle->fd),
814 newHandle->lzx_state = NULL;
815 newHandle->cache_blocks = NULL;
816 newHandle->cache_block_indices = NULL;
817 newHandle->cache_num_blocks = 0;
818
819 /* initialize mutexes, if needed */
821 newHandle->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.mutex");
823 newHandle->lzx_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.lzx_mutex");
825 newHandle->cache_mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": chmFile.cache_mutex");
826
827 /* initialize cache */
830
831 return newHandle;
832}
833
834/* close an ITS archive */
835void chm_close(struct chmFile *h)
836{
837 if (h != NULL)
838 {
839 if (h->fd != CHM_NULL_FD)
840 CHM_CLOSE_FILE(h->fd);
841 h->fd = CHM_NULL_FD;
842
843 h->mutex.DebugInfo->Spare[0] = 0;
844 DeleteCriticalSection(&h->mutex);
845 h->lzx_mutex.DebugInfo->Spare[0] = 0;
846 DeleteCriticalSection(&h->lzx_mutex);
847 h->cache_mutex.DebugInfo->Spare[0] = 0;
848 DeleteCriticalSection(&h->cache_mutex);
849
850 if (h->lzx_state)
851 LZXteardown(h->lzx_state);
852 h->lzx_state = NULL;
853
854 if (h->cache_blocks)
855 {
856 int i;
857 for (i=0; i<h->cache_num_blocks; i++)
858 {
859 HeapFree(GetProcessHeap(), 0, h->cache_blocks[i]);
860 }
861 HeapFree(GetProcessHeap(), 0, h->cache_blocks);
862 h->cache_blocks = NULL;
863 }
864
865 HeapFree(GetProcessHeap(), 0, h->cache_block_indices);
866 h->cache_block_indices = NULL;
867
869 }
870}
871
872/*
873 * helper methods for chm_resolve_object
874 */
875
876/* skip a compressed dword */
878{
879 while (*(*pEntry)++ >= 0x80)
880 ;
881}
882
883/* skip the data from a PMGL entry */
885{
889}
890
891/* parse a compressed dword */
893{
894 UInt64 accum = 0;
895 UChar temp;
896 while ((temp=*(*pEntry)++) >= 0x80)
897 {
898 accum <<= 7;
899 accum += temp & 0x7f;
900 }
901
902 return (accum << 7) + temp;
903}
904
905/* parse a utf-8 string into an ASCII char buffer */
907{
909 path[length] = '\0';
910 *pEntry += count;
911 return !!length;
912}
913
914/* parse a PMGL entry into a chmUnitInfo struct; return 1 on success. */
916{
917 UInt64 strLen;
918
919 /* parse str len */
920 strLen = _chm_parse_cword(pEntry);
921 if (strLen > CHM_MAX_PATHLEN)
922 return FALSE;
923
924 /* parse path */
925 if (! _chm_parse_UTF8(pEntry, strLen, ui->path))
926 return FALSE;
927
928 /* parse info */
929 ui->space = (int)_chm_parse_cword(pEntry);
930 ui->start = _chm_parse_cword(pEntry);
931 ui->length = _chm_parse_cword(pEntry);
932 return TRUE;
933}
934
935/* find an exact entry in PMGL; return NULL if we fail */
936static UChar *_chm_find_in_PMGL(UChar *page_buf,
938 const WCHAR *objPath)
939{
940 /* XXX: modify this to do a binary search using the nice index structure
941 * that is provided for us.
942 */
943 struct chmPmglHeader header;
944 unsigned int hremain;
945 UChar *end;
946 UChar *cur;
947 UChar *temp;
948 UInt64 strLen;
950
951 /* figure out where to start and end */
952 cur = page_buf;
953 hremain = _CHM_PMGL_LEN;
954 if (! _unmarshal_pmgl_header(&cur, &hremain, &header))
955 return NULL;
956 end = page_buf + block_len - (header.free_space);
957
958 /* now, scan progressively */
959 while (cur < end)
960 {
961 /* grab the name */
962 temp = cur;
963 strLen = _chm_parse_cword(&cur);
964 if (! _chm_parse_UTF8(&cur, strLen, buffer))
965 return NULL;
966
967 /* check if it is the right name */
968 if (! wcsicmp(buffer, objPath))
969 return temp;
970
972 }
973
974 return NULL;
975}
976
977/* find which block should be searched next for the entry; -1 if no block */
979 UInt32 block_len,
980 const WCHAR *objPath)
981{
982 /* XXX: modify this to do a binary search using the nice index structure
983 * that is provided for us
984 */
985 struct chmPmgiHeader header;
986 unsigned int hremain;
987 int page=-1;
988 UChar *end;
989 UChar *cur;
990 UInt64 strLen;
992
993 /* figure out where to start and end */
994 cur = page_buf;
995 hremain = _CHM_PMGI_LEN;
996 if (! _unmarshal_pmgi_header(&cur, &hremain, &header))
997 return -1;
998 end = page_buf + block_len - (header.free_space);
999
1000 /* now, scan progressively */
1001 while (cur < end)
1002 {
1003 /* grab the name */
1004 strLen = _chm_parse_cword(&cur);
1005 if (! _chm_parse_UTF8(&cur, strLen, buffer))
1006 return -1;
1007
1008 /* check if it is the right name */
1009 if (wcsicmp(buffer, objPath) > 0)
1010 return page;
1011
1012 /* load next value for path */
1014 }
1015
1016 return page;
1017}
1018
1019/* resolve a particular object from the archive */
1021 const WCHAR *objPath,
1022 struct chmUnitInfo *ui)
1023{
1024 /*
1025 * XXX: implement caching scheme for dir pages
1026 */
1027
1028 Int32 curPage;
1029
1030 /* buffer to hold whatever page we're looking at */
1031 UChar *page_buf = HeapAlloc(GetProcessHeap(), 0, h->block_len);
1032
1033 /* starting page */
1034 curPage = h->index_root;
1035
1036 /* until we have either returned or given up */
1037 while (curPage != -1)
1038 {
1039
1040 /* try to fetch the index page */
1041 if (_chm_fetch_bytes(h, page_buf,
1042 h->dir_offset + (UInt64)curPage*h->block_len,
1043 h->block_len) != h->block_len)
1044 {
1045 HeapFree(GetProcessHeap(), 0, page_buf);
1046 return CHM_RESOLVE_FAILURE;
1047 }
1048
1049 /* now, if it is a leaf node: */
1050 if (memcmp(page_buf, _chm_pmgl_marker, 4) == 0)
1051 {
1052 /* scan block */
1053 UChar *pEntry = _chm_find_in_PMGL(page_buf,
1054 h->block_len,
1055 objPath);
1056 if (pEntry == NULL)
1057 {
1058 HeapFree(GetProcessHeap(), 0, page_buf);
1059 return CHM_RESOLVE_FAILURE;
1060 }
1061
1062 /* parse entry and return */
1064 HeapFree(GetProcessHeap(), 0, page_buf);
1065 return CHM_RESOLVE_SUCCESS;
1066 }
1067
1068 /* else, if it is a branch node: */
1069 else if (memcmp(page_buf, _chm_pmgi_marker, 4) == 0)
1070 curPage = _chm_find_in_PMGI(page_buf, h->block_len, objPath);
1071
1072 /* else, we are confused. give up. */
1073 else
1074 {
1075 HeapFree(GetProcessHeap(), 0, page_buf);
1076 return CHM_RESOLVE_FAILURE;
1077 }
1078 }
1079
1080 /* didn't find anything. fail. */
1081 HeapFree(GetProcessHeap(), 0, page_buf);
1082 return CHM_RESOLVE_FAILURE;
1083}
1084
1085/*
1086 * utility methods for dealing with compressed data
1087 */
1088
1089/* get the bounds of a compressed block. Returns FALSE on failure */
1091 UInt64 block,
1092 UInt64 *start,
1093 Int64 *len)
1094{
1095 UChar buffer[8], *dummy;
1096 unsigned int remain;
1097
1098 /* for all but the last block, use the reset table */
1099 if (block < h->reset_table.block_count-1)
1100 {
1101 /* unpack the start address */
1102 dummy = buffer;
1103 remain = 8;
1105 h->data_offset
1106 + h->rt_unit.start
1107 + h->reset_table.table_offset
1108 + block*8,
1109 remain) != remain ||
1110 !_unmarshal_uint64(&dummy, &remain, start))
1111 return FALSE;
1112
1113 /* unpack the end address */
1114 dummy = buffer;
1115 remain = 8;
1117 h->data_offset
1118 + h->rt_unit.start
1119 + h->reset_table.table_offset
1120 + block*8 + 8,
1121 remain) != remain ||
1122 !_unmarshal_int64(&dummy, &remain, len))
1123 return FALSE;
1124 }
1125
1126 /* for the last block, use the span in addition to the reset table */
1127 else
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 *len = h->reset_table.compressed_len;
1142 }
1143
1144 /* compute the length and absolute start address */
1145 *len -= *start;
1146 *start += h->data_offset + h->cn_unit.start;
1147
1148 return TRUE;
1149}
1150
1151/* decompress the block. must have lzx_mutex. */
1153 UInt64 block,
1154 UChar **ubuffer)
1155{
1156 UChar *cbuffer = HeapAlloc( GetProcessHeap(), 0,
1157 ((unsigned int)h->reset_table.block_len + 6144));
1158 UInt64 cmpStart; /* compressed start */
1159 Int64 cmpLen; /* compressed len */
1160 int indexSlot; /* cache index slot */
1161 UChar *lbuffer; /* local buffer ptr */
1162 UInt32 blockAlign = (UInt32)(block % h->reset_blkcount); /* reset interval align */
1163 UInt32 i; /* local loop index */
1164
1165 /* let the caching system pull its weight! */
1166 if (block - blockAlign <= h->lzx_last_block &&
1167 block >= h->lzx_last_block)
1168 blockAlign = (block - h->lzx_last_block);
1169
1170 /* check if we need previous blocks */
1171 if (blockAlign != 0)
1172 {
1173 /* fetch all required previous blocks since last reset */
1174 for (i = blockAlign; i > 0; i--)
1175 {
1176 UInt32 curBlockIdx = block - i;
1177
1178 /* check if we most recently decompressed the previous block */
1179 if (h->lzx_last_block != curBlockIdx)
1180 {
1181 if ((curBlockIdx % h->reset_blkcount) == 0)
1182 {
1183#ifdef CHM_DEBUG
1184 fprintf(stderr, "***RESET (1)***\n");
1185#endif
1186 LZXreset(h->lzx_state);
1187 }
1188
1189 indexSlot = (int)((curBlockIdx) % h->cache_num_blocks);
1190 h->cache_block_indices[indexSlot] = curBlockIdx;
1191 if (! h->cache_blocks[indexSlot])
1192 h->cache_blocks[indexSlot] =
1194 (unsigned int)(h->reset_table.block_len));
1195 lbuffer = h->cache_blocks[indexSlot];
1196
1197 /* decompress the previous block */
1198#ifdef CHM_DEBUG
1199 fprintf(stderr, "Decompressing block #%4d (EXTRA)\n", curBlockIdx);
1200#endif
1201 if (!_chm_get_cmpblock_bounds(h, curBlockIdx, &cmpStart, &cmpLen) ||
1202 _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen ||
1203 LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
1204 (int)h->reset_table.block_len) != DECR_OK)
1205 {
1206#ifdef CHM_DEBUG
1207 fprintf(stderr, " (DECOMPRESS FAILED!)\n");
1208#endif
1209 HeapFree(GetProcessHeap(), 0, cbuffer);
1210 return 0;
1211 }
1212
1213 h->lzx_last_block = (int)curBlockIdx;
1214 }
1215 }
1216 }
1217 else
1218 {
1219 if ((block % h->reset_blkcount) == 0)
1220 {
1221#ifdef CHM_DEBUG
1222 fprintf(stderr, "***RESET (2)***\n");
1223#endif
1224 LZXreset(h->lzx_state);
1225 }
1226 }
1227
1228 /* allocate slot in cache */
1229 indexSlot = (int)(block % h->cache_num_blocks);
1230 h->cache_block_indices[indexSlot] = block;
1231 if (! h->cache_blocks[indexSlot])
1232 h->cache_blocks[indexSlot] =
1233 HeapAlloc(GetProcessHeap(), 0, ((unsigned int)h->reset_table.block_len));
1234 lbuffer = h->cache_blocks[indexSlot];
1235 *ubuffer = lbuffer;
1236
1237 /* decompress the block we actually want */
1238#ifdef CHM_DEBUG
1239 fprintf(stderr, "Decompressing block #%4d (REAL )\n", block);
1240#endif
1241 if (! _chm_get_cmpblock_bounds(h, block, &cmpStart, &cmpLen) ||
1242 _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen ||
1243 LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
1244 (int)h->reset_table.block_len) != DECR_OK)
1245 {
1246#ifdef CHM_DEBUG
1247 fprintf(stderr, " (DECOMPRESS FAILED!)\n");
1248#endif
1249 HeapFree(GetProcessHeap(), 0, cbuffer);
1250 return 0;
1251 }
1252 h->lzx_last_block = (int)block;
1253
1254 /* XXX: modify LZX routines to return the length of the data they
1255 * decompressed and return that instead, for an extra sanity check.
1256 */
1257 HeapFree(GetProcessHeap(), 0, cbuffer);
1258 return h->reset_table.block_len;
1259}
1260
1261/* grab a region from a compressed block */
1263 UChar *buf,
1264 UInt64 start,
1265 Int64 len)
1266{
1267 UInt64 nBlock, nOffset;
1268 UInt64 nLen;
1269 UInt64 gotLen;
1270 UChar *ubuffer = NULL;
1271
1272 if (len <= 0)
1273 return 0;
1274
1275 /* figure out what we need to read */
1276 nBlock = start / h->reset_table.block_len;
1277 nOffset = start % h->reset_table.block_len;
1278 nLen = len;
1279 if (nLen > (h->reset_table.block_len - nOffset))
1280 nLen = h->reset_table.block_len - nOffset;
1281
1282 /* if block is cached, return data from it. */
1283 CHM_ACQUIRE_LOCK(h->lzx_mutex);
1284 CHM_ACQUIRE_LOCK(h->cache_mutex);
1285 if (h->cache_block_indices[nBlock % h->cache_num_blocks] == nBlock &&
1286 h->cache_blocks[nBlock % h->cache_num_blocks] != NULL)
1287 {
1288 memcpy(buf,
1289 h->cache_blocks[nBlock % h->cache_num_blocks] + nOffset,
1290 (unsigned int)nLen);
1291 CHM_RELEASE_LOCK(h->cache_mutex);
1292 CHM_RELEASE_LOCK(h->lzx_mutex);
1293 return nLen;
1294 }
1295 CHM_RELEASE_LOCK(h->cache_mutex);
1296
1297 /* data request not satisfied, so... start up the decompressor machine */
1298 if (! h->lzx_state)
1299 {
1300 h->lzx_last_block = -1;
1301 h->lzx_state = LZXinit(h->window_size);
1302 }
1303
1304 /* decompress some data */
1305 gotLen = _chm_decompress_block(h, nBlock, &ubuffer);
1306 if (gotLen < nLen)
1307 nLen = gotLen;
1308 memcpy(buf, ubuffer+nOffset, (unsigned int)nLen);
1309 CHM_RELEASE_LOCK(h->lzx_mutex);
1310 return nLen;
1311}
1312
1313/* retrieve (part of) an object */
1315 struct chmUnitInfo *ui,
1316 unsigned char *buf,
1318 LONGINT64 len)
1319{
1320 /* must be valid file handle */
1321 if (h == NULL)
1322 return 0;
1323
1324 /* starting address must be in correct range */
1325 if (addr >= ui->length)
1326 return 0;
1327
1328 /* clip length */
1329 if (addr + len > ui->length)
1330 len = ui->length - addr;
1331
1332 /* if the file is uncompressed, it's simple */
1333 if (ui->space == CHM_UNCOMPRESSED)
1334 {
1335 /* read data */
1336 return _chm_fetch_bytes(h,
1337 buf,
1338 h->data_offset + ui->start + addr,
1339 len);
1340 }
1341
1342 /* else if the file is compressed, it's a little trickier */
1343 else /* ui->space == CHM_COMPRESSED */
1344 {
1345 Int64 swath=0, total=0;
1346
1347 /* if compression is not enabled for this file... */
1348 if (! h->compression_enabled)
1349 return total;
1350
1351 do {
1352
1353 /* swill another mouthful */
1354 swath = _chm_decompress_region(h, buf, ui->start + addr, len);
1355
1356 /* if we didn't get any... */
1357 if (swath == 0)
1358 return total;
1359
1360 /* update stats */
1361 total += swath;
1362 len -= swath;
1363 addr += swath;
1364 buf += swath;
1365
1366 } while (len != 0);
1367
1368 return total;
1369 }
1370}
1371
1373 const WCHAR *prefix,
1374 int what,
1376 void *context)
1377{
1378 /*
1379 * XXX: do this efficiently (i.e. using the tree index)
1380 */
1381
1382 Int32 curPage;
1383
1384 /* buffer to hold whatever page we're looking at */
1385 UChar *page_buf = HeapAlloc(GetProcessHeap(), 0, h->block_len);
1386 struct chmPmglHeader header;
1387 UChar *end;
1388 UChar *cur;
1389 unsigned int lenRemain;
1390
1391 /* set to TRUE once we've started */
1392 BOOL it_has_begun = FALSE;
1393
1394 /* the current ui */
1395 struct chmUnitInfo ui;
1396 int flag;
1397 UInt64 ui_path_len;
1398
1399 /* the length of the prefix */
1400 WCHAR prefixRectified[CHM_MAX_PATHLEN+1];
1401 int prefixLen;
1402 WCHAR lastPath[CHM_MAX_PATHLEN];
1403 int lastPathLen;
1404
1405 /* starting page */
1406 curPage = h->index_head;
1407
1408 /* initialize pathname state */
1409 lstrcpynW(prefixRectified, prefix, CHM_MAX_PATHLEN);
1410 prefixLen = lstrlenW(prefixRectified);
1411 if (prefixLen != 0)
1412 {
1413 if (prefixRectified[prefixLen-1] != '/')
1414 {
1415 prefixRectified[prefixLen] = '/';
1416 prefixRectified[prefixLen+1] = '\0';
1417 ++prefixLen;
1418 }
1419 }
1420 lastPath[0] = '\0';
1421 lastPathLen = -1;
1422
1423 /* until we have either returned or given up */
1424 while (curPage != -1)
1425 {
1426
1427 /* try to fetch the index page */
1428 if (_chm_fetch_bytes(h,
1429 page_buf,
1430 h->dir_offset + (UInt64)curPage*h->block_len,
1431 h->block_len) != h->block_len)
1432 {
1433 HeapFree(GetProcessHeap(), 0, page_buf);
1434 return FALSE;
1435 }
1436
1437 /* figure out start and end for this page */
1438 cur = page_buf;
1439 lenRemain = _CHM_PMGL_LEN;
1440 if (! _unmarshal_pmgl_header(&cur, &lenRemain, &header))
1441 {
1442 HeapFree(GetProcessHeap(), 0, page_buf);
1443 return FALSE;
1444 }
1445 end = page_buf + h->block_len - (header.free_space);
1446
1447 /* loop over this page */
1448 while (cur < end)
1449 {
1450 if (! _chm_parse_PMGL_entry(&cur, &ui))
1451 {
1452 HeapFree(GetProcessHeap(), 0, page_buf);
1453 return FALSE;
1454 }
1455
1456 /* check if we should start */
1457 if (! it_has_begun)
1458 {
1459 if (ui.length == 0 && wcsnicmp(ui.path, prefixRectified, prefixLen) == 0)
1460 it_has_begun = TRUE;
1461 else
1462 continue;
1463
1464 if (ui.path[prefixLen] == '\0')
1465 continue;
1466 }
1467
1468 /* check if we should stop */
1469 else
1470 {
1471 if (wcsnicmp(ui.path, prefixRectified, prefixLen) != 0)
1472 {
1473 HeapFree(GetProcessHeap(), 0, page_buf);
1474 return TRUE;
1475 }
1476 }
1477
1478 /* check if we should include this path */
1479 if (lastPathLen != -1)
1480 {
1481 if (wcsnicmp(ui.path, lastPath, lastPathLen) == 0)
1482 continue;
1483 }
1484 lstrcpyW(lastPath, ui.path);
1485 lastPathLen = lstrlenW(lastPath);
1486
1487 /* get the length of the path */
1488 ui_path_len = lstrlenW(ui.path)-1;
1489
1490 /* check for DIRS */
1491 if (ui.path[ui_path_len] == '/' && !(what & CHM_ENUMERATE_DIRS))
1492 continue;
1493
1494 /* check for FILES */
1495 if (ui.path[ui_path_len] != '/' && !(what & CHM_ENUMERATE_FILES))
1496 continue;
1497
1498 /* check for NORMAL vs. META */
1499 if (ui.path[0] == '/')
1500 {
1501
1502 /* check for NORMAL vs. SPECIAL */
1503 if (ui.path[1] == '#' || ui.path[1] == '$')
1505 else
1507 }
1508 else
1510 if (! (what & flag))
1511 continue;
1512
1513 /* call the enumerator */
1514 {
1515 int status = (*e)(h, &ui, context);
1516 switch (status)
1517 {
1519 HeapFree(GetProcessHeap(), 0, page_buf);
1520 return FALSE;
1522 break;
1524 HeapFree(GetProcessHeap(), 0, page_buf);
1525 return TRUE;
1526 default:
1527 break;
1528 }
1529 }
1530 }
1531
1532 /* advance to next page */
1533 curPage = header.block_next;
1534 }
1535
1536 HeapFree(GetProcessHeap(), 0, page_buf);
1537 return TRUE;
1538}
#define _CHM_ITSF_V2_LEN
Definition: chm_lib.c:211
static Int32 _chm_find_in_PMGI(UChar *page_buf, UInt32 block_len, const WCHAR *objPath)
Definition: chm_lib.c:978
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:884
#define _CHM_LZXC_RESETTABLE_V1_LEN
Definition: chm_lib.c:407
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:588
LONGINT64 chm_retrieve_object(struct chmFile *h, struct chmUnitInfo *ui, unsigned char *buf, LONGUINT64 addr, LONGINT64 len)
Definition: chm_lib.c:1314
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:1020
static BOOL _unmarshal_pmgl_header(unsigned char **pData, unsigned int *pDataLen, struct chmPmglHeader *dest)
Definition: chm_lib.c:356
#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:379
static Int64 _chm_decompress_region(struct chmFile *h, UChar *buf, UInt64 start, Int64 len)
Definition: chm_lib.c:1262
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:936
static BOOL _unmarshal_itsp_header(unsigned char **pData, unsigned int *pDataLen, struct chmItspHeader *dest)
Definition: chm_lib.c:308
static BOOL _unmarshal_pmgi_header(unsigned char **pData, unsigned int *pDataLen, struct chmPmgiHeader *dest)
Definition: chm_lib.c:387
static BOOL _unmarshal_lzxc_reset_table(unsigned char **pData, unsigned int *pDataLen, struct chmLzxcResetTable *dest)
Definition: chm_lib.c:419
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:288
struct chmFile * chm_dup(struct chmFile *oldHandle)
Definition: chm_lib.c:803
#define _CHM_LZXC_V2_LEN
Definition: chm_lib.c:445
static BOOL _unmarshal_int64(unsigned char **pData, unsigned int *pLenRemain, Int64 *dest)
Definition: chm_lib.c:159
BOOL chm_enumerate_dir(struct chmFile *h, const WCHAR *prefix, int what, CHM_ENUMERATOR e, void *context)
Definition: chm_lib.c:1372
static void _chm_skip_cword(UChar **pEntry)
Definition: chm_lib.c:877
static Int64 _chm_decompress_block(struct chmFile *h, UInt64 block, UChar **ubuffer)
Definition: chm_lib.c:1152
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:444
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:457
static BOOL _chm_parse_UTF8(UChar **pEntry, UInt64 count, WCHAR *path)
Definition: chm_lib.c:906
BYTE UChar
Definition: chm_lib.c:100
struct chmFile * chm_openW(const WCHAR *filename)
Definition: chm_lib.c:653
#define _CHM_ITSF_V3_LEN
Definition: chm_lib.c:212
ULONGLONG UInt64
Definition: chm_lib.c:106
static BOOL _unmarshal_itsf_header(unsigned char **pData, unsigned int *pDataLen, struct chmItsfHeader *dest)
Definition: chm_lib.c:230
void chm_close(struct chmFile *h)
Definition: chm_lib.c:835
#define _CHM_PMGL_LEN
Definition: chm_lib.c:346
#define CHM_NULL_FD
Definition: chm_lib.c:77
static UInt64 _chm_parse_cword(UChar **pEntry)
Definition: chm_lib.c:892
static BOOL _chm_parse_PMGL_entry(UChar **pEntry, struct chmUnitInfo *ui)
Definition: chm_lib.c:915
static BOOL _chm_get_cmpblock_bounds(struct chmFile *h, UInt64 block, UInt64 *start, Int64 *len)
Definition: chm_lib.c:1090
#define _CHM_PMGI_LEN
Definition: chm_lib.c:380
static const char _chm_pmgl_marker[4]
Definition: chm_lib.c:345
static Int64 _chm_fetch_bytes(struct chmFile *h, UChar *buf, UInt64 os, Int64 len)
Definition: chm_lib.c:541
#define CHM_COMPRESSED
Definition: chm_lib.h:60
#define CHM_ENUMERATE_NORMAL
Definition: chm_lib.h:94
#define CHM_RESOLVE_FAILURE
Definition: chm_lib.h:83
ULONGLONG LONGUINT64
Definition: chm_lib.h:53
#define CHM_ENUMERATOR_CONTINUE
Definition: chm_lib.h:101
LONGLONG LONGINT64
Definition: chm_lib.h:54
#define CHM_ENUMERATE_META
Definition: chm_lib.h:95
#define CHM_ENUMERATE_SPECIAL
Definition: chm_lib.h:96
#define CHM_RESOLVE_SUCCESS
Definition: chm_lib.h:82
#define CHM_ENUMERATE_DIRS
Definition: chm_lib.h:98
#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:91
#define CHM_ENUMERATE_FILES
Definition: chm_lib.h:97
#define CHM_ENUMERATOR_SUCCESS
Definition: chm_lib.h:102
#define CHM_ENUMERATOR_FAILURE
Definition: chm_lib.h:100
#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 wcsnicmp
Definition: compat.h:14
#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
BOOL WINAPI InitializeCriticalSectionEx(OUT LPCRITICAL_SECTION lpCriticalSection, IN DWORD dwSpinCount, IN DWORD flags)
Definition: sync.c:107
int WINAPIV fprintf(FILE *file, const char *format,...)
Definition: file.c:5549
#define stderr
_ACRTIMP int __cdecl memcmp(const void *, const void *, size_t)
Definition: string.c:2807
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define L(x)
Definition: resources.c:13
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 GLsizei count
Definition: gl.h:1545
GLuint GLuint end
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
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:149
UINT ui
Definition: oleauto.h:49
short WCHAR
Definition: pedump.c:58
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
#define CP_UTF8
Definition: nls.h:20
PRTL_CRITICAL_SECTION_DEBUG DebugInfo
Definition: rtltypes.h:1478
Int64 * cache_block_indices
Definition: chm_lib.c:532
UInt32 reset_blkcount
Definition: chm_lib.c:524
UInt32 window_size
Definition: chm_lib.c:522
Int32 index_root
Definition: chm_lib.c:511
Int32 cache_num_blocks
Definition: chm_lib.c:533
UInt64 dir_offset
Definition: chm_lib.c:508
HANDLE fd
Definition: chm_lib.c:502
int lzx_last_block
Definition: chm_lib.c:528
UInt64 span
Definition: chm_lib.c:515
struct chmUnitInfo rt_unit
Definition: chm_lib.c:516
CRITICAL_SECTION cache_mutex
Definition: chm_lib.c:506
UChar ** cache_blocks
Definition: chm_lib.c:531
struct chmUnitInfo cn_unit
Definition: chm_lib.c:517
int compression_enabled
Definition: chm_lib.c:521
struct LZXstate * lzx_state
Definition: chm_lib.c:527
CRITICAL_SECTION lzx_mutex
Definition: chm_lib.c:505
Int32 index_head
Definition: chm_lib.c:512
CRITICAL_SECTION mutex
Definition: chm_lib.c:504
UInt32 reset_interval
Definition: chm_lib.c:523
UInt64 dir_len
Definition: chm_lib.c:509
UInt64 data_offset
Definition: chm_lib.c:510
UInt32 block_len
Definition: chm_lib.c:513
struct chmLzxcResetTable reset_table
Definition: chm_lib.c:518
Int32 version
Definition: chm_lib.c:216
UChar stream_uuid[16]
Definition: chm_lib.c:222
Int32 unknown_000c
Definition: chm_lib.c:218
UInt64 unknown_len
Definition: chm_lib.c:224
UInt32 last_modified
Definition: chm_lib.c:219
Int32 header_len
Definition: chm_lib.c:217
UInt64 data_offset
Definition: chm_lib.c:227
UInt32 lang_id
Definition: chm_lib.c:220
UInt64 dir_len
Definition: chm_lib.c:226
UInt64 dir_offset
Definition: chm_lib.c:225
UChar dir_uuid[16]
Definition: chm_lib.c:221
UInt64 unknown_offset
Definition: chm_lib.c:223
Int32 unknown_000c
Definition: chm_lib.c:294
UInt32 block_len
Definition: chm_lib.c:295
Int32 version
Definition: chm_lib.c:292
Int32 unknown_0024
Definition: chm_lib.c:300
Int32 index_depth
Definition: chm_lib.c:297
UInt32 num_blocks
Definition: chm_lib.c:301
UInt32 lang_id
Definition: chm_lib.c:303
Int32 index_head
Definition: chm_lib.c:299
UChar unknown_0044[16]
Definition: chm_lib.c:305
Int32 index_root
Definition: chm_lib.c:298
Int32 header_len
Definition: chm_lib.c:293
Int32 blockidx_intvl
Definition: chm_lib.c:296
Int32 unknown_002c
Definition: chm_lib.c:302
UChar system_uuid[16]
Definition: chm_lib.c:304
UInt32 resetInterval
Definition: chm_lib.c:451
UInt32 windowSize
Definition: chm_lib.c:452
UInt32 windowsPerReset
Definition: chm_lib.c:453
UInt32 unknown_18
Definition: chm_lib.c:454
UInt64 compressed_len
Definition: chm_lib.c:415
UInt32 version
Definition: chm_lib.c:410
UInt32 unknown
Definition: chm_lib.c:412
UInt32 table_offset
Definition: chm_lib.c:413
UInt32 block_count
Definition: chm_lib.c:411
UInt64 block_len
Definition: chm_lib.c:416
UInt64 uncompressed_len
Definition: chm_lib.c:414
UInt32 free_space
Definition: chm_lib.c:384
Int32 block_prev
Definition: chm_lib.c:352
UInt32 free_space
Definition: chm_lib.c:350
Int32 block_next
Definition: chm_lib.c:353
UInt32 unknown_0008
Definition: chm_lib.c:351
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
Character const *const prefix
Definition: tempnam.cpp:195
#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:116
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO
Definition: winnt_old.h:1156
#define DUPLICATE_SAME_ACCESS
static unsigned int block
Definition: xmlmemory.c:101
unsigned char BYTE
Definition: xxhash.c:193