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.

2283 lines
48 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. parseini.c
  5. Abstract:
  6. This modules contains routines to parse an inf file. This is based on
  7. the code from the osloader. All indices are zero based.
  8. Author:
  9. Santosh Jodh (santoshj) 08-Aug-1998
  10. Environment:
  11. Kernel mode.
  12. Revision History:
  13. --*/
  14. #include "cmp.h"
  15. #include "string.h"
  16. #include "ctype.h"
  17. #include "stdlib.h"
  18. #include "parseini.h"
  19. typedef struct _value VALUE, *PVALUE;
  20. typedef struct _line LINE, *PLINE;
  21. typedef struct _section SECTION, *PSECTION;
  22. typedef struct _inf INF, *PINF;
  23. typedef struct _cm_token CM_TOKEN,*PCM_TOKEN;
  24. typedef enum _tokentype TOKENTYPE, *PTOKENTTYPE;
  25. typedef enum _stringsSectionType STRINGSSECTIONTYPE;;
  26. struct _value
  27. {
  28. PVALUE pNext;
  29. PCHAR pName;
  30. BOOLEAN Allocated;
  31. };
  32. struct _line
  33. {
  34. PLINE pNext;
  35. PCHAR pName;
  36. PVALUE pValue;
  37. BOOLEAN Allocated;
  38. };
  39. struct _section
  40. {
  41. PSECTION pNext;
  42. PCHAR pName;
  43. PLINE pLine;
  44. BOOLEAN Allocated;
  45. };
  46. struct _inf
  47. {
  48. PSECTION pSection;
  49. PSECTION pSectionRecord;
  50. PLINE pLineRecord;
  51. PVALUE pValueRecord;
  52. STRINGSSECTIONTYPE StringsSectionType;
  53. PSECTION StringsSection;
  54. };
  55. //
  56. // [Strings] section types.
  57. //
  58. enum _stringsSectionType
  59. {
  60. StringsSectionNone,
  61. StringsSectionPlain,
  62. StringsSectionLoosePrimaryMatch,
  63. StringsSectionExactPrimaryMatch,
  64. StringsSectionExactMatch
  65. };
  66. enum _tokentype
  67. {
  68. TOK_EOF,
  69. TOK_EOL,
  70. TOK_LBRACE,
  71. TOK_RBRACE,
  72. TOK_STRING,
  73. TOK_EQUAL,
  74. TOK_COMMA,
  75. TOK_ERRPARSE,
  76. TOK_ERRNOMEM
  77. };
  78. struct _cm_token
  79. {
  80. TOKENTYPE Type;
  81. PCHAR pValue;
  82. BOOLEAN Allocated;
  83. };
  84. VOID
  85. CmpFreeValueList(
  86. IN PVALUE pValue
  87. );
  88. VOID
  89. CmpFreeLineList(
  90. IN PLINE pLine
  91. );
  92. VOID
  93. CmpFreeSectionList(
  94. IN PSECTION pSection
  95. );
  96. PCHAR
  97. CmpProcessForSimpleStringSub(
  98. IN PINF pInf,
  99. IN PCHAR String
  100. );
  101. BOOLEAN
  102. CmpAppendSection(
  103. IN PINF pInf,
  104. IN PCHAR pSectionName,
  105. IN BOOLEAN Allocated
  106. );
  107. BOOLEAN
  108. CmpAppendLine(
  109. IN PINF pInf,
  110. IN PCHAR pLineKey,
  111. IN BOOLEAN Allocated
  112. );
  113. BOOLEAN
  114. CmpAppendValue(
  115. IN PINF pInf,
  116. IN PCHAR pValueString,
  117. IN BOOLEAN Allocated
  118. );
  119. VOID
  120. CmpGetToken(
  121. IN OUT PCHAR *Stream,
  122. IN PCHAR MaxStream,
  123. IN OUT PCM_TOKEN Token
  124. );
  125. PINF
  126. CmpParseInfBuffer(
  127. IN PCHAR Buffer,
  128. IN ULONG Size,
  129. IN OUT PULONG ErrorLine
  130. );
  131. PVALUE
  132. CmpSearchValueInLine(
  133. IN PLINE pLine,
  134. IN ULONG ValueIndex
  135. );
  136. PLINE
  137. CmpSearchLineInSectionByIndex(
  138. IN PSECTION pSection,
  139. IN ULONG LineIndex
  140. );
  141. PSECTION
  142. CmpSearchSectionByName(
  143. IN PINF pInf,
  144. IN PCHAR SectionName
  145. );
  146. #ifdef ALLOC_PRAGMA
  147. #pragma alloc_text(INIT,CmpFreeValueList)
  148. #pragma alloc_text(INIT,CmpFreeLineList)
  149. #pragma alloc_text(INIT,CmpFreeSectionList)
  150. #pragma alloc_text(INIT,CmpProcessForSimpleStringSub)
  151. #pragma alloc_text(INIT,CmpAppendSection)
  152. #pragma alloc_text(INIT,CmpAppendLine)
  153. #pragma alloc_text(INIT,CmpAppendValue)
  154. #pragma alloc_text(INIT,CmpGetToken)
  155. #pragma alloc_text(INIT,CmpParseInfBuffer)
  156. #pragma alloc_text(INIT,CmpSearchValueInLine)
  157. #pragma alloc_text(INIT,CmpSearchLineInSectionByIndex)
  158. #pragma alloc_text(INIT,CmpSearchSectionByName)
  159. #pragma alloc_text(INIT,CmpSearchInfLine)
  160. #pragma alloc_text(INIT,CmpOpenInfFile)
  161. #pragma alloc_text(INIT,CmpCloseInfFile)
  162. #pragma alloc_text(INIT,CmpGetKeyName)
  163. #pragma alloc_text(INIT,CmpSearchInfSection)
  164. #pragma alloc_text(INIT,CmpGetSectionLineIndex)
  165. #pragma alloc_text(INIT,CmpGetSectionLineIndexValueCount)
  166. #pragma alloc_text(INIT,CmpGetIntField)
  167. #pragma alloc_text(INIT,CmpGetBinaryField)
  168. #endif
  169. //
  170. // Globals used by the token parser.
  171. // String terminators are the whitespace characters (isspace: space, tab,
  172. // linefeed, formfeed, vertical tab, carriage return) or the chars given below.
  173. //
  174. #ifdef ALLOC_DATA_PRAGMA
  175. #pragma const_seg("INITCONST")
  176. #endif
  177. const CHAR StringTerminators[] = "[]=,\t \"\n\f\v\r";
  178. CHAR const* const QStringTerminators = StringTerminators + 6;
  179. const CHAR EmptyValue[] = "";
  180. BOOLEAN
  181. CmpAppendSection(
  182. IN PINF pInf,
  183. IN PCHAR pSectionName,
  184. IN BOOLEAN Allocated
  185. )
  186. /*++
  187. Routine Description:
  188. This routine creates a new section or merges with an existing section in the inf.
  189. Input Parameters:
  190. pInf - Pointer to the inf to be processed.
  191. pSectionName - Name of the section.
  192. Allocated - TRUE if memory was allocated for the section name.
  193. Return Value:
  194. TRUE iff successful.
  195. --*/
  196. {
  197. PSECTION pNewSection;
  198. PLINE pLineRecord;
  199. STRINGSSECTIONTYPE type;
  200. USHORT id;
  201. USHORT threadLang;
  202. PCHAR p;
  203. //
  204. // Check to see if INF initialised and the parameters passed in is valid
  205. //
  206. if ( pInf == (PINF)NULL ||
  207. pSectionName == (PCHAR)NULL)
  208. {
  209. return (FALSE);
  210. }
  211. //
  212. // See if we already have a section by this name. If so we want
  213. // to merge sections.
  214. //
  215. for( pNewSection = pInf->pSection;
  216. pNewSection;
  217. pNewSection = pNewSection->pNext)
  218. {
  219. if(pNewSection->pName && _stricmp(pNewSection->pName,pSectionName) == 0)
  220. {
  221. break;
  222. }
  223. }
  224. if(pNewSection)
  225. {
  226. //
  227. // Set pLineRecord to point to the last line currently in the section.
  228. //
  229. for( pLineRecord = pNewSection->pLine;
  230. pLineRecord && pLineRecord->pNext;
  231. pLineRecord = pLineRecord->pNext);
  232. pInf->pLineRecord = pLineRecord;
  233. }
  234. else
  235. {
  236. //
  237. // Allocate memory for the new section
  238. //
  239. pNewSection = (PSECTION)ExAllocatePoolWithTag(PagedPool, sizeof(SECTION), CM_PARSEINI_TAG);
  240. if (pNewSection == (PSECTION)NULL)
  241. {
  242. ASSERT(pNewSection);
  243. return (FALSE);
  244. }
  245. //
  246. // Initialize the new section.
  247. //
  248. pNewSection->pNext = NULL;
  249. pNewSection->pLine = NULL;
  250. pNewSection->pName = pSectionName;
  251. pNewSection->Allocated = Allocated;
  252. //
  253. // Link it in.
  254. //
  255. pNewSection->pNext = pInf->pSection;
  256. pInf->pSection = pNewSection;
  257. if(_strnicmp(pSectionName, "Strings", 7) == 0)
  258. {
  259. type = StringsSectionNone;
  260. if(pSectionName[7] == '.')
  261. {
  262. //
  263. // The langid part must be in the form of 4 hex digits.
  264. //
  265. id = (USHORT)strtoul(pSectionName + 8, &p, 16);
  266. if(p == (pSectionName + 8 + 5) && *p == '\0')
  267. {
  268. threadLang = LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale);
  269. if(threadLang == id)
  270. {
  271. type = StringsSectionExactMatch;
  272. }
  273. else
  274. {
  275. if(id == PRIMARYLANGID(threadLang))
  276. {
  277. type = StringsSectionExactPrimaryMatch;
  278. }
  279. else
  280. {
  281. if(PRIMARYLANGID(id) == PRIMARYLANGID(threadLang))
  282. {
  283. type = StringsSectionLoosePrimaryMatch;
  284. }
  285. }
  286. }
  287. }
  288. }
  289. else
  290. {
  291. if(!pSectionName[7])
  292. {
  293. type = StringsSectionPlain;
  294. }
  295. }
  296. if(type > pInf->StringsSectionType)
  297. {
  298. pInf->StringsSection = pNewSection;
  299. }
  300. }
  301. //
  302. // Reset the current line record.
  303. //
  304. pInf->pLineRecord = NULL;
  305. }
  306. pInf->pSectionRecord = pNewSection;
  307. pInf->pValueRecord = NULL;
  308. return (TRUE);
  309. }
  310. BOOLEAN
  311. CmpAppendLine(
  312. IN PINF pInf,
  313. IN PCHAR pLineKey,
  314. IN BOOLEAN Allocated
  315. )
  316. /*++
  317. Routine Description:
  318. This routine creates a new line and appends it to the end of the line list.
  319. Input Parameters:
  320. pInf - Pointer to the inf to be processed.
  321. pLineKey - Name of the line.
  322. Allocated - TRUE if memory was allocated for the line name.
  323. Return Value:
  324. TRUE iff successful.
  325. --*/
  326. {
  327. PLINE pNewLine;
  328. //
  329. // Check to see if current section initialized.
  330. //
  331. if (pInf->pSectionRecord == (PSECTION)NULL)
  332. {
  333. return (FALSE);
  334. }
  335. //
  336. // Allocate memory for the new Line.
  337. //
  338. pNewLine = (PLINE)ExAllocatePoolWithTag(PagedPool, sizeof(LINE), CM_PARSEINI_TAG);
  339. if (pNewLine == (PLINE)NULL)
  340. {
  341. ASSERT(pNewLine);
  342. return (FALSE);
  343. }
  344. //
  345. // Link it in.
  346. //
  347. pNewLine->pNext = (PLINE)NULL;
  348. pNewLine->pValue = (PVALUE)NULL;
  349. pNewLine->pName = pLineKey;
  350. pNewLine->Allocated = Allocated;
  351. if (pInf->pLineRecord == (PLINE)NULL)
  352. {
  353. pInf->pSectionRecord->pLine = pNewLine;
  354. }
  355. else
  356. {
  357. pInf->pLineRecord->pNext = pNewLine;
  358. }
  359. pInf->pLineRecord = pNewLine;
  360. //
  361. // Reset the current value record
  362. //
  363. pInf->pValueRecord = (PVALUE)NULL;
  364. return (TRUE);
  365. }
  366. BOOLEAN
  367. CmpAppendValue(
  368. IN PINF pInf,
  369. IN PCHAR pValueString,
  370. IN BOOLEAN Allocated
  371. )
  372. /*++
  373. Routine Description:
  374. This routine creates a new value and appends it to the end of the value list.
  375. Input Parameters:
  376. pInf - Pointer to the inf to be processed.
  377. pValueString - Name of the value.
  378. Allocated - TRUE if memory was allocated for the value name.
  379. Return Value:
  380. TRUE iff successful.
  381. --*/
  382. {
  383. PVALUE pNewValue;
  384. //
  385. // Check to see if current line record has been initialised and
  386. // the parameter passed in is valid.
  387. //
  388. if ( pInf->pLineRecord == (PLINE)NULL ||
  389. pValueString == (PCHAR)NULL)
  390. {
  391. return (FALSE);
  392. }
  393. //
  394. // Allocate memory for the new value record.
  395. //
  396. pNewValue = (PVALUE)ExAllocatePoolWithTag(PagedPool, sizeof(VALUE), CM_PARSEINI_TAG);
  397. if (pNewValue == (PVALUE)NULL)
  398. {
  399. ASSERT(pNewValue);
  400. return (FALSE);
  401. }
  402. //
  403. // Link it in.
  404. //
  405. pNewValue->pNext = (PVALUE)NULL;
  406. pNewValue->pName = pValueString;
  407. pNewValue->Allocated = Allocated;
  408. if (pInf->pValueRecord == (PVALUE)NULL)
  409. {
  410. pInf->pLineRecord->pValue = pNewValue;
  411. }
  412. else
  413. {
  414. pInf->pValueRecord->pNext = pNewValue;
  415. }
  416. pInf->pValueRecord = pNewValue;
  417. return (TRUE);
  418. }
  419. VOID
  420. CmpGetToken(
  421. IN OUT PCHAR *Stream,
  422. IN PCHAR MaxStream,
  423. IN OUT PCM_TOKEN Token
  424. )
  425. /*++
  426. Routine Description:
  427. This function returns the Next token from the configuration stream.
  428. Arguments:
  429. Stream - Supplies the address of the configuration stream. Returns
  430. the address of where to start looking for tokens within the
  431. stream.
  432. MaxStream - Supplies the address of the last character in the stream.
  433. Return Value:
  434. None.
  435. --*/
  436. {
  437. PCHAR pch;
  438. PCHAR pchStart;
  439. PCHAR pchNew;
  440. ULONG length;
  441. BOOLEAN done;
  442. Token->Allocated = FALSE;
  443. Token->pValue = NULL;
  444. do
  445. {
  446. done = TRUE;
  447. //
  448. // Skip whitespace (except for EOL).
  449. //
  450. for ( pch = *Stream;
  451. pch < MaxStream && *pch != '\n' && isspace(*pch);
  452. pch++);
  453. //
  454. // Check for comments and remove them.
  455. //
  456. if ( pch < MaxStream &&
  457. (*pch == '#' || *pch == ';'))
  458. {
  459. while (pch < MaxStream && *pch != '\n')
  460. {
  461. pch++;
  462. }
  463. }
  464. //
  465. // Check to see if EOF has been reached, set the token to the right
  466. // value.
  467. //
  468. if (pch >= MaxStream || *pch == 26)
  469. {
  470. *Stream = pch;
  471. Token->Type = TOK_EOF;
  472. Token->pValue = NULL;
  473. return;
  474. }
  475. switch (*pch)
  476. {
  477. case '[':
  478. pch++;
  479. Token->Type = TOK_LBRACE;
  480. break;
  481. case ']':
  482. pch++;
  483. Token->Type = TOK_RBRACE;
  484. break;
  485. case '=':
  486. pch++;
  487. Token->Type = TOK_EQUAL;
  488. break;
  489. case ',':
  490. pch++;
  491. Token->Type = TOK_COMMA;
  492. break;
  493. case '\n':
  494. pch++;
  495. Token->Type = TOK_EOL;
  496. break;
  497. case '\"':
  498. pch++;
  499. //
  500. // Determine quoted string.
  501. //
  502. for ( pchStart = pch;
  503. pch < MaxStream && (strchr(QStringTerminators, *pch) == NULL);
  504. pch++);
  505. if (pch >= MaxStream || *pch != '\"')
  506. {
  507. Token->Type = TOK_ERRPARSE;
  508. }
  509. else
  510. {
  511. //
  512. // We require a quoted string to end with a double-quote.
  513. // (If the string ended with anything else, the if() above
  514. // would not have let us into the else clause.) The quote
  515. // character is irrelevent, however, and can be overwritten.
  516. // So we'll save some heap and use the string in-place.
  517. // No need to make a copy.
  518. //
  519. // Note that this alters the image of txtsetup.sif we pass
  520. // to setupdd.sys. Thus the inf parser in setupdd.sys must
  521. // be able to treat a nul character as if it were a terminating
  522. // double quote.
  523. //
  524. *pch++ = '\0';
  525. Token->Type = TOK_STRING;
  526. Token->pValue = pchStart;
  527. }
  528. break;
  529. case '\\':
  530. for ( pchNew = ++pch;
  531. pchNew < MaxStream &&
  532. *pchNew != '\n' && isspace(*pchNew);
  533. pchNew++);
  534. if (pch >= MaxStream)
  535. {
  536. Token->Type = TOK_ERRPARSE;
  537. break;
  538. }
  539. else if (*pchNew == '\n')
  540. {
  541. pch = pchNew + 1;
  542. done = FALSE;
  543. break;
  544. }
  545. default:
  546. //
  547. // Determine regular string.
  548. //
  549. for ( pchStart = pch;
  550. pch < MaxStream && (strchr(StringTerminators, *pch) == NULL);
  551. pch++);
  552. if (pch == pchStart)
  553. {
  554. pch++;
  555. Token->Type = TOK_ERRPARSE;
  556. }
  557. else
  558. {
  559. length = (ULONG)(pch - pchStart);
  560. pchNew = ExAllocatePoolWithTag(PagedPool, length + 1, CM_PARSEINI_TAG);
  561. if (pchNew == NULL)
  562. {
  563. ASSERT(pchNew);
  564. Token->Type = TOK_ERRNOMEM;
  565. }
  566. else
  567. {
  568. strncpy(pchNew, pchStart, length);
  569. pchNew[length] = 0;
  570. Token->Type = TOK_STRING;
  571. Token->pValue = pchNew;
  572. Token->Allocated = TRUE;
  573. }
  574. }
  575. break;
  576. }
  577. *Stream = pch;
  578. }
  579. while (!done);
  580. return;
  581. }
  582. PINF
  583. CmpParseInfBuffer(
  584. IN PCHAR Buffer,
  585. IN ULONG Size,
  586. IN OUT PULONG ErrorLine
  587. )
  588. /*++
  589. Routine Description:
  590. Given a character buffer containing the INF file, this routine parses
  591. the INF into an internal form with Section records, Line records and
  592. Value records.
  593. Arguments:
  594. Buffer - contains to ptr to a buffer containing the INF file
  595. Size - contains the size of the buffer.
  596. ErrorLine - if a parse error occurs, this variable receives the line
  597. number of the line containing the error.
  598. Return Value:
  599. PVOID - INF handle ptr to be used in subsequent INF calls.
  600. --*/
  601. {
  602. PINF pInf;
  603. ULONG state;
  604. PCHAR stream;
  605. PCHAR maxStream;
  606. PCHAR pchSectionName;
  607. PCHAR pchValue;
  608. CM_TOKEN token;
  609. BOOLEAN done;
  610. BOOLEAN error;
  611. ULONG infLine;
  612. BOOLEAN allocated = FALSE;
  613. //
  614. // Allocate memory for the INF record.
  615. //
  616. pInf = (PINF)ExAllocatePoolWithTag(PagedPool, sizeof(INF), CM_PARSEINI_TAG);
  617. if (pInf == NULL)
  618. {
  619. return NULL;
  620. }
  621. pInf->pSection = NULL;
  622. pInf->pSectionRecord = NULL;
  623. pInf->pLineRecord = NULL;
  624. pInf->pValueRecord = NULL;
  625. pInf->StringsSectionType = StringsSectionNone;
  626. pInf->StringsSection = NULL;
  627. //
  628. // Set initial state.
  629. //
  630. state = 1;
  631. stream = Buffer;
  632. maxStream = Buffer + Size;
  633. pchSectionName = NULL;
  634. pchValue = NULL;
  635. done = FALSE;
  636. error = FALSE;
  637. infLine = 1;
  638. //
  639. // Enter token processing loop.
  640. //
  641. while (!done)
  642. {
  643. CmpGetToken(&stream, maxStream, &token);
  644. switch (state)
  645. {
  646. //
  647. // STATE1: Start of file, this state remains till first
  648. // section is found
  649. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
  650. //
  651. case 1:
  652. switch (token.Type)
  653. {
  654. case TOK_EOL:
  655. break;
  656. case TOK_EOF:
  657. done = TRUE;
  658. break;
  659. case TOK_LBRACE:
  660. state = 2;
  661. break;
  662. case TOK_STRING:
  663. ASSERT(token.Type != TOK_STRING);
  664. error = done = TRUE;
  665. break;
  666. default:
  667. error = done = TRUE;
  668. break;
  669. }
  670. break;
  671. //
  672. // STATE 2: Section LBRACE has been received, expecting STRING
  673. //
  674. // Valid Tokens: TOK_STRING, TOK_RBRACE
  675. //
  676. case 2:
  677. switch (token.Type)
  678. {
  679. case TOK_STRING:
  680. state = 3;
  681. pchSectionName = token.pValue;
  682. allocated = token.Allocated;
  683. break;
  684. case TOK_RBRACE:
  685. token.pValue = (PCHAR)EmptyValue;
  686. token.Allocated = FALSE;
  687. allocated = FALSE;
  688. state = 4;
  689. break;
  690. default:
  691. error = done = TRUE;
  692. break;
  693. }
  694. break;
  695. //
  696. // STATE 3: Section Name received, expecting RBRACE
  697. //
  698. // Valid Tokens: TOK_RBRACE
  699. //
  700. case 3:
  701. switch (token.Type)
  702. {
  703. case TOK_RBRACE:
  704. state = 4;
  705. break;
  706. default:
  707. error = done = TRUE;
  708. break;
  709. }
  710. break;
  711. //
  712. // STATE 4: Section Definition Complete, expecting EOL
  713. //
  714. // Valid Tokens: TOK_EOL, TOK_EOF
  715. //
  716. case 4:
  717. switch (token.Type)
  718. {
  719. case TOK_EOL:
  720. if (!CmpAppendSection(pInf, pchSectionName, allocated))
  721. {
  722. error = done = TRUE;
  723. }
  724. else
  725. {
  726. pchSectionName = NULL;
  727. state = 5;
  728. }
  729. break;
  730. case TOK_EOF:
  731. if (!CmpAppendSection(pInf, pchSectionName, allocated))
  732. {
  733. error = done = TRUE;
  734. }
  735. else
  736. {
  737. pchSectionName = NULL;
  738. done = TRUE;
  739. }
  740. break;
  741. default:
  742. error = done = TRUE;
  743. break;
  744. }
  745. break;
  746. //
  747. // STATE 5: Expecting Section Lines
  748. //
  749. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
  750. //
  751. case 5:
  752. switch (token.Type)
  753. {
  754. case TOK_EOL:
  755. break;
  756. case TOK_EOF:
  757. done = TRUE;
  758. break;
  759. case TOK_STRING:
  760. pchValue = token.pValue;
  761. allocated = token.Allocated;
  762. state = 6;
  763. break;
  764. case TOK_LBRACE:
  765. state = 2;
  766. break;
  767. default:
  768. error = done = TRUE;
  769. break;
  770. }
  771. break;
  772. //
  773. // STATE 6: String returned, not sure whether it is key or value
  774. //
  775. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
  776. //
  777. case 6:
  778. switch (token.Type)
  779. {
  780. case TOK_EOL:
  781. if ( !CmpAppendLine(pInf, NULL, FALSE) ||
  782. !CmpAppendValue(pInf, pchValue, allocated))
  783. {
  784. error = done = TRUE;
  785. }
  786. else
  787. {
  788. pchValue = NULL;
  789. state = 5;
  790. }
  791. break;
  792. case TOK_EOF:
  793. if ( !CmpAppendLine(pInf, NULL, FALSE) ||
  794. !CmpAppendValue(pInf, pchValue, allocated))
  795. {
  796. error = done = TRUE;
  797. }
  798. else
  799. {
  800. pchValue = NULL;
  801. done = TRUE;
  802. }
  803. break;
  804. case TOK_COMMA:
  805. if ( !CmpAppendLine(pInf, NULL, FALSE) ||
  806. !CmpAppendValue(pInf, pchValue, allocated))
  807. {
  808. error = done = TRUE;
  809. }
  810. else
  811. {
  812. pchValue = NULL;
  813. state = 7;
  814. }
  815. break;
  816. case TOK_EQUAL:
  817. if (!CmpAppendLine(pInf, pchValue, allocated))
  818. {
  819. error = done = TRUE;
  820. }
  821. else
  822. {
  823. pchValue = NULL;
  824. state = 8;
  825. }
  826. break;
  827. default:
  828. error = done = TRUE;
  829. break;
  830. }
  831. break;
  832. //
  833. // STATE 7: Comma received, Expecting another string
  834. //
  835. // Valid Tokens: TOK_STRING TOK_COMMA
  836. // A comma means we have an empty value.
  837. //
  838. case 7:
  839. switch (token.Type)
  840. {
  841. case TOK_COMMA:
  842. token.pValue = (PCHAR)EmptyValue;
  843. token.Allocated = FALSE;
  844. allocated = FALSE;
  845. if (!CmpAppendValue(pInf, token.pValue, FALSE))
  846. {
  847. error = done = TRUE;
  848. }
  849. //
  850. // State stays at 7 because we are expecting a string
  851. //
  852. break;
  853. case TOK_STRING:
  854. if (!CmpAppendValue(pInf, token.pValue, token.Allocated))
  855. {
  856. error = done = TRUE;
  857. }
  858. else
  859. {
  860. state = 9;
  861. }
  862. break;
  863. default:
  864. error = done = TRUE;
  865. break;
  866. }
  867. break;
  868. //
  869. // STATE 8: Equal received, Expecting another string
  870. // If none, assume there is a single empty string on the RHS
  871. //
  872. // Valid Tokens: TOK_STRING, TOK_EOL, TOK_EOF
  873. //
  874. case 8:
  875. switch (token.Type)
  876. {
  877. case TOK_EOF:
  878. token.pValue = (PCHAR)EmptyValue;
  879. token.Allocated = FALSE;
  880. allocated = FALSE;
  881. if(!CmpAppendValue(pInf, token.pValue, FALSE))
  882. {
  883. error = TRUE;
  884. }
  885. done = TRUE;
  886. break;
  887. case TOK_EOL:
  888. token.pValue = (PCHAR)EmptyValue;
  889. token.Allocated = FALSE;
  890. allocated = FALSE;
  891. if(!CmpAppendValue(pInf, token.pValue, FALSE))
  892. {
  893. error = TRUE;
  894. done = TRUE;
  895. }
  896. else
  897. {
  898. state = 5;
  899. }
  900. break;
  901. case TOK_STRING:
  902. if (!CmpAppendValue(pInf, token.pValue, FALSE))
  903. {
  904. error = done = TRUE;
  905. }
  906. else
  907. {
  908. state = 9;
  909. }
  910. break;
  911. default:
  912. error = done = TRUE;
  913. break;
  914. }
  915. break;
  916. //
  917. // STATE 9: String received after equal, value string
  918. //
  919. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  920. //
  921. case 9:
  922. switch (token.Type)
  923. {
  924. case TOK_EOL:
  925. state = 5;
  926. break;
  927. case TOK_EOF:
  928. done = TRUE;
  929. break;
  930. case TOK_COMMA:
  931. state = 7;
  932. break;
  933. default:
  934. error = done = TRUE;
  935. break;
  936. }
  937. break;
  938. //
  939. // STATE 10: Value string definitely received
  940. //
  941. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  942. //
  943. case 10:
  944. switch (token.Type)
  945. {
  946. case TOK_EOL:
  947. state =5;
  948. break;
  949. case TOK_EOF:
  950. done = TRUE;
  951. break;
  952. case TOK_COMMA:
  953. state = 7;
  954. break;
  955. default:
  956. error = done = TRUE;
  957. break;
  958. }
  959. break;
  960. default:
  961. error = done = TRUE;
  962. break;
  963. } // END switch(state)
  964. if (error)
  965. {
  966. *ErrorLine = infLine;
  967. if (pchSectionName != (PCHAR)NULL && allocated)
  968. {
  969. ExFreePool(pchSectionName);
  970. }
  971. if (pchValue != (PCHAR)NULL && allocated)
  972. {
  973. ExFreePool(pchValue);
  974. }
  975. ExFreePool(pInf);
  976. pInf = (PINF)NULL;
  977. }
  978. else
  979. {
  980. //
  981. // Keep track of line numbers for error reporting.
  982. //
  983. if (token.Type == TOK_EOL)
  984. {
  985. infLine++;
  986. }
  987. }
  988. } // END while
  989. if (pInf)
  990. {
  991. pInf->pSectionRecord = NULL;
  992. }
  993. return(pInf);
  994. }
  995. PCHAR
  996. CmpProcessForSimpleStringSub(
  997. IN PINF pInf,
  998. IN PCHAR String
  999. )
  1000. /*++
  1001. Routine Description:
  1002. This routine substitutes reference to string in the STRINGS section of the inf.
  1003. Input Parameters:
  1004. pInf - Pointer to the inf to be processed.
  1005. String - String to be substituted.
  1006. Return Value:
  1007. None.
  1008. --*/
  1009. {
  1010. SIZE_T len;
  1011. PCHAR returnString;
  1012. PSECTION pSection;
  1013. PLINE pLine;
  1014. //
  1015. // Assume no substitution necessary.
  1016. //
  1017. returnString = String;
  1018. len = strlen(String);
  1019. pSection = pInf->StringsSection;
  1020. //
  1021. // If it starts and end with % then look it up in the
  1022. // strings section. Note the initial check before doing a
  1023. // wcslen, to preserve performance in the 99% case where
  1024. // there is no substitution.
  1025. //
  1026. if( String[0] == '%' &&
  1027. len > 2 &&
  1028. String[len - 1] == '%' &&
  1029. pSection)
  1030. {
  1031. for(pLine = pSection->pLine; pLine; pLine = pLine->pNext)
  1032. {
  1033. if( pLine->pName &&
  1034. _strnicmp(pLine->pName, String + 1, len - 2) == 0 &&
  1035. pLine->pName[len - 2] == '\0')
  1036. {
  1037. break;
  1038. }
  1039. }
  1040. if(pLine && pLine->pValue && pLine->pValue->pName)
  1041. {
  1042. returnString = pLine->pValue->pName;
  1043. }
  1044. }
  1045. return(returnString);
  1046. }
  1047. VOID
  1048. CmpFreeValueList(
  1049. IN PVALUE pValue
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. This routine releases memory for the list of values.
  1054. Input Parameters:
  1055. pValue - Pointer to the value list to be freed.
  1056. Return Value:
  1057. None.
  1058. --*/
  1059. {
  1060. PVALUE pNext;
  1061. while (pValue)
  1062. {
  1063. //
  1064. // Save the next pointer so we dont access memory after it has
  1065. // been freed.
  1066. //
  1067. pNext = pValue->pNext;
  1068. //
  1069. // Free any data inside this value.
  1070. //
  1071. if (pValue->Allocated && pValue->pName)
  1072. {
  1073. ExFreePool((PVOID)pValue->pName);
  1074. }
  1075. //
  1076. // Free memory for this value.
  1077. //
  1078. ExFreePool(pValue);
  1079. //
  1080. // Go to the next value.
  1081. //
  1082. pValue = pNext;
  1083. }
  1084. }
  1085. VOID
  1086. CmpFreeLineList(
  1087. IN PLINE pLine
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. This routine releases memory for the list of lines and
  1092. values under it.
  1093. Input Parameters:
  1094. pLine - Pointer to the line list to be freed.
  1095. Return Value:
  1096. None.
  1097. --*/
  1098. {
  1099. PLINE pNext;
  1100. while (pLine)
  1101. {
  1102. //
  1103. // Save the next pointer so we dont access memory after it has
  1104. // been freed.
  1105. //
  1106. pNext = pLine->pNext;
  1107. //
  1108. // Free any data inside this Line.
  1109. //
  1110. if (pLine->Allocated && pLine->pName)
  1111. {
  1112. ExFreePool((PVOID)pLine->pName);
  1113. }
  1114. //
  1115. // Free the list of values inside this Line.
  1116. //
  1117. CmpFreeValueList(pLine->pValue);
  1118. //
  1119. // Free memory for this line itself.
  1120. //
  1121. ExFreePool((PVOID)pLine);
  1122. //
  1123. // Go to the next line.
  1124. //
  1125. pLine = pNext;
  1126. }
  1127. }
  1128. VOID
  1129. CmpFreeSectionList(
  1130. IN PSECTION pSection
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. This routine releases memory for the list of sections and
  1135. lines under it.
  1136. Input Parameters:
  1137. pSection - Pointer to the section list to be freed.
  1138. Return Value:
  1139. None.
  1140. --*/
  1141. {
  1142. PSECTION pNext;
  1143. while (pSection)
  1144. {
  1145. //
  1146. // Save the next pointer so we dont access memory after it has
  1147. // been freed.
  1148. //
  1149. pNext = pSection->pNext;
  1150. //
  1151. // Free any data inside this Line.
  1152. //
  1153. if (pSection->Allocated && pSection->pName)
  1154. {
  1155. ExFreePool((PVOID)pSection->pName);
  1156. }
  1157. //
  1158. // Free the list of values inside this Line.
  1159. //
  1160. CmpFreeLineList(pSection->pLine);
  1161. //
  1162. // Free memory for this line itself.
  1163. //
  1164. ExFreePool((PVOID)pSection);
  1165. //
  1166. // Go to the next line.
  1167. //
  1168. pSection = pNext;
  1169. }
  1170. }
  1171. PVALUE
  1172. CmpSearchValueInLine(
  1173. IN PLINE pLine,
  1174. IN ULONG ValueIndex
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. This routine searches for the specified value in the inf.
  1179. Input Parameters:
  1180. pLine - Pointer to the line to be searched.
  1181. ValueIndex - Index of the value to be searched.
  1182. Return Value:
  1183. Pointer to the value iff found. Else NULL.
  1184. --*/
  1185. {
  1186. ULONG i;
  1187. PVALUE pValue = NULL;
  1188. if (pLine)
  1189. {
  1190. for ( i = 0, pValue = pLine->pValue;
  1191. i < ValueIndex && pValue;
  1192. i++, pValue = pValue->pNext);
  1193. }
  1194. return (pValue);
  1195. }
  1196. PSECTION
  1197. CmpSearchSectionByName(
  1198. IN PINF pInf,
  1199. IN PCHAR SectionName
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. This routine searches for the specified section in the inf.
  1204. Input Parameters:
  1205. pInf - Pointer to the inf to be searched.
  1206. SectionName - Name of the section to be searched.
  1207. Return Value:
  1208. Pointer to the section iff found. Else NULL.
  1209. --*/
  1210. {
  1211. PSECTION pSection = NULL;
  1212. PSECTION pFirstSearchedSection;
  1213. //
  1214. // Validate the parameters passed in.
  1215. //
  1216. if (pInf && SectionName)
  1217. {
  1218. //
  1219. // Traverse down the section list searching each section for the
  1220. // section name mentioned.
  1221. //
  1222. for ( pSection = pFirstSearchedSection = pInf->pSectionRecord;
  1223. pSection && _stricmp(pSection->pName, SectionName);
  1224. pSection = pSection->pNext);
  1225. //
  1226. // If we did not find the section, search from the beginning.
  1227. //
  1228. if (pSection == NULL)
  1229. {
  1230. for ( pSection = pInf->pSection;
  1231. pSection && pSection != pFirstSearchedSection;
  1232. pSection = pSection->pNext)
  1233. {
  1234. if (pSection->pName && _stricmp(pSection->pName, SectionName) == 0)
  1235. {
  1236. break;
  1237. }
  1238. }
  1239. if (pSection == pFirstSearchedSection)
  1240. {
  1241. pSection = NULL;
  1242. }
  1243. }
  1244. if (pSection)
  1245. {
  1246. pInf->pSectionRecord = pSection;
  1247. }
  1248. }
  1249. //
  1250. // Return the section at which we stopped.
  1251. //
  1252. return (pSection);
  1253. }
  1254. PLINE
  1255. CmpSearchLineInSectionByIndex(
  1256. IN PSECTION pSection,
  1257. IN ULONG LineIndex
  1258. )
  1259. /*++
  1260. Routine Description:
  1261. This routine searches for the specified line in the inf.
  1262. Input Parameters:
  1263. pSection - Pointer to the section to be searched.
  1264. LineIndex - Index of the line to be searched.
  1265. Return Value:
  1266. Pointer to the line iff found. Else NULL.
  1267. --*/
  1268. {
  1269. PLINE pLine = NULL;
  1270. ULONG i;
  1271. //
  1272. // Validate the parameters passed in.
  1273. //
  1274. if (pSection)
  1275. {
  1276. //
  1277. // Traverse down the current line list to the LineIndex line.
  1278. //
  1279. for( i = 0, pLine = pSection->pLine;
  1280. i < LineIndex && pLine;
  1281. i++, pLine = pLine->pNext);
  1282. }
  1283. //
  1284. // Return the Line found
  1285. //
  1286. return (pLine);
  1287. }
  1288. PVOID
  1289. CmpOpenInfFile(
  1290. IN PVOID InfImage,
  1291. IN ULONG ImageSize
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. This routine opens an handle to the inf.
  1296. Input Parameters:
  1297. InfImage - Pointer to the inf image read into memory.
  1298. ImageSize - Image size.
  1299. Return Value:
  1300. Returns handle to the inf iff successful. Else NULL.
  1301. --*/
  1302. {
  1303. PINF infHandle;
  1304. ULONG errorLine = 0;
  1305. //
  1306. // Parse the inf buffer.
  1307. //
  1308. infHandle = CmpParseInfBuffer(InfImage, ImageSize, &errorLine);
  1309. if (infHandle == NULL)
  1310. {
  1311. #ifndef _CM_LDR_
  1312. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Error on line %d in CmpOpenInfFile!\n", errorLine);
  1313. #endif //_CM_LDR_
  1314. }
  1315. return (infHandle);
  1316. }
  1317. VOID
  1318. CmpCloseInfFile(
  1319. PVOID InfHandle
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. This routine closes the inf handle by releasing any
  1324. memory allocated for it during parsing.
  1325. Input Parameters:
  1326. InfHandle - Handle to the inf to be closed.
  1327. Return Value:
  1328. None.
  1329. --*/
  1330. {
  1331. if (InfHandle)
  1332. {
  1333. CmpFreeSectionList(((PINF)InfHandle)->pSection);
  1334. ExFreePool(InfHandle);
  1335. }
  1336. }
  1337. LOGICAL
  1338. CmpSearchInfSection(
  1339. IN PINF pInf,
  1340. IN PCHAR Section
  1341. )
  1342. /*++
  1343. Routine Description:
  1344. This routine searches for the specified section in the inf.
  1345. Input Parameters:
  1346. InfHandle - Handle to the inf to be read.
  1347. Section - Name of the section to be read.
  1348. Return Value:
  1349. TRUE iff section is found in the inf.
  1350. --*/
  1351. {
  1352. return (CmpSearchSectionByName(pInf, Section) != NULL);
  1353. }
  1354. PCHAR
  1355. CmpGetKeyName(
  1356. IN PVOID InfHandle,
  1357. IN PCHAR Section,
  1358. IN ULONG LineIndex
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. This routine returns the name of the specified line in the inf.
  1363. Input Parameters:
  1364. InfHandle - Handle to the inf to be read.
  1365. Section - Name of the section to be read.
  1366. LineIndex - Index of the line to be read.
  1367. Return Value:
  1368. Pointer to the name of line in the inf iff successful. Else NULL.
  1369. --*/
  1370. {
  1371. PSECTION pSection;
  1372. PLINE pLine;
  1373. //
  1374. // First search the section.
  1375. //
  1376. pSection = CmpSearchSectionByName((PINF)InfHandle, Section);
  1377. if(pSection)
  1378. {
  1379. //
  1380. // Get the line in the section.
  1381. //
  1382. pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex);
  1383. if(pLine)
  1384. {
  1385. return(pLine->pName);
  1386. }
  1387. }
  1388. return (NULL);
  1389. }
  1390. LOGICAL
  1391. CmpSearchInfLine(
  1392. IN PVOID InfHandle,
  1393. IN PCHAR Section,
  1394. IN ULONG LineIndex
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. This routine searches for the specified line in the inf.
  1399. Input Parameters:
  1400. InfHandle - Handle to the inf to be read.
  1401. Section - Name of the section to be read.
  1402. LineIndex - Index of the line to be read.
  1403. Return Value:
  1404. TRUE iff line is found in the section in the inf.
  1405. --*/
  1406. {
  1407. PSECTION pSection;
  1408. PLINE pLine = NULL;
  1409. //
  1410. // First search the section.
  1411. //
  1412. pSection = CmpSearchSectionByName((PINF)InfHandle, Section);
  1413. if(pSection)
  1414. {
  1415. //
  1416. // Search the line in the section.
  1417. //
  1418. pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex);
  1419. }
  1420. return (pLine != NULL);
  1421. }
  1422. PCHAR
  1423. CmpGetSectionLineIndex (
  1424. IN PVOID InfHandle,
  1425. IN PCHAR Section,
  1426. IN ULONG LineIndex,
  1427. IN ULONG ValueIndex
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. This routine returns the value at the specified location in the inf.
  1432. Input Parameters:
  1433. InfHandle - Handle to the inf to be read.
  1434. Section - Name of the section to be read.
  1435. LineIndex - Index of the line to be read.
  1436. ValueIndex - Index of the value to be read.
  1437. Return Value:
  1438. Pointer to the value iff successful. Else NULL.
  1439. --*/
  1440. {
  1441. PSECTION pSection;
  1442. PLINE pLine;
  1443. PVALUE pValue;
  1444. //
  1445. // Search the section in the inf.
  1446. //
  1447. pSection = CmpSearchSectionByName((PINF)InfHandle, Section);
  1448. if(pSection)
  1449. {
  1450. //
  1451. // Search the line in the section.
  1452. //
  1453. pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex);
  1454. if(pLine)
  1455. {
  1456. //
  1457. // Search the value in the line.
  1458. //
  1459. pValue = CmpSearchValueInLine(pLine, ValueIndex);
  1460. if(pValue)
  1461. {
  1462. //
  1463. // The value may need to be replaced by one of the strings
  1464. // from the string section.
  1465. //
  1466. return(CmpProcessForSimpleStringSub(InfHandle, pValue->pName));
  1467. }
  1468. }
  1469. }
  1470. return(NULL);
  1471. }
  1472. ULONG
  1473. CmpGetSectionLineIndexValueCount(
  1474. IN PVOID InfHandle,
  1475. IN PCHAR Section,
  1476. IN ULONG LineIndex
  1477. )
  1478. /*++
  1479. Routine Description:
  1480. This routine returns the number of values in the inf line.
  1481. Input Parameters:
  1482. InfHandle - Handle to the inf to be read.
  1483. Section - Name of the section to be read.
  1484. LineIndex - Index of the line to be read.
  1485. Return Value:
  1486. Number of values in the inf line.
  1487. --*/
  1488. {
  1489. PSECTION pSection;
  1490. PLINE pLine;
  1491. PVALUE pValue;
  1492. ULONG count = 0;
  1493. //
  1494. // Search the section in the inf.
  1495. //
  1496. pSection = CmpSearchSectionByName((PINF)InfHandle, Section);
  1497. if(pSection)
  1498. {
  1499. //
  1500. // Search the line in the section.
  1501. //
  1502. pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex);
  1503. if (pLine)
  1504. {
  1505. //
  1506. // Count the number of values in this line.
  1507. //
  1508. for( pValue = pLine->pValue;
  1509. pValue;
  1510. pValue = pValue->pNext, count++);
  1511. }
  1512. }
  1513. return (count);
  1514. }
  1515. BOOLEAN
  1516. CmpGetIntField(
  1517. IN PVOID InfHandle,
  1518. IN PCHAR Section,
  1519. IN ULONG LineIndex,
  1520. IN ULONG ValueIndex,
  1521. IN OUT PULONG Data
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. This routine reads integer data from the inf.
  1526. Input Parameters:
  1527. InfHandle - Handle to the inf to be read.
  1528. Section - Name of the section to be read.
  1529. LineIndex - Index of the line to be read.
  1530. ValueIndex - Index of the value to be read.
  1531. Data - Receives the integer data.
  1532. Return Value:
  1533. TRUE iff successful.
  1534. --*/
  1535. {
  1536. PCHAR valueStr;
  1537. //
  1538. // Get the specified value.
  1539. //
  1540. valueStr = CmpGetSectionLineIndex( InfHandle,
  1541. Section,
  1542. LineIndex,
  1543. ValueIndex);
  1544. //
  1545. // If valid value is found, convert it to an integer.
  1546. //
  1547. if (valueStr && *valueStr)
  1548. {
  1549. *Data = strtoul(valueStr, NULL, 16);
  1550. return (TRUE);
  1551. }
  1552. return (FALSE);
  1553. }
  1554. BOOLEAN
  1555. CmpGetBinaryField(
  1556. IN PVOID InfHandle,
  1557. IN PCHAR Section,
  1558. IN ULONG LineIndex,
  1559. IN ULONG ValueIndex,
  1560. IN OUT PVOID Buffer,
  1561. IN ULONG BufferSize,
  1562. IN OUT PULONG ActualSize
  1563. )
  1564. /*++
  1565. Routine Description:
  1566. This routine reads binary data from the inf.
  1567. Input Parameters:
  1568. InfHandle - Handle to the inf to be read.
  1569. Section - Name of the section to be read.
  1570. LineIndex - Index of the line to be read.
  1571. ValueIndex - Index of the value to be read.
  1572. Buffer - Receives the binary data read.
  1573. BufferSize - Size of the buffer.
  1574. ActualSize - Receives the size of the data buffer required.
  1575. Return Value:
  1576. TRUE iff successful.
  1577. --*/
  1578. {
  1579. BOOLEAN result = FALSE;
  1580. ULONG requiredSize;
  1581. PSECTION pSection;
  1582. PLINE pLine;
  1583. PVALUE pValue;
  1584. ULONG count;
  1585. PCHAR valueStr = NULL;
  1586. PUCHAR charBuf;
  1587. //
  1588. // Compute the size of buffer required to read in the binary data.
  1589. //
  1590. requiredSize = (CmpGetSectionLineIndexValueCount( InfHandle,
  1591. Section,
  1592. LineIndex) - ValueIndex) * sizeof(UCHAR);
  1593. //
  1594. // Validate input parameters.
  1595. //
  1596. if (Buffer && BufferSize >= requiredSize)
  1597. {
  1598. //
  1599. // Search the section in the inf.
  1600. //
  1601. pSection = CmpSearchSectionByName((PINF)InfHandle, Section);
  1602. if(pSection)
  1603. {
  1604. //
  1605. // Search the line in this section.
  1606. //
  1607. pLine = CmpSearchLineInSectionByIndex(pSection, LineIndex);
  1608. if (pLine)
  1609. {
  1610. //
  1611. // Go to the specified value.
  1612. //
  1613. for( pValue = pLine->pValue, count = 0;
  1614. pValue && count < ValueIndex;
  1615. pValue = pValue->pNext, count++);
  1616. //
  1617. // Read in and convert the binary data.
  1618. //
  1619. charBuf = (PUCHAR) Buffer;
  1620. for ( ;
  1621. pValue;
  1622. pValue = pValue->pNext)
  1623. {
  1624. valueStr = CmpGetSectionLineIndex( InfHandle,
  1625. Section,
  1626. LineIndex,
  1627. ValueIndex++);
  1628. if (valueStr == NULL)
  1629. {
  1630. break;
  1631. }
  1632. *charBuf++ = (UCHAR)strtoul(valueStr, NULL, 16);
  1633. }
  1634. if (valueStr)
  1635. {
  1636. result = TRUE;
  1637. }
  1638. }
  1639. }
  1640. }
  1641. //
  1642. // The caller wants to know the buffer size required.
  1643. //
  1644. if (ActualSize)
  1645. {
  1646. *ActualSize = requiredSize;
  1647. result = TRUE;
  1648. }
  1649. return (result);
  1650. }
  1651. #ifdef ALLOC_DATA_PRAGMA
  1652. #pragma const_seg()
  1653. #endif