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

2296 lines
47 KiB

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