Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

722 lines
19 KiB

  1. /*************************************************************************
  2. * helpdec - HelpDecomp routine and Other ASM code
  3. *
  4. * Copyright <C> 1988, Microsoft Corporation
  5. *
  6. * Purpose:
  7. *
  8. * Revision History:
  9. *
  10. * 08-Oct-1990 RJSA Converted to C
  11. * 22-Dec-1988 LN Removed MASM High Level Lang support (Need
  12. * to control segments better than that will
  13. * let me)
  14. * 08-Dec-1988 LN CSEG
  15. * 16-Feb-1988 LN Rewrite for (some) speed
  16. * [] 17-Jan-1988 LN Created
  17. *
  18. **************************************************************************/
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #if defined (OS2)
  23. #define INCL_BASE
  24. #include <os2.h>
  25. #else
  26. #include <windows.h>
  27. #endif
  28. #include <help.h>
  29. #include <helpfile.h>
  30. #pragma function( memset, memcpy, memcmp, strcpy, strcmp, strcat )
  31. // In order to increase performance, and because of the functions
  32. // decomp and NextChar being tightly coupled, global variables are
  33. // used instead of passing parameters.
  34. //
  35. PBYTE pHuffmanRoot; // Root of Huffman Tree
  36. PBYTE pCompTopic; // Current pointer to text (compressed)
  37. BYTE BitMask; // Rotating bit mask
  38. BOOL IsCompressed; // True if text is compressed
  39. BYTE NextChar (void);
  40. BOOL pascal HelpCmp (PCHAR fpsz1, PCHAR fpsz2, USHORT cbCmp, BOOL fCase, BOOL fTerm);
  41. /**************************************************************************
  42. *
  43. * Decomp - Decompress Topic Text
  44. * f near pascal Decomp(fpHuffmanRoot, fpKeyphrase, fpTopic, fpDest)
  45. * uchar far *fpHuffmanRoot
  46. * uchar far *fpKeyphrase
  47. * uchar far *fpTopic
  48. * uchar far *fpDest
  49. *
  50. * Purpose:
  51. * Fully decompress topic text. Decompresses based on current file, from one
  52. * buffer to another.
  53. *
  54. * Entry:
  55. * fpHuffmanRoot - Pointer to root of huffman tree (or NULL if no huffman)
  56. * fpKeyphrase - Pointer to keyphrase table (or NULL if no keyphrase)
  57. * fpTopic - Pointer to compressed topic text
  58. * fpDest - Pointer to destination buffer
  59. *
  60. * Exit:
  61. * FALSE on successful completion
  62. *
  63. * Exceptions:
  64. * Returns TRUE on any error.
  65. *
  66. **************************************************************************/
  67. BOOL pascal decomp (
  68. PCHAR fpHuffmanRoot,
  69. PCHAR fpKeyphrase,
  70. PCHAR fpTopic,
  71. PCHAR fpDest
  72. ){
  73. int cDecomp; /* count of totally decompressed */
  74. BYTE c; /* byte read */
  75. #ifdef BIGDEBUG
  76. char DbgB[128];
  77. char *DbgP = fpDest;
  78. #endif
  79. // Initialize global variables.
  80. pHuffmanRoot = (PBYTE)fpHuffmanRoot;
  81. pCompTopic = (PBYTE)fpTopic + sizeof(USHORT);
  82. BitMask = 0x01;
  83. IsCompressed = fpHuffmanRoot
  84. ? ((*(USHORT UNALIGNED *)((PBYTE)fpHuffmanRoot + 2)) != 0xFFFF)
  85. : FALSE;
  86. cDecomp = *((USHORT UNALIGNED *)fpTopic);
  87. #ifdef BIGDEBUG
  88. sprintf(DbgB, "DECOMPRESSING: HuffmanRoot: %lx, Keyphrase: %lx\n", fpHuffmanRoot, fpKeyphrase );
  89. OutputDebugString(DbgB);
  90. sprintf(DbgB, " Topic: %lx, Dest: %lx\n", fpTopic, fpDest );
  91. OutputDebugString(DbgB);
  92. if ( IsCompressed ) {
  93. OutputDebugString(" The Topic IS Compressed\n");
  94. }
  95. #endif
  96. while ( cDecomp > 0 ) {
  97. c = NextChar();
  98. //
  99. // At this point a valid character has been found and huffman decoded. We must
  100. // now perform any other decoding on it that is required.
  101. //
  102. // Variables are:
  103. // c = character
  104. // cDecomp = Output count remaining
  105. // BitMask = bit mask for interpreting input stream
  106. //
  107. // "Magic Cookie" decompression.
  108. // The chararacter stream after huffman encoding is "cookie" encoded, in that
  109. // certain characters are flags which when encountered mean something other than
  110. // themselves. All characters which are NOT such flags (or cookies, as they seem
  111. // to be called), are simply copied to the output stream.
  112. //
  113. // We first check the character to see if it IS a cookie. If it is NOT, we just
  114. // store it, and get the next input byte
  115. //
  116. if ((c >= C_MIN) && (c <= C_MAX)) {
  117. BYTE Cookie = c ;
  118. #ifdef BIGDEBUG
  119. OutputDebugString("Cookie\n");
  120. #endif
  121. // c is a cookie of some sort, jump to the appropriate
  122. // cookie eater.
  123. c = NextChar();
  124. switch (Cookie) {
  125. case C_KEYPHRASE0:
  126. case C_KEYPHRASE1:
  127. case C_KEYPHRASE2:
  128. case C_KEYPHRASE3:
  129. case C_KEYPHRASE_SPACE0:
  130. case C_KEYPHRASE_SPACE1:
  131. case C_KEYPHRASE_SPACE2:
  132. case C_KEYPHRASE_SPACE3:
  133. {
  134. ULONG Index; /* Keyword index */
  135. PBYTE pKey; /* Keyword */
  136. BYTE Size; /* Keyword size */
  137. if ((Cookie >= C_KEYPHRASE_SPACE0) && (Cookie <= C_KEYPHRASE_SPACE3)) {
  138. Index = (ULONG)((int)Cookie - C_MIN - 4);
  139. } else {
  140. Index = (ULONG)((int)Cookie - C_MIN);
  141. }
  142. Index = (ULONG)(((Index * 0x100) + c) * sizeof(PVOID));
  143. pKey = *(PBYTE *)(((PBYTE)fpKeyphrase) + Index);
  144. // pKey = *(PBYTE *)(fpKeyphrase + Index);
  145. Size = *pKey++;
  146. {
  147. BYTE i = Size;
  148. while (i--) {
  149. *fpDest++ = *pKey++;
  150. }
  151. cDecomp -=Size;
  152. }
  153. if ((Cookie >= C_KEYPHRASE_SPACE0) && (Cookie <= C_KEYPHRASE_SPACE3)) {
  154. *fpDest++ = ' ';
  155. cDecomp--;
  156. }
  157. break;
  158. }
  159. case C_RUNSPACE:
  160. {
  161. BYTE Count = c;
  162. while (Count--) {
  163. *fpDest++ = ' ';
  164. }
  165. cDecomp -= c;
  166. break;
  167. }
  168. case C_RUN:
  169. {
  170. BYTE b = c;
  171. BYTE Cnt;
  172. Cnt = c = NextChar();
  173. while (Cnt--) {
  174. *fpDest++ = b;
  175. }
  176. cDecomp -= c;
  177. break;
  178. }
  179. case C_QUOTE:
  180. *fpDest++ = c;
  181. cDecomp--;
  182. break;
  183. }
  184. } else {
  185. // c is not a cookie
  186. *fpDest++ = c;
  187. cDecomp--;
  188. }
  189. }
  190. *fpDest++ = '\00'; // Null terminate string
  191. #ifdef BIGDEBUG
  192. sprintf( DbgB, "Decompressed topic: [%s]\n", DbgP );
  193. OutputDebugString( DbgB );
  194. if ( cDecomp < 0 ) {
  195. sprintf( DbgB, "DECOMPRESSION ERROR: cDecomp = %d!\n", cDecomp );
  196. OutputDebugString(DbgB);
  197. }
  198. #endif
  199. return FALSE;
  200. }
  201. /**************************************************************************
  202. *
  203. * NextChar - Return next character from input stream
  204. *
  205. * Purpose:
  206. * Returns next character from input stream, performing huffman decompression
  207. * if enabled.
  208. *
  209. * Entry:
  210. * fpHuffmanRoot = pointer to root of huffman tree
  211. * pfpTopic = pointer to pointer to Topic
  212. * pBitmask = pointer to bit mask of current bit
  213. *
  214. * Exit:
  215. * Returns character
  216. * *pfpTopic and *pBitMask updated.
  217. *
  218. **************************************************************************
  219. *
  220. * Format of Huffman decode tree:
  221. * The Huffman decode tree is a binary tree used to decode a bitstream into a
  222. * character stream. The tree consists of nodes (internal nodes and leaves).
  223. * Each node is represented by a word. If the high bit in the word is set then
  224. * the node is a leaf. If the node is an internal node, then the value of the
  225. * node is the index of the right branch in the binary tree. The left branch is
  226. * the node following the current node (in memory). If the node is a leaf, then
  227. * the low byte of the node is a character.
  228. *
  229. * e.g.
  230. * 0: 0004 0
  231. * 1: 0003 / \
  232. * 2: 8020 / \
  233. * 3: 8065 1 \------4
  234. * 4: 0006 / \ / \
  235. * 5: 806C / \ / \
  236. * 6: 8040 2 3 5 6
  237. * ' ' 'e' 'l' '@'
  238. *
  239. * Using the Huffman decode tree:
  240. * The huffman decode tree is used to decode a bitstream into a character
  241. * string. The bitstream is used to traverse the decode tree. Whenever a zero
  242. * is detected in the bit stream we take the right branch, when one is detected
  243. * we take the left branch. When a leaf is reached in the tree, the value of
  244. * the leaf (a character) is output, and the current node is set back to the
  245. *
  246. ********************************************************************/
  247. BYTE
  248. NextChar (
  249. void
  250. ) {
  251. BYTE b; // current source byte
  252. #ifdef BIGDEBUG
  253. char DbgB[128];
  254. OutputDebugString("NextChar:\n");
  255. #endif
  256. if (IsCompressed) {
  257. USHORT HuffmanNode; // curent node in the huffman tree
  258. USHORT UNALIGNED *pHuffmanNext; // next node in the huffman tree
  259. //
  260. // Huffman decoding.
  261. // This first part of the decode loop performs the actual huffman decode. This
  262. // code is very speed critical. We walk the tree, as defined by the bit pattern
  263. // coming in, and exit this portion of the code when we reach a leaf which
  264. // contains the character that the bit pattern represented.
  265. //
  266. pHuffmanNext = (USHORT UNALIGNED *)pHuffmanRoot;
  267. HuffmanNode = *pHuffmanNext;
  268. b = *(pCompTopic - 1); // get last byte read
  269. while (!(HuffmanNode & 0x8000)) { // while not leaf
  270. BitMask >>= 1;
  271. if (!(BitMask)) {
  272. //
  273. // Get new byte from input
  274. //
  275. b = *pCompTopic++;
  276. BitMask = 0x80;
  277. #ifdef BIGDEBUG
  278. sprintf(DbgB, "\tb=%02x Mask=%02x Node=%04x", b, BitMask, HuffmanNode );
  279. OutputDebugString(DbgB);
  280. #endif
  281. } else {
  282. #ifdef BIGDEBUG
  283. sprintf(DbgB, "\tb=%02x Mask=%02x Node=%04x", b, BitMask, HuffmanNode );
  284. OutputDebugString(DbgB);
  285. #endif
  286. }
  287. if (b & BitMask) {
  288. //
  289. // one: take left branch
  290. //
  291. pHuffmanNext++;
  292. } else {
  293. //
  294. // zero: take right branch
  295. //
  296. pHuffmanNext = (PUSHORT)((PBYTE)pHuffmanRoot + HuffmanNode);
  297. #ifdef BIGDEBUG
  298. sprintf(DbgB, " <%04x+%02x=%04x (%04x)>", pHuffmanRoot, HuffmanNode,
  299. pHuffmanNext, *pHuffmanNext );
  300. OutputDebugString( DbgB );
  301. #endif
  302. }
  303. HuffmanNode = *pHuffmanNext;
  304. #ifdef BIGDEBUG
  305. sprintf(DbgB, " Next=%04x\n", HuffmanNode );
  306. OutputDebugString(DbgB);
  307. #endif
  308. }
  309. b = (BYTE)HuffmanNode; // character is low byte of leaf node
  310. } else {
  311. b = *pCompTopic++; // not compressed, simply return byte
  312. }
  313. #ifdef BIGDEBUG
  314. sprintf(DbgB, "\t---->%2x [%c]\n", b,b);
  315. OutputDebugString(DbgB);
  316. #endif
  317. return b;
  318. }
  319. /**************************************************************************
  320. *
  321. * HelpCmpSz - help system string comparison routine.
  322. * f near pascal HelpCmpSz (fpsz1, fpsz2)
  323. * uchar far *fpsz1*
  324. * uchar far *fpsz2*
  325. *
  326. * Purpose:
  327. * Perform string comparisons for help system look-up.
  328. * Default case of HelpCmp below.
  329. *
  330. * Entry:
  331. * fpsz1 = Far pointer to string 1. (Usually the constant string
  332. * being "looked-up".
  333. * fpsz2 = Far pointer to string 2. This is usually the string table
  334. * being searched.
  335. *
  336. * Exit:
  337. * TRUE on match
  338. *
  339. ********************************************************************/
  340. BOOL pascal
  341. HelpCmpSz (
  342. PCHAR fpsz1,
  343. PCHAR fpsz2
  344. ){
  345. return HelpCmp(fpsz1, fpsz2, (USHORT)0xFFFF, TRUE, FALSE); // fcase, fTerm
  346. }
  347. /**************************************************************************
  348. *
  349. * HelpCmp - help system string comparison routine.
  350. * f near pascal HelpCmp (fpsz1, fpsz2, cbCmp, fCase, fTerm)
  351. * uchar far *fpsz1
  352. * uchar far *fpsz2
  353. * ushort cbCmp
  354. * f fCase
  355. * f fTerm
  356. *
  357. * Purpose:
  358. * Perform string comparisons for help system look-up.
  359. *
  360. * Entry:
  361. * fpsz1 = Far pointer to string 1. (Usually the constant string being
  362. * "looked-up"). NOTE THAT IF THIS STRING IS NULL, WE RETURN
  363. * TRUE!
  364. * fpsz2 = Far pointer to string 2. This is usually the string table
  365. * being searched.
  366. * cbCmp = Max number of bytes to compare.
  367. * fCase = TRUE if search is to be case sensitive.
  368. * fTerm = TRUE if we allow special termination processing.
  369. *
  370. * Exit:
  371. * TRUE on match
  372. *
  373. ********************************************************************/
  374. BOOL pascal
  375. HelpCmp (
  376. PCHAR fpsz1,
  377. PCHAR fpsz2,
  378. USHORT cbCmp,
  379. BOOL fCase,
  380. BOOL fTerm
  381. ){
  382. register PBYTE p1 = (PBYTE)fpsz1;
  383. register PBYTE p2 = (PBYTE)fpsz2;
  384. while (cbCmp--) {
  385. if ((!*p1) && (!*p2)) {
  386. //
  387. // Got a match
  388. //
  389. return TRUE;
  390. }
  391. if (!fCase) {
  392. if (toupper((char)*p1) != toupper((char)*p2)) {
  393. break;
  394. }
  395. p1++;
  396. p2++;
  397. } else {
  398. if (*p1++ != *p2++) {
  399. break;
  400. }
  401. }
  402. }
  403. if (!cbCmp) {
  404. return TRUE;
  405. }
  406. // At this point, we have terminated the comparison. Termination conditions
  407. // were:
  408. //
  409. // character count exausted: CX == zero. (Complete match, return TRUE)
  410. // Null terminator found: CX != zero, & Zero flag set. (Complete match,
  411. // return TRUE)
  412. // non-match found CX != zero, & Zero flag clear.
  413. //
  414. // In the later case, if special termination processing is NOT selected, we
  415. // return FALSE, having found a mis-match.
  416. //
  417. // If special termination processing is TRUE, then if the mismatched character
  418. // from string 1 is a null, and the mismatched character from string 2 is any
  419. // whitespace or CR, we declare a match. (This is used in minascii processing).
  420. //
  421. if (fTerm) {
  422. p1--; p2--;
  423. if ((! *p1) &&
  424. ((*p2 == '\n') || (*p2 == '\t') || (*p2 == ' '))) {
  425. return TRUE;
  426. }
  427. }
  428. return FALSE;
  429. }
  430. /*************************************************************************
  431. *
  432. * hfstrlen - far string length
  433. *
  434. * Purpose:
  435. * return length of null terminated string.
  436. *
  437. * Entry:
  438. * fpszSrc = pointer to source
  439. *
  440. * Exit:
  441. * returns length
  442. *
  443. *************************************************************************/
  444. USHORT
  445. hfstrlen (
  446. PCHAR fpszSrc
  447. ){
  448. return (USHORT)strlen(fpszSrc);
  449. }
  450. /*************************************************************************
  451. *
  452. * hfstrcpy - far string copy
  453. *
  454. * Purpose:
  455. * copy strings
  456. *
  457. * Entry:
  458. * fpszDst = pointer to destination
  459. * fpszSrc = pointer to source
  460. *
  461. * Exit:
  462. * pointer to terminating null in destination
  463. *
  464. *************************************************************************/
  465. PCHAR
  466. hfstrcpy (
  467. PCHAR fpszDst,
  468. PCHAR fpszSrc
  469. ) {
  470. return (PCHAR)strcpy(fpszDst, fpszSrc);
  471. }
  472. /*************************************************************************
  473. *
  474. * hfstrchr - search for character in far string
  475. *
  476. * Purpose:
  477. * a near, pascal routine (for size/speed) to search for a character in
  478. * a far string.
  479. *
  480. * Entry:
  481. * fpsz = far pointer to string
  482. * c = character to locate
  483. *
  484. * Exit:
  485. * returns far pointer into string
  486. *
  487. * Exceptions:
  488. * returns NULL on character not in string
  489. *
  490. *************************************************************************/
  491. PCHAR
  492. hfstrchr (
  493. PCHAR fpsz,
  494. char c
  495. ){
  496. return (PCHAR)strchr(fpsz, c);
  497. }
  498. /*************************************************************************
  499. *
  500. * hfmemzer - zero out memory area.
  501. *
  502. * Purpose:
  503. * a near, pascal routine (for size/speed) to fill an area with zero
  504. *
  505. * Entry:
  506. * fpb = far pointer to buffer
  507. * cb = count of zeros to store
  508. *
  509. * Exit:
  510. *
  511. *************************************************************************/
  512. void
  513. hfmemzer (
  514. PVOID fpb,
  515. ULONG cb
  516. ) {
  517. memset(fpb, '\00', cb);
  518. }
  519. /*************************************************************************
  520. *
  521. * NctoFo - extract file offset from NC
  522. *
  523. * Purpose:
  524. * Extracts the file offset for a minascii file, and returns it as a long.
  525. *
  526. * Entry:
  527. * nc = context number
  528. *
  529. * Exit:
  530. * returns file offset
  531. *
  532. *************************************************************************/
  533. ULONG
  534. NctoFo (
  535. ULONG nc
  536. ) {
  537. nc = nc & 0x0000FFFF;
  538. nc *= 4;
  539. return nc;
  540. }
  541. /*************************************************************************
  542. *
  543. * combineNc - combine a minascii file offset and fdb handle into nc.
  544. *
  545. * Purpose:
  546. * Combines a minascii file offset and fdb memory handle into an NC. If the
  547. * file offset is 0xffffffff, we return zero.
  548. *
  549. * Entry:
  550. * offset = long file offset
  551. * mh = fdb mem handle
  552. *
  553. * Exit:
  554. * returns NC (DX = mem handle, AX = filepos/4), or 0L if offset==FFFFFFFF
  555. *
  556. *************************************************************************/
  557. nc pascal
  558. combineNc (
  559. ULONG offset,
  560. mh mh
  561. ){
  562. nc ncRet = {0,0};
  563. if (offset = 0xFFFFFFFF) {
  564. return ncRet;
  565. }
  566. ncRet.mh = mh;
  567. ncRet.cn = offset/4;
  568. return ncRet;
  569. }
  570. /*************************************************************************
  571. *
  572. * toupr - convert char to upper case
  573. *
  574. * Purpose:
  575. *
  576. * Entry:
  577. * chr = character
  578. *
  579. * Exit:
  580. * returns upper case character
  581. *
  582. *************************************************************************/
  583. char
  584. toupr (
  585. char chr
  586. ){
  587. return (char)toupper(chr);
  588. }
  589. /*************************************************************************
  590. *kwPtrBuild - Build table of pointers to keywords.
  591. *void pascal near kwPtrBuild(uchar far *fpTable, ushort tsize)
  592. *
  593. *Purpose:
  594. * Builds a table of pointers to the keyword strings in the passed string array.
  595. * The table is built in the first 4k of the passed buffer. The strings are
  596. * assummed to start immediately thereafter.
  597. *
  598. *Entry:
  599. * fpTable - pointer to string table
  600. * tsize - size, in bytes, of strings
  601. *
  602. *Exit:
  603. * none
  604. *
  605. *******************************************************************************/
  606. void
  607. kwPtrBuild (
  608. PVOID fpTable,
  609. USHORT tsize
  610. ) {
  611. PBYTE fpStr = (PBYTE)fpTable + 1024 * sizeof (PVOID);
  612. PBYTE *fpTbl = fpTable;
  613. while (tsize > 0) {
  614. UCHAR sSize = (UCHAR)(*fpStr) + (UCHAR)1;
  615. *fpTbl++ = fpStr;
  616. tsize -= sSize;
  617. fpStr += sSize;
  618. }
  619. }