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.

2493 lines
58 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. inf.c
  5. Abstract:
  6. This module implements functions to access the INF using the same
  7. parser as the loader and textmode setup.
  8. Author:
  9. Vijesh Shetty
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //#include <string.h>
  15. //#include <ctype.h>
  16. #define ISSPACE(x) (((x) == TEXT(' ')) || ((x) == TEXT('\t')) || ((x) == TEXT('\r')))
  17. #define STRNCPY(s1,s2,n) CopyMemory((s1),(s2),(n)*sizeof(WCHAR))
  18. //
  19. // EXPORTED BY THE PARSER AND USED BY BOTH THE PARSER AND
  20. // THE INF HANDLING COMPONENTS
  21. //
  22. // typedefs exported
  23. //
  24. DWORD Verbose=NOSPEW;
  25. PTCHAR EmptyValue;
  26. typedef struct _value {
  27. struct _value *pNext;
  28. PTSTR pName;
  29. BOOL IsStringId;
  30. } XVALUE, *PXVALUE;
  31. typedef struct _line {
  32. struct _line *pNext;
  33. PTSTR pName;
  34. PXVALUE pValue;
  35. } LINE, *PLINE;
  36. typedef struct _section {
  37. struct _section *pNext;
  38. PTSTR pName;
  39. PLINE pLine;
  40. } SECTION, *PSECTION;
  41. typedef struct _inf {
  42. PSECTION pSection;
  43. } INF, *PINF;
  44. DWORD
  45. ParseInfBuffer(
  46. PTSTR Buffer,
  47. DWORD Size,
  48. PVOID *Handle,
  49. DWORD Phase
  50. );
  51. //
  52. // DEFINES USED FOR THE PARSER INTERNALLY
  53. //
  54. //
  55. // typedefs used
  56. //
  57. typedef enum _tokentype {
  58. TOK_EOF,
  59. TOK_EOL,
  60. TOK_LBRACE,
  61. TOK_RBRACE,
  62. TOK_STRING,
  63. TOK_STRING_ID,
  64. TOK_EQUAL,
  65. TOK_COMMA,
  66. TOK_ERRPARSE,
  67. TOK_ERRNOMEM
  68. } TOKENTYPE, *PTOKENTTYPE;
  69. //
  70. // We often need an empty string while processing the inf files. Rather
  71. // than incur the overhead of allocating memory for an empty string, we'll
  72. // just point to this empty string for all cases.
  73. //
  74. PTSTR CommonStrings[11] =
  75. { (PTSTR)(TEXT("0")),
  76. (PTSTR)(TEXT("1")),
  77. (PTSTR)(TEXT("2")),
  78. (PTSTR)(TEXT("3")),
  79. (PTSTR)(TEXT("4")),
  80. (PTSTR)(TEXT("5")),
  81. (PTSTR)(TEXT("6")),
  82. (PTSTR)(TEXT("7")),
  83. (PTSTR)(TEXT("8")),
  84. (PTSTR)(TEXT("9")),
  85. (PTSTR)(TEXT(""))
  86. };
  87. typedef struct _token {
  88. TOKENTYPE Type;
  89. PTSTR pValue;
  90. } TOKEN, *PTOKEN;
  91. //
  92. // Routine defines
  93. //
  94. DWORD
  95. DnAppendSection(
  96. IN PTSTR pSectionName
  97. );
  98. DWORD
  99. DnAppendLine(
  100. IN PTSTR pLineKey
  101. );
  102. DWORD
  103. DnAppendValue(
  104. IN PTSTR pValueString,
  105. IN BOOL IsStringId
  106. );
  107. TOKEN
  108. DnGetToken(
  109. IN OUT PTSTR *Stream,
  110. IN PTSTR MaxStream,
  111. IN DWORD Phase
  112. );
  113. BOOL
  114. IsStringTerminator(
  115. IN TCHAR ch
  116. );
  117. BOOL
  118. IsQStringTerminator(
  119. IN TCHAR ch,
  120. IN TCHAR term
  121. );
  122. // what follows was alinf.c
  123. //
  124. // Internal Routine Declarations for freeing inf structure members
  125. //
  126. VOID
  127. FreeSectionList (
  128. IN PSECTION pSection
  129. );
  130. VOID
  131. FreeLineList (
  132. IN PLINE pLine
  133. );
  134. VOID
  135. FreeValueList (
  136. IN PXVALUE pValue
  137. );
  138. //
  139. // Internal Routine declarations for searching in the INF structures
  140. //
  141. PXVALUE
  142. SearchValueInLine(
  143. IN PLINE pLine,
  144. IN unsigned ValueIndex
  145. );
  146. PLINE
  147. SearchLineInSectionByKey(
  148. IN PSECTION pSection,
  149. IN LPCTSTR Key
  150. );
  151. PLINE
  152. SearchLineInSectionByIndex(
  153. IN PSECTION pSection,
  154. IN unsigned LineIndex
  155. );
  156. PSECTION
  157. SearchSectionByName(
  158. IN PINF pINF,
  159. IN LPCTSTR SectionName
  160. );
  161. BOOL
  162. ProcessStringSection(
  163. PINF pINF
  164. );
  165. LPTSTR
  166. DupString(
  167. IN LPCTSTR String
  168. );
  169. DWORD
  170. UnmapFile(
  171. IN HANDLE MappingHandle,
  172. IN PVOID BaseAddress
  173. );
  174. DWORD
  175. MapFileForRead(
  176. IN LPCTSTR FileName,
  177. OUT PDWORD FileSize,
  178. OUT PHANDLE FileHandle,
  179. OUT PHANDLE MappingHandle,
  180. OUT PVOID *BaseAddress
  181. );
  182. DWORD
  183. LoadInfFile(
  184. IN LPCTSTR Filename,
  185. IN BOOL OemCodepage,
  186. OUT PVOID *InfHandle,
  187. IN DWORD Phase
  188. )
  189. /*++
  190. Routine Description:
  191. Arguments:
  192. Filename - supplies win32 filename of inf file to be loaded.
  193. OemCodepage - if TRUE amd the file named by Filename is not
  194. Unicode text, then the file is assumed to be in the OEM
  195. codepage (otherwise it's in the ANSI codepage).
  196. InfHandle - if successful, receives a handle to be used with
  197. subsequent inf operations.
  198. Return Value:
  199. ERROR_FILE_NOT_FOUND - file does not exist or error opening it.
  200. ERROR_INVALID_DATA - syntax error in inf file.
  201. ERROR_READ_FAULT - unable to read file.
  202. ERROR_NOT_ENOUGH_MEMORY - mem alloc failed
  203. NO_ERROR - file read and parsed.
  204. --*/
  205. {
  206. DWORD err;
  207. DWORD FileSize;
  208. HANDLE FileHandle;
  209. HANDLE MappingHandle;
  210. PVOID BaseAddress;
  211. BOOL IsUnicode;
  212. DWORD ParseCount;
  213. PVOID ParseBuffer;
  214. //
  215. // Open and map the inf file.
  216. //
  217. err = MapFileForRead(Filename,&FileSize,&FileHandle,&MappingHandle,&BaseAddress);
  218. if(err != NO_ERROR) {
  219. err = ERROR_FILE_NOT_FOUND;
  220. goto c0;
  221. }
  222. //
  223. // Determine whether the file is unicode. If it's got the byte order mark
  224. // then it's unicode, otherwise call the IsTextUnicode API. We do it this way
  225. // because IsTextUnicode always returns FALSE on Win95 so we need to break out
  226. // the BOM to detect Unicode files on Win95.
  227. //
  228. if((FileSize >= sizeof(WCHAR)) && (*(PWCHAR)BaseAddress == 0xfeff)) {
  229. IsUnicode = 2;
  230. } else {
  231. IsUnicode = IsTextUnicode(BaseAddress,FileSize,NULL) ? 1 : 0;
  232. }
  233. #ifdef UNICODE
  234. if(IsUnicode) {
  235. //
  236. // Copy into local buffer, skipping BOM if necessary.
  237. //
  238. ParseBuffer = malloc(FileSize);
  239. if(!ParseBuffer) {
  240. err = ERROR_NOT_ENOUGH_MEMORY;
  241. goto c1;
  242. }
  243. try {
  244. CopyMemory(
  245. ParseBuffer,
  246. (PTCHAR)BaseAddress + ((IsUnicode == 2) ? sizeof(WCHAR) : 0),
  247. FileSize - ((IsUnicode == 2) ? sizeof(WCHAR) : 0)
  248. );
  249. } except(EXCEPTION_EXECUTE_HANDLER) {
  250. err = ERROR_READ_FAULT;
  251. }
  252. ParseCount = (FileSize / sizeof(WCHAR)) - ((IsUnicode == 2) ? 1 : 0);
  253. } else {
  254. //
  255. // Convert to Unicode.
  256. //
  257. // Allocate a buffer large enough to hold the maximum sized unicode
  258. // equivalent of the multibyte text. This size occurs when all chars
  259. // in the file are single-byte and thus double in size when converted.
  260. //
  261. ParseBuffer = malloc(FileSize * sizeof(WCHAR));
  262. if(!ParseBuffer) {
  263. err = ERROR_NOT_ENOUGH_MEMORY;
  264. goto c1;
  265. }
  266. try {
  267. ParseCount = MultiByteToWideChar(
  268. OemCodepage ? CP_OEMCP : CP_ACP,
  269. MB_PRECOMPOSED,
  270. BaseAddress,
  271. FileSize,
  272. ParseBuffer,
  273. FileSize
  274. );
  275. if(!ParseCount) {
  276. //
  277. // Assume inpage i/o error
  278. //
  279. err = ERROR_READ_FAULT;
  280. }
  281. } except(EXCEPTION_EXECUTE_HANDLER) {
  282. err = ERROR_READ_FAULT;
  283. }
  284. }
  285. #else
  286. if(IsUnicode) {
  287. //
  288. // Text is unicode but internal routines want ansi. Convert here.
  289. //
  290. // Maximum required buffer is when each unicode char ends up as
  291. // a double-byte char.
  292. //
  293. ParseBuffer = malloc(FileSize);
  294. if(!ParseBuffer) {
  295. err = ERROR_NOT_ENOUGH_MEMORY;
  296. goto c1;
  297. }
  298. try {
  299. ParseCount = WideCharToMultiByte(
  300. CP_ACP,
  301. 0,
  302. (PWCHAR)BaseAddress + ((IsUnicode == 2) ? 1 : 0),
  303. (FileSize / sizeof(WCHAR)) - ((IsUnicode == 2) ? 1 : 0),
  304. ParseBuffer,
  305. FileSize,
  306. NULL,
  307. NULL
  308. );
  309. if(!ParseCount) {
  310. //
  311. // Assume inpage i/o error
  312. //
  313. err = ERROR_READ_FAULT;
  314. }
  315. } except(EXCEPTION_EXECUTE_HANDLER) {
  316. err = ERROR_READ_FAULT;
  317. }
  318. } else {
  319. //
  320. // Text is not unicode. It might be OEM though and could thus still
  321. // require translation.
  322. //
  323. ParseCount = FileSize;
  324. ParseBuffer = malloc(FileSize);
  325. if(!ParseBuffer) {
  326. err = ERROR_NOT_ENOUGH_MEMORY;
  327. goto c1;
  328. }
  329. try {
  330. CopyMemory(ParseBuffer,BaseAddress,FileSize);
  331. } except(EXCEPTION_EXECUTE_HANDLER) {
  332. err = ERROR_READ_FAULT;
  333. }
  334. if(err != NO_ERROR) {
  335. goto c2;
  336. }
  337. if(OemCodepage && (GetOEMCP() != GetACP())) {
  338. OemToCharBuff(ParseBuffer,ParseBuffer,ParseCount);
  339. }
  340. }
  341. #endif
  342. if(err != NO_ERROR) {
  343. goto c2;
  344. }
  345. /*_tprintf(TEXT("\nCalling ParseInfBuffer..\n"));*/
  346. err = ParseInfBuffer(ParseBuffer,ParseCount,InfHandle,Phase);
  347. /*_tprintf(TEXT("\nErr=%d\n"),err);*/
  348. c2:
  349. free(ParseBuffer);
  350. c1:
  351. UnmapFile(MappingHandle,BaseAddress);
  352. CloseHandle(FileHandle);
  353. c0:
  354. return(err);
  355. }
  356. VOID
  357. UnloadInfFile(
  358. IN PVOID InfHandle
  359. )
  360. /*++
  361. Routine Description:
  362. Unload a file previously loaded by LoadInfFile().
  363. Arguments:
  364. InfHandle - supplies a habdle previously returned by a successful
  365. call to LoadInfFile().
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. PINF pINF;
  371. pINF = InfHandle;
  372. FreeSectionList(pINF->pSection);
  373. free(pINF);
  374. }
  375. VOID
  376. FreeSectionList (
  377. IN PSECTION pSection
  378. )
  379. /*++
  380. Routine Description:
  381. Arguments:
  382. Return Value:
  383. --*/
  384. {
  385. PSECTION Next;
  386. while(pSection) {
  387. Next = pSection->pNext;
  388. FreeLineList(pSection->pLine);
  389. if(pSection->pName) {
  390. free(pSection->pName);
  391. }
  392. free(pSection);
  393. pSection = Next;
  394. }
  395. }
  396. VOID
  397. FreeLineList(
  398. IN PLINE pLine
  399. )
  400. /*++
  401. Routine Description:
  402. Arguments:
  403. Return Value:
  404. --*/
  405. {
  406. PLINE Next;
  407. while(pLine) {
  408. Next = pLine->pNext;
  409. FreeValueList(pLine->pValue);
  410. if(pLine->pName) {
  411. free(pLine->pName);
  412. }
  413. free(pLine);
  414. pLine = Next;
  415. }
  416. }
  417. VOID
  418. FreeValueList (
  419. IN PXVALUE pValue
  420. )
  421. /*++
  422. Routine Description:
  423. Arguments:
  424. Return Value:
  425. --*/
  426. {
  427. PXVALUE Next;
  428. while(pValue) {
  429. Next = pValue->pNext;
  430. if(pValue->pName) {
  431. free(pValue->pName);
  432. }
  433. free(pValue);
  434. pValue = Next;
  435. }
  436. }
  437. //
  438. // searches for the existance of a particular section,
  439. // returns line count (-1 if not found)
  440. //
  441. LONG
  442. InfGetSectionLineCount(
  443. IN PVOID INFHandle,
  444. IN PTSTR SectionName
  445. )
  446. /*++
  447. Routine Description:
  448. Arguments:
  449. Return Value:
  450. --*/
  451. {
  452. PSECTION pSection;
  453. PLINE pLine;
  454. LONG count;
  455. //
  456. // if search for section fails return failure
  457. //
  458. if ((pSection = SearchSectionByName(INFHandle,SectionName)) == NULL) {
  459. return(-1);
  460. }
  461. for(count=0,pLine=pSection->pLine; pLine; pLine=pLine->pNext) {
  462. count++;
  463. }
  464. return(count);
  465. }
  466. //
  467. // given section name, line number and index return the value.
  468. //
  469. LPCTSTR
  470. InfGetFieldByIndex(
  471. IN PVOID INFHandle,
  472. IN LPCTSTR SectionName,
  473. IN unsigned LineIndex,
  474. IN unsigned ValueIndex
  475. )
  476. /*++
  477. Routine Description:
  478. Arguments:
  479. Return Value:
  480. --*/
  481. {
  482. PSECTION pSection;
  483. PLINE pLine;
  484. PXVALUE pValue;
  485. if((pSection = SearchSectionByName(
  486. (PINF)INFHandle,
  487. SectionName
  488. ))
  489. == NULL)
  490. return(NULL);
  491. if((pLine = SearchLineInSectionByIndex(
  492. pSection,
  493. LineIndex
  494. ))
  495. == NULL)
  496. return(NULL);
  497. if((pValue = SearchValueInLine(
  498. pLine,
  499. ValueIndex
  500. ))
  501. == NULL)
  502. return(NULL);
  503. return (pValue->pName);
  504. }
  505. BOOL
  506. InfDoesLineExistInSection(
  507. IN PVOID INFHandle,
  508. IN LPCTSTR SectionName,
  509. IN LPCTSTR Key
  510. )
  511. /*++
  512. Routine Description:
  513. Arguments:
  514. Return Value:
  515. --*/
  516. {
  517. PSECTION pSection;
  518. if((pSection = SearchSectionByName(
  519. (PINF)INFHandle,
  520. SectionName
  521. ))
  522. == NULL) {
  523. return( FALSE );
  524. }
  525. if (SearchLineInSectionByKey(pSection, Key) == NULL) {
  526. return( FALSE );
  527. }
  528. return( TRUE );
  529. }
  530. LPCTSTR
  531. InfGetLineKeyName(
  532. IN PVOID INFHandle,
  533. IN LPCTSTR SectionName,
  534. IN unsigned LineIndex
  535. )
  536. {
  537. PSECTION pSection;
  538. PLINE pLine;
  539. pSection = SearchSectionByName((PINF)INFHandle,SectionName);
  540. if(pSection == NULL) {
  541. return(NULL);
  542. }
  543. pLine = SearchLineInSectionByIndex(pSection,LineIndex);
  544. if(pLine == NULL) {
  545. return(NULL);
  546. }
  547. return(pLine->pName);
  548. }
  549. //
  550. // given section name, key and index return the value
  551. //
  552. LPCTSTR
  553. InfGetFieldByKey(
  554. IN PVOID INFHandle,
  555. IN LPCTSTR SectionName,
  556. IN LPCTSTR Key,
  557. IN unsigned ValueIndex
  558. )
  559. /*++
  560. Routine Description:
  561. Arguments:
  562. Return Value:
  563. --*/
  564. {
  565. PSECTION pSection;
  566. PLINE pLine;
  567. PXVALUE pValue;
  568. if((pSection = SearchSectionByName(
  569. (PINF)INFHandle,
  570. SectionName
  571. ))
  572. == NULL)
  573. return(NULL);
  574. if((pLine = SearchLineInSectionByKey(
  575. pSection,
  576. Key
  577. ))
  578. == NULL)
  579. return(NULL);
  580. if((pValue = SearchValueInLine(
  581. pLine,
  582. ValueIndex
  583. ))
  584. == NULL)
  585. return(NULL);
  586. return (pValue->pName);
  587. }
  588. PXVALUE
  589. SearchValueInLine(
  590. IN PLINE pLine,
  591. IN unsigned ValueIndex
  592. )
  593. /*++
  594. Routine Description:
  595. Arguments:
  596. Return Value:
  597. --*/
  598. {
  599. PXVALUE pValue;
  600. unsigned i;
  601. if (pLine == NULL)
  602. return (NULL);
  603. pValue = pLine->pValue;
  604. for (i = 0; (i < ValueIndex) && (pValue = pValue->pNext); i++)
  605. ;
  606. return pValue;
  607. }
  608. PLINE
  609. SearchLineInSectionByKey(
  610. IN PSECTION pSection,
  611. IN LPCTSTR Key
  612. )
  613. /*++
  614. Routine Description:
  615. Arguments:
  616. Return Value:
  617. --*/
  618. {
  619. PLINE pLine;
  620. if (pSection == NULL || Key == NULL) {
  621. return (NULL);
  622. }
  623. pLine = pSection->pLine;
  624. while(pLine && ((pLine->pName == NULL) || lstrcmpi(pLine->pName, Key))) {
  625. pLine = pLine->pNext;
  626. }
  627. return pLine;
  628. }
  629. PLINE
  630. SearchLineInSectionByIndex(
  631. IN PSECTION pSection,
  632. IN unsigned LineIndex
  633. )
  634. /*++
  635. Routine Description:
  636. Arguments:
  637. Return Value:
  638. --*/
  639. {
  640. PLINE pLine;
  641. unsigned i;
  642. //
  643. // Validate the parameters passed in
  644. //
  645. if(pSection == NULL) {
  646. return (NULL);
  647. }
  648. //
  649. // find the start of the line list in the section passed in
  650. //
  651. pLine = pSection->pLine;
  652. //
  653. // traverse down the current line list to the LineIndex th line
  654. //
  655. for (i = 0; (i < LineIndex) && (pLine = pLine->pNext); i++) {
  656. ;
  657. }
  658. //
  659. // return the Line found
  660. //
  661. return pLine;
  662. }
  663. PSECTION
  664. SearchSectionByName(
  665. IN PINF pINF,
  666. IN LPCTSTR SectionName
  667. )
  668. /*++
  669. Routine Description:
  670. Arguments:
  671. Return Value:
  672. --*/
  673. {
  674. PSECTION pSection;
  675. //
  676. // validate the parameters passed in
  677. //
  678. if (pINF == NULL || SectionName == NULL) {
  679. return (NULL);
  680. }
  681. //
  682. // find the section list
  683. //
  684. pSection = pINF->pSection;
  685. //
  686. // traverse down the section list searching each section for the section
  687. // name mentioned
  688. //
  689. while (pSection && lstrcmpi(pSection->pName, SectionName)) {
  690. pSection = pSection->pNext;
  691. }
  692. //
  693. // return the section at which we stopped (either NULL or the section
  694. // which was found
  695. //
  696. return pSection;
  697. }
  698. // what follows was alparse.c
  699. //
  700. // Globals used to make building the lists easier
  701. //
  702. PINF pINF;
  703. PSECTION pSectionRecord;
  704. PLINE pLineRecord;
  705. PXVALUE pValueRecord;
  706. //
  707. // Globals used by the token parser
  708. //
  709. // string terminators are the whitespace characters (isspace: space, tab,
  710. // linefeed, formfeed, vertical tab, carriage return) or the chars given below
  711. TCHAR StringTerminators[] = { TEXT('['),
  712. TEXT(']'),
  713. TEXT('='),
  714. TEXT(','),
  715. TEXT('\"'),
  716. TEXT(' '),
  717. TEXT('\t'),
  718. TEXT('\n'),
  719. TEXT('\f'),
  720. TEXT('\v'),
  721. TEXT('\r'),
  722. TEXT('\032')
  723. };
  724. unsigned NumberOfTerminators = sizeof(StringTerminators)/sizeof(TCHAR);
  725. // string terminators are the whitespace characters (isspace: space, tab,
  726. // linefeed, formfeed, vertical tab, carriage return) or the chars given below - For the loader and textmode
  727. TCHAR LStringTerminators[] = { TEXT('['),
  728. TEXT(']'),
  729. TEXT('='),
  730. TEXT(','),
  731. TEXT('\"'),
  732. TEXT(' '),
  733. TEXT('\t'),
  734. TEXT('\n'),
  735. TEXT('\f'),
  736. TEXT('\v'),
  737. TEXT('\r')
  738. };
  739. //
  740. // quoted string terminators allow some of the regular terminators to
  741. // appear as characters
  742. TCHAR QStringTerminators[] = { TEXT('\n'),
  743. TEXT('\f'),
  744. TEXT('\v'),
  745. TEXT('\r'),
  746. TEXT('\032')
  747. };
  748. unsigned QNumberOfTerminators = sizeof(QStringTerminators)/sizeof(TCHAR);
  749. //
  750. // quoted string terminators allow some of the regular terminators to
  751. // appear as characters - This is for the Loader & Textmode
  752. TCHAR LQStringTerminators[] = { TEXT('\"'),
  753. TEXT('\n'),
  754. TEXT('\f'),
  755. TEXT('\v'),
  756. TEXT('\r')
  757. };
  758. //
  759. // Main parser routine
  760. //
  761. DWORD
  762. ParseInfBuffer(
  763. PTSTR Buffer,
  764. DWORD Size,
  765. PVOID *Handle,
  766. DWORD Phase
  767. )
  768. /*++
  769. Routine Description:
  770. Given a character buffer containing the INF file, this routine parses
  771. the INF into an internal form with Section records, Line records and
  772. Value records.
  773. If this module is compiler for unicode, the input is assumed to be
  774. a bufferful of unicode characters.
  775. Arguments:
  776. Buffer - contains to ptr to a buffer containing the INF file
  777. Size - contains the size of the buffer in characters.
  778. Handle - receives INF handle ptr to be used in subsequent INF calls.
  779. Return Value:
  780. Win32 error code indicating outcome. One of NO_ERROR, ERROR_INVALID_DATA,
  781. or ERROR_NOT_ENOUGH_MEMORY.
  782. --*/
  783. {
  784. LPTSTR Stream, MaxStream, pchSectionName, pchValue;
  785. unsigned State, InfLine;
  786. TOKEN Token;
  787. BOOL Done;
  788. BOOL Error;
  789. DWORD ErrorCode;
  790. BOOL IsStringId;
  791. PTSTR NearestValue=NULL;
  792. //
  793. // Initialise the globals
  794. //
  795. pINF = NULL;
  796. pSectionRecord = NULL;
  797. pLineRecord = NULL;
  798. pValueRecord = NULL;
  799. //
  800. // Need EmptyValue to point at a nul character
  801. //
  802. EmptyValue = StringTerminators + lstrlen(StringTerminators);
  803. //
  804. // Get INF record
  805. //
  806. pINF = malloc(sizeof(INF));
  807. if(!pINF) {
  808. return(ERROR_NOT_ENOUGH_MEMORY);
  809. }
  810. pINF->pSection = NULL;
  811. //
  812. // Set initial state
  813. //
  814. State = 1;
  815. InfLine = 1;
  816. Stream = Buffer;
  817. MaxStream = Buffer + Size;
  818. Done = FALSE;
  819. Error = FALSE;
  820. ErrorCode = NO_ERROR;
  821. IsStringId = FALSE;
  822. pchSectionName = NULL;
  823. pchValue = NULL;
  824. //
  825. // Enter token processing loop
  826. //
  827. while (!Done) {
  828. Token = DnGetToken(&Stream, MaxStream, Phase);
  829. if(Token.pValue){
  830. NearestValue = Token.pValue;
  831. if( Verbose >= DETAIL)
  832. _tprintf(TEXT("Token - %s\n"), Token.pValue);
  833. }
  834. switch (State) {
  835. //
  836. // STATE1: Start of file, this state remains till first
  837. // section is found
  838. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
  839. //
  840. case 1:
  841. switch (Token.Type) {
  842. case TOK_EOL:
  843. break;
  844. case TOK_EOF:
  845. Done = TRUE;
  846. break;
  847. case TOK_LBRACE:
  848. State = 2;
  849. break;
  850. default:
  851. Error = Done = TRUE;
  852. ErrorCode = ERROR_INVALID_DATA;
  853. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  854. _tprintf(TEXT("Syntax Error - Expecting a section left brace\n"));
  855. if(Verbose >= BRIEF)
  856. _tprintf(TEXT("Expecting End of line, End of File or Left Brace - \nSTATE1: Start of file, this state remains until first section is found\n"));
  857. break;
  858. }
  859. break;
  860. //
  861. // STATE 2: Section LBRACE has been received, expecting STRING
  862. //
  863. // Valid Tokens: TOK_STRING
  864. //
  865. case 2:
  866. switch (Token.Type) {
  867. case TOK_STRING:
  868. State = 3;
  869. pchSectionName = Token.pValue;
  870. break;
  871. case TOK_RBRACE:
  872. if( Phase == TEXTMODE_PHASE){
  873. State = 4;
  874. pchSectionName = CommonStrings[10];
  875. break;
  876. }
  877. default:
  878. Error = Done = TRUE;
  879. ErrorCode = ERROR_INVALID_DATA;
  880. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  881. _tprintf(TEXT("Syntax Error - Expecting the section name\n"));
  882. if(Verbose >= BRIEF)
  883. _tprintf(TEXT("Expecting String - \nSTATE 2: Section LBRACE has been received, expecting STRING\n"));
  884. break;
  885. }
  886. break;
  887. //
  888. // STATE 3: Section Name received, expecting RBRACE
  889. //
  890. // Valid Tokens: TOK_RBRACE
  891. //
  892. case 3:
  893. switch (Token.Type) {
  894. case TOK_RBRACE:
  895. State = 4;
  896. break;
  897. default:
  898. Error = Done = TRUE;
  899. ErrorCode = ERROR_INVALID_DATA;
  900. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  901. _tprintf(TEXT("Syntax Error - Expecting a section right Brace after Section Name\n"));
  902. if(Verbose >= BRIEF)
  903. _tprintf(TEXT("Expecting Right Brace - \nSTATE 3: Section Name received, expecting RBRACE\n"));
  904. break;
  905. }
  906. break;
  907. //
  908. // STATE 4: Section Definition Complete, expecting EOL
  909. //
  910. // Valid Tokens: TOK_EOL, TOK_EOF
  911. //
  912. case 4:
  913. switch (Token.Type) {
  914. case TOK_EOL:
  915. //_tprintf(TEXT("pchSectionName - %s\n"), pchSectionName);
  916. if ((ErrorCode = DnAppendSection(pchSectionName)) != NO_ERROR)
  917. Error = Done = TRUE;
  918. else {
  919. pchSectionName = NULL;
  920. State = 5;
  921. }
  922. break;
  923. case TOK_EOF:
  924. _tprintf(TEXT("pchSectionName - %s\n"), pchSectionName);
  925. if ((ErrorCode = DnAppendSection(pchSectionName)) != NO_ERROR)
  926. Error = Done = TRUE;
  927. else {
  928. pchSectionName = NULL;
  929. Done = TRUE;
  930. }
  931. break;
  932. default:
  933. Error = Done = TRUE;
  934. ErrorCode = ERROR_INVALID_DATA;
  935. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  936. _tprintf(TEXT("Syntax Error - Expecting End of line after Section Definition\n"));
  937. if(Verbose >= BRIEF)
  938. _tprintf(TEXT("Expecting End of line or End of File - \nSTATE 4: Section Definition Complete, expecting EOL\n"));
  939. break;
  940. }
  941. break;
  942. //
  943. // STATE 5: Expecting Section Lines
  944. //
  945. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
  946. //
  947. case 5:
  948. switch (Token.Type) {
  949. case TOK_EOL:
  950. break;
  951. case TOK_EOF:
  952. Done = TRUE;
  953. break;
  954. case TOK_STRING_ID:
  955. if( Phase == WINNT32_PHASE )
  956. IsStringId = TRUE;
  957. case TOK_STRING:
  958. pchValue = Token.pValue;
  959. State = 6;
  960. break;
  961. case TOK_LBRACE:
  962. State = 2;
  963. break;
  964. default:
  965. Error = Done = TRUE;
  966. ErrorCode = ERROR_INVALID_DATA;
  967. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  968. _tprintf(TEXT("Syntax Error - Expecting Section lines - Did not find End of line, End of File, String/StringID, or Left Brace\n"));
  969. if(Verbose >= BRIEF)
  970. _tprintf(TEXT("Expecting End of line, End of File, String/StringID, or Left Brace - \nSTATE 5: Expecting Section Lines\n"));
  971. break;
  972. }
  973. break;
  974. //
  975. // STATE 6: String returned, not sure whether it is key or value
  976. //
  977. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
  978. //
  979. case 6:
  980. switch (Token.Type) {
  981. case TOK_EOL:
  982. if ( (ErrorCode = DnAppendLine(NULL)) != NO_ERROR ||
  983. (ErrorCode = DnAppendValue(pchValue,IsStringId)) !=NO_ERROR ) {
  984. Error = Done = TRUE;
  985. } else {
  986. pchValue = NULL;
  987. State = 5;
  988. }
  989. break;
  990. case TOK_EOF:
  991. if ( (ErrorCode = DnAppendLine(NULL)) != NO_ERROR ||
  992. (ErrorCode = DnAppendValue(pchValue,IsStringId)) !=NO_ERROR ) {
  993. Error = Done = TRUE;
  994. } else {
  995. pchValue = NULL;
  996. Done = TRUE;
  997. }
  998. break;
  999. case TOK_COMMA:
  1000. if ( (ErrorCode = DnAppendLine(NULL)) != NO_ERROR ||
  1001. (ErrorCode = DnAppendValue(pchValue,IsStringId)) !=NO_ERROR ) {
  1002. Error = Done = TRUE;
  1003. } else {
  1004. pchValue = NULL;
  1005. State = 7;
  1006. }
  1007. break;
  1008. case TOK_EQUAL:
  1009. if ( (ErrorCode = DnAppendLine(pchValue)) !=NO_ERROR)
  1010. Error = Done = TRUE;
  1011. else {
  1012. pchValue = NULL;
  1013. State = 8;
  1014. }
  1015. break;
  1016. default:
  1017. Error = Done = TRUE;
  1018. ErrorCode = ERROR_INVALID_DATA;
  1019. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  1020. _tprintf(TEXT("Syntax Error - Processing a section line - Expecting End of line, End of File, Comma or Equals\n"));
  1021. if(Verbose >= BRIEF)
  1022. _tprintf(TEXT("Expecting End of line, End of File, Comma or Equals - \nSTATE 6: String returned, not sure whether it is key or value\n"));
  1023. break;
  1024. }
  1025. if( Phase == WINNT32_PHASE )
  1026. IsStringId = FALSE;
  1027. break;
  1028. //
  1029. // STATE 7: Comma received, Expecting another string
  1030. //
  1031. // Valid Tokens: TOK_STRING
  1032. //
  1033. case 7:
  1034. switch (Token.Type) {
  1035. case TOK_COMMA:
  1036. Token.pValue = EmptyValue;
  1037. ErrorCode = DnAppendValue(Token.pValue,FALSE);
  1038. if(ErrorCode != NO_ERROR) {
  1039. Error = Done = TRUE;
  1040. }
  1041. break;
  1042. case TOK_STRING_ID:
  1043. if( Phase == WINNT32_PHASE )
  1044. IsStringId = TRUE;
  1045. case TOK_STRING:
  1046. if ((ErrorCode = DnAppendValue(Token.pValue,IsStringId)) != NO_ERROR) {
  1047. Error = Done = TRUE;
  1048. } else {
  1049. State = 9;
  1050. }
  1051. if(Phase == WINNT32_PHASE)
  1052. IsStringId = FALSE;
  1053. break;
  1054. case TOK_EOL:
  1055. case TOK_EOF:
  1056. Token.pValue = EmptyValue;
  1057. if ((ErrorCode = DnAppendValue(Token.pValue, IsStringId)) != NO_ERROR)
  1058. Error = Done = TRUE;
  1059. else
  1060. State = 9;
  1061. break;
  1062. default:
  1063. Error = Done = TRUE;
  1064. ErrorCode = ERROR_INVALID_DATA;
  1065. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  1066. _tprintf(TEXT("Syntax Error - Comma received on section line - Expecting Comma, String/StringID, End of Line or End of File\n"));
  1067. if(Verbose >= BRIEF)
  1068. _tprintf(TEXT("Expecting Comma or String/StringID - \nSTATE 7: Comma received, Expecting another string\n"));
  1069. break;
  1070. }
  1071. break;
  1072. //
  1073. // STATE 8: Equal received, Expecting another string
  1074. //
  1075. // Valid Tokens: TOK_STRING TOK_EOL, TOK_EOF
  1076. //
  1077. case 8:
  1078. switch (Token.Type) {
  1079. case TOK_STRING_ID:
  1080. if(Phase == WINNT32_PHASE)
  1081. IsStringId = TRUE;
  1082. case TOK_STRING:
  1083. if ((ErrorCode = DnAppendValue(Token.pValue,IsStringId)) != NO_ERROR) {
  1084. Error = Done = TRUE;
  1085. } else {
  1086. State = 9;
  1087. }
  1088. if(Phase == WINNT32_PHASE)
  1089. IsStringId = FALSE;
  1090. break;
  1091. case TOK_EOF:
  1092. if( Phase != WINNT32_PHASE){
  1093. Token.pValue = EmptyValue;
  1094. if ((ErrorCode = DnAppendValue(Token.pValue,FALSE)) != NO_ERROR) {
  1095. Error = TRUE;
  1096. }
  1097. Done = TRUE;
  1098. break;
  1099. }
  1100. case TOK_EOL:
  1101. Token.pValue = EmptyValue;
  1102. if ((ErrorCode = DnAppendValue(Token.pValue,FALSE)) != NO_ERROR) {
  1103. Error = Done = TRUE;
  1104. } else {
  1105. State = 5;
  1106. }
  1107. if(Phase == WINNT32_PHASE)
  1108. IsStringId = FALSE;
  1109. break;
  1110. default:
  1111. Error = Done = TRUE;
  1112. ErrorCode = ERROR_INVALID_DATA;
  1113. _tprintf(TEXT("Error in line %i, Nearest string - %s - %d\n"), InfLine, NearestValue, Token.Type);
  1114. _tprintf(TEXT("Syntax Error - Equals received on Section line - Expecting String/StringID, End of line or End of File\n\n"));
  1115. if(Verbose >= BRIEF)
  1116. _tprintf(TEXT("Expecting String/StringID, End of line or End of File - \nSTATE 8: Equal received, Expecting another string\n"));
  1117. break;
  1118. }
  1119. break;
  1120. //
  1121. // STATE 9: String received after equal, value string
  1122. //
  1123. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  1124. //
  1125. case 9:
  1126. switch (Token.Type) {
  1127. case TOK_EOL:
  1128. State = 5;
  1129. break;
  1130. case TOK_EOF:
  1131. Done = TRUE;
  1132. break;
  1133. case TOK_COMMA:
  1134. State = 7;
  1135. break;
  1136. default:
  1137. Error = Done = TRUE;
  1138. ErrorCode = ERROR_INVALID_DATA;
  1139. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  1140. _tprintf(TEXT("Syntax Error - Recieved string on line - Expecting End of line, End of File or Comma\n"));
  1141. if(Verbose >= BRIEF)
  1142. _tprintf(TEXT("Expecting End of line, End of File or Comma - \nSTATE 9: String received after equal, value string\n"));
  1143. break;
  1144. }
  1145. break;
  1146. //
  1147. // STATE 10: Value string definitely received
  1148. //
  1149. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  1150. //
  1151. case 10:
  1152. _tprintf(TEXT("Was Here\n"));
  1153. switch (Token.Type) {
  1154. case TOK_EOL:
  1155. State =5;
  1156. break;
  1157. case TOK_EOF:
  1158. Done = TRUE;
  1159. break;
  1160. case TOK_COMMA:
  1161. State = 7;
  1162. break;
  1163. default:
  1164. Error = Done = TRUE;
  1165. ErrorCode = ERROR_INVALID_DATA;
  1166. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  1167. _tprintf(TEXT("Syntax Error - Expecting End of line, End of File or Comma - \nSTATE 10: Value string definitely received\n"));
  1168. if(Verbose >= BRIEF)
  1169. _tprintf(TEXT("Expecting End of line, End of File or Comma - \nSTATE 10: Value string definitely received\n"));
  1170. break;
  1171. }
  1172. break;
  1173. default:
  1174. Error = Done = TRUE;
  1175. ErrorCode = ERROR_INVALID_DATA;
  1176. _tprintf(TEXT("Error in line %i, Nearest string - %s\n"), InfLine, NearestValue);
  1177. break;
  1178. } // end switch(State)
  1179. if (Error) {
  1180. UnloadInfFile(pINF);
  1181. if(pchSectionName) {
  1182. free(pchSectionName);
  1183. }
  1184. if(pchValue) {
  1185. free(pchValue);
  1186. }
  1187. pINF = NULL;
  1188. }
  1189. else {
  1190. //
  1191. // Keep track of line numbers so that we can display Errors
  1192. //
  1193. if (Token.Type == TOK_EOL)
  1194. InfLine++;
  1195. }
  1196. } // End while
  1197. if(!Error && (Phase == WINNT32_PHASE)) {
  1198. ProcessStringSection( pINF );
  1199. *Handle = pINF;
  1200. }
  1201. return(Error ? ErrorCode : NO_ERROR);
  1202. }
  1203. DWORD
  1204. DnAppendSection(
  1205. IN PTSTR pSectionName
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This appends a new section to the section list in the current INF.
  1210. All further lines and values pertain to this new section, so it resets
  1211. the line list and value lists too.
  1212. Arguments:
  1213. pSectionName - Name of the new section. ( [SectionName] )
  1214. Return Value:
  1215. NO_ERROR - if successful.
  1216. ERROR_INVALID_DATA - if invalid parameters passed in or the INF buffer not
  1217. initialised
  1218. --*/
  1219. {
  1220. PSECTION pNewSection;
  1221. //
  1222. // See if we already have a section by this name. If so we want
  1223. // to merge sections.
  1224. //
  1225. for(pNewSection=pINF->pSection; pNewSection; pNewSection=pNewSection->pNext) {
  1226. if(pNewSection->pName && !lstrcmpi(pNewSection->pName,pSectionName)) {
  1227. break;
  1228. }
  1229. }
  1230. if(pNewSection) {
  1231. //
  1232. // Set pLineRecord to point to the list line currently in the section.
  1233. //
  1234. for(pLineRecord = pNewSection->pLine;
  1235. pLineRecord && pLineRecord->pNext;
  1236. pLineRecord = pLineRecord->pNext)
  1237. ;
  1238. } else {
  1239. //
  1240. // Allocate memory for the new section
  1241. //
  1242. pNewSection = malloc(sizeof(SECTION));
  1243. if(!pNewSection) {
  1244. return(ERROR_NOT_ENOUGH_MEMORY);
  1245. }
  1246. //
  1247. // initialise the new section
  1248. //
  1249. pNewSection->pNext = NULL;
  1250. pNewSection->pLine = NULL;
  1251. pNewSection->pName = pSectionName;
  1252. //
  1253. // link it in
  1254. //
  1255. pNewSection->pNext = pINF->pSection;
  1256. pINF->pSection = pNewSection;
  1257. //
  1258. // reset the current line record
  1259. //
  1260. pLineRecord = NULL;
  1261. }
  1262. pSectionRecord = pNewSection;
  1263. pValueRecord = NULL;
  1264. return NO_ERROR;
  1265. }
  1266. DWORD
  1267. DnAppendLine(
  1268. IN PTSTR pLineKey
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This appends a new line to the line list in the current section.
  1273. All further values pertain to this new line, so it resets
  1274. the value list too.
  1275. Arguments:
  1276. pLineKey - Key to be used for the current line, this could be NULL.
  1277. Return Value:
  1278. NO_ERROR - if successful.
  1279. ERROR_INVALID_DATA - if invalid parameters passed in or current section not
  1280. initialised
  1281. --*/
  1282. {
  1283. PLINE pNewLine;
  1284. //
  1285. // Allocate memory for the new Line
  1286. //
  1287. pNewLine = malloc(sizeof(LINE));
  1288. if(!pNewLine) {
  1289. return(ERROR_NOT_ENOUGH_MEMORY);
  1290. }
  1291. //
  1292. // Link it in
  1293. //
  1294. pNewLine->pNext = NULL;
  1295. pNewLine->pValue = NULL;
  1296. pNewLine->pName = pLineKey;
  1297. if (pLineRecord == NULL) {
  1298. pSectionRecord->pLine = pNewLine;
  1299. }
  1300. else {
  1301. pLineRecord->pNext = pNewLine;
  1302. }
  1303. pLineRecord = pNewLine;
  1304. //
  1305. // Reset the current value record
  1306. //
  1307. pValueRecord = NULL;
  1308. return NO_ERROR;
  1309. }
  1310. DWORD
  1311. DnAppendValue(
  1312. IN PTSTR pValueString,
  1313. IN BOOL IsStringId
  1314. )
  1315. /*++
  1316. Routine Description:
  1317. This appends a new value to the value list in the current line.
  1318. Arguments:
  1319. pValueString - The value string to be added.
  1320. Return Value:
  1321. NO_ERROR - if successful.
  1322. ERROR_INVALID_DATA - if invalid parameters passed in or current line not
  1323. initialised.
  1324. --*/
  1325. {
  1326. PXVALUE pNewValue;
  1327. //
  1328. // Allocate memory for the new value record
  1329. //
  1330. pNewValue = malloc(sizeof(XVALUE));
  1331. if(!pNewValue) {
  1332. return(ERROR_NOT_ENOUGH_MEMORY);
  1333. }
  1334. //
  1335. // Link it in.
  1336. //
  1337. pNewValue->pNext = NULL;
  1338. pNewValue->pName = pValueString;
  1339. pNewValue->IsStringId = IsStringId;
  1340. if (pValueRecord == NULL)
  1341. pLineRecord->pValue = pNewValue;
  1342. else
  1343. pValueRecord->pNext = pNewValue;
  1344. pValueRecord = pNewValue;
  1345. return NO_ERROR;
  1346. }
  1347. TOKEN
  1348. DnGetToken(
  1349. IN OUT PTSTR *Stream,
  1350. IN PTSTR MaxStream,
  1351. IN DWORD Phase
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. This function returns the Next token from the configuration stream.
  1356. Arguments:
  1357. Stream - Supplies the address of the configuration stream. Returns
  1358. the address of where to start looking for tokens within the
  1359. stream.
  1360. MaxStream - Supplies the address of the last character in the stream.
  1361. Return Value:
  1362. TOKEN - Returns the next token
  1363. --*/
  1364. {
  1365. PTSTR pch, pchStart, pchNew;
  1366. unsigned Length, QuotedQuotes;
  1367. TOKEN Token;
  1368. //
  1369. // Skip whitespace (except for eol)
  1370. //
  1371. pch = *Stream;
  1372. while (pch < MaxStream && *pch != TEXT('\n') && (ISSPACE(*pch) || (*pch == TEXT('\032'))))
  1373. pch++;
  1374. //
  1375. // Check for comments and remove them
  1376. //
  1377. if (pch < MaxStream &&
  1378. ((*pch == TEXT(';')) || (*pch == TEXT('#'))
  1379. || (*pch == TEXT('/') && pch+1 < MaxStream && *(pch+1) == TEXT('/'))))
  1380. while (pch < MaxStream && *pch != TEXT('\n'))
  1381. pch++;
  1382. //
  1383. // Check to see if EOF has been reached, set the token to the right
  1384. // value
  1385. //
  1386. if (( pch >= MaxStream ) ||
  1387. (!(Phase == WINNT32_PHASE) &&
  1388. (*pch == 26)) ){
  1389. *Stream = pch;
  1390. Token.Type = TOK_EOF;
  1391. Token.pValue = NULL;
  1392. return Token;
  1393. }
  1394. switch (*pch) {
  1395. case TEXT('[') :
  1396. pch++;
  1397. Token.Type = TOK_LBRACE;
  1398. Token.pValue = NULL;
  1399. break;
  1400. case TEXT(']') :
  1401. pch++;
  1402. Token.Type = TOK_RBRACE;
  1403. Token.pValue = NULL;
  1404. break;
  1405. case TEXT('=') :
  1406. pch++;
  1407. Token.Type = TOK_EQUAL;
  1408. Token.pValue = NULL;
  1409. break;
  1410. case TEXT(',') :
  1411. pch++;
  1412. Token.Type = TOK_COMMA;
  1413. Token.pValue = NULL;
  1414. break;
  1415. case TEXT('\n') :
  1416. pch++;
  1417. Token.Type = TOK_EOL;
  1418. Token.pValue = NULL;
  1419. break;
  1420. case TEXT('\"'):
  1421. pch++;
  1422. //
  1423. // determine quoted string
  1424. //
  1425. pchStart = pch;
  1426. QuotedQuotes = 0;
  1427. morequotedstring:
  1428. if(Phase == WINNT32_PHASE){
  1429. while (pch < MaxStream && *pch && !IsQStringTerminator(*pch,TEXT('\"'))) {
  1430. pch++;
  1431. }
  1432. }else{
  1433. while (pch < MaxStream && (_tcschr(LQStringTerminators,*pch) == NULL)) {
  1434. pch++;
  1435. }
  1436. }
  1437. if(Phase == TEXTMODE_PHASE){
  1438. if(((pch+1) < MaxStream) && (*pch == TEXT('\"')) && ((*(pch+1)) == TEXT('\"'))) {
  1439. QuotedQuotes++;
  1440. //_tprintf( TEXT("Quoted Quotes found - %d\n"), QuotedQuotes);
  1441. pch += 2;
  1442. goto morequotedstring;
  1443. }
  1444. }
  1445. if (pch >=MaxStream || (*pch && (*pch != TEXT('\"')))) {
  1446. Token.Type = TOK_ERRPARSE;
  1447. Token.pValue = NULL;
  1448. }
  1449. else {
  1450. if(Phase == LOADER_PHASE){
  1451. //
  1452. // We require a quoted string to end with a double-quote.
  1453. // (If the string ended with anything else, the if() above
  1454. // would not have let us into the else clause.) The quote
  1455. // character is irrelevent, however, and can be overwritten.
  1456. // So we'll save some heap and use the string in-place.
  1457. // No need to make a copy.
  1458. //
  1459. // Note that this alters the image of txtsetup.sif we pass
  1460. // to setupdd.sys. Thus the inf parser in setupdd.sys must
  1461. // be able to treat a nul character as if it were a terminating
  1462. // double quote. In this tool we call this function with LOADER_PHASE
  1463. // before we call it with TEXTMODE_PHASE.
  1464. //
  1465. *pch++ = 0;
  1466. Token.Type = TOK_STRING;
  1467. Token.pValue = pchStart;
  1468. }else if( Phase == TEXTMODE_PHASE ){
  1469. Length = (unsigned)(pch - pchStart);
  1470. //_tprintf( TEXT("L - %d pch %x pchstart %x - Q - %d\n"), Length, pch, pchStart, QuotedQuotes);
  1471. if ((pchNew = malloc(((Length + 1) - QuotedQuotes) * sizeof(TCHAR) )) == NULL) {
  1472. Token.Type = TOK_ERRNOMEM;
  1473. Token.pValue = NULL;
  1474. } else{
  1475. if(Length) { // Null quoted strings are allowed
  1476. if(QuotedQuotes) {
  1477. for(Length=0; pchStart<pch; pchStart++) {
  1478. if((pchNew[Length++] = *pchStart) == TEXT('\"')) {
  1479. //
  1480. // The only way this could happen is if there's
  1481. // another double-quote char after this one, since
  1482. // otherwise this would have terminated the string.
  1483. //
  1484. pchStart++;
  1485. }
  1486. }
  1487. } else {
  1488. _tcsncpy(pchNew,pchStart,Length);
  1489. }
  1490. }
  1491. pchNew[Length] = 0;
  1492. Token.Type = TOK_STRING;
  1493. Token.pValue = pchNew;
  1494. }
  1495. pch++; // advance past the quote
  1496. }else if( Phase == WINNT32_PHASE ){
  1497. Length = (unsigned)(pch - pchStart);
  1498. if (pchNew = malloc((Length + 1) * sizeof(TCHAR))){
  1499. _tcsncpy(pchNew,pchStart,Length);
  1500. pchNew[Length] = 0;
  1501. Token.Type = TOK_STRING;
  1502. Token.pValue = pchNew;
  1503. pch++; // advance past the quote
  1504. }else{
  1505. Token.Type = TOK_ERRNOMEM;
  1506. Token.pValue = NULL;
  1507. }
  1508. }
  1509. }
  1510. break;
  1511. case TEXT('%'):
  1512. if(Phase == WINNT32_PHASE){
  1513. pch++;
  1514. //
  1515. // determine percented string
  1516. //
  1517. pchStart = pch;
  1518. while (pch < MaxStream && !IsQStringTerminator(*pch,TEXT('%'))) {
  1519. pch++;
  1520. }
  1521. if (pch >=MaxStream || *pch != TEXT('%')) {
  1522. Token.Type = TOK_ERRPARSE;
  1523. Token.pValue = NULL;
  1524. }
  1525. else {
  1526. Length = (unsigned)(pch - pchStart);
  1527. if( pchNew = malloc((Length+1) * sizeof(TCHAR))){
  1528. _tcsncpy(pchNew,pchStart,Length);
  1529. pchNew[Length] = 0;
  1530. Token.Type = TOK_STRING_ID;
  1531. Token.pValue = pchNew;
  1532. pch++; // advance past the percent
  1533. }else{
  1534. Token.Type = TOK_ERRNOMEM;
  1535. Token.pValue = NULL;
  1536. }
  1537. }
  1538. break;
  1539. }// if not WINNT32_PHASE go on with default processing
  1540. default:
  1541. pchStart = pch;
  1542. /* -- We don't implement line continuation checks for now.
  1543. if(Phase == TEXTMODE_PHASE ){
  1544. //
  1545. // Check to see if we have a line continuation,
  1546. // which is \ followed by only whitespace on the line
  1547. //
  1548. if((*pch == L'\\')) {
  1549. pch++;
  1550. //
  1551. // Keep skipping until we hit the end of the file,
  1552. // or the newline, or a non-space character.
  1553. //
  1554. while((pch < MaxStream) && (*pch != L'\n') && ISSPACE(*pch)) {
  1555. pch++;
  1556. }
  1557. if(*pch == L'\n') {
  1558. //
  1559. // No non-space chars between the \ and the end of the line.
  1560. // Ignore the newline.
  1561. //
  1562. pch++;
  1563. *LineNumber = *LineNumber + 1;
  1564. goto restart;
  1565. } else {
  1566. if(pch < MaxStream) {
  1567. //
  1568. // Not line continuation.
  1569. // Reset the input to the start of the field.
  1570. //
  1571. pch = pchStart;
  1572. }
  1573. }
  1574. }
  1575. } */
  1576. //
  1577. // determine regular string
  1578. //
  1579. pchStart = pch;
  1580. if( Phase == WINNT32_PHASE ){
  1581. while (pch < MaxStream && !IsStringTerminator(*pch))
  1582. pch++;
  1583. }else{
  1584. while (pch < MaxStream && (_tcschr(LStringTerminators,*pch) == NULL)) {
  1585. pch++;
  1586. }
  1587. }
  1588. if (pch == pchStart) {
  1589. pch++;
  1590. Token.Type = TOK_ERRPARSE;
  1591. Token.pValue = NULL;
  1592. }
  1593. else {
  1594. Length = (unsigned)((pch - pchStart));
  1595. //_tprintf( TEXT("L - %d pch %x pchstart %x\n"), Length, pch, pchStart);
  1596. if( (Phase == WINNT32_PHASE) || (Phase == LOADER_PHASE)){
  1597. if(pchNew = malloc((Length + 1) * sizeof(TCHAR))){
  1598. _tcsncpy(pchNew,pchStart,Length);
  1599. pchNew[Length] = 0;
  1600. Token.Type = TOK_STRING;
  1601. Token.pValue = pchNew;
  1602. }else{
  1603. Token.Type = TOK_ERRNOMEM;
  1604. Token.pValue = NULL;
  1605. }
  1606. }else if (Phase == TEXTMODE_PHASE) {
  1607. ULONG i;
  1608. //
  1609. // Check for a common string...
  1610. //
  1611. for( i = 0; i < sizeof(CommonStrings)/sizeof(PTSTR); i++ ) {
  1612. if( !_tcsnicmp( pchStart, CommonStrings[i], Length) ) {
  1613. break;
  1614. }
  1615. }
  1616. if( i < sizeof(CommonStrings)/sizeof(PTSTR) ) {
  1617. //
  1618. // Hit...
  1619. //
  1620. Token.Type = TOK_STRING;
  1621. Token.pValue = CommonStrings[i];
  1622. } else if((pchNew = malloc((Length + 1) * sizeof(TCHAR))) == NULL) {
  1623. Token.Type = TOK_ERRNOMEM;
  1624. Token.pValue = NULL;
  1625. }
  1626. else {
  1627. _tcsncpy(pchNew, pchStart, Length);
  1628. pchNew[Length] = 0;
  1629. //_tprintf( TEXT("Token2 - %s\n"), pchNew);
  1630. Token.Type = TOK_STRING;
  1631. Token.pValue = pchNew;
  1632. }
  1633. }
  1634. }
  1635. break;
  1636. }
  1637. *Stream = pch;
  1638. return (Token);
  1639. }
  1640. BOOL
  1641. IsStringTerminator(
  1642. TCHAR ch
  1643. )
  1644. /*++
  1645. Routine Description:
  1646. This routine tests whether the given character terminates a quoted
  1647. string.
  1648. Arguments:
  1649. ch - The current character.
  1650. Return Value:
  1651. TRUE if the character is a quoted string terminator, FALSE otherwise.
  1652. --*/
  1653. {
  1654. unsigned i;
  1655. //
  1656. // one of the string terminator array
  1657. //
  1658. for (i = 0; i < NumberOfTerminators; i++) {
  1659. if (ch == StringTerminators[i]) {
  1660. return (TRUE);
  1661. }
  1662. }
  1663. return FALSE;
  1664. }
  1665. BOOL
  1666. IsQStringTerminator(
  1667. TCHAR ch,
  1668. TCHAR term
  1669. )
  1670. /*++
  1671. Routine Description:
  1672. This routine tests whether the given character terminates a quoted
  1673. string.
  1674. Arguments:
  1675. ch - The current character.
  1676. Return Value:
  1677. TRUE if the character is a quoted string terminator, FALSE otherwise.
  1678. --*/
  1679. {
  1680. unsigned i;
  1681. //
  1682. // one of quoted string terminators array
  1683. //
  1684. for (i = 0; i < QNumberOfTerminators; i++) {
  1685. if (ch == QStringTerminators[i] || ch == term) {
  1686. return (TRUE);
  1687. }
  1688. }
  1689. return FALSE;
  1690. }
  1691. typedef struct _STRING_ENTRY {
  1692. LPCTSTR StringId;
  1693. LPCTSTR StringValue;
  1694. } STRING_ENTRY, *PSTRING_ENTRY;
  1695. BOOL
  1696. ProcessStringSection(
  1697. PINF pINF
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. This routine processes the strings sections on the
  1702. specified inf file. The processing scans all values
  1703. in the inf and replaces any string ids that are
  1704. referenced.
  1705. Arguments:
  1706. pINF - pointer to the specified inf structure
  1707. Return Value:
  1708. TRUE if the strings section is processed properly
  1709. --*/
  1710. {
  1711. PSTRING_ENTRY StringTable;
  1712. DWORD StringTableCount;
  1713. DWORD LineCount;
  1714. DWORD i;
  1715. LPCTSTR StringId;
  1716. LPCTSTR StringValue;
  1717. PSECTION pSection;
  1718. PLINE pLine;
  1719. PXVALUE pValue;
  1720. LineCount = InfGetSectionLineCount( pINF, TEXT("Strings") );
  1721. if (LineCount == 0 || LineCount == 0xffffffff) {
  1722. _tprintf(TEXT("Warning - No strings section\n"));
  1723. return FALSE;
  1724. }
  1725. StringTable = (PSTRING_ENTRY) malloc( LineCount * sizeof(STRING_ENTRY) );
  1726. if (StringTable == NULL) {
  1727. _tprintf(TEXT("Error - Out of Memory processing Strings section\n"));
  1728. return FALSE;
  1729. }
  1730. StringTableCount = 0;
  1731. for (i=0; i<LineCount; i++) {
  1732. StringId = InfGetLineKeyName( pINF, TEXT("Strings"), i );
  1733. StringValue = InfGetFieldByIndex( pINF, TEXT("Strings"), i, 0 );
  1734. if (StringId && StringValue) {
  1735. StringTable[i].StringId = StringId;
  1736. StringTable[i].StringValue = StringValue;
  1737. StringTableCount += 1;
  1738. }
  1739. }
  1740. pSection = pINF->pSection;
  1741. while(pSection) {
  1742. pLine = pSection->pLine;
  1743. while(pLine) {
  1744. pValue = pLine->pValue;
  1745. while(pValue) {
  1746. if (pValue->IsStringId) {
  1747. for (i=0; i<StringTableCount; i++) {
  1748. if (_tcsicmp( StringTable[i].StringId, pValue->pName ) == 0) {
  1749. free(pValue->pName);
  1750. pValue->pName = DupString( (PTSTR)StringTable[i].StringValue );
  1751. break;
  1752. }
  1753. }
  1754. }
  1755. pValue = pValue->pNext;
  1756. }
  1757. pLine = pLine->pNext;
  1758. }
  1759. pSection = pSection->pNext;
  1760. }
  1761. free( StringTable );
  1762. return TRUE;
  1763. }
  1764. DWORD
  1765. MapFileForRead(
  1766. IN LPCTSTR FileName,
  1767. OUT PDWORD FileSize,
  1768. OUT PHANDLE FileHandle,
  1769. OUT PHANDLE MappingHandle,
  1770. OUT PVOID *BaseAddress
  1771. )
  1772. /*++
  1773. Routine Description:
  1774. Open and map an entire file for read access. The file must
  1775. not be 0-length or the routine fails.
  1776. Arguments:
  1777. FileName - supplies pathname to file to be mapped.
  1778. FileSize - receives the size in bytes of the file.
  1779. FileHandle - receives the win32 file handle for the open file.
  1780. The file will be opened for generic read access.
  1781. MappingHandle - receives the win32 handle for the file mapping
  1782. object. This object will be for read access. This value is
  1783. undefined if the file being opened is 0 length.
  1784. BaseAddress - receives the address where the file is mapped. This
  1785. value is undefined if the file being opened is 0 length.
  1786. Return Value:
  1787. NO_ERROR if the file was opened and mapped successfully.
  1788. The caller must unmap the file with UnmapFile when
  1789. access to the file is no longer desired.
  1790. Win32 error code if the file was not successfully mapped.
  1791. --*/
  1792. {
  1793. DWORD rc;
  1794. //
  1795. // Open the file -- fail if it does not exist.
  1796. //
  1797. *FileHandle = CreateFile(
  1798. FileName,
  1799. GENERIC_READ,
  1800. FILE_SHARE_READ,
  1801. NULL,
  1802. OPEN_EXISTING,
  1803. 0,
  1804. NULL
  1805. );
  1806. if(*FileHandle == INVALID_HANDLE_VALUE) {
  1807. rc = GetLastError();
  1808. } else {
  1809. //
  1810. // Get the size of the file.
  1811. //
  1812. *FileSize = GetFileSize(*FileHandle,NULL);
  1813. if(*FileSize == (DWORD)(-1)) {
  1814. rc = GetLastError();
  1815. } else {
  1816. //
  1817. // Create file mapping for the whole file.
  1818. //
  1819. *MappingHandle = CreateFileMapping(
  1820. *FileHandle,
  1821. NULL,
  1822. PAGE_READONLY,
  1823. 0,
  1824. *FileSize,
  1825. NULL
  1826. );
  1827. if(*MappingHandle) {
  1828. //
  1829. // Map the whole file.
  1830. //
  1831. *BaseAddress = MapViewOfFile(
  1832. *MappingHandle,
  1833. FILE_MAP_READ,
  1834. 0,
  1835. 0,
  1836. *FileSize
  1837. );
  1838. if(*BaseAddress) {
  1839. return(NO_ERROR);
  1840. }
  1841. rc = GetLastError();
  1842. CloseHandle(*MappingHandle);
  1843. } else {
  1844. rc = GetLastError();
  1845. }
  1846. }
  1847. CloseHandle(*FileHandle);
  1848. }
  1849. return(rc);
  1850. }
  1851. DWORD
  1852. UnmapFile(
  1853. IN HANDLE MappingHandle,
  1854. IN PVOID BaseAddress
  1855. )
  1856. /*++
  1857. Routine Description:
  1858. Unmap and close a file.
  1859. Arguments:
  1860. MappingHandle - supplies the win32 handle for the open file mapping
  1861. object.
  1862. BaseAddress - supplies the address where the file is mapped.
  1863. Return Value:
  1864. NO_ERROR if the file was unmapped successfully.
  1865. Win32 error code if the file was not successfully unmapped.
  1866. --*/
  1867. {
  1868. DWORD rc;
  1869. rc = UnmapViewOfFile(BaseAddress) ? NO_ERROR : GetLastError();
  1870. if(!CloseHandle(MappingHandle)) {
  1871. if(rc == NO_ERROR) {
  1872. rc = GetLastError();
  1873. }
  1874. }
  1875. return(rc);
  1876. }
  1877. LPTSTR
  1878. DupString(
  1879. IN LPCTSTR String
  1880. )
  1881. /*++
  1882. Routine Description:
  1883. Make a duplicate of a nul-terminated string.
  1884. Arguments:
  1885. String - supplies pointer to nul-terminated string to copy.
  1886. Return Value:
  1887. Copy of string or NULL if OOM. Caller can free with FREE().
  1888. --*/
  1889. {
  1890. LPTSTR p;
  1891. if(p = malloc((lstrlen(String)+1)*sizeof(TCHAR))) {
  1892. lstrcpy(p,String);
  1893. }
  1894. return(p);
  1895. }