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.

1502 lines
42 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. infold.c
  5. Abstract:
  6. Routines to load an old-style inf file.
  7. Based on prsinf\spinf.c
  8. Author:
  9. Ted Miller (tedm) 19-Jan-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // Internal temporary representation of the inf file.
  16. // The win95 representation is built from these structures
  17. // which are then throw away.
  18. //
  19. typedef struct _X_VALUE {
  20. struct _X_VALUE *Next;
  21. PTCHAR Name;
  22. } X_VALUE, *PX_VALUE;
  23. typedef struct _X_LINE {
  24. struct _X_LINE *Next;
  25. PTCHAR Name;
  26. PX_VALUE Value;
  27. UINT ValueCount;
  28. } X_LINE, *PX_LINE;
  29. typedef struct _X_SECTION {
  30. struct _X_SECTION *Next;
  31. PTCHAR Name;
  32. PX_LINE Line;
  33. UINT LineCount;
  34. } X_SECTION, *PX_SECTION;
  35. typedef struct _X_INF {
  36. PX_SECTION Section;
  37. UINT SectionCount;
  38. UINT TotalLineCount;
  39. UINT TotalValueCount;
  40. } X_INF, *PX_INF;
  41. //
  42. // Global parse context.
  43. //
  44. typedef struct _PARSE_CONTEXT {
  45. PX_INF Inf;
  46. PX_SECTION Section;
  47. PX_LINE Line;
  48. PX_VALUE Value;
  49. } PARSE_CONTEXT, *PPARSE_CONTEXT;
  50. //
  51. // Token parser values.
  52. //
  53. typedef enum _X_TOKENTYPE {
  54. TOK_EOF,
  55. TOK_EOL,
  56. TOK_LBRACE,
  57. TOK_RBRACE,
  58. TOK_STRING,
  59. TOK_EQUAL,
  60. TOK_COMMA,
  61. TOK_ERRPARSE,
  62. TOK_ERRNOMEM
  63. } X_TOKENTYPE, *PX_TOKENTTYPE;
  64. //
  65. // Token parser data type
  66. //
  67. typedef struct _X_TOKEN {
  68. X_TOKENTYPE Type;
  69. PTCHAR pValue;
  70. } X_TOKEN, *PX_TOKEN;
  71. //
  72. // string terminators are the whitespace characters (isspace: space, tab,
  73. // linefeed, formfeed, vertical tab, carriage return) or the chars given below
  74. //
  75. // quoted string terminators allow some of the regular terminators to
  76. // appear as characters
  77. //
  78. PTCHAR szStrTerms = TEXT("[]=,\" \t\n\f\v\r");
  79. PTCHAR szBrcStrTerms = TEXT("[]=,\"\t\n\f\v\r");
  80. PTCHAR szQStrTerms = TEXT("\"\n\f\v\r");
  81. PTCHAR szCBrStrTerms = TEXT("}\n\f\v\r");
  82. #define IsStringTerminator(terminators,ch) (_tcschr((terminators),(ch)) != NULL)
  83. VOID
  84. SpFreeTemporaryParseStructures(
  85. IN PX_INF Inf
  86. )
  87. /*++
  88. Routine Description:
  89. Free the structures built by the old-style-inf parser.
  90. Arguments:
  91. Inf - supplies pointer to inf descriptor structure.
  92. Return Value:
  93. None.
  94. --*/
  95. {
  96. PX_SECTION Section,NextSection;
  97. PX_LINE Line,NextLine;
  98. PX_VALUE Value,NextValue;
  99. for(Section=Inf->Section; Section; Section=NextSection) {
  100. for(Line=Section->Line; Line; Line=NextLine) {
  101. for(Value=Line->Value; Value; Value=NextValue) {
  102. NextValue = Value->Next;
  103. if(Value->Name) {
  104. MyFree(Value->Name);
  105. }
  106. MyFree(Value);
  107. }
  108. NextLine = Line->Next;
  109. if(Line->Name) {
  110. MyFree(Line->Name);
  111. }
  112. MyFree(Line);
  113. }
  114. NextSection = Section->Next;
  115. MyFree(Section->Name);
  116. MyFree(Section);
  117. }
  118. MyFree(Inf);
  119. }
  120. BOOL
  121. SpAppendSection(
  122. IN PPARSE_CONTEXT Context,
  123. IN PTCHAR SectionName
  124. )
  125. /*++
  126. Routine Description:
  127. This appends a new section to the section list in the current INF.
  128. All further lines and values pertain to this new section, so it resets
  129. the line list and value lists too.
  130. Arguments:
  131. Context - supplies the parse context
  132. SectionName - Name of the new section. ( [SectionName] )
  133. Return Value:
  134. BOOL - FALSE if failure (out of memory)
  135. --*/
  136. {
  137. PX_SECTION NewSection;
  138. MYASSERT(Context->Inf);
  139. //
  140. // Allocate memory for the new section
  141. //
  142. if((NewSection = MyMalloc(sizeof(X_SECTION))) == NULL) {
  143. return(FALSE);
  144. }
  145. //
  146. // initialize the new section
  147. //
  148. ZeroMemory(NewSection,sizeof(X_SECTION));
  149. NewSection->Name = SectionName;
  150. //
  151. // Link it in
  152. //
  153. if(Context->Section) {
  154. Context->Section->Next = NewSection;
  155. } else {
  156. Context->Inf->Section = NewSection;
  157. }
  158. Context->Section = NewSection;
  159. //
  160. // reset the current line record and current value record field
  161. //
  162. Context->Line = NULL;
  163. Context->Value = NULL;
  164. Context->Inf->SectionCount++;
  165. return(TRUE);
  166. }
  167. BOOL
  168. SpAppendLine(
  169. IN PPARSE_CONTEXT Context,
  170. IN PTCHAR LineKey
  171. )
  172. /*++
  173. Routine Description:
  174. This appends a new line to the line list in the current section.
  175. All further values pertain to this new line, so it resets
  176. the value list too.
  177. Arguments:
  178. Context - supplies the parse context.
  179. LineKey - Key to be used for the current line, this could be NULL.
  180. Return Value:
  181. BOOL - FALSE if failure (out of memory)
  182. --*/
  183. {
  184. PX_LINE NewLine;
  185. MYASSERT(Context->Section);
  186. //
  187. // Allocate memory for the new Line
  188. //
  189. if((NewLine = MyMalloc(sizeof(X_LINE))) == NULL) {
  190. return(FALSE);
  191. }
  192. ZeroMemory(NewLine,sizeof(X_LINE));
  193. NewLine->Name = LineKey;
  194. //
  195. // Link it in
  196. //
  197. if(Context->Line) {
  198. Context->Line->Next = NewLine;
  199. } else {
  200. Context->Section->Line = NewLine;
  201. }
  202. Context->Line = NewLine;
  203. //
  204. // Reset the current value record
  205. //
  206. Context->Value = NULL;
  207. //
  208. // Adjust counts.
  209. //
  210. Context->Inf->TotalLineCount++;
  211. Context->Section->LineCount++;
  212. if(LineKey) {
  213. Context->Inf->TotalValueCount++;
  214. NewLine->ValueCount = 1;
  215. }
  216. return(TRUE);
  217. }
  218. BOOL
  219. SpAppendValue(
  220. IN PPARSE_CONTEXT Context,
  221. IN PTCHAR ValueString
  222. )
  223. /*++
  224. Routine Description:
  225. This appends a new value to the value list in the current line.
  226. Arguments:
  227. Context - supplies the parse context.
  228. ValueString - The value string to be added.
  229. Return Value:
  230. BOOL - FALSE if failure (out of memory)
  231. --*/
  232. {
  233. PX_VALUE NewValue;
  234. MYASSERT(Context->Line);
  235. //
  236. // Allocate memory for the new value record
  237. //
  238. if((NewValue = MyMalloc(sizeof(X_VALUE))) == NULL) {
  239. return(FALSE);
  240. }
  241. ZeroMemory(NewValue,sizeof(X_VALUE));
  242. NewValue->Name = ValueString;
  243. //
  244. // Link it in.
  245. //
  246. if(Context->Value) {
  247. Context->Value->Next = NewValue;
  248. } else {
  249. Context->Line->Value = NewValue;
  250. }
  251. //
  252. // Adjust counts
  253. //
  254. Context->Value = NewValue;
  255. Context->Inf->TotalValueCount++;
  256. Context->Line->ValueCount++;
  257. return(TRUE);
  258. }
  259. X_TOKEN
  260. SpGetToken(
  261. IN OUT PCTSTR *Stream,
  262. IN PCTSTR StreamEnd,
  263. IN PTCHAR pszStrTerms,
  264. IN PTCHAR pszQStrTerms,
  265. IN PTCHAR pszCBrStrTerms
  266. )
  267. /*++
  268. Routine Description:
  269. This function returns the Next token from the configuration stream.
  270. Arguments:
  271. Stream - Supplies the address of the configuration stream. Returns
  272. the address of where to start looking for tokens within the
  273. stream.
  274. StreamEnd - Supplies the memory address immediately following the
  275. character stream.
  276. Return Value:
  277. The next token
  278. --*/
  279. {
  280. PCTSTR pch, pchStart;
  281. PTCHAR pchNew;
  282. DWORD Length, i;
  283. X_TOKEN Token;
  284. //
  285. // Skip whitespace (except for eol)
  286. //
  287. pch = *Stream;
  288. while(pch < StreamEnd) {
  289. SkipWhitespace(&pch, StreamEnd);
  290. if((pch < StreamEnd) && !(*pch)) {
  291. //
  292. // We hit a NULL char--skip it
  293. // and keep looking for a token.
  294. //
  295. pch++;
  296. } else {
  297. break;
  298. }
  299. }
  300. //
  301. // Check for comments and remove them
  302. //
  303. if((pch < StreamEnd) &&
  304. ((*pch == TEXT(';')) || (*pch == TEXT('#')) ||
  305. ((*pch == TEXT('/')) && (*(pch+1) == TEXT('/')))))
  306. {
  307. do {
  308. pch++;
  309. } while((pch < StreamEnd) && (*pch != TEXT('\n')));
  310. }
  311. if(pch == StreamEnd) {
  312. *Stream = pch;
  313. Token.Type = TOK_EOF;
  314. Token.pValue = NULL;
  315. return(Token);
  316. }
  317. switch (*pch) {
  318. case TEXT('['):
  319. pch++;
  320. Token.Type = TOK_LBRACE;
  321. Token.pValue = NULL;
  322. break;
  323. case TEXT(']'):
  324. pch++;
  325. Token.Type = TOK_RBRACE;
  326. Token.pValue = NULL;
  327. break;
  328. case TEXT('='):
  329. pch++;
  330. Token.Type = TOK_EQUAL;
  331. Token.pValue = NULL;
  332. break;
  333. case TEXT(','):
  334. pch++;
  335. Token.Type = TOK_COMMA;
  336. Token.pValue = NULL;
  337. break;
  338. case TEXT('\n'):
  339. pch++;
  340. Token.Type = TOK_EOL;
  341. Token.pValue = NULL;
  342. break;
  343. case TEXT('\"'):
  344. pch++;
  345. //
  346. // determine quoted string
  347. //
  348. pchStart = pch;
  349. while((pch < StreamEnd) && !IsStringTerminator(pszQStrTerms,*pch)) {
  350. pch++;
  351. }
  352. //
  353. //
  354. // Only valid terminator is double quote
  355. //
  356. if((pch == StreamEnd) || (*pch != TEXT('\"'))) {
  357. Token.Type = TOK_ERRPARSE;
  358. Token.pValue = NULL;
  359. } else {
  360. //
  361. // Got a valid string. Allocate space for it and save.
  362. //
  363. Length = (DWORD)(pch - pchStart);
  364. if((pchNew = MyMalloc((Length+1)*sizeof(TCHAR))) == NULL) {
  365. Token.Type = TOK_ERRNOMEM;
  366. Token.pValue = NULL;
  367. } else {
  368. //
  369. // We can't use string copy here, since there may be
  370. // NULL chars in the string (which we convert to
  371. // spaces during the copy).
  372. //
  373. // lstrcpyn(pchNew,pchStart,Length+1);
  374. //
  375. for(i = 0; i < Length; i++) {
  376. if(!(pchNew[i] = pchStart[i])) {
  377. pchNew[i] = TEXT(' ');
  378. }
  379. }
  380. pchNew[Length] = 0;
  381. Token.Type = TOK_STRING;
  382. Token.pValue = pchNew;
  383. }
  384. pch++; // advance past the quote
  385. }
  386. break;
  387. case TEXT('{'):
  388. //
  389. // determine quoted string
  390. //
  391. pchStart = pch;
  392. while((pch < StreamEnd) && !IsStringTerminator(pszCBrStrTerms,*pch)) {
  393. pch++;
  394. }
  395. //
  396. // Only valid terminator is curly brace
  397. if((pch == StreamEnd) || (*pch != TEXT('}'))) {
  398. Token.Type = TOK_ERRPARSE;
  399. Token.pValue = NULL;
  400. } else {
  401. //
  402. // Got a valid string. Allocate space for it and save.
  403. //
  404. Length = (DWORD)(pch - pchStart) + 1;
  405. if((pchNew = MyMalloc((Length+1)*sizeof(TCHAR))) == NULL) {
  406. Token.Type = TOK_ERRNOMEM;
  407. Token.pValue = NULL;
  408. } else {
  409. //
  410. // We can't use string copy here, since there may be
  411. // NULL chars in the string (which we convert to
  412. // spaces during the copy).
  413. //
  414. // lstrcpyn(pchNew,pchStart,Length+1);
  415. //
  416. for(i = 0; i < Length; i++) {
  417. if(!(pchNew[i] = pchStart[i])) {
  418. pchNew[i] = TEXT(' ');
  419. }
  420. }
  421. pchNew[Length] = TEXT('\0');
  422. Token.Type = TOK_STRING;
  423. Token.pValue = pchNew;
  424. }
  425. pch++; // advance past the brace
  426. }
  427. break;
  428. default:
  429. //
  430. // determine regular string
  431. //
  432. pchStart = pch;
  433. while((pch < StreamEnd) && !IsStringTerminator(pszStrTerms,*pch)) {
  434. pch++;
  435. }
  436. //
  437. // Disallow empty strings here
  438. //
  439. if(pch == pchStart) {
  440. pch++;
  441. Token.Type = TOK_ERRPARSE;
  442. Token.pValue = NULL;
  443. } else {
  444. Length = (DWORD)(pch - pchStart);
  445. if((pchNew = MyMalloc((Length+1)*sizeof(TCHAR))) == NULL) {
  446. Token.Type = TOK_ERRNOMEM;
  447. Token.pValue = NULL;
  448. } else {
  449. //
  450. // We can't use string copy here, since there may be
  451. // NULL chars in the string (which we convert to
  452. // spaces during the copy).
  453. //
  454. // lstrcpyn(pchNew,pchStart,Length+1);
  455. //
  456. for(i = 0; i < Length; i++) {
  457. if(!(pchNew[i] = pchStart[i])) {
  458. pchNew[i] = TEXT(' ');
  459. }
  460. }
  461. pchNew[Length] = 0;
  462. Token.Type = TOK_STRING;
  463. Token.pValue = pchNew;
  464. }
  465. }
  466. break;
  467. }
  468. *Stream = pch;
  469. return(Token);
  470. }
  471. DWORD
  472. ParseInfBuffer(
  473. IN PCTSTR Buffer,
  474. IN DWORD BufferSize,
  475. OUT PX_INF *Inf,
  476. OUT UINT *ErrorLineNumber
  477. )
  478. /*++
  479. Routine Description:
  480. Given a character buffer containing the INF file, this routine parses
  481. the INF into an internal form with Section records, Line records and
  482. Value records.
  483. Arguments:
  484. Buffer - contains to ptr to a buffer containing the INF file
  485. BufferSize - contains the size of Buffer, in characters.
  486. Inf - if the return value is NO_ERROR, receives a pointer to the
  487. inf descriptor for the parsed inf.
  488. ErrorLineNumber - receives the line number where a syntax/oom error
  489. was encountered, if the return value is not NO_ERROR.
  490. Return Value:
  491. Win32 error code (with inf extensions) indicating outcome.
  492. If NO_ERROR, Inf is filled in.
  493. If not NO_ERROR, ErrorLineNumber is filled in.
  494. --*/
  495. {
  496. PCTSTR Stream, StreamEnd;
  497. PTCHAR pchSectionName, pchValue, pchEmptyString;
  498. DWORD State, InfLine;
  499. DWORD LastState;
  500. X_TOKEN Token;
  501. BOOL Done;
  502. PTCHAR pszStrTermsCur = szStrTerms;
  503. PTCHAR pszQStrTermsCur = szQStrTerms;
  504. PTCHAR pszCBrStrTermsCur = szCBrStrTerms;
  505. DWORD ErrorCode;
  506. PARSE_CONTEXT Context;
  507. //
  508. // Initialize the globals and create an inf record structure.
  509. //
  510. ZeroMemory(&Context,sizeof(PARSE_CONTEXT));
  511. if((Context.Inf = MyMalloc(sizeof(X_INF))) == NULL) {
  512. return(ERROR_NOT_ENOUGH_MEMORY);
  513. }
  514. ZeroMemory(Context.Inf,sizeof(X_INF));
  515. //
  516. // Set initial state
  517. //
  518. State = 1;
  519. LastState = State;
  520. InfLine = 1;
  521. StreamEnd = (Stream = Buffer) + BufferSize;
  522. Done = FALSE;
  523. ErrorCode = NO_ERROR;
  524. //
  525. // Initialize the token type, so we'll know not to free any
  526. // memory for it if we hit an exception right off the bat.
  527. //
  528. Token.Type = TOK_ERRPARSE;
  529. pchSectionName = NULL;
  530. pchValue = NULL;
  531. pchEmptyString = NULL;
  532. //
  533. // Guard token processing loop with try/except in case we
  534. // get an inpage error.
  535. //
  536. try {
  537. while(!Done) {
  538. Token = SpGetToken(&Stream,
  539. StreamEnd,
  540. pszStrTermsCur,
  541. pszQStrTermsCur,
  542. pszCBrStrTermsCur
  543. );
  544. //
  545. // If you need to debug the parser, uncomment the following:
  546. #if 0
  547. DebugPrintEx(DPFLTR_ERROR_LEVEL, TEXT("STATE: %u TOKEN: %u (%s) LAST: %u\r\n"),
  548. State, Token.Type,
  549. Token.pValue ? Token.pValue : TEXT("NULL"),
  550. LastState);
  551. #endif
  552. if(Token.Type == TOK_ERRNOMEM) {
  553. Done = TRUE;
  554. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  555. } else {
  556. switch (State) {
  557. //
  558. // STATE1: Start of file, this state remains till first
  559. // section is found
  560. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
  561. //
  562. case 1:
  563. switch (Token.Type) {
  564. case TOK_EOL:
  565. break;
  566. case TOK_EOF:
  567. Done = TRUE;
  568. break;
  569. case TOK_LBRACE:
  570. pszStrTermsCur = szBrcStrTerms;
  571. State = 2;
  572. break;
  573. default:
  574. Done = TRUE;
  575. ErrorCode = ERROR_EXPECTED_SECTION_NAME;
  576. break;
  577. }
  578. break;
  579. //
  580. // STATE 2: Section LBRACE has been received, expecting STRING
  581. //
  582. // Valid Tokens: TOK_STRING
  583. //
  584. case 2:
  585. //
  586. // allow spaces in section names
  587. //
  588. switch (Token.Type) {
  589. case TOK_STRING:
  590. State = 3;
  591. //
  592. // restore term. string with space
  593. //
  594. pszStrTermsCur = szStrTerms;
  595. pchSectionName = Token.pValue;
  596. break;
  597. default:
  598. Done = TRUE;
  599. ErrorCode = ERROR_BAD_SECTION_NAME_LINE;
  600. break;
  601. }
  602. break;
  603. //
  604. // STATE 3: Section Name received, expecting RBRACE
  605. //
  606. // Valid Tokens: TOK_RBRACE
  607. //
  608. case 3:
  609. switch (Token.Type) {
  610. case TOK_RBRACE:
  611. State = 4;
  612. break;
  613. default:
  614. Done = TRUE;
  615. ErrorCode = ERROR_BAD_SECTION_NAME_LINE;
  616. break;
  617. }
  618. break;
  619. //
  620. // STATE 4: Section Definition Complete, expecting EOL
  621. //
  622. // Valid Tokens: TOK_EOL, TOK_EOF
  623. //
  624. case 4:
  625. switch (Token.Type) {
  626. case TOK_EOL:
  627. if(SpAppendSection(&Context,pchSectionName)) {
  628. pchSectionName = NULL;
  629. State = 5;
  630. } else {
  631. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  632. Done = TRUE;
  633. }
  634. break;
  635. case TOK_EOF:
  636. if(SpAppendSection(&Context,pchSectionName)) {
  637. pchSectionName = NULL;
  638. } else {
  639. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  640. }
  641. Done = TRUE;
  642. break;
  643. default:
  644. ErrorCode = ERROR_BAD_SECTION_NAME_LINE;
  645. Done = TRUE;
  646. break;
  647. }
  648. break;
  649. //
  650. // STATE 5: Expecting Section Lines
  651. //
  652. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
  653. //
  654. case 5:
  655. switch (Token.Type) {
  656. case TOK_EOL:
  657. break;
  658. case TOK_EOF:
  659. Done = TRUE;
  660. break;
  661. case TOK_STRING:
  662. pchValue = Token.pValue;
  663. //
  664. // Set token's pValue pointer to NULL, so we won't
  665. // try to free the same memory twice if we hit an
  666. // exception
  667. //
  668. Token.pValue = NULL;
  669. State = 6;
  670. break;
  671. case TOK_LBRACE:
  672. pszStrTermsCur = szBrcStrTerms;
  673. State = 2;
  674. break;
  675. default:
  676. // Done = TRUE;
  677. // ErrorCode = ERROR_GENERAL_SYNTAX;
  678. State = 20;
  679. LastState = 5;
  680. break;
  681. }
  682. break;
  683. //
  684. // STATE 6: String returned, not sure whether it is key or value
  685. //
  686. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
  687. //
  688. case 6:
  689. switch (Token.Type) {
  690. case TOK_EOL:
  691. if(SpAppendLine(&Context,NULL) && SpAppendValue(&Context,pchValue)) {
  692. pchValue = NULL;
  693. State = 5;
  694. } else {
  695. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  696. Done = TRUE;
  697. }
  698. break;
  699. case TOK_EOF:
  700. if(SpAppendLine(&Context,NULL) && SpAppendValue(&Context,pchValue)) {
  701. pchValue = NULL;
  702. } else {
  703. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  704. }
  705. Done = TRUE;
  706. break;
  707. case TOK_COMMA:
  708. if(SpAppendLine(&Context,NULL) && SpAppendValue(&Context,pchValue)) {
  709. pchValue = NULL;
  710. State = 7;
  711. } else {
  712. Done = TRUE;
  713. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  714. }
  715. break;
  716. case TOK_EQUAL:
  717. if(SpAppendLine(&Context,pchValue)) {
  718. pchValue = NULL;
  719. State = 8;
  720. } else {
  721. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  722. Done = TRUE;
  723. }
  724. break;
  725. case TOK_STRING:
  726. MyFree(Token.pValue);
  727. Token.pValue = NULL;
  728. // fall through
  729. default:
  730. // Done = TRUE;
  731. // ErrorCode = ERROR_GENERAL_SYNTAX;
  732. //
  733. if(pchValue) {
  734. MyFree(pchValue);
  735. pchValue = NULL;
  736. }
  737. State = 20;
  738. LastState = 5;
  739. break;
  740. }
  741. break;
  742. //
  743. // STATE 7: Comma received, Expecting another string
  744. //
  745. // Valid Tokens: TOK_STRING, TOK_EOL, TOK_EOF, TOK_COMMA
  746. //
  747. case 7:
  748. switch (Token.Type) {
  749. case TOK_STRING:
  750. if(SpAppendValue(&Context,Token.pValue)) {
  751. State = 9;
  752. } else {
  753. Done = TRUE;
  754. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  755. }
  756. break;
  757. case TOK_COMMA:
  758. case TOK_EOL:
  759. case TOK_EOF:
  760. //
  761. // If we hit end-of-line or end-of-file, then add an
  762. // empty-string value.
  763. //
  764. if(pchEmptyString = MyMalloc(sizeof(TCHAR))) {
  765. *pchEmptyString = TEXT('\0');
  766. if(SpAppendValue(&Context, pchEmptyString)) {
  767. if(Token.Type == TOK_EOL) {
  768. State = 5;
  769. } else if (Token.Type == TOK_COMMA) {
  770. State = 7;
  771. } else {
  772. Done = TRUE;
  773. }
  774. } else {
  775. MyFree(pchEmptyString);
  776. pchEmptyString = NULL;
  777. Done = TRUE;
  778. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  779. }
  780. } else {
  781. Done = TRUE;
  782. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  783. }
  784. pchEmptyString = NULL;
  785. break;
  786. default:
  787. // Done = TRUE;
  788. // ErrorCode = ERROR_GENERAL_SYNTAX;
  789. State = 20;
  790. LastState = 7;
  791. break;
  792. }
  793. break;
  794. //
  795. // STATE 8: Equal received, Expecting another string
  796. //
  797. // Valid Tokens: TOK_STRING, TOK_EOL, TOK_EOF, TOK_COMMA
  798. //
  799. case 8:
  800. switch (Token.Type) {
  801. case TOK_STRING:
  802. if(SpAppendValue(&Context,Token.pValue)) {
  803. State = 9;
  804. } else {
  805. Done = TRUE;
  806. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  807. }
  808. break;
  809. case TOK_COMMA:
  810. case TOK_EOL:
  811. case TOK_EOF:
  812. //
  813. // If we hit end-of-line or end-of-file, then add an
  814. // empty-string value.
  815. //
  816. if(pchEmptyString = MyMalloc(sizeof(TCHAR))) {
  817. *pchEmptyString = TEXT('\0');
  818. if(SpAppendValue(&Context, pchEmptyString)) {
  819. if(Token.Type == TOK_EOL) {
  820. State = 5;
  821. } else if (Token.Type == TOK_COMMA) {
  822. State = 7;
  823. } else {
  824. Done = TRUE;
  825. }
  826. } else {
  827. MyFree(pchEmptyString);
  828. pchEmptyString = NULL;
  829. Done = TRUE;
  830. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  831. }
  832. } else {
  833. Done = TRUE;
  834. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  835. }
  836. pchEmptyString = NULL;
  837. break;
  838. default:
  839. // Done = TRUE;
  840. // ErrorCode = ERROR_GENERAL_SYNTAX;
  841. State = 20;
  842. LastState = 8;
  843. break;
  844. }
  845. break;
  846. //
  847. // STATE 9: String received after equal, value string
  848. //
  849. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  850. //
  851. case 9:
  852. switch (Token.Type) {
  853. case TOK_EOL:
  854. State = 5;
  855. break;
  856. case TOK_EOF:
  857. Done = TRUE;
  858. break;
  859. case TOK_COMMA:
  860. State = 7;
  861. break;
  862. case TOK_STRING:
  863. MyFree(Token.pValue);
  864. Token.pValue = NULL;
  865. // fall through
  866. default:
  867. // Done = TRUE;
  868. // ErrorCode = ERROR_GENERAL_SYNTAX;
  869. State = 20;
  870. LastState = 5;
  871. break;
  872. }
  873. break;
  874. //
  875. // STATE 10: Value string definitely received
  876. //
  877. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  878. //
  879. case 10:
  880. switch (Token.Type) {
  881. case TOK_EOL:
  882. State =5;
  883. break;
  884. case TOK_EOF:
  885. Done = TRUE;
  886. break;
  887. case TOK_COMMA:
  888. State = 7;
  889. break;
  890. case TOK_STRING:
  891. MyFree(Token.pValue);
  892. Token.pValue = NULL;
  893. // fall through
  894. default:
  895. // Done = TRUE;
  896. // ErrorCode = ERROR_GENERAL_SYNTAX;
  897. State = 20;
  898. LastState = 10;
  899. break;
  900. }
  901. break;
  902. //
  903. // STATE 20: Eat a line of INF
  904. //
  905. // Valid Tokens: TOK_EOL, TOK_EOF
  906. //
  907. case 20:
  908. switch (Token.Type) {
  909. case TOK_EOL:
  910. State = LastState;
  911. break;
  912. case TOK_EOF:
  913. Done = TRUE;
  914. break;
  915. case TOK_STRING:
  916. MyFree(Token.pValue);
  917. Token.pValue = NULL;
  918. // fall through
  919. default:
  920. break;
  921. }
  922. break;
  923. default:
  924. Done = TRUE;
  925. ErrorCode = ERROR_GENERAL_SYNTAX;
  926. break;
  927. } // end switch(State)
  928. } // end else
  929. if(ErrorCode == NO_ERROR) {
  930. //
  931. // Keep track of line numbers
  932. //
  933. if(Token.Type == TOK_EOL) {
  934. InfLine++;
  935. }
  936. }
  937. } // End while
  938. } except(EXCEPTION_EXECUTE_HANDLER) {
  939. ErrorCode = ERROR_READ_FAULT;
  940. //
  941. // Reference the following string pointers here in the except clause so that
  942. // the compiler won't re-order the code in such a way that we don't know whether
  943. // or not to free the corresponding buffers.
  944. //
  945. Token.pValue = Token.pValue;
  946. pchEmptyString = pchEmptyString;
  947. pchSectionName = pchSectionName;
  948. pchValue = pchValue;
  949. }
  950. if(ErrorCode != NO_ERROR) {
  951. if((Token.Type == TOK_STRING) && Token.pValue) {
  952. MyFree(Token.pValue);
  953. }
  954. if(pchEmptyString) {
  955. MyFree(pchEmptyString);
  956. }
  957. if(pchSectionName) {
  958. MyFree(pchSectionName);
  959. }
  960. if(pchValue) {
  961. MyFree(pchValue);
  962. }
  963. SpFreeTemporaryParseStructures(Context.Inf);
  964. Context.Inf = NULL;
  965. *ErrorLineNumber = InfLine;
  966. }
  967. *Inf = Context.Inf;
  968. return(ErrorCode);
  969. }
  970. DWORD
  971. ParseOldInf(
  972. IN PCTSTR FileImage,
  973. IN DWORD FileImageSize,
  974. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  975. OUT PLOADED_INF *Inf,
  976. OUT UINT *ErrorLineNumber
  977. )
  978. /*++
  979. Routine Description:
  980. Top-level routine to parse an old-style inf file.
  981. The file is first parsed using the old parser, into data structures
  982. understood by that parser. Following that those structures are converted
  983. into the universal internal inf format.
  984. Arguments:
  985. FileImage - supplies a pointer to the in-memory image of the file.
  986. The image is assumed to be terminated by a nul character.
  987. FileImageSize - supplies the number of wide chars in the FileImage.
  988. LogContext - supplies optional logging context
  989. Inf - receives a pointer to the inf descriptor for the file.
  990. ErrorLineNumber - receives the line number of a syntx error if one is
  991. detected in the inf file.
  992. Return Value:
  993. Win32 error code (with inf extensions) indicating outcome.
  994. If NO_ERROR, Inf is filled in.
  995. If not NO_ERROR, ErrorLineNumber is filled in.
  996. --*/
  997. {
  998. PLOADED_INF inf;
  999. PX_INF X_Inf;
  1000. DWORD rc;
  1001. PX_SECTION X_Section;
  1002. PX_LINE X_Line;
  1003. PX_VALUE X_Value;
  1004. LONG StringId, StringId2;
  1005. BOOL b;
  1006. UINT LineNumber;
  1007. UINT ValueNumber;
  1008. PLONG TempValueBlock;
  1009. PTSTR SearchString;
  1010. //
  1011. // First go off and parse the file into the temporary (old-style)
  1012. // inf structures.
  1013. //
  1014. rc = ParseInfBuffer(FileImage,FileImageSize,&X_Inf,ErrorLineNumber);
  1015. if(rc != NO_ERROR) {
  1016. return(rc);
  1017. }
  1018. //
  1019. // Allocate a new-style inf descriptor. (Note that we allocate an additional
  1020. // <TotalLineCount> number of values, since each line may have a key, which
  1021. // requires two values each. We'll trim this down later on.)
  1022. //
  1023. inf = AllocateLoadedInfDescriptor(X_Inf->SectionCount,
  1024. X_Inf->TotalLineCount,
  1025. X_Inf->TotalValueCount + X_Inf->TotalLineCount,
  1026. LogContext
  1027. );
  1028. if(!inf) {
  1029. SpFreeTemporaryParseStructures(X_Inf);
  1030. return(ERROR_NOT_ENOUGH_MEMORY);
  1031. }
  1032. inf->Style = INF_STYLE_OLDNT;
  1033. //
  1034. // Now, parse the old-style inf structures into new-style inf structures.
  1035. //
  1036. b = TRUE;
  1037. LineNumber = 0;
  1038. ValueNumber = 0;
  1039. for(X_Section=X_Inf->Section; b && X_Section; X_Section=X_Section->Next) {
  1040. //
  1041. // Add the section to the section block.
  1042. //
  1043. StringId = pStringTableAddString(inf->StringTable,
  1044. X_Section->Name,
  1045. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  1046. NULL,0
  1047. );
  1048. if(StringId == -1) {
  1049. b = FALSE;
  1050. } else {
  1051. inf->SectionBlock[inf->SectionCount].SectionName = StringId;
  1052. inf->SectionBlock[inf->SectionCount].LineCount = X_Section->LineCount;
  1053. inf->SectionBlock[inf->SectionCount].Lines = LineNumber;
  1054. inf->SectionCount++;
  1055. }
  1056. for(X_Line=X_Section->Line; b && X_Line; X_Line=X_Line->Next) {
  1057. //
  1058. // Add the line to the line block.
  1059. //
  1060. inf->LineBlock[LineNumber].ValueCount = (WORD)X_Line->ValueCount;
  1061. if(X_Line->Name) {
  1062. inf->LineBlock[LineNumber].Flags = INF_LINE_HASKEY | INF_LINE_SEARCHABLE;
  1063. inf->LineBlock[LineNumber].ValueCount++;
  1064. } else if(X_Line->ValueCount == 1) {
  1065. //
  1066. // If the line only has a single value, then it's searchable, even if it
  1067. // doesn't have a key.
  1068. //
  1069. inf->LineBlock[LineNumber].Flags = INF_LINE_SEARCHABLE;
  1070. inf->LineBlock[LineNumber].ValueCount++;
  1071. } else {
  1072. inf->LineBlock[LineNumber].Flags = 0;
  1073. }
  1074. if(b) {
  1075. inf->LineBlock[LineNumber].Values = ValueNumber;
  1076. X_Value = X_Line->Value;
  1077. //
  1078. // If the line is searchable (i.e., has a key xor a single value), then add the
  1079. // search value twice--once case insensitively and once case-sensitively.
  1080. //
  1081. if(ISSEARCHABLE(&(inf->LineBlock[LineNumber]))) {
  1082. if(X_Line->Name) {
  1083. SearchString = X_Line->Name;
  1084. } else {
  1085. SearchString = X_Value->Name;
  1086. X_Value = X_Value->Next;
  1087. }
  1088. //
  1089. // First get the case-sensitive string id...
  1090. //
  1091. StringId = pStringTableAddString(
  1092. inf->StringTable,
  1093. SearchString,
  1094. STRTAB_CASE_SENSITIVE,
  1095. NULL,0
  1096. );
  1097. //
  1098. // And now get the case-insensitive string id...
  1099. //
  1100. StringId2 = pStringTableAddString(inf->StringTable,
  1101. SearchString,
  1102. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  1103. NULL,0
  1104. );
  1105. if((StringId == -1) || (StringId2 == -1)) {
  1106. b = FALSE;
  1107. } else {
  1108. inf->ValueBlock[ValueNumber++] = StringId2; // Add the searchable string...
  1109. inf->ValueBlock[ValueNumber++] = StringId; // and then the displayable one.
  1110. }
  1111. }
  1112. for( ; b && X_Value; X_Value=X_Value->Next) {
  1113. //
  1114. // Add the value to the value block.
  1115. //
  1116. StringId = pStringTableAddString(inf->StringTable,
  1117. X_Value->Name,
  1118. STRTAB_CASE_SENSITIVE,
  1119. NULL,0
  1120. );
  1121. if(StringId == -1) {
  1122. b = FALSE;
  1123. } else {
  1124. inf->ValueBlock[ValueNumber++] = StringId;
  1125. }
  1126. }
  1127. LineNumber++;
  1128. }
  1129. }
  1130. }
  1131. //
  1132. // Record the sizes of the INF data blocks.
  1133. //
  1134. inf->SectionBlockSizeBytes = X_Inf->SectionCount * sizeof(INF_SECTION);
  1135. inf->LineBlockSizeBytes = X_Inf->TotalLineCount * sizeof(INF_LINE);
  1136. //
  1137. // We don't need the temporary inf descriptors any more.
  1138. //
  1139. SpFreeTemporaryParseStructures(X_Inf);
  1140. //
  1141. // Attempt to trim the value block down to exact size necessary. Since this buffer is
  1142. // either shrinking or staying the same, the realloc shouldn't fail, but if it does, we'll
  1143. // just continue to use the original block.
  1144. //
  1145. inf->ValueBlockSizeBytes = ValueNumber * sizeof(LONG);
  1146. if(TempValueBlock = MyRealloc(inf->ValueBlock, ValueNumber * sizeof(LONG))) {
  1147. inf->ValueBlock = TempValueBlock;
  1148. }
  1149. //
  1150. // If an error has occured, free the inf descriptor we've
  1151. // been building. Otherwise we want to pass that descriptor
  1152. // back to the caller.
  1153. //
  1154. if(b) {
  1155. *Inf = inf;
  1156. } else {
  1157. *ErrorLineNumber = 0;
  1158. FreeLoadedInfDescriptor(inf);
  1159. }
  1160. return(b ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY);
  1161. }
  1162. DWORD
  1163. ProcessOldInfVersionBlock(
  1164. IN PLOADED_INF Inf
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. Set up a version node for an old-style inf file. The version node is
  1169. simulated in that there is no [Version] section; we look for other stuff
  1170. in the file to simulate version information.
  1171. Class is determined from [Identification].OptionType.
  1172. Signature is determined from [Signature].FileType.
  1173. If the signature is MICROSOFT_FILE then we set the Provider to the localized
  1174. version of "Microsoft."
  1175. Arguments:
  1176. Inf - supplies a pointer to the inf descriptor for the file.
  1177. Return Value:
  1178. Win32 error code (with inf extensions) indicating outcome.
  1179. --*/
  1180. {
  1181. TCHAR StrBuf[128];
  1182. PTSTR String;
  1183. //
  1184. // Class
  1185. //
  1186. if(String = InfGetKeyOrValue(Inf, TEXT("Identification"), TEXT("OptionType"), 0, 1, NULL)) {
  1187. if(!AddDatumToVersionBlock(&(Inf->VersionBlock), pszClass, String)) {
  1188. return ERROR_NOT_ENOUGH_MEMORY;
  1189. }
  1190. }
  1191. //
  1192. // Signature
  1193. //
  1194. if(String = InfGetKeyOrValue(Inf, pszSignature, TEXT("FileType"), 0, 1, NULL)) {
  1195. if(!AddDatumToVersionBlock(&(Inf->VersionBlock), pszSignature, String)) {
  1196. return ERROR_NOT_ENOUGH_MEMORY;
  1197. }
  1198. }
  1199. //
  1200. // Provider
  1201. //
  1202. if(String && !_tcsicmp(String, TEXT("MICROSOFT_FILE"))) {
  1203. LoadString(MyDllModuleHandle, IDS_MICROSOFT, StrBuf, sizeof(StrBuf)/sizeof(TCHAR));
  1204. if(!AddDatumToVersionBlock(&(Inf->VersionBlock), pszProvider, StrBuf)) {
  1205. return ERROR_NOT_ENOUGH_MEMORY;
  1206. }
  1207. }
  1208. return NO_ERROR;
  1209. }