Leaked source code of windows server 2003
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.

3507 lines
76 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. stftable.c
  5. Abstract:
  6. The routines in this file manipulate the STF/INF pair used by
  7. ACME Setup.
  8. Author:
  9. Jim Schmidt (jimschm) 12-Sept-1997
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #include "migmainp.h"
  14. #include "stftable.h"
  15. #define DBG_STF "STF"
  16. #define USE_FILE_MAPPING 1
  17. #define DBLQUOTECHAR TEXT('\"')
  18. #define FIELD_QUOTED 0x0001
  19. #define FIELD_BINARY 0x0002
  20. //
  21. // Declaration of functions for use only in this file
  22. //
  23. VOID
  24. pFreeTableEntryString (
  25. IN OUT PSETUPTABLE TablePtr,
  26. IN OUT PTABLEENTRY TableEntryPtr
  27. );
  28. VOID
  29. pFreeTableEntryPtr (
  30. IN OUT PSETUPTABLE TablePtr,
  31. IN PTABLEENTRY TableEntryPtr,
  32. IN BOOL DeallocateStruct,
  33. OUT PTABLEENTRY *NextTableEntryPtr OPTIONAL
  34. );
  35. PTABLELINE
  36. pInsertEmptyLineInTable (
  37. IN OUT PSETUPTABLE TablePtr,
  38. IN UINT InsertBeforeLine
  39. );
  40. BOOL
  41. pInitHashTable (
  42. IN PSETUPTABLE TablePtr
  43. );
  44. BOOL
  45. pAddToHashTable (
  46. IN OUT PSETUPTABLE TablePtr,
  47. IN PCTSTR Text,
  48. IN UINT Len,
  49. IN UINT Line
  50. );
  51. PHASHBUCKET
  52. pFindInHashTable (
  53. IN PSETUPTABLE TablePtr,
  54. IN PCTSTR Text,
  55. OUT PUINT Item
  56. );
  57. BOOL
  58. pRemoveFromHashTable (
  59. IN OUT PSETUPTABLE TablePtr,
  60. IN PCTSTR Text
  61. );
  62. VOID
  63. pFreeHashTable (
  64. IN OUT PSETUPTABLE TablePtr
  65. );
  66. //
  67. // Table access functions
  68. //
  69. PTABLELINE
  70. pGetTableLinePtr (
  71. IN PSETUPTABLE TablePtr,
  72. IN UINT Line
  73. )
  74. /*++
  75. Routine Description:
  76. pGetTableLinePtr returns a pointer to the PTABLELINE structure
  77. for the specified line. The PTABLELINE pointers are kept in
  78. an array, so lookup for the line is very fast.
  79. Arguments:
  80. TablePtr - Specifies the table that contains the line
  81. Line - Specifies the zero-based line to look up
  82. Return Value:
  83. A pointer to the table line
  84. --*/
  85. {
  86. PTABLELINE TableLinePtr;
  87. if (Line >= TablePtr->LineCount) {
  88. return NULL;
  89. }
  90. TableLinePtr = (PTABLELINE) TablePtr->Lines.Buf;
  91. return &TableLinePtr[Line];
  92. }
  93. PTABLEENTRY
  94. pGetFirstTableEntryPtr (
  95. IN PSETUPTABLE TablePtr,
  96. IN UINT Line // zero-based
  97. )
  98. /*++
  99. Routine Description:
  100. pGetFirstTableEntryPtr provides a pointer to the first column
  101. for a line.
  102. Arguments:
  103. TablePtr - Specifies the table that contains the line
  104. Line - Specifies the zero-based line to enumerate
  105. Return Value:
  106. A pointer to the first column's TABLEENTRY structure, or
  107. NULL if the line has no columns.
  108. --*/
  109. {
  110. PTABLELINE TableLinePtr;
  111. TableLinePtr = pGetTableLinePtr (TablePtr, Line);
  112. if (!TableLinePtr) {
  113. return NULL;
  114. }
  115. return TableLinePtr->FirstCol;
  116. }
  117. PTABLEENTRY
  118. pGetNextTableEntryPtr (
  119. IN PTABLEENTRY CurrentEntryPtr
  120. )
  121. /*++
  122. Routine Description:
  123. pGetNextTableEntryPtr returns a pointer to the next column's
  124. TABLEENTRY structure, or NULL if no more columns exist on
  125. the line.
  126. Arguments:
  127. CurrentEntryPtr - Specifies the entry returned by
  128. pGetFirstTableEntryPtr or pGetNextTableEntryPtr.
  129. Return Value:
  130. A pointer to the next column's TABLEENTRY structure, or NULL
  131. if the line has no more columns.
  132. --*/
  133. {
  134. return CurrentEntryPtr->Next;
  135. }
  136. PTABLEENTRY
  137. GetTableEntry (
  138. IN PSETUPTABLE TablePtr,
  139. IN UINT Line,
  140. IN UINT Col,
  141. OUT PCTSTR *StringPtr OPTIONAL
  142. )
  143. /*++
  144. Routine Description:
  145. GetTableEntry is the exposed entry point that finds a column
  146. on a line and returns a pointer to it. It also optionally
  147. copies the read-only pointer to the entry text.
  148. Arguments:
  149. TablePtr - Specifies the setup table that contains the line and col
  150. Line - Specifies the zero-based line in the table
  151. Col - Specifies the col in the table
  152. StringPtr - Receives a pointer to the entry's read-only string
  153. Return Value:
  154. A pointer to the TABLEENTRY structure, or NULL if the line/
  155. column part does not exist.
  156. --*/
  157. {
  158. PTABLEENTRY TableEntryPtr;
  159. TableEntryPtr = pGetFirstTableEntryPtr (TablePtr, Line);
  160. while (TableEntryPtr) {
  161. if (!Col) {
  162. if (StringPtr) {
  163. *StringPtr = TableEntryPtr->String;
  164. }
  165. return TableEntryPtr;
  166. }
  167. Col--;
  168. TableEntryPtr = pGetNextTableEntryPtr (TableEntryPtr);
  169. }
  170. return NULL;
  171. }
  172. //
  173. // String mapping, unmapping and conversion functions
  174. //
  175. VOID
  176. pFreeTableEntryString (
  177. IN OUT PSETUPTABLE TablePtr,
  178. IN OUT PTABLEENTRY TableEntryPtr
  179. )
  180. /*++
  181. Routine Description:
  182. pFreeTableEntryString is used to free the allocation of a replaced
  183. string before it is replaced again. This routine is called by
  184. ReplaceTableEntryStr.
  185. Arguments:
  186. TablePtr - Specifies the table containing the entry
  187. TableEntryPtr - Specifies the entry containing the resources to deallocate
  188. Return Value:
  189. none
  190. --*/
  191. {
  192. if (TableEntryPtr->String) {
  193. if (TableEntryPtr->StringReplaced) {
  194. PoolMemReleaseMemory (TablePtr->ReplacePool, (PVOID) TableEntryPtr->String);
  195. }
  196. }
  197. TableEntryPtr->String = NULL;
  198. TableEntryPtr->StringReplaced = FALSE;
  199. }
  200. PCSTR
  201. pGenerateUnquotedText (
  202. IN POOLHANDLE Pool,
  203. IN PCSTR Text,
  204. IN INT Chars
  205. )
  206. /*++
  207. Routine Description:
  208. pGenerateUnqutoedText converts the pairs of dbl quotes in the specified
  209. string into a single set of dbl quotes. This routine is used by the
  210. STF file parser, because quoted STF entries have pairs of dbl quotes
  211. to indicate a single dbl-quote symbol.
  212. Arguments:
  213. Pool - Specifies the pool to allocate memory from
  214. Text - Specifies the text that may contain the pairs of dbl quotes
  215. Chars - Specifies the number of characters in Text. If -1,
  216. Text is nul-terminated.
  217. Return Value:
  218. A pointer to the converted string, or NULL if the pool allocation
  219. failed.
  220. --*/
  221. {
  222. PSTR Buf;
  223. PSTR d, p;
  224. PCSTR s;
  225. if (Chars < 0) {
  226. Chars = LcharCountA (Text);
  227. }
  228. Buf = (PSTR) PoolMemGetAlignedMemory (
  229. Pool,
  230. (Chars + 1) * sizeof (WCHAR)
  231. );
  232. if (!Buf) {
  233. return NULL;
  234. }
  235. s = Text;
  236. d = Buf;
  237. //
  238. // Remove double-quotes
  239. //
  240. while (Chars > 0) {
  241. if (Chars > 1 && _mbsnextc (s) == '\"') {
  242. p = _mbsinc (s);
  243. if (_mbsnextc (p) == '\"') {
  244. // Skip the first of two dbl quotes
  245. Chars--;
  246. s = p;
  247. }
  248. }
  249. // Copy character
  250. if (IsLeadByte (s)) {
  251. *d++ = *s++;
  252. }
  253. *d++ = *s++;
  254. Chars--;
  255. }
  256. *d = 0;
  257. return Buf;
  258. }
  259. PCSTR
  260. pGenerateQuotedText (
  261. IN POOLHANDLE Pool,
  262. IN PCSTR Text,
  263. IN INT Chars
  264. )
  265. /*++
  266. Routine Description:
  267. pGenerateQuotedText converts dbl quote characters in a string into
  268. pairs of dbl quotes.
  269. Arguments:
  270. Pool - Specifies the pool to allocate memory from
  271. Text - Specifies the string to convert
  272. Chars - Specifies the number of characters to convert. If -1,
  273. Text is nul terminated.
  274. Return Value:
  275. A pointer to the converted text, or NULL if an allocation failed.
  276. --*/
  277. {
  278. PSTR Buf;
  279. PSTR d;
  280. PCSTR s;
  281. if (Chars < 0) {
  282. Chars = LcharCountA (Text);
  283. }
  284. Buf = (PSTR) PoolMemGetAlignedMemory (
  285. Pool,
  286. (Chars + 3) * (sizeof (WCHAR) * 2)
  287. );
  288. if (!Buf) {
  289. return NULL;
  290. }
  291. s = Text;
  292. d = Buf;
  293. //
  294. // Add quotes, double quotes already in the string
  295. //
  296. *d++ = '\"';
  297. while (Chars > 0) {
  298. if (_mbsnextc (s) == '\"') {
  299. *d++ = '\"';
  300. }
  301. if (IsLeadByte (s)) {
  302. *d++ = *s++;
  303. }
  304. *d++ = *s++;
  305. Chars--;
  306. }
  307. *d++ = '\"';
  308. *d = 0;
  309. return Buf;
  310. }
  311. VOID
  312. pFreeQuoteConvertedText (
  313. IN POOLHANDLE Pool,
  314. IN PCSTR Text
  315. )
  316. /*++
  317. Routine Description:
  318. Frees the text converted by pGenerateUnquotedText or
  319. pGenerateQuotedText.
  320. Arguments:
  321. Pool - Specifies the pool that the string was allocated
  322. from
  323. Text - Specifies the pointer returned by the conversion
  324. function
  325. Return Value:
  326. none
  327. --*/
  328. {
  329. if (Text) {
  330. PoolMemReleaseMemory (Pool, (PVOID) Text);
  331. }
  332. }
  333. PCTSTR
  334. GetTableEntryStr (
  335. IN OUT PSETUPTABLE TablePtr,
  336. IN OUT PTABLEENTRY TableEntryPtr
  337. )
  338. /*++
  339. Routine Description:
  340. Returns a pointer to the read-only string for
  341. the specified table entry.
  342. Arguments:
  343. TablePtr - Specifies the table holding the entry
  344. TableEntryPtr - Specifies the entry to obtain the
  345. string for
  346. Return Value:
  347. A pointer to the string.
  348. --*/
  349. {
  350. return TableEntryPtr->String;
  351. }
  352. BOOL
  353. ReplaceTableEntryStr (
  354. IN OUT PSETUPTABLE TablePtr,
  355. IN OUT PTABLEENTRY TableEntryPtr,
  356. IN PCTSTR NewString
  357. )
  358. /*++
  359. Routine Description:
  360. ReplaceTableEntryStr replaces a string for a table
  361. entry. The specified string is duplicated.
  362. Arguments:
  363. TablePtr - Specifies the table holding the entry
  364. TableEntryPtr - Specifies the entry whos string is
  365. to be replaced
  366. NewString - Specifies the new string
  367. Return Value:
  368. TRUE if success, FALSE if failure.
  369. --*/
  370. {
  371. INT ch;
  372. PCTSTR p;
  373. //
  374. // First free all the resources associated wit the table entry
  375. //
  376. pFreeTableEntryPtr (
  377. TablePtr,
  378. TableEntryPtr,
  379. FALSE, // don't dealloc
  380. NULL // we don't need next entry ptr
  381. );
  382. //
  383. // Then duplicate the string and use it
  384. //
  385. TableEntryPtr->String = PoolMemDuplicateString (TablePtr->ReplacePool, NewString);
  386. TableEntryPtr->StringReplaced = (TableEntryPtr->String != NULL);
  387. //
  388. // Determine if new string needs quotes
  389. //
  390. TableEntryPtr->Quoted = FALSE;
  391. p = NewString;
  392. while (*p) {
  393. ch = _tcsnextc (p);
  394. if (ch < 32 || ch > 127 || ch == '\"') {
  395. TableEntryPtr->Quoted = TRUE;
  396. break;
  397. }
  398. p = _tcsinc (p);
  399. }
  400. return TableEntryPtr->StringReplaced;
  401. }
  402. BOOL
  403. pInsertTableEntry (
  404. IN OUT PSETUPTABLE TablePtr,
  405. IN UINT Line, // zero-based
  406. IN UINT Col,
  407. IN DWORD Flags,
  408. IN PCTSTR String, // ownership taken over
  409. IN BOOL Replaced
  410. )
  411. /*++
  412. Routine Description:
  413. pInsertTableEntry inserts a column into a line, and possibly
  414. creates the line if it does not exist.
  415. Arguments:
  416. TablePtr - Specifies the table to insert an entry into
  417. Line - Specifies the line to insert the entry on, or INSERT_LINE_LAST
  418. to add a line.
  419. Col - Specifies the column to insert before, or INSERT_LAST_COL to
  420. append to the end of the line.
  421. Flags - Specifies any of the following:
  422. FIELD_QUOTED
  423. FIELD_BINARY
  424. String - Specifies the string to insert.
  425. Replaced - Specifies TRUE if the text comes from the ReplacePool, or
  426. FALSE if it comes from the TextPool. All memory in ReplacePool
  427. must be freed, while all memory in the TextPool is freed at
  428. once during termination. (The TextPool is used for parsed
  429. strings, the ReplacePool is used for modifications.)
  430. Return Value:
  431. TRUE if success, FALSE if failure.
  432. --*/
  433. {
  434. PTABLELINE TableLinePtr;
  435. PTABLEENTRY NextTableEntryPtr, PrevTableEntryPtr, ThisTableEntryPtr;
  436. UINT OrgCol;
  437. BOOL Quoted;
  438. BOOL Binary;
  439. Quoted = (Flags & FIELD_QUOTED) != 0;
  440. Binary = (Flags & FIELD_BINARY) != 0;
  441. //
  442. // Make sure Line exists
  443. //
  444. TableLinePtr = pGetTableLinePtr (TablePtr, Line);
  445. if (!TableLinePtr) {
  446. //
  447. // Add a line to the end if Line is 1 more than the current count
  448. //
  449. if (Line > TablePtr->LineCount) {
  450. return FALSE;
  451. }
  452. TableLinePtr = pInsertEmptyLineInTable (TablePtr, INSERT_LINE_LAST);
  453. if (!TableLinePtr) {
  454. return FALSE;
  455. }
  456. }
  457. //
  458. // Locate the previous table entry (for linkage update)
  459. //
  460. PrevTableEntryPtr = NULL;
  461. OrgCol = Col;
  462. NextTableEntryPtr = pGetFirstTableEntryPtr (TablePtr, Line);
  463. while (Col > 0) {
  464. if (!NextTableEntryPtr) {
  465. if (OrgCol == INSERT_COL_LAST) {
  466. break;
  467. }
  468. DEBUGMSG ((DBG_WHOOPS, "pInsertTableEntry cannot insert beyond end of line"));
  469. return FALSE;
  470. }
  471. PrevTableEntryPtr = NextTableEntryPtr;
  472. NextTableEntryPtr = pGetNextTableEntryPtr (NextTableEntryPtr);
  473. Col--;
  474. }
  475. //
  476. // Allocate a new entry
  477. //
  478. ThisTableEntryPtr = (PTABLEENTRY) PoolMemGetAlignedMemory (
  479. TablePtr->ColumnStructPool,
  480. sizeof (TABLEENTRY)
  481. );
  482. if (!ThisTableEntryPtr) {
  483. return FALSE;
  484. }
  485. ZeroMemory (ThisTableEntryPtr, sizeof (TABLEENTRY));
  486. //
  487. // Adjust linkage
  488. //
  489. if (PrevTableEntryPtr) {
  490. PrevTableEntryPtr->Next = ThisTableEntryPtr;
  491. } else {
  492. TableLinePtr->FirstCol = ThisTableEntryPtr;
  493. }
  494. if (NextTableEntryPtr) {
  495. NextTableEntryPtr->Prev = ThisTableEntryPtr;
  496. }
  497. ThisTableEntryPtr->Next = NextTableEntryPtr;
  498. ThisTableEntryPtr->Prev = PrevTableEntryPtr;
  499. //
  500. // Fill members
  501. //
  502. ThisTableEntryPtr->Line = Line;
  503. ThisTableEntryPtr->Quoted = Quoted;
  504. ThisTableEntryPtr->Binary = Binary;
  505. ThisTableEntryPtr->String = String;
  506. ThisTableEntryPtr->StringReplaced = Replaced;
  507. //
  508. // Add to hash table
  509. //
  510. if (!PrevTableEntryPtr) {
  511. pAddToHashTable (TablePtr, String, LcharCount (String), Line);
  512. if ((UINT) _ttoi (String) > TablePtr->MaxObj) {
  513. TablePtr->MaxObj = (UINT) _ttoi (String);
  514. }
  515. }
  516. return TRUE;
  517. }
  518. VOID
  519. pFreeTableEntryPtr (
  520. IN OUT PSETUPTABLE TablePtr,
  521. IN PTABLEENTRY TableEntryPtr,
  522. IN BOOL DeallocateStruct,
  523. OUT PTABLEENTRY *NextTableEntryPtr OPTIONAL
  524. )
  525. /*++
  526. Routine Description:
  527. pFreeTableEntryPtr deallocates all resources associated with
  528. a table entry and is used for the delete routines.
  529. Arguments:
  530. TablePtr - Specifies the table containing the entyr
  531. TableEntryPtr - Specifies the table entry to free
  532. DeallocateStruct - Specifies TRUE to completely deallocate the
  533. entry, or FALSE if the entry is to be reset
  534. but not deallocated.
  535. NextTableEntryPtr - Receives a pointer to the next table entry,
  536. useful for deleting a chain of entries.
  537. Return Value:
  538. TRUE if success, FALSE if failure.
  539. --*/
  540. {
  541. //
  542. // Give caller a pointer to the next table entry if requested
  543. //
  544. if (NextTableEntryPtr) {
  545. *NextTableEntryPtr = TableEntryPtr->Next;
  546. }
  547. //
  548. // Free any text pointers
  549. //
  550. pFreeTableEntryString (TablePtr, TableEntryPtr);
  551. //
  552. // Free the struct if necessary
  553. //
  554. if (DeallocateStruct) {
  555. PoolMemReleaseMemory (TablePtr->ColumnStructPool, TableEntryPtr);
  556. }
  557. }
  558. BOOL
  559. pDeleteTableEntry (
  560. IN OUT PSETUPTABLE TablePtr,
  561. IN PTABLEENTRY EntryToDeletePtr
  562. )
  563. /*++
  564. Routine Description:
  565. pDeleteTableEntry removes the specific table line, adjusts the
  566. SETUPTABLE struct accordingly, and cleans up resources.
  567. Arguments:
  568. TablePtr - Specifies the table to process
  569. EntryToDeletePtr - Specifies the entry to delete from the table
  570. Return Value:
  571. TRUE if success, FALSE if failure.
  572. --*/
  573. {
  574. PTABLELINE TableLinePtr;
  575. //
  576. // Update linkage
  577. //
  578. if (EntryToDeletePtr->Prev) {
  579. EntryToDeletePtr->Prev->Next = EntryToDeletePtr->Next;
  580. } else {
  581. TableLinePtr = pGetTableLinePtr (TablePtr, EntryToDeletePtr->Line);
  582. MYASSERT(TableLinePtr);
  583. TableLinePtr->FirstCol = EntryToDeletePtr->Next;
  584. }
  585. if (EntryToDeletePtr->Next) {
  586. EntryToDeletePtr->Next->Prev = EntryToDeletePtr->Prev;
  587. }
  588. // Deallocate the entry's resources
  589. pFreeTableEntryPtr (
  590. TablePtr,
  591. EntryToDeletePtr,
  592. TRUE, // dealloc
  593. NULL // we don't need the next entry ptr
  594. );
  595. return TRUE;
  596. }
  597. UINT
  598. pGetColFromTableEntryPtr (
  599. IN PSETUPTABLE TablePtr,
  600. IN PTABLEENTRY FindMePtr
  601. )
  602. /*++
  603. Routine Description:
  604. pGetColFromTableEntryPtr returns the column number of the specified
  605. table entry.
  606. Arguments:
  607. TablePtr - Specifies the table to process
  608. FindMePtr - Specifies the table entry to find
  609. Return Value:
  610. The zero-based column number, or INVALID_COL if the column was not
  611. found.
  612. --*/
  613. {
  614. UINT Col;
  615. PTABLEENTRY ColSearchPtr;
  616. MYASSERT(FindMePtr);
  617. Col = 0;
  618. ColSearchPtr = pGetFirstTableEntryPtr (TablePtr, FindMePtr->Line);
  619. while (ColSearchPtr && ColSearchPtr != FindMePtr) {
  620. Col++;
  621. ColSearchPtr = pGetNextTableEntryPtr (ColSearchPtr);
  622. }
  623. if (!ColSearchPtr) {
  624. DEBUGMSG ((DBG_WHOOPS, "Col not found for specified entry"));
  625. return INVALID_COL;
  626. }
  627. return Col;
  628. }
  629. BOOL
  630. InsertTableEntryStr (
  631. IN OUT PSETUPTABLE TablePtr,
  632. IN PTABLEENTRY InsertBeforePtr,
  633. IN PCTSTR NewString
  634. )
  635. /*++
  636. Routine Description:
  637. InsertTableEntryStr inserts a string in a line, shifting columns to the
  638. right. This routine increases the number of columns on the line.
  639. To append a string to the line, call AppendTableEntryStr instead.
  640. Arguments:
  641. TablePtr - Specifies the table to process
  642. InsertBeforePtr - Specifies the column to insert the string ahead of.
  643. Return Value:
  644. TRUE if success, FALSE if failure.
  645. --*/
  646. {
  647. UINT Col;
  648. PCTSTR DupStr;
  649. MYASSERT (NewString);
  650. MYASSERT (InsertBeforePtr);
  651. Col = pGetColFromTableEntryPtr (TablePtr, InsertBeforePtr);
  652. if (Col == INVALID_COL) {
  653. return FALSE;
  654. }
  655. DupStr = PoolMemDuplicateString (TablePtr->ReplacePool, NewString);
  656. if (!DupStr) {
  657. return FALSE;
  658. }
  659. return pInsertTableEntry (
  660. TablePtr,
  661. InsertBeforePtr->Line,
  662. Col,
  663. 0, // not quoted, not binary
  664. DupStr,
  665. TRUE // from ReplacePool
  666. );
  667. }
  668. BOOL
  669. DeleteTableEntryStr (
  670. IN OUT PSETUPTABLE TablePtr,
  671. IN PTABLEENTRY DeleteEntryPtr
  672. )
  673. /*++
  674. Routine Description:
  675. DeleteTableEntryStr removes the specific table entry, shifting columns
  676. to the left. This routine reduces the number of columns on the line by
  677. one.
  678. Arguments:
  679. TablePtr - Specifies the table to process
  680. DeleteEntryPtr - Specifies the entry to delete from the table
  681. Return Value:
  682. TRUE if success, FALSE if failure.
  683. --*/
  684. {
  685. return pDeleteTableEntry (TablePtr, DeleteEntryPtr);
  686. }
  687. BOOL
  688. AppendTableEntryStr (
  689. IN OUT PSETUPTABLE TablePtr,
  690. IN UINT Line,
  691. IN PCTSTR NewString
  692. )
  693. /*++
  694. Routine Description:
  695. AppendTableEntryStr adds a new column to the end of the specified
  696. line, increasing the number of columns on the line by one.
  697. Arguments:
  698. TablePtr - Specifies the table to process
  699. Line - Specifies the zero-based line to append to
  700. NewString - Specifies the text for the new column
  701. Return Value:
  702. TRUE if success, FALSE if failure.
  703. --*/
  704. {
  705. PCTSTR DupStr;
  706. MYASSERT (NewString);
  707. DupStr = PoolMemDuplicateString (TablePtr->ReplacePool, NewString);
  708. if (!DupStr) {
  709. return FALSE;
  710. }
  711. return pInsertTableEntry (
  712. TablePtr,
  713. Line,
  714. INSERT_COL_LAST,
  715. 0, // not quoted, not binary
  716. DupStr,
  717. TRUE // from ReplacePool
  718. );
  719. }
  720. BOOL
  721. AppendTableEntry (
  722. IN OUT PSETUPTABLE TablePtr,
  723. IN UINT DestLine,
  724. IN PTABLEENTRY SrcEntry
  725. )
  726. /*++
  727. Routine Description:
  728. AppendTableEntry adds a new column to the end of the specified
  729. line, increasing the number of columns on the line by one. It
  730. copies the data specified from the entry, including the formatting
  731. information.
  732. Arguments:
  733. TablePtr - Specifies the table to process
  734. DestLine - Specifies the zero-based line to append to
  735. SrcEntry - Specifies the entry to duplicate to the new column
  736. Return Value:
  737. TRUE if success, FALSE if failure.
  738. --*/
  739. {
  740. PCTSTR DupStr;
  741. MYASSERT (SrcEntry);
  742. MYASSERT (SrcEntry->String);
  743. DupStr = PoolMemDuplicateString (TablePtr->ReplacePool, SrcEntry->String);
  744. if (!DupStr) {
  745. return FALSE;
  746. }
  747. return pInsertTableEntry (
  748. TablePtr,
  749. DestLine,
  750. INSERT_COL_LAST,
  751. SrcEntry->Quoted ? FIELD_QUOTED : 0,
  752. DupStr,
  753. TRUE // from ReplacePool
  754. );
  755. }
  756. PTABLEENTRY
  757. FindTableEntry (
  758. IN PSETUPTABLE TablePtr,
  759. IN PCTSTR FirstColText,
  760. IN UINT Col,
  761. OUT PUINT Line, OPTIONAL
  762. OUT PCTSTR *String OPTIONAL
  763. )
  764. /*++
  765. Routine Description:
  766. FindTableEntry searches the setup table for caller-specified text
  767. by scaning the first column. This routine is fast because it
  768. first searches a hash table to determine if the string actually
  769. exists in the table.
  770. While the search is done on the first column, the routine actually
  771. returns the column specified by the Col parameter.
  772. Arguments:
  773. TablePtr - Specifies the table to process
  774. FirstColText - Specifies the text to find
  775. Col - Specifies the column to return
  776. Return Value:
  777. TRUE if success, FALSE if failure.
  778. --*/
  779. {
  780. PHASHBUCKET BucketPtr;
  781. UINT Item;
  782. BucketPtr = pFindInHashTable (TablePtr, FirstColText, &Item);
  783. if (!BucketPtr) {
  784. //
  785. // Not found
  786. //
  787. return NULL;
  788. }
  789. if (Line) {
  790. *Line = BucketPtr->Elements[Item];
  791. }
  792. return GetTableEntry (TablePtr, BucketPtr->Elements[Item], Col, String);
  793. }
  794. PTABLELINE
  795. pInsertEmptyLineInTable (
  796. IN OUT PSETUPTABLE TablePtr,
  797. IN UINT InsertBeforeLine
  798. )
  799. /*++
  800. Routine Description:
  801. pInsertEmptyLineInTable creates a table line that has no columns. This
  802. routine is used to establish a line where columns can be added.
  803. Arguments:
  804. TablePtr - Specifies the table to process
  805. InsertBeforeLine - Specifies the line that is moved down to make room for
  806. the blank line
  807. Return Value:
  808. A pointer to the new line, or NULL if the routine fails.
  809. --*/
  810. {
  811. PTABLELINE LastLinePtr;
  812. PTABLELINE InsertBeforePtr = NULL;
  813. UINT BytesToMove;
  814. //
  815. // Validate InsertBeforeLine
  816. //
  817. if (InsertBeforeLine != INSERT_LINE_LAST) {
  818. InsertBeforePtr = pGetTableLinePtr (TablePtr, InsertBeforeLine);
  819. if (!InsertBeforePtr) {
  820. LOG ((
  821. LOG_ERROR,
  822. "Can't find InsertBeforeLine (which is %u, total lines=%u)",
  823. InsertBeforeLine,
  824. TablePtr->LineCount
  825. ));
  826. return NULL;
  827. }
  828. }
  829. //
  830. // Grow the array
  831. //
  832. LastLinePtr = (PTABLELINE) GrowBuffer (&TablePtr->Lines, sizeof (TABLELINE));
  833. if (!LastLinePtr) {
  834. return NULL;
  835. }
  836. ZeroMemory (LastLinePtr, sizeof (TABLELINE));
  837. //
  838. // If adding to the end, simply inc line count
  839. //
  840. TablePtr->LineCount++;
  841. if (InsertBeforeLine == INSERT_LINE_LAST) {
  842. return LastLinePtr;
  843. }
  844. //
  845. // Otherwise move memory to make room for new entry
  846. //
  847. BytesToMove = sizeof (TABLELINE) * (TablePtr->LineCount - InsertBeforeLine);
  848. MoveMemory (&InsertBeforePtr[1], InsertBeforePtr, BytesToMove);
  849. //
  850. // Zero new entry
  851. //
  852. ZeroMemory (InsertBeforePtr, sizeof (TABLELINE));
  853. return InsertBeforePtr;
  854. }
  855. BOOL
  856. InsertEmptyLineInTable (
  857. IN OUT PSETUPTABLE TablePtr,
  858. IN UINT InsertBeforeLine
  859. )
  860. /*++
  861. Routine Description:
  862. InsertEmptyLineInTable is a wrapper of pInsertEmptyLineInTable and is
  863. used by callers who shouldn't have knowledge of the TABLELINE struct.
  864. Arguments:
  865. TablePtr - Specifies the table to process
  866. InsertBeforeLine - Specifies the line that is moved down to make room for
  867. the blank line
  868. Return Value:
  869. TRUE if success, FALSE if failure.
  870. --*/
  871. {
  872. if (InsertBeforeLine == TablePtr->LineCount) {
  873. InsertBeforeLine = INSERT_LINE_LAST;
  874. }
  875. if (!pInsertEmptyLineInTable (TablePtr, InsertBeforeLine)) {
  876. return FALSE;
  877. }
  878. return TRUE;
  879. }
  880. BOOL
  881. DeleteLineInTable (
  882. IN OUT PSETUPTABLE TablePtr,
  883. IN UINT LineToDelete
  884. )
  885. /*++
  886. Routine Description:
  887. DeleteLineInTable removes a complete line from the table, cleaning up
  888. all resources used by the line structs.
  889. Arguments:
  890. TablePtr - Specifies the table to process
  891. LineToDelete - Specifies the line to delete from the table. This line
  892. is validated before delete occurs.
  893. Return Value:
  894. TRUE if success, FALSE if failure.
  895. --*/
  896. {
  897. PTABLELINE DeletePtr;
  898. PTABLEENTRY TableEntryPtr;
  899. UINT BytesToMove;
  900. //
  901. // Validate line number
  902. //
  903. DeletePtr = pGetTableLinePtr (TablePtr, LineToDelete);
  904. if (!DeletePtr) {
  905. LOG ((
  906. LOG_ERROR,
  907. "Can't find LineToDelete (which is %u, total lines=%u)",
  908. LineToDelete,
  909. TablePtr->LineCount
  910. ));
  911. return FALSE;
  912. }
  913. //
  914. // Free the entire line's entries
  915. //
  916. TableEntryPtr = pGetFirstTableEntryPtr (TablePtr, LineToDelete);
  917. while (TableEntryPtr) {
  918. pFreeTableEntryPtr (
  919. TablePtr,
  920. TableEntryPtr,
  921. TRUE, // dealloc
  922. &TableEntryPtr
  923. );
  924. }
  925. //
  926. // If not deleting the last line, move memory
  927. //
  928. TablePtr->LineCount--;
  929. if (TablePtr->LineCount != LineToDelete) {
  930. BytesToMove = sizeof (TABLELINE) * (TablePtr->LineCount + 1 - LineToDelete);
  931. MoveMemory (DeletePtr, &DeletePtr[1], BytesToMove);
  932. }
  933. //
  934. // Adjust growbuffer
  935. //
  936. TablePtr->Lines.End -= sizeof (TABLELINE);
  937. return TRUE;
  938. }
  939. //
  940. // .STF file parser
  941. //
  942. PSTR
  943. pIncrementStrPos (
  944. IN PCSTR p,
  945. IN PCSTR End
  946. )
  947. /*++
  948. Routine Description:
  949. Increments the specified string pointer, returning NULL if the pointer
  950. is incremented beyond the specified end.
  951. Arguments:
  952. p - Specifies the pointer to increment
  953. End - Specifies the address of the first character beyond the end
  954. Return Value:
  955. The incremented pointer, or NULL if the pointer extends beyond the end.
  956. --*/
  957. {
  958. if (!p || p >= End) {
  959. return NULL;
  960. }
  961. if (p + 1 == End) {
  962. return NULL;
  963. }
  964. return _mbsinc (p);
  965. }
  966. MBCHAR
  967. pGetCharAtStrPos (
  968. IN PCSTR p,
  969. IN PCSTR End
  970. )
  971. /*++
  972. Routine Description:
  973. pGetCharAtStrPos returns the DBCS character at the specified position.
  974. It returns an incomplete character of a DBCS lead byte is at the end
  975. of the file, and it returns \n if the pointer is beyond the end of the
  976. file.
  977. Arguments:
  978. p - Specifies the address to get the character
  979. End - Specifies the address of the first character beyond the end
  980. Return Value:
  981. The DBCS character at position p.
  982. --*/
  983. {
  984. if (!p || p >= End) {
  985. return '\n';
  986. }
  987. if (p + 1 == End) {
  988. return *p;
  989. }
  990. return _mbsnextc (p);
  991. }
  992. BOOL
  993. pIsCharColSeperator (
  994. IN MBCHAR ch
  995. )
  996. /*++
  997. Routine Description:
  998. pIsCharColSeparator returns TRUE if the specified character can be used
  999. to separate columns in an STF file. The list of characters comes from
  1000. the STF spec.
  1001. Arguments:
  1002. ch - Specifies the character to examine
  1003. Return Value:
  1004. TRUE if the character is a column separator, or FALSE if it is not.
  1005. --*/
  1006. {
  1007. return ch == '\t' || ch == '\r' || ch == '\n';
  1008. }
  1009. PCSTR
  1010. pCreateDbcsStr (
  1011. IN POOLHANDLE Pool,
  1012. IN PCSTR Text,
  1013. IN UINT ByteCount
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. pCreateDbcsStr allocates a string from the specifies pool and copies
  1018. the data up to a specified byte count.
  1019. Arguments:
  1020. Pool - Specifies the pool to allocate memory from
  1021. Text - Specifies the source string to copy into the newly allocated string
  1022. ByteCount - Specifies the length of the source string, in bytes
  1023. Return Value:
  1024. A pointer to the zero-terminated string, or NULL if memory could not
  1025. be allocated.
  1026. --*/
  1027. {
  1028. UINT Size;
  1029. PSTR p;
  1030. Size = ByteCount + 1;
  1031. p = (PSTR) PoolMemGetAlignedMemory (Pool, Size);
  1032. if (!p) {
  1033. return NULL;
  1034. }
  1035. CopyMemory (p, Text, ByteCount);
  1036. p[ByteCount] = 0;
  1037. return p;
  1038. }
  1039. BOOL
  1040. pParseLine (
  1041. IN OUT PSETUPTABLE TablePtr,
  1042. IN PCSTR FileText,
  1043. IN UINT MaxOffset,
  1044. IN UINT StartOffset,
  1045. OUT PUINT EndOffset,
  1046. IN OUT PUINT LinePtr
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. pParseLine scans the STF file, extracting the current line, updating
  1051. the SETUPTABLE structure, and returning the offset to the next line.
  1052. Arguments:
  1053. TablePtr - Specifies the table to process
  1054. FileText - Specifies the complete file text (mapped in to memory)
  1055. MaxOffset - Specifies the number of bytes in FileText
  1056. StartOffset - Specifies the offset of the start of the current line
  1057. EndOffset - Receives the offset to the start of the next line
  1058. LinePtr - Specifies the current line number and is incremented
  1059. Return Value:
  1060. TRUE if the line was parsed successfully, or FALSE if an error was
  1061. encountered.
  1062. --*/
  1063. {
  1064. PCSTR p, q;
  1065. PCSTR LastNonSpace;
  1066. MBCHAR ch = 0;
  1067. PCSTR End;
  1068. PCSTR Start;
  1069. UINT Length;
  1070. BOOL QuoteMode;
  1071. PCSTR QuoteStart, QuoteEnd;
  1072. PCTSTR Text;
  1073. UINT Chars;
  1074. PCSTR CopyStart;
  1075. PBYTE CopyDest;
  1076. #ifdef UNICODE
  1077. PCSTR UnquotedAnsiText;
  1078. #endif
  1079. End = &FileText[MaxOffset];
  1080. Start = &FileText[StartOffset];
  1081. if (Start >= End) {
  1082. SetLastError (ERROR_SUCCESS);
  1083. return FALSE;
  1084. }
  1085. //
  1086. // Special case: Setup Status is a binary line
  1087. //
  1088. if (StringIMatchTcharCountA (Start, "Setup Status\t", 13)) {
  1089. //
  1090. // Locate the end of the line. We know it must have "\r\n at the end.
  1091. // When the loop completes, p will point to the character after the
  1092. // ending dbl quote, and q will point to the \n in the line.
  1093. //
  1094. p = Start;
  1095. q = NULL;
  1096. do {
  1097. if (*p == 0) {
  1098. LOG ((LOG_ERROR, "Nul found in STF status!"));
  1099. return FALSE;
  1100. }
  1101. ch = pGetCharAtStrPos (p, End);
  1102. if (ch == '\r') {
  1103. //
  1104. // Break while loop when line break is found
  1105. //
  1106. q = pIncrementStrPos (p, End);
  1107. ch = pGetCharAtStrPos (q, End);
  1108. if (ch != '\n') {
  1109. q = p;
  1110. }
  1111. break;
  1112. } else if (ch == '\n') {
  1113. break;
  1114. }
  1115. p = pIncrementStrPos (p, End);
  1116. } while (p);
  1117. MYASSERT (p); // we did not hit the end of the file
  1118. MYASSERT (q); // we have a valid end-of-line pointer
  1119. if (!p || !q) {
  1120. return FALSE;
  1121. }
  1122. //
  1123. // Copy binary line into buffer. We know that the binary line cannot have
  1124. // \r, \n or nul in it. Terminate the line with a nul.
  1125. //
  1126. Length = p - Start;
  1127. CopyDest = (PBYTE) PoolMemGetAlignedMemory (TablePtr->TextPool, Length + 2);
  1128. if (!CopyDest) {
  1129. return FALSE;
  1130. }
  1131. CopyMemory (CopyDest, Start, Length);
  1132. CopyDest[Length] = 0;
  1133. CopyDest[Length + 1] = 0;
  1134. //
  1135. // Add binary line as a single field
  1136. //
  1137. if (!pInsertTableEntry (
  1138. TablePtr,
  1139. *LinePtr,
  1140. INSERT_COL_LAST,
  1141. FIELD_BINARY,
  1142. (PCTSTR) CopyDest,
  1143. FALSE // from text pool
  1144. )) {
  1145. return FALSE;
  1146. }
  1147. //
  1148. // Advance pointer beyond end of line and return
  1149. //
  1150. q++;
  1151. *EndOffset = q - FileText;
  1152. *LinePtr += 1;
  1153. return TRUE;
  1154. }
  1155. //
  1156. // Normal case: line is all text
  1157. //
  1158. p = Start;
  1159. QuoteMode = FALSE;
  1160. QuoteStart = NULL;
  1161. QuoteEnd = NULL;
  1162. //
  1163. // Find item in tab-separated list
  1164. //
  1165. while (p) {
  1166. if (*p == 0) {
  1167. LOG ((LOG_ERROR, "Nul found in STF field!"));
  1168. return FALSE;
  1169. }
  1170. ch = pGetCharAtStrPos (p, End);
  1171. if (ch == '\"') {
  1172. if (!QuoteMode && p == Start) {
  1173. QuoteMode = TRUE;
  1174. p = pIncrementStrPos (p, End);
  1175. QuoteStart = p;
  1176. continue;
  1177. } else if (QuoteMode) {
  1178. q = pIncrementStrPos (p, End);
  1179. if (!q || pGetCharAtStrPos (q, End) != '\"') {
  1180. QuoteEnd = p;
  1181. QuoteMode = FALSE;
  1182. p = q;
  1183. continue;
  1184. } else {
  1185. p = q;
  1186. }
  1187. }
  1188. }
  1189. if (!QuoteMode) {
  1190. if (pIsCharColSeperator (ch)) {
  1191. break;
  1192. }
  1193. } else {
  1194. if (pIsCharColSeperator (ch) && ch != '\t') {
  1195. QuoteEnd = p;
  1196. QuoteMode = FALSE;
  1197. break;
  1198. }
  1199. }
  1200. p = pIncrementStrPos (p, End);
  1201. }
  1202. if (!p) {
  1203. p = End;
  1204. }
  1205. if (QuoteStart && QuoteEnd) {
  1206. StartOffset = QuoteStart - FileText;
  1207. Length = QuoteEnd - QuoteStart;
  1208. } else {
  1209. //
  1210. // Trim spaces on both sides of string
  1211. //
  1212. //
  1213. // Find first non space in string
  1214. //
  1215. q = Start;
  1216. while (pGetCharAtStrPos (q, End) == ' ' && q < p) {
  1217. q = pIncrementStrPos (q, End);
  1218. }
  1219. if (q) {
  1220. StartOffset = q - FileText;
  1221. //
  1222. // Find last non space in string
  1223. //
  1224. LastNonSpace = q;
  1225. Start = q;
  1226. while (q && q < p) {
  1227. if (pGetCharAtStrPos (q, End) != ' ') {
  1228. LastNonSpace = q;
  1229. }
  1230. q = pIncrementStrPos (q, End);
  1231. }
  1232. if (!q) {
  1233. LastNonSpace = p;
  1234. } else {
  1235. LastNonSpace = pIncrementStrPos (LastNonSpace, End);
  1236. if (!LastNonSpace || LastNonSpace > p) {
  1237. LastNonSpace = p;
  1238. }
  1239. }
  1240. Length = LastNonSpace - Start;
  1241. } else {
  1242. StartOffset = Start - FileText;
  1243. Length = p - Start;
  1244. }
  1245. }
  1246. if (Length > 1024) {
  1247. SetLastError (ERROR_BAD_FORMAT);
  1248. return FALSE;
  1249. }
  1250. //
  1251. // Remove pairs of dbl quotes
  1252. //
  1253. CopyStart = &FileText[StartOffset];
  1254. Chars = ByteCountToCharsA (CopyStart, Length);
  1255. if (QuoteStart != NULL && QuoteEnd != NULL) {
  1256. #ifdef UNICODE
  1257. UnquotedAnsiText = pGenerateUnquotedText (
  1258. TablePtr->ReplacePool,
  1259. CopyStart,
  1260. Chars
  1261. );
  1262. //
  1263. // Convert text to UNICODE
  1264. //
  1265. Text = DbcsToUnicode (TablePtr->TextPool, UnquotedAnsiText);
  1266. PoolMemReleaseMemory (TablePtr->ReplacePool, (PVOID) UnquotedAnsiText);
  1267. if (!Text) {
  1268. return FALSE;
  1269. }
  1270. #else
  1271. //
  1272. // No conversion needed for DBCS
  1273. //
  1274. Text = pGenerateUnquotedText (
  1275. TablePtr->TextPool,
  1276. CopyStart,
  1277. Chars
  1278. );
  1279. #endif
  1280. } else {
  1281. //
  1282. // For text that didn't need quote processing, allocate a
  1283. // string in TextPool
  1284. //
  1285. #ifdef UNICODE
  1286. Text = DbcsToUnicodeN (TablePtr->TextPool, CopyStart, Chars);
  1287. #else
  1288. Text = pCreateDbcsStr (TablePtr->TextPool, CopyStart, Length);
  1289. #endif
  1290. if (!Text) {
  1291. return FALSE;
  1292. }
  1293. }
  1294. if (!pInsertTableEntry (
  1295. TablePtr,
  1296. *LinePtr,
  1297. INSERT_COL_LAST,
  1298. QuoteStart != NULL && QuoteEnd != NULL ? FIELD_QUOTED : 0,
  1299. Text,
  1300. FALSE // from text pool
  1301. )) {
  1302. return FALSE;
  1303. }
  1304. //
  1305. // Find next item
  1306. //
  1307. if (ch == '\r' || ch == '\n') {
  1308. *LinePtr += 1;
  1309. }
  1310. if (ch == '\r' && p < End) {
  1311. q = pIncrementStrPos (p, End);
  1312. if (pGetCharAtStrPos (q, End) == '\n') {
  1313. p = q;
  1314. }
  1315. }
  1316. p = pIncrementStrPos (p, End);
  1317. if (!p) {
  1318. p = End;
  1319. }
  1320. *EndOffset = p - FileText;
  1321. return TRUE;
  1322. }
  1323. VOID
  1324. pResetTableStruct (
  1325. OUT PSETUPTABLE TablePtr
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. pResetTableStruct initializes the specified table
  1330. Arguments:
  1331. TablePtr - Specifies the uninitialized table struct
  1332. Return Value:
  1333. none
  1334. --*/
  1335. {
  1336. ZeroMemory (TablePtr, sizeof (SETUPTABLE));
  1337. TablePtr->SourceStfFile = INVALID_HANDLE_VALUE;
  1338. TablePtr->SourceInfFile = INVALID_HANDLE_VALUE;
  1339. TablePtr->DestStfFile = INVALID_HANDLE_VALUE;
  1340. TablePtr->DestInfFile = INVALID_HANDLE_VALUE;
  1341. TablePtr->SourceInfHandle = INVALID_HANDLE_VALUE;
  1342. }
  1343. BOOL
  1344. pCreateViewOfFile (
  1345. IN OUT PSETUPTABLE TablePtr,
  1346. IN UINT FileSize
  1347. )
  1348. /*++
  1349. Routine Description:
  1350. pCreateViewOfFile establishes a pointer that points to a continuous
  1351. buffer for the file.
  1352. Arguments:
  1353. TablePtr - Specifies the table that provides file names, handles and
  1354. so on.
  1355. FileSize - Specifies the size of the STF file
  1356. Return Value:
  1357. TRUE if the file was read or mapped into memory, FALSE if an error
  1358. occurred.
  1359. --*/
  1360. {
  1361. #if USE_FILE_MAPPING
  1362. TablePtr->FileMapping = CreateFileMapping (
  1363. TablePtr->SourceStfFile,
  1364. NULL,
  1365. PAGE_READONLY|SEC_RESERVE,
  1366. 0,
  1367. 0,
  1368. NULL
  1369. );
  1370. if (!TablePtr->FileMapping) {
  1371. LOG ((LOG_ERROR, "Create Setup Table: Can't create file mapping."));
  1372. return FALSE;
  1373. }
  1374. TablePtr->FileText = (PCSTR) MapViewOfFile (
  1375. TablePtr->FileMapping,
  1376. FILE_MAP_READ,
  1377. 0, // start offset high
  1378. 0, // start offset low
  1379. 0 // bytes to map - 0=all
  1380. );
  1381. if (!TablePtr->FileText) {
  1382. LOG ((LOG_ERROR, "Create Setup Table: Can't map file into memory."));
  1383. return FALSE;
  1384. }
  1385. #else
  1386. TablePtr->FileText = MemAlloc (g_hHeap, 0, FileSize);
  1387. if (!TablePtr->FileText) {
  1388. LOG ((LOG_ERROR, "Create Setup Table: Cannot allocate %u bytes", FileSize));
  1389. return FALSE;
  1390. }
  1391. SetFilePointer (TablePtr->SourceStfFile, 0, NULL, FILE_BEGIN);
  1392. if (!ReadFile (
  1393. TablePtr->SourceStfFile,
  1394. (PBYTE) (TablePtr->FileText),
  1395. FileSize,
  1396. &Offset,
  1397. NULL
  1398. )) {
  1399. LOG ((LOG_ERROR, "Create Setup Table: Cannot read %u bytes", FileSize));
  1400. return FALSE;
  1401. }
  1402. #endif
  1403. return TRUE;
  1404. }
  1405. VOID
  1406. pFreeViewOfFile (
  1407. IN OUT PSETUPTABLE TablePtr
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. pFreeViewOfFile cleans up the resources allocated by pCreateViewOfFile.
  1412. Arguments:
  1413. TablePtr - Specifies the table to process
  1414. Return Value:
  1415. none
  1416. --*/
  1417. {
  1418. #ifdef USE_FILE_MAPPING
  1419. //
  1420. // Free all views of the file
  1421. //
  1422. if (TablePtr->FileText) {
  1423. UnmapViewOfFile (TablePtr->FileText);
  1424. }
  1425. //
  1426. // Close file mapping handle
  1427. //
  1428. if (TablePtr->FileMapping) {
  1429. CloseHandle (TablePtr->FileMapping);
  1430. TablePtr->FileMapping = NULL;
  1431. }
  1432. #else
  1433. //
  1434. // Free memory used for file
  1435. //
  1436. if (TablePtr->FileText) {
  1437. MemFree (g_hHeap, 0, TablePtr->FileText);
  1438. TablePtr->FileText = NULL;
  1439. }
  1440. #endif
  1441. }
  1442. BOOL
  1443. CreateSetupTable (
  1444. IN PCTSTR SourceStfFileSpec,
  1445. OUT PSETUPTABLE TablePtr
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. CreateSetupTable is the master STF parsing routine. Given a file
  1450. spec, it performs all steps necessary to prepare the SETUPTABLE
  1451. structure so that other routines can access and modify the table.
  1452. Arguments:
  1453. SourceStfFileSpec - Specifies the STF file name to open
  1454. TablePtr - Receives all data structures needed to manipulate the
  1455. STF, including the INF associated with it.
  1456. Return Value:
  1457. TRUE if parsing was successful, or FALSE if an error occurred.
  1458. --*/
  1459. {
  1460. UINT Offset;
  1461. BOOL b = FALSE;
  1462. UINT FileSize;
  1463. UINT LineNum;
  1464. PCTSTR Text;
  1465. TCHAR DestSpec[MAX_TCHAR_PATH];
  1466. TCHAR DirSpec[MAX_TCHAR_PATH];
  1467. PTSTR FilePart;
  1468. pResetTableStruct (TablePtr);
  1469. __try {
  1470. //
  1471. // Extract directory from SourceStfFileSpec
  1472. //
  1473. if (!OurGetFullPathName (SourceStfFileSpec, MAX_TCHAR_PATH, DirSpec, &FilePart)) {
  1474. LOG ((LOG_ERROR, "Create Setup Table: GetFullPathName failed"));
  1475. __leave;
  1476. }
  1477. if (FilePart) {
  1478. FilePart = _tcsdec2 (DirSpec, FilePart);
  1479. MYASSERT (FilePart);
  1480. if (FilePart) {
  1481. *FilePart = 0;
  1482. }
  1483. }
  1484. //
  1485. // Allocate memory pools
  1486. //
  1487. TablePtr->ColumnStructPool = PoolMemInitNamedPool ("STF: Column Structs");
  1488. TablePtr->ReplacePool = PoolMemInitNamedPool ("STF: Replacement Text");
  1489. TablePtr->TextPool = PoolMemInitNamedPool ("STF: Read-Only Text");
  1490. TablePtr->InfPool = PoolMemInitNamedPool("STF: INF structs");
  1491. if (!TablePtr->ColumnStructPool ||
  1492. !TablePtr->ReplacePool ||
  1493. !TablePtr->TextPool ||
  1494. !TablePtr->InfPool
  1495. ) {
  1496. DEBUGMSG ((DBG_WARNING, "CreateSetupTable: Could not allocate a pool"));
  1497. __leave;
  1498. }
  1499. //
  1500. // Disable checked-build tracking on these pools
  1501. //
  1502. PoolMemDisableTracking (TablePtr->ColumnStructPool);
  1503. PoolMemDisableTracking (TablePtr->TextPool);
  1504. PoolMemDisableTracking (TablePtr->ReplacePool);
  1505. PoolMemDisableTracking (TablePtr->InfPool);
  1506. if (!pInitHashTable (TablePtr)) {
  1507. DEBUGMSG ((DBG_WARNING, "CreateSetupTable: Could not init hash table"));
  1508. __leave;
  1509. }
  1510. //
  1511. // Open STF file
  1512. //
  1513. TablePtr->SourceStfFile = CreateFile (
  1514. SourceStfFileSpec,
  1515. GENERIC_READ,
  1516. 0,
  1517. NULL,
  1518. OPEN_EXISTING,
  1519. FILE_ATTRIBUTE_NORMAL,
  1520. NULL
  1521. );
  1522. if (TablePtr->SourceStfFile == INVALID_HANDLE_VALUE) {
  1523. LOG ((LOG_ERROR, "Create Setup Table: Could not open %s", SourceStfFileSpec));
  1524. __leave;
  1525. }
  1526. //
  1527. // Limit file size to 4M
  1528. //
  1529. FileSize = SetFilePointer (TablePtr->SourceStfFile, 0, NULL, FILE_END);
  1530. if (FileSize > 0x400000) {
  1531. LOG ((LOG_ERROR, "Create Setup Table: File too big to parse"));
  1532. __leave;
  1533. }
  1534. //
  1535. // Copy SourceStfFileSpec to table struct
  1536. //
  1537. TablePtr->SourceStfFileSpec = PoolMemDuplicateString (
  1538. TablePtr->ReplacePool,
  1539. SourceStfFileSpec
  1540. );
  1541. if (!TablePtr->SourceStfFileSpec) {
  1542. __leave;
  1543. }
  1544. //
  1545. // Copy DirSpec to table struct
  1546. //
  1547. TablePtr->DirSpec = PoolMemDuplicateString (TablePtr->ReplacePool, DirSpec);
  1548. if (!TablePtr->DirSpec) {
  1549. __leave;
  1550. }
  1551. //
  1552. // Generate DestStfFileSpec but do not open yet (see WriteSetupTable)
  1553. //
  1554. _tcssafecpy (DestSpec, TablePtr->SourceStfFileSpec, MAX_TCHAR_PATH - 4);
  1555. StringCat (DestSpec, TEXT(".$$$"));
  1556. TablePtr->DestStfFileSpec = PoolMemDuplicateString (
  1557. TablePtr->ReplacePool,
  1558. DestSpec
  1559. );
  1560. if (!TablePtr->DestStfFileSpec) {
  1561. __leave;
  1562. }
  1563. //
  1564. // Map the file into memory
  1565. //
  1566. if (!pCreateViewOfFile (TablePtr, FileSize)) {
  1567. __leave;
  1568. }
  1569. //
  1570. // Parse each line of the file until there are no more lines left
  1571. //
  1572. Offset = 0;
  1573. LineNum = 0;
  1574. while (TRUE) {
  1575. if (!pParseLine (
  1576. TablePtr,
  1577. TablePtr->FileText,
  1578. FileSize,
  1579. Offset,
  1580. &Offset,
  1581. &LineNum
  1582. )) {
  1583. if (GetLastError() != ERROR_SUCCESS) {
  1584. __leave;
  1585. }
  1586. break;
  1587. }
  1588. }
  1589. //
  1590. // Obtain name of INF file
  1591. //
  1592. if (!FindTableEntry (TablePtr, TEXT("Inf File Name"), 1, &LineNum, &Text)) {
  1593. DEBUGMSG ((
  1594. DBG_WARNING,
  1595. "CreateSetupTable: File %s does not have an 'Inf File Name' entry",
  1596. SourceStfFileSpec
  1597. ));
  1598. __leave;
  1599. }
  1600. if (!Text[0]) {
  1601. DEBUGMSG ((
  1602. DBG_WARNING,
  1603. "CreateSetupTable: File %s has an empty 'Inf File Name' entry",
  1604. SourceStfFileSpec
  1605. ));
  1606. __leave;
  1607. }
  1608. StringCopy (DestSpec, DirSpec);
  1609. StringCopy (AppendWack (DestSpec), Text);
  1610. TablePtr->SourceInfFileSpec = PoolMemDuplicateString (
  1611. TablePtr->ReplacePool,
  1612. DestSpec
  1613. );
  1614. if (!TablePtr->SourceInfFileSpec) {
  1615. __leave;
  1616. }
  1617. //
  1618. // Open the INF file, then parse it into our structures for later
  1619. // modification.
  1620. //
  1621. #if 0
  1622. TablePtr->SourceInfFile = CreateFile (
  1623. TablePtr->SourceInfFileSpec,
  1624. GENERIC_READ,
  1625. 0,
  1626. NULL,
  1627. OPEN_EXISTING,
  1628. FILE_ATTRIBUTE_NORMAL,
  1629. NULL
  1630. );
  1631. #else
  1632. //
  1633. // We can't modify the INF
  1634. //
  1635. TablePtr->SourceInfFile = INVALID_HANDLE_VALUE;
  1636. #endif
  1637. if (TablePtr->SourceInfFile != INVALID_HANDLE_VALUE) {
  1638. if (!InfParse_ReadInfIntoTable (TablePtr)) {
  1639. DEBUGMSG ((
  1640. DBG_WARNING,
  1641. "CreateSetupTable: Can't parse %s",
  1642. TablePtr->SourceInfFileSpec
  1643. ));
  1644. __leave;
  1645. }
  1646. //
  1647. // Generate output name for INF file
  1648. //
  1649. _tcssafecpy (DestSpec, TablePtr->SourceInfFileSpec, MAX_TCHAR_PATH - 4);
  1650. StringCat (DestSpec, TEXT(".$$$"));
  1651. TablePtr->DestInfFileSpec = PoolMemDuplicateString (
  1652. TablePtr->ReplacePool,
  1653. DestSpec
  1654. );
  1655. if (!TablePtr->DestInfFileSpec) {
  1656. __leave;
  1657. }
  1658. } else {
  1659. LOG ((
  1660. LOG_INFORMATION,
  1661. (PCSTR)MSG_STF_MISSING_INF_LOG,
  1662. TablePtr->SourceStfFileSpec,
  1663. TablePtr->SourceInfFileSpec
  1664. ));
  1665. }
  1666. b = TRUE;
  1667. }
  1668. __finally {
  1669. pFreeViewOfFile (TablePtr);
  1670. if (!b) {
  1671. DestroySetupTable (TablePtr);
  1672. }
  1673. }
  1674. return b;
  1675. }
  1676. VOID
  1677. DestroySetupTable (
  1678. IN OUT PSETUPTABLE TablePtr
  1679. )
  1680. /*++
  1681. Routine Description:
  1682. DestroySetupTable cleans up all resources associated with the specified
  1683. table. The table is reset.
  1684. Arguments:
  1685. TablePtr - Specifies the table to clean up
  1686. Return Value:
  1687. none
  1688. --*/
  1689. {
  1690. //
  1691. // Close all file handles
  1692. //
  1693. if (TablePtr->SourceStfFile != INVALID_HANDLE_VALUE) {
  1694. CloseHandle (TablePtr->SourceStfFile);
  1695. }
  1696. if (TablePtr->SourceInfFile != INVALID_HANDLE_VALUE) {
  1697. CloseHandle (TablePtr->SourceInfFile);
  1698. }
  1699. if (TablePtr->DestStfFile != INVALID_HANDLE_VALUE) {
  1700. CloseHandle (TablePtr->DestStfFile);
  1701. }
  1702. if (TablePtr->DestInfFile != INVALID_HANDLE_VALUE) {
  1703. CloseHandle (TablePtr->DestInfFile);
  1704. }
  1705. if (TablePtr->SourceInfHandle != INVALID_HANDLE_VALUE) {
  1706. InfCloseInfFile (TablePtr->SourceInfHandle);
  1707. }
  1708. //
  1709. // Free pools
  1710. //
  1711. FreeGrowBuffer (&TablePtr->Lines);
  1712. if (TablePtr->ColumnStructPool) {
  1713. PoolMemDestroyPool (TablePtr->ColumnStructPool);
  1714. }
  1715. if (TablePtr->ReplacePool) {
  1716. PoolMemDestroyPool (TablePtr->ReplacePool);
  1717. }
  1718. if (TablePtr->TextPool) {
  1719. PoolMemDestroyPool (TablePtr->TextPool);
  1720. }
  1721. if (TablePtr->InfPool) {
  1722. PoolMemDestroyPool (TablePtr->InfPool);
  1723. }
  1724. pFreeHashTable (TablePtr);
  1725. pResetTableStruct (TablePtr);
  1726. }
  1727. BOOL
  1728. pWriteTableEntry (
  1729. IN HANDLE File,
  1730. IN PSETUPTABLE TablePtr,
  1731. IN PTABLEENTRY TableEntryPtr
  1732. )
  1733. /*++
  1734. Routine Description:
  1735. pWriteTableEntry is a worker that writes out an STF table entry to
  1736. disk, enclosing the entry in quotes if necessary.
  1737. Arguments:
  1738. File - Specifies the output file handle
  1739. TablePtr - Specifies the table being processed
  1740. TableEntryPtr - Specifies the entry to write
  1741. Return Value:
  1742. TRUE if successful, FALSE if an error occurred.
  1743. --*/
  1744. {
  1745. PCSTR AnsiStr;
  1746. BOOL b = TRUE;
  1747. PCSTR QuotedText;
  1748. BOOL FreeQuotedText = FALSE;
  1749. PCTSTR EntryStr;
  1750. DWORD DontCare;
  1751. EntryStr = GetTableEntryStr (TablePtr, TableEntryPtr);
  1752. if (!EntryStr) {
  1753. return FALSE;
  1754. }
  1755. //
  1756. // If binary, write the binary line and return
  1757. //
  1758. if (TableEntryPtr->Binary) {
  1759. b = WriteFile (
  1760. File,
  1761. EntryStr,
  1762. strchr ((PSTR) EntryStr, 0) - (PSTR) EntryStr,
  1763. &DontCare,
  1764. NULL
  1765. );
  1766. return b;
  1767. }
  1768. AnsiStr = CreateDbcs (EntryStr);
  1769. if (!AnsiStr) {
  1770. return FALSE;
  1771. }
  1772. //
  1773. // Quote string if necessary
  1774. //
  1775. if (TableEntryPtr->Quoted) {
  1776. QuotedText = pGenerateQuotedText (TablePtr->ReplacePool, AnsiStr, -1);
  1777. if (!QuotedText) {
  1778. b = FALSE;
  1779. } else {
  1780. FreeQuotedText = TRUE;
  1781. }
  1782. } else {
  1783. QuotedText = AnsiStr;
  1784. }
  1785. //
  1786. // Write the ANSI string to disk
  1787. //
  1788. if (b && *QuotedText) {
  1789. b = WriteFileStringA (File, QuotedText);
  1790. }
  1791. //
  1792. // Clean up string
  1793. //
  1794. DestroyDbcs (AnsiStr);
  1795. if (FreeQuotedText) {
  1796. pFreeQuoteConvertedText (TablePtr->ReplacePool, QuotedText);
  1797. }
  1798. return b;
  1799. }
  1800. BOOL
  1801. pWriteStfToDisk (
  1802. IN PSETUPTABLE TablePtr
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. pWriteStfToDisk dumps an entire STF file to disk by enumerating all
  1807. lines in the file and writing all columns for each line.
  1808. Arguments:
  1809. TablePtr - Specifies the table to write
  1810. Return Value:
  1811. TRUE if successful, FALSE if an error occurred.
  1812. --*/
  1813. {
  1814. UINT Line;
  1815. BOOL b = TRUE;
  1816. PTABLELINE TableLinePtr;
  1817. PTABLEENTRY TableEntryPtr;
  1818. MYASSERT (TablePtr->DestStfFile != INVALID_HANDLE_VALUE);
  1819. Line = 0;
  1820. SetFilePointer (TablePtr->DestStfFile, 0, NULL, FILE_BEGIN);
  1821. SetEndOfFile (TablePtr->DestStfFile);
  1822. do {
  1823. TableLinePtr = pGetTableLinePtr (TablePtr, Line);
  1824. if (TableLinePtr) {
  1825. //
  1826. // Write the line by enumerating each entry, then writing a tab
  1827. //
  1828. TableEntryPtr = pGetFirstTableEntryPtr (TablePtr, Line);
  1829. while (TableEntryPtr) {
  1830. //
  1831. // Write the entry
  1832. //
  1833. if (!pWriteTableEntry (TablePtr->DestStfFile, TablePtr, TableEntryPtr)) {
  1834. b = FALSE;
  1835. break;
  1836. }
  1837. //
  1838. // Continue to next entry
  1839. //
  1840. TableEntryPtr = pGetNextTableEntryPtr (TableEntryPtr);
  1841. //
  1842. // Write a tab
  1843. //
  1844. if (TableEntryPtr) {
  1845. if (!WriteFileStringA (TablePtr->DestStfFile, "\t")) {
  1846. b = FALSE;
  1847. break;
  1848. }
  1849. }
  1850. }
  1851. if (!b) {
  1852. break;
  1853. }
  1854. //
  1855. // Write a return/line-feed to end the line
  1856. //
  1857. if (!WriteFileStringA (TablePtr->DestStfFile, "\r\n")) {
  1858. b = FALSE;
  1859. break;
  1860. }
  1861. Line++;
  1862. }
  1863. } while (TableLinePtr);
  1864. return b;
  1865. }
  1866. BOOL
  1867. WriteSetupTable (
  1868. IN PSETUPTABLE TablePtr
  1869. )
  1870. /*++
  1871. Routine Description:
  1872. WriteSetupTable writes the STF and INF represented by TablePtr. This
  1873. saves all changes to disk, writing to the output files indicated within
  1874. the TablePtr structure.
  1875. Arguments:
  1876. TablePtr - Specifies the table to write
  1877. Return Value:
  1878. TRUE if successful, FALSE if an error occurred.
  1879. --*/
  1880. {
  1881. BOOL b = FALSE;
  1882. //
  1883. // Open INF file for reading
  1884. //
  1885. __try {
  1886. //
  1887. // Create the output STF file
  1888. //
  1889. if (TablePtr->DestStfFile != INVALID_HANDLE_VALUE) {
  1890. CloseHandle (TablePtr->DestStfFile);
  1891. }
  1892. TablePtr->DestStfFile = CreateFile (
  1893. TablePtr->DestStfFileSpec,
  1894. GENERIC_WRITE,
  1895. 0,
  1896. NULL,
  1897. CREATE_ALWAYS,
  1898. FILE_ATTRIBUTE_NORMAL,
  1899. NULL
  1900. );
  1901. if (TablePtr->DestStfFile == INVALID_HANDLE_VALUE) {
  1902. LOG ((LOG_ERROR, "Write Setup Table: Could not create %s (STF file)", TablePtr->DestStfFileSpec));
  1903. __leave;
  1904. }
  1905. //
  1906. // Write the STF structure to disk
  1907. //
  1908. if (!pWriteStfToDisk (TablePtr)) {
  1909. LOG ((LOG_ERROR, "Write Setup Table: Error while writing %s (STF file)", TablePtr->DestStfFileSpec));
  1910. __leave;
  1911. }
  1912. if (TablePtr->SourceInfFile != INVALID_HANDLE_VALUE) {
  1913. //
  1914. // Create the output INF file
  1915. //
  1916. DEBUGMSG ((DBG_STF, "Writing new INF file for STF"));
  1917. if (TablePtr->DestInfFile != INVALID_HANDLE_VALUE) {
  1918. CloseHandle (TablePtr->DestInfFile);
  1919. }
  1920. TablePtr->DestInfFile = CreateFile (
  1921. TablePtr->DestInfFileSpec,
  1922. GENERIC_WRITE,
  1923. 0,
  1924. NULL,
  1925. CREATE_ALWAYS,
  1926. FILE_ATTRIBUTE_NORMAL,
  1927. NULL
  1928. );
  1929. if (TablePtr->DestInfFile == INVALID_HANDLE_VALUE) {
  1930. LOG ((LOG_ERROR, "Write Setup Table: Could not create %s (INF file)", TablePtr->DestInfFileSpec));
  1931. __leave;
  1932. }
  1933. //
  1934. // Write the modified INF to disk
  1935. //
  1936. if (!InfParse_WriteInfToDisk (TablePtr)) {
  1937. LOG ((LOG_ERROR, "Write Setup Table: Error while writing %s (INF file)", TablePtr->DestInfFileSpec));
  1938. __leave;
  1939. }
  1940. }
  1941. b = TRUE;
  1942. }
  1943. __finally {
  1944. //
  1945. // Close new STF, and on failure, delete the new STF
  1946. //
  1947. if (TablePtr->DestStfFile != INVALID_HANDLE_VALUE) {
  1948. CloseHandle (TablePtr->DestStfFile);
  1949. TablePtr->DestStfFile = INVALID_HANDLE_VALUE;
  1950. }
  1951. if (!b) {
  1952. DeleteFile (TablePtr->DestStfFileSpec);
  1953. }
  1954. //
  1955. // Close new INF, and on failure, delete the new INF
  1956. //
  1957. if (TablePtr->SourceInfFile != INVALID_HANDLE_VALUE) {
  1958. if (TablePtr->DestInfFile != INVALID_HANDLE_VALUE) {
  1959. CloseHandle (TablePtr->DestInfFile);
  1960. TablePtr->DestInfFile = INVALID_HANDLE_VALUE;
  1961. }
  1962. if (!b) {
  1963. DeleteFile (TablePtr->DestInfFileSpec);
  1964. }
  1965. }
  1966. }
  1967. return b;
  1968. }
  1969. PCTSTR *
  1970. ParseCommaList (
  1971. IN PSETUPTABLE TablePtr,
  1972. IN PCTSTR CommaListString
  1973. )
  1974. /*++
  1975. Routine Description:
  1976. ParseCommaList divides a comma-separated list into an array of string pointers.
  1977. The array is cleaned up by FreeCommaList.
  1978. Arguments:
  1979. TablePtr - Specifies the table being processed and is used for memory allocation
  1980. CommaListString - Specifies the string to parse
  1981. Return Value:
  1982. An array of string pointers, with the last element set to NULL, or NULL if an
  1983. error occurred.
  1984. --*/
  1985. {
  1986. PCTSTR p;
  1987. PTSTR *ArgArray;
  1988. UINT Args = 1;
  1989. UINT PoolSize;
  1990. PTSTR DestBuf;
  1991. PTSTR d;
  1992. PTSTR SpaceTrim;
  1993. BOOL QuoteEnclosed;
  1994. //
  1995. // Pass 1: Count the commas
  1996. //
  1997. p = SkipSpace (CommaListString);
  1998. if (*p) {
  1999. Args++;
  2000. }
  2001. while (*p) {
  2002. if (_tcsnextc (p) == DBLQUOTECHAR) {
  2003. p = _tcsinc (p);
  2004. while (*p) {
  2005. if (_tcsnextc (p) == DBLQUOTECHAR) {
  2006. if (_tcsnextc (_tcsinc (p)) == DBLQUOTECHAR) {
  2007. p = _tcsinc (p);
  2008. } else {
  2009. break;
  2010. }
  2011. }
  2012. p = _tcsinc (p);
  2013. }
  2014. if (*p) {
  2015. p = _tcsinc (p);
  2016. DEBUGMSG_IF ((*p && _tcsnextc(SkipSpace(p)) != TEXT(','), DBG_STF, "Comma List String %s has text outside the quotes", CommaListString));
  2017. }
  2018. ELSE_DEBUGMSG ((DBG_STF, "Comma List String %s does not have balanced dbl quotes", CommaListString));
  2019. } else {
  2020. while (*p && _tcsnextc (p) != TEXT(',')) {
  2021. p = _tcsinc (p);
  2022. }
  2023. }
  2024. if (_tcsnextc (p) == TEXT(',')) {
  2025. Args++;
  2026. }
  2027. if (*p) {
  2028. p = SkipSpace (_tcsinc (p));
  2029. }
  2030. }
  2031. //
  2032. // Pass 2: Prepare list of args
  2033. //
  2034. ArgArray = (PTSTR *) PoolMemGetAlignedMemory (TablePtr->ReplacePool, sizeof (PCTSTR *) * Args);
  2035. if (!ArgArray) {
  2036. return NULL;
  2037. }
  2038. p = SkipSpace (CommaListString);
  2039. if (!(*p)) {
  2040. *ArgArray = NULL;
  2041. return ArgArray;
  2042. }
  2043. PoolSize = SizeOfString (CommaListString) + Args * sizeof (TCHAR);
  2044. DestBuf = (PTSTR) PoolMemGetAlignedMemory (TablePtr->ReplacePool, PoolSize);
  2045. if (!DestBuf) {
  2046. PoolMemReleaseMemory (TablePtr->ReplacePool, (PVOID) ArgArray);
  2047. return NULL;
  2048. }
  2049. d = DestBuf;
  2050. Args = 0;
  2051. while (*p) {
  2052. //
  2053. // Extract next string
  2054. //
  2055. ArgArray[Args] = d;
  2056. SpaceTrim = d;
  2057. Args++;
  2058. if (_tcsnextc (p) == DBLQUOTECHAR) {
  2059. //
  2060. // Quote-enclosed arg
  2061. //
  2062. QuoteEnclosed = TRUE;
  2063. while (TRUE) {
  2064. p = _tcsinc (p);
  2065. if (!(*p)) {
  2066. break;
  2067. }
  2068. if (_tcsnextc (p) == DBLQUOTECHAR) {
  2069. p = _tcsinc (p);
  2070. if (_tcsnextc (p) != DBLQUOTECHAR) {
  2071. break;
  2072. }
  2073. }
  2074. _copytchar (d, p);
  2075. d = _tcsinc (d);
  2076. }
  2077. while (*p && _tcsnextc (p) != TEXT(',')) {
  2078. p = _tcsinc (p);
  2079. }
  2080. } else {
  2081. //
  2082. // Non-quote-enclosed arg
  2083. //
  2084. QuoteEnclosed = FALSE;
  2085. while (*p && _tcsnextc (p) != TEXT(',')) {
  2086. _copytchar (d, p);
  2087. d = _tcsinc (d);
  2088. p = _tcsinc (p);
  2089. }
  2090. }
  2091. //
  2092. // Terminate string
  2093. //
  2094. *d = 0;
  2095. if (!QuoteEnclosed) {
  2096. SpaceTrim = (PTSTR) SkipSpaceR (SpaceTrim, d);
  2097. if (SpaceTrim) {
  2098. d = _tcsinc (SpaceTrim);
  2099. *d = 0;
  2100. }
  2101. }
  2102. d = _tcsinc (d);
  2103. if (*p) {
  2104. // Skip past comma
  2105. p = SkipSpace (_tcsinc (p));
  2106. }
  2107. }
  2108. ArgArray[Args] = NULL;
  2109. return ArgArray;
  2110. }
  2111. VOID
  2112. FreeCommaList (
  2113. PSETUPTABLE TablePtr,
  2114. PCTSTR *ArgArray
  2115. )
  2116. /*++
  2117. Routine Description:
  2118. FreeCommaList cleans up the resources allocated by ParseCommaList.
  2119. Arguments:
  2120. TablePtr - Specifies the table to that holds the resources
  2121. ArgArray - Specifies the return value from ParseCommaList
  2122. Return Value:
  2123. none
  2124. --*/
  2125. {
  2126. if (ArgArray) {
  2127. if (*ArgArray) {
  2128. PoolMemReleaseMemory (TablePtr->ReplacePool, (PVOID) *ArgArray);
  2129. }
  2130. PoolMemReleaseMemory (TablePtr->ReplacePool, (PVOID) ArgArray);
  2131. }
  2132. }
  2133. PCTSTR
  2134. pUnencodeDestDir (
  2135. IN PSETUPTABLE TablePtr,
  2136. IN PCTSTR EncodedDestDir
  2137. )
  2138. /*++
  2139. Routine Description:
  2140. pUnencodeDestDir translates the directory encoding as defined by the
  2141. STF spec. It scans for certain fields that point to other STF lines
  2142. and generates the full path.
  2143. Arguments:
  2144. TablePtr - Specifies the table to process
  2145. EncodedDestDir - Specifies the encoded directory string, as obtained
  2146. from the STF
  2147. Return Value:
  2148. A pointer to the converted string, or NULL if an error occurred.
  2149. --*/
  2150. {
  2151. GROWBUFFER String = GROWBUF_INIT;
  2152. PTSTR Base, p, q;
  2153. PCTSTR SubDestDir;
  2154. PTSTR DestDir = NULL;
  2155. CHARTYPE c;
  2156. UINT Line;
  2157. p = (PTSTR) GrowBuffer (&String, SizeOfString (EncodedDestDir));
  2158. if (!p) {
  2159. return NULL;
  2160. }
  2161. Base = p;
  2162. __try {
  2163. //
  2164. // Copy until a percent symbol is encountered
  2165. //
  2166. while (*EncodedDestDir) {
  2167. c = (CHARTYPE)_tcsnextc (EncodedDestDir);
  2168. if (c == TEXT('%')) {
  2169. EncodedDestDir = _tcsinc (EncodedDestDir);
  2170. c = (CHARTYPE)_tcsnextc (EncodedDestDir);
  2171. DEBUGMSG ((DBG_VERBOSE, "Percent processing"));
  2172. if (_istdigit (c)) {
  2173. Line = _tcstoul (EncodedDestDir, &q, 10);
  2174. EncodedDestDir = q;
  2175. SubDestDir = GetDestDir (TablePtr, Line);
  2176. if (!SubDestDir) {
  2177. __leave;
  2178. }
  2179. __try {
  2180. // Expand buffer
  2181. GrowBuffer (&String, ByteCount (SubDestDir));
  2182. // Recalculate p because buffer may have moved
  2183. p = (PTSTR) (String.Buf + (p - Base));
  2184. Base = (PTSTR) String.Buf;
  2185. // Copy SubDestDir into string
  2186. *p = 0;
  2187. p = _tcsappend (p, SubDestDir);
  2188. }
  2189. __finally {
  2190. FreeDestDir (TablePtr, SubDestDir);
  2191. }
  2192. } else {
  2193. DEBUGMSG ((DBG_WARNING, "STF uses option %%%c which is ignored", c));
  2194. EncodedDestDir = _tcsinc (EncodedDestDir);
  2195. }
  2196. }
  2197. else {
  2198. _copytchar (p, EncodedDestDir);
  2199. p = _tcsinc (p);
  2200. }
  2201. EncodedDestDir = _tcsinc (EncodedDestDir);
  2202. }
  2203. //
  2204. // Terminate string
  2205. //
  2206. *p = 0;
  2207. //
  2208. // Copy string into a pool mem buffer
  2209. //
  2210. DestDir = (PTSTR) PoolMemGetAlignedMemory (
  2211. TablePtr->ReplacePool,
  2212. SizeOfString ((PTSTR) String.Buf)
  2213. );
  2214. StringCopy (DestDir, (PCTSTR) String.Buf);
  2215. }
  2216. __finally {
  2217. FreeGrowBuffer (&String);
  2218. }
  2219. return DestDir;
  2220. }
  2221. VOID
  2222. FreeDestDir (
  2223. IN PSETUPTABLE TablePtr,
  2224. IN PCTSTR DestDir
  2225. )
  2226. /*++
  2227. Routine Description:
  2228. FreeDestDir cleans up the string allocated by pUnencodeDestDir or
  2229. GetDestDir.
  2230. Arguments:
  2231. TablePtr - Specifies the table being processed
  2232. DestDir - Specifies the string to clean up
  2233. Return Value:
  2234. none
  2235. --*/
  2236. {
  2237. if (DestDir) {
  2238. PoolMemReleaseMemory (TablePtr->ReplacePool, (PVOID) DestDir);
  2239. }
  2240. }
  2241. PCTSTR
  2242. GetDestDir (
  2243. IN PSETUPTABLE TablePtr,
  2244. IN UINT Line
  2245. )
  2246. /*++
  2247. Routine Description:
  2248. GetDestDir returns the destination directory stored for the caller-
  2249. specified line. The destination directory is column 14 in the STF file
  2250. line.
  2251. Arguments:
  2252. TablePtr - Specifies the table to process
  2253. Line - Specifies the table zero-based line to access
  2254. Return Value:
  2255. A pointer to the full destination directory, or NULL if an error occurred
  2256. or the destination directory field does not exist on the STF line.
  2257. --*/
  2258. {
  2259. PCTSTR EncodedDestDir;
  2260. PCTSTR DestDir;
  2261. if (!GetTableEntry (TablePtr, Line, 14, &EncodedDestDir)) {
  2262. return NULL;
  2263. }
  2264. DestDir = pUnencodeDestDir (TablePtr, EncodedDestDir);
  2265. return DestDir;
  2266. }
  2267. //
  2268. // Hash table routines
  2269. //
  2270. BOOL
  2271. pInitHashTable (
  2272. IN OUT PSETUPTABLE TablePtr
  2273. )
  2274. /*++
  2275. Routine Description:
  2276. pInitHashTable allocates an array of bucket pointers for the hash
  2277. table, and zero-initializes them. Each element of the hash bucket
  2278. array holds a pointer to an a bucket of items, or is NULL if no
  2279. items exist.
  2280. Arguments:
  2281. TablePtr - Specifies the table to process
  2282. Return Value:
  2283. Always TRUE
  2284. --*/
  2285. {
  2286. TablePtr->HashBuckets = (PHASHBUCKET *) MemAlloc (
  2287. g_hHeap,
  2288. HEAP_ZERO_MEMORY,
  2289. sizeof (PHASHBUCKET) * STF_HASH_BUCKETS
  2290. );
  2291. return TRUE;
  2292. }
  2293. VOID
  2294. pFreeHashTable (
  2295. IN OUT PSETUPTABLE TablePtr
  2296. )
  2297. /*++
  2298. Routine Description:
  2299. pFreeHashTable frees all allocated buckets, and then frees the
  2300. bucket array.
  2301. Arguments:
  2302. TablePtr - Specifies the table to process
  2303. Return Value:
  2304. none
  2305. --*/
  2306. {
  2307. INT i;
  2308. for (i = 0 ; i < STF_HASH_BUCKETS ; i++) {
  2309. if (TablePtr->HashBuckets[i]) {
  2310. MemFree (g_hHeap, 0, TablePtr->HashBuckets[i]);
  2311. }
  2312. }
  2313. MemFree (g_hHeap, 0, TablePtr->HashBuckets);
  2314. TablePtr->HashBuckets = NULL;
  2315. }
  2316. UINT
  2317. pCalculateHashValue (
  2318. IN PCTSTR Text,
  2319. IN UINT Len
  2320. )
  2321. /*++
  2322. Routine Description:
  2323. pCalculateHashValue produces a hash value based on the number
  2324. embedded at the start of the string (if any), or a shifted
  2325. and xor'd combination of all characters in the string.
  2326. Arguments:
  2327. Text - Specifies the text to process
  2328. Len - Specifies the length fo the text
  2329. Return Value:
  2330. The hash value.
  2331. --*/
  2332. {
  2333. UINT Value = 0;
  2334. if (Len == NO_LENGTH) {
  2335. Len = LcharCount (Text);
  2336. }
  2337. if (Len && _tcsnextc(Text) >= '0' && _tcsnextc(Text) <= '9') {
  2338. do {
  2339. Value = Value * 10 + (_tcsnextc (Text) - '0');
  2340. Text = _tcsinc (Text);
  2341. Len--;
  2342. } while (Len && _tcsnextc(Text) >= '0' && _tcsnextc(Text) <= '9');
  2343. if (!Len) {
  2344. return Value % STF_HASH_BUCKETS;
  2345. }
  2346. }
  2347. while (Len > 0) {
  2348. Value = (Value << 2) | (Value >> 30);
  2349. Value ^= _totlower ((WORD) _tcsnextc (Text));
  2350. Text = _tcsinc (Text);
  2351. Len--;
  2352. }
  2353. Value = Value % STF_HASH_BUCKETS;
  2354. return Value;
  2355. }
  2356. BOOL
  2357. pAddToHashTable (
  2358. IN OUT PSETUPTABLE TablePtr,
  2359. IN PCTSTR Text,
  2360. IN UINT Len,
  2361. IN UINT Line
  2362. )
  2363. /*++
  2364. Routine Description:
  2365. pAddToHashTable adds a line reference to the bucket. The bucket
  2366. number is calculated from the specified text.
  2367. Arguments:
  2368. TablePtr - Specifies the table to process
  2369. Text - Specifies the text to hash
  2370. Len - Specifies the length of Text
  2371. Line - Specifies the line to add to the bucket
  2372. Return Value:
  2373. none
  2374. --*/
  2375. {
  2376. UINT HashValue;
  2377. PHASHBUCKET HashBucket, NewBucket;
  2378. PHASHBUCKET *HashBucketPtr;
  2379. UINT Size;
  2380. #ifdef DEBUG
  2381. UINT Item;
  2382. #endif
  2383. // Ignore empty strings
  2384. if (!(*Text)) {
  2385. return TRUE;
  2386. }
  2387. #ifdef DEBUG
  2388. if (pFindInHashTable (TablePtr, Text, &Item)) {
  2389. DEBUGMSG ((DBG_WARNING, "String %s already in hash table", Text));
  2390. }
  2391. #endif
  2392. HashValue = pCalculateHashValue (Text, Len);
  2393. HashBucketPtr = &TablePtr->HashBuckets[HashValue];
  2394. HashBucket = *HashBucketPtr;
  2395. //
  2396. // Grow the bucket as necessary
  2397. //
  2398. if (HashBucket) {
  2399. if (HashBucket->Count == HashBucket->Size) {
  2400. Size = sizeof (Line) *
  2401. (HashBucket->Size + BUCKET_GROW_RATE) +
  2402. sizeof (HASHBUCKET);
  2403. NewBucket = (PHASHBUCKET) MemReAlloc (
  2404. g_hHeap,
  2405. 0,
  2406. HashBucket,
  2407. Size
  2408. );
  2409. if (!NewBucket) {
  2410. return FALSE;
  2411. }
  2412. *HashBucketPtr = NewBucket;
  2413. HashBucket = NewBucket;
  2414. HashBucket->Size += BUCKET_GROW_RATE;
  2415. }
  2416. } else {
  2417. Size = sizeof (Line) * BUCKET_GROW_RATE + sizeof (HASHBUCKET);
  2418. NewBucket = (PHASHBUCKET) MemAlloc (
  2419. g_hHeap,
  2420. HEAP_ZERO_MEMORY,
  2421. Size
  2422. );
  2423. *HashBucketPtr = NewBucket;
  2424. HashBucket = NewBucket;
  2425. HashBucket->Size = BUCKET_GROW_RATE;
  2426. }
  2427. //
  2428. // Get a pointer to the end of the bucket and stick the line in there
  2429. //
  2430. HashBucket->Elements[HashBucket->Count] = Line;
  2431. HashBucket->Count++;
  2432. return TRUE;
  2433. }
  2434. PHASHBUCKET
  2435. pFindInHashTable (
  2436. IN PSETUPTABLE TablePtr,
  2437. IN PCTSTR Text,
  2438. OUT PUINT BucketItem
  2439. )
  2440. /*++
  2441. Routine Description:
  2442. pFindInHashTable scans the hash bucket for an exact match with
  2443. the specified text. If a match if found, a pointer to the hash
  2444. bucket is returned, along with an index to the bucket item.
  2445. Arguments:
  2446. TablePtr - Specifies the table to process
  2447. Text - Specifies the text to find
  2448. BucketItem - Receives the index to the hash bucket if a match was
  2449. found, otherwise has an undetermined value.
  2450. Return Value:
  2451. A pointer to the hash bucket that contains the item corresponding
  2452. to the matched text, or NULL if no match was found.
  2453. --*/
  2454. {
  2455. UINT HashValue;
  2456. PHASHBUCKET HashBucket;
  2457. PCTSTR EntryString;
  2458. UINT d;
  2459. HashValue = pCalculateHashValue (Text, NO_LENGTH);
  2460. HashBucket = TablePtr->HashBuckets[HashValue];
  2461. if (!HashBucket) {
  2462. return NULL;
  2463. }
  2464. for (d = 0 ; d < HashBucket->Count ; d++) {
  2465. if (!GetTableEntry (TablePtr, HashBucket->Elements[d], 0, &EntryString)) {
  2466. DEBUGMSG ((DBG_WHOOPS, "pFindInHashTable could not get string"));
  2467. return NULL;
  2468. }
  2469. if (StringIMatch (Text, EntryString)) {
  2470. *BucketItem = d;
  2471. return HashBucket;
  2472. }
  2473. }
  2474. return NULL;
  2475. }
  2476. BOOL
  2477. pRemoveFromHashTable (
  2478. IN OUT PSETUPTABLE TablePtr,
  2479. IN PCTSTR Text
  2480. )
  2481. /*++
  2482. Routine Description:
  2483. pRemoveFromHashTable removes the specified text entry from the
  2484. hash table. The bucket item count is reduced, but the memory
  2485. allocation is not reduced.
  2486. Arguments:
  2487. TablePtr - Specifies the table to process
  2488. Text - Specifies the text to remove from the hash table
  2489. Return Value:
  2490. TRUE if delete was sucessful, or FALSE if the item was not found.
  2491. --*/
  2492. {
  2493. PHASHBUCKET DelBucket;
  2494. UINT Item;
  2495. PUINT LastItem, ThisItem;
  2496. DelBucket = pFindInHashTable (TablePtr, Text, &Item);
  2497. if (!DelBucket) {
  2498. LOG ((LOG_ERROR, "Remove From Hash Table: Could not find string %s", Text));
  2499. return FALSE;
  2500. }
  2501. ThisItem = &DelBucket->Elements[Item];
  2502. LastItem = &DelBucket->Elements[DelBucket->Count - 1];
  2503. if (ThisItem != LastItem) {
  2504. *ThisItem = *LastItem;
  2505. }
  2506. DelBucket->Count--;
  2507. return TRUE;
  2508. }