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.

1885 lines
40 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. infparse.c
  5. Abstract:
  6. The code in this file read in an INF file, organizing it into a data
  7. structure that can be manipulated.
  8. The entry points are:
  9. OpenInfFile - Parses the INF associated with the STF file.
  10. InfParse_WriteInfToDisk - Writes the INF memory structure to disk
  11. AddInfSectionToTable - Adds a new section to the INF memory structure
  12. AddInfLineToTable - Adds a new line to a section's memory structure
  13. FindInfSectionInTable - Performs a sequential search for a specific
  14. section name
  15. FindLineInInfSection - Locates a line given a specific key
  16. DeleteLineInInfSection - Removes a line from an INF section
  17. DeleteSectionInInfFile - Removes a complete section from the INF memory
  18. structure
  19. GetInfSectionLineCount - Returns the number of lines in a section
  20. GetFirstLineInSectionStruct - Begins a line enumeration given an INF
  21. section ptr
  22. GetFirstLineInSectionStr - Begins a line enumeration given an INF
  23. section string
  24. GetNextLineInSection - Continues a line enumeration
  25. Author:
  26. Jim Schmidt (jimschm) 20-Sept-1997
  27. Revision History:
  28. --*/
  29. #include "pch.h"
  30. //
  31. // Globals to manage INF file reading
  32. //
  33. static PBYTE g_Buf1, g_Buf2;
  34. static DWORD g_Buf1Start, g_Buf2Start;
  35. static DWORD g_Buf1End, g_Buf2End;
  36. #define INF_BUFFER_SIZE 32768
  37. WCHAR
  38. pGetInfFileWchar (
  39. IN HANDLE File,
  40. IN DWORD Pos,
  41. OUT PBOOL Error
  42. );
  43. PCWSTR
  44. pGetNextInfLine (
  45. IN HANDLE File,
  46. IN PGROWBUFFER LineBuf,
  47. IN OUT PDWORD Pos,
  48. IN BOOL UnicodeMode
  49. );
  50. typedef struct {
  51. HANDLE SourceInfFile;
  52. HANDLE DestInfFile;
  53. PMHANDLE InfPool; // A pool for appended INF data
  54. PINFSECTION FirstInfSection; // The first section of the parsed INF
  55. PINFSECTION LastInfSection; // The last section of the parsed INF
  56. BOOL InfIsUnicode;
  57. } INFFILE, *PINFFILE;
  58. BOOL
  59. pReadInfIntoTable (
  60. IN OUT PINFFILE InfFile,
  61. IN PWSTR SectionList,
  62. IN BOOL KeepComments
  63. )
  64. /*++
  65. Routine Description:
  66. Reads the specified file into memory, parsing the lines according to basic
  67. INF structure.
  68. Arguments:
  69. InfFile - Specifies the structure initilized with the INF file handle.
  70. Receives the complete INF structure.
  71. Return Value:
  72. TRUE if parsing was successful, or FALSE if parsing failed.
  73. --*/
  74. {
  75. WCHAR ch;
  76. BOOL Error;
  77. GROWBUFFER LineBuf = INIT_GROWBUFFER;
  78. PCWSTR Text;
  79. DWORD Pos;
  80. PCWSTR Key, Data;
  81. PWSTR p, q;
  82. DWORD i;
  83. PINFSECTION Section = NULL;
  84. DWORD LineFlags;
  85. BOOL Result = FALSE;
  86. HASHTABLE ht = NULL;
  87. BOOL neededSection = FALSE;
  88. PWSTR list;
  89. Section = AddInfSectionToTableW (InfFile, L"");
  90. if (!Section) {
  91. LOG ((LOG_ERROR, "Read Inf Into Table: Could not add comment section"));
  92. return FALSE;
  93. }
  94. //
  95. // If we have a list of sections to fill, add them to a ht, for faster retrieval.
  96. //
  97. if (SectionList) {
  98. list = PmDuplicateStringW (InfFile->InfPool, SectionList);
  99. ht = HtAllocW ();
  100. if (ht) {
  101. while (list) {
  102. p = wcschr (list, L',');
  103. if (p) {
  104. *p = 0;
  105. }
  106. HtAddStringW (ht, SkipSpaceW(list));
  107. if (p) {
  108. *p = L',';
  109. list = p + 1;
  110. }
  111. else {
  112. list = p;
  113. }
  114. }
  115. }
  116. else {
  117. LOG ((LOG_ERROR, "Read Inf Into Table: Could not allocate section hash table."));
  118. return FALSE;
  119. }
  120. }
  121. g_Buf1Start = 0;
  122. g_Buf2Start = 0;
  123. g_Buf1End = 0;
  124. g_Buf2End = 0;
  125. g_Buf1 = (PBYTE) MemAlloc (g_hHeap, 0, INF_BUFFER_SIZE);
  126. g_Buf2 = (PBYTE) MemAlloc (g_hHeap, 0, INF_BUFFER_SIZE);
  127. __try {
  128. //
  129. // Determine if this file is UNICODE
  130. //
  131. ch = pGetInfFileWchar (InfFile->SourceInfFile, 0, &Error);
  132. InfFile->InfIsUnicode = (ch == 0xfeff) && !Error;
  133. //
  134. // Parse each line.
  135. //
  136. Pos = 0;
  137. for (;;) {
  138. //
  139. // Get the line
  140. //
  141. Text = pGetNextInfLine (
  142. InfFile->SourceInfFile,
  143. &LineBuf,
  144. &Pos,
  145. InfFile->InfIsUnicode
  146. );
  147. if (!Text) {
  148. break;
  149. }
  150. //
  151. // If a comment line or blank line, skip it
  152. //
  153. p = (PWSTR) SkipSpaceW (Text);
  154. if (!p[0] || p[0] == L';') {
  155. if (KeepComments && !AddInfLineToTableW (InfFile, Section, NULL, Text, LINEFLAG_ALL_COMMENTS)) {
  156. LOG ((LOG_ERROR, "Read Inf Into Table: Can't add line comments to table", Text));
  157. __leave;
  158. }
  159. continue;
  160. }
  161. //
  162. // If a section line, start the new section
  163. //
  164. if (p[0] == L'[') {
  165. p++;
  166. q = wcschr (p, L']');
  167. if (!q) {
  168. q = GetEndOfStringW (p);
  169. } else {
  170. *q = 0;
  171. }
  172. if (!ht || HtFindStringW (ht, p)) {
  173. Section = AddInfSectionToTableW (InfFile, p);
  174. neededSection = TRUE;
  175. if (!Section) {
  176. LOG ((LOG_ERROR, "Read Inf Into Table: Could not add section %s", p));
  177. __leave;
  178. }
  179. }
  180. else {
  181. //
  182. // We must not care about this section. Make sure we don't add any lines.
  183. //
  184. neededSection = FALSE;
  185. }
  186. }
  187. //
  188. // Otherwise it must be a valid line
  189. //
  190. else {
  191. if (!Section) {
  192. DEBUGMSG ((DBG_WARNING, "InfParse_ReadInfIntoTable: Ignoring unrecognized line %s", p));
  193. continue;
  194. }
  195. if (!neededSection) {
  196. continue;
  197. }
  198. //
  199. // Split key and line: Skip key that is surrounded by quotes, then
  200. // find the first
  201. //
  202. LineFlags = 0;
  203. q = p;
  204. Key = NULL;
  205. Data = Text;
  206. while (q[0] == L'\"') {
  207. q = wcschr (q + 1, L'\"');
  208. if (!q) {
  209. q = p;
  210. break;
  211. } else {
  212. q++;
  213. }
  214. }
  215. i = (DWORD)wcscspn (q, L"\"=");
  216. if (q[i] == L'=') {
  217. q += i;
  218. Data = SkipSpaceW (q + 1);
  219. *q = 0;
  220. q = (PWSTR) SkipSpaceRW (Text, q);
  221. if (q && *q) {
  222. q++;
  223. *q = 0;
  224. }
  225. Key = p;
  226. if (Key[0] == L'\"') {
  227. LineFlags |= LINEFLAG_KEY_QUOTED;
  228. Key++;
  229. p = GetEndOfStringW (Key);
  230. p = (PWSTR) SkipSpaceRW (Key, p);
  231. if (p && *p) {
  232. if (p[0] != L'\"') {
  233. p++;
  234. }
  235. *p = 0;
  236. }
  237. }
  238. }
  239. if (!AddInfLineToTableW (InfFile, Section, Key, Data, LineFlags)) {
  240. LOG ((LOG_ERROR, "Read Inf Into Table: Can't add line %s to table", Text));
  241. __leave;
  242. }
  243. }
  244. }
  245. if (Pos != GetFileSize (InfFile->SourceInfFile, NULL)) {
  246. LOG ((LOG_ERROR, "Read Inf Into Table: Could not read entire INF"));
  247. __leave;
  248. }
  249. Result = TRUE;
  250. }
  251. __finally {
  252. MemFree (g_hHeap, 0, g_Buf1);
  253. MemFree (g_hHeap, 0, g_Buf2);
  254. GbFree (&LineBuf);
  255. if (ht) {
  256. HtFree (ht);
  257. }
  258. }
  259. return Result;
  260. }
  261. VOID
  262. CloseInfFile (
  263. HINF InfFile
  264. )
  265. {
  266. PINFFILE inf = (PINFFILE) InfFile;
  267. PmEmptyPool (inf->InfPool);
  268. PmDestroyPool (inf->InfPool);
  269. MemFree (g_hHeap, 0, inf);
  270. }
  271. HINF
  272. OpenInfFileExA (
  273. IN PCSTR InfFilePath,
  274. IN PSTR SectionList,
  275. IN BOOL KeepComments
  276. )
  277. {
  278. PINFFILE InfFile;
  279. BOOL b = TRUE;
  280. PWSTR wSectionList = NULL;
  281. if (SectionList) {
  282. wSectionList = (PWSTR) ConvertAtoW (SectionList);
  283. }
  284. InfFile = MemAlloc (g_hHeap, HEAP_ZERO_MEMORY, sizeof (INFFILE));
  285. InfFile->SourceInfFile = CreateFileA (
  286. InfFilePath,
  287. GENERIC_READ,
  288. FILE_SHARE_READ,
  289. NULL,
  290. OPEN_EXISTING,
  291. FILE_ATTRIBUTE_NORMAL,
  292. NULL
  293. );
  294. if (InfFile->SourceInfFile == INVALID_HANDLE_VALUE) {
  295. b = FALSE;
  296. } else {
  297. InfFile->InfPool = PmCreateNamedPool ("INF File");
  298. b = pReadInfIntoTable (InfFile, wSectionList, KeepComments);
  299. }
  300. if (wSectionList) {
  301. FreeConvertedStr (wSectionList);
  302. }
  303. if (!b) {
  304. if (InfFile->InfPool) {
  305. PmDestroyPool (InfFile->InfPool);
  306. }
  307. MemFree (g_hHeap, 0, InfFile);
  308. return INVALID_HANDLE_VALUE;
  309. }
  310. CloseHandle (InfFile->SourceInfFile);
  311. InfFile->SourceInfFile = INVALID_HANDLE_VALUE;
  312. return (HINF) InfFile;
  313. }
  314. HINF
  315. OpenInfFileExW (
  316. IN PCWSTR InfFilePath,
  317. IN PWSTR SectionList,
  318. IN BOOL KeepComments
  319. )
  320. {
  321. PINFFILE InfFile;
  322. BOOL b = TRUE;
  323. InfFile = MemAlloc (g_hHeap, HEAP_ZERO_MEMORY, sizeof (INFFILE));
  324. InfFile->SourceInfFile = CreateFileW (
  325. InfFilePath,
  326. GENERIC_READ,
  327. FILE_SHARE_READ,
  328. NULL,
  329. OPEN_EXISTING,
  330. FILE_ATTRIBUTE_NORMAL,
  331. NULL
  332. );
  333. if (InfFile->SourceInfFile == INVALID_HANDLE_VALUE) {
  334. b = FALSE;
  335. } else {
  336. InfFile->InfPool = PmCreateNamedPool ("INF File");
  337. b = pReadInfIntoTable (InfFile, SectionList, KeepComments);
  338. }
  339. if (!b) {
  340. if (InfFile->InfPool) {
  341. PmDestroyPool (InfFile->InfPool);
  342. }
  343. MemFree (g_hHeap, 0, InfFile);
  344. return INVALID_HANDLE_VALUE;
  345. }
  346. CloseHandle (InfFile->SourceInfFile);
  347. InfFile->SourceInfFile = INVALID_HANDLE_VALUE;
  348. return (HINF) InfFile;
  349. }
  350. BOOL
  351. pSaveInfToFile (
  352. IN PINFFILE InfFile
  353. )
  354. /*++
  355. Routine Description:
  356. InfParse_WriteInfToDisk writes the INF represented by the given memory
  357. image to disk. This is done by enumerating the INF data structures in
  358. the INF.
  359. Arguments:
  360. InfFile - Specifies the table to process
  361. Return Value:
  362. TRUE if successful, FALSE if not.
  363. --*/
  364. {
  365. PINFSECTION Section;
  366. PINFLINE Line;
  367. BYTE UnicodeHeader[] = { 0xff, 0xfe };
  368. DWORD DontCare;
  369. PCSTR AnsiStr = NULL;
  370. BOOL b = TRUE;
  371. MYASSERT (InfFile->SourceInfFile == INVALID_HANDLE_VALUE);
  372. MYASSERT (InfFile->DestInfFile != INVALID_HANDLE_VALUE);
  373. //
  374. // Write the INF as we have it in memory
  375. //
  376. __try {
  377. if (InfFile->InfIsUnicode) {
  378. if (!WriteFile (InfFile->DestInfFile, UnicodeHeader, sizeof (UnicodeHeader), &DontCare, NULL)) {
  379. __leave;
  380. }
  381. if (!WriteFileStringW (InfFile->DestInfFile, L"\r\n")) {
  382. __leave;
  383. }
  384. } else {
  385. if (!WriteFileStringA (InfFile->DestInfFile, "\r\n")) {
  386. __leave;
  387. }
  388. }
  389. Section = InfFile->FirstInfSection;
  390. while (Section) {
  391. if (Section->Name[0]) {
  392. if (InfFile->InfIsUnicode) {
  393. if (!WriteFileStringW (InfFile->DestInfFile, L"[") ||
  394. !WriteFileStringW (InfFile->DestInfFile, Section->Name) ||
  395. !WriteFileStringW (InfFile->DestInfFile, L"]\r\n")
  396. ) {
  397. __leave;
  398. }
  399. } else {
  400. AnsiStr = ConvertWtoA (Section->Name);
  401. if (!WriteFileStringA (InfFile->DestInfFile, "[") ||
  402. !WriteFileStringA (InfFile->DestInfFile, AnsiStr) ||
  403. !WriteFileStringA (InfFile->DestInfFile, "]\r\n")
  404. ) {
  405. __leave;
  406. }
  407. FreeConvertedStr (AnsiStr);
  408. AnsiStr = NULL;
  409. }
  410. }
  411. Line = Section->FirstLine;
  412. while (Line) {
  413. if (Line->Key) {
  414. if (Line->LineFlags & LINEFLAG_KEY_QUOTED) {
  415. if (!WriteFile (InfFile->DestInfFile, L"\"", InfFile->InfIsUnicode ? 2 : 1, &DontCare, NULL)) {
  416. __leave;
  417. }
  418. }
  419. if (InfFile->InfIsUnicode) {
  420. if (!WriteFileStringW (InfFile->DestInfFile, Line->Key)) {
  421. __leave;
  422. }
  423. } else {
  424. AnsiStr = ConvertWtoA (Line->Key);
  425. if (!WriteFileStringA (InfFile->DestInfFile, AnsiStr)) {
  426. __leave;
  427. }
  428. FreeConvertedStr (AnsiStr);
  429. AnsiStr = NULL;
  430. }
  431. if (Line->LineFlags & LINEFLAG_KEY_QUOTED) {
  432. if (!WriteFile (InfFile->DestInfFile, L"\"", InfFile->InfIsUnicode ? 2 : 1, &DontCare, NULL)) {
  433. __leave;
  434. }
  435. }
  436. if (InfFile->InfIsUnicode) {
  437. if (!WriteFileStringW (InfFile->DestInfFile, L" = ")) {
  438. __leave;
  439. }
  440. } else {
  441. if (!WriteFileStringA (InfFile->DestInfFile, " = ")) {
  442. __leave;
  443. }
  444. }
  445. }
  446. if (InfFile->InfIsUnicode) {
  447. if (!WriteFileStringW (InfFile->DestInfFile, Line->Data) ||
  448. !WriteFileStringW (InfFile->DestInfFile, L"\r\n")
  449. ) {
  450. __leave;
  451. }
  452. } else {
  453. AnsiStr = ConvertWtoA (Line->Data);
  454. if (!WriteFileStringA (InfFile->DestInfFile, AnsiStr) ||
  455. !WriteFileStringA (InfFile->DestInfFile, "\r\n")
  456. ) {
  457. __leave;
  458. }
  459. FreeConvertedStr (AnsiStr);
  460. AnsiStr = NULL;
  461. }
  462. Line = Line->Next;
  463. }
  464. if (InfFile->InfIsUnicode) {
  465. if (!WriteFileStringW (InfFile->DestInfFile, L"\r\n")) {
  466. __leave;
  467. }
  468. } else {
  469. if (!WriteFileStringA (InfFile->DestInfFile, "\r\n")) {
  470. __leave;
  471. }
  472. }
  473. Section = Section->Next;
  474. }
  475. }
  476. __finally {
  477. if (AnsiStr) {
  478. FreeConvertedStr (AnsiStr);
  479. }
  480. DEBUGMSG_IF((!b, DBG_ERROR, "Write Inf To Disk: Cannot write INF"));
  481. }
  482. return b;
  483. }
  484. BOOL
  485. SaveInfFileA (
  486. IN HINF Inf,
  487. IN PCSTR SaveToFileSpec
  488. )
  489. {
  490. PINFFILE InfFile = (PINFFILE) Inf;
  491. BOOL b;
  492. if (Inf == INVALID_HANDLE_VALUE) {
  493. return FALSE;
  494. }
  495. InfFile->DestInfFile = CreateFileA (
  496. SaveToFileSpec,
  497. GENERIC_WRITE,
  498. 0,
  499. NULL,
  500. CREATE_ALWAYS,
  501. FILE_ATTRIBUTE_NORMAL,
  502. NULL
  503. );
  504. if (InfFile->DestInfFile == INVALID_HANDLE_VALUE) {
  505. return FALSE;
  506. }
  507. b = pSaveInfToFile (InfFile);
  508. CloseHandle (InfFile->DestInfFile);
  509. InfFile->DestInfFile = INVALID_HANDLE_VALUE;
  510. if (!b) {
  511. DeleteFileA (SaveToFileSpec);
  512. }
  513. return b;
  514. }
  515. BOOL
  516. SaveInfFileW (
  517. IN HINF Inf,
  518. IN PCWSTR SaveToFileSpec
  519. )
  520. {
  521. PINFFILE InfFile = (PINFFILE) Inf;
  522. BOOL b;
  523. if (Inf == INVALID_HANDLE_VALUE) {
  524. return FALSE;
  525. }
  526. InfFile->DestInfFile = CreateFileW (
  527. SaveToFileSpec,
  528. GENERIC_WRITE,
  529. 0,
  530. NULL,
  531. CREATE_ALWAYS,
  532. FILE_ATTRIBUTE_NORMAL,
  533. NULL
  534. );
  535. if (InfFile->DestInfFile == INVALID_HANDLE_VALUE) {
  536. return FALSE;
  537. }
  538. b = pSaveInfToFile (InfFile);
  539. CloseHandle (InfFile->DestInfFile);
  540. InfFile->DestInfFile = INVALID_HANDLE_VALUE;
  541. if (!b) {
  542. DeleteFileW (SaveToFileSpec);
  543. }
  544. return b;
  545. }
  546. PINFSECTION
  547. AddInfSectionToTableA (
  548. IN HINF Inf,
  549. IN PCSTR SectionName
  550. )
  551. {
  552. PINFSECTION SectionPtr;
  553. PCWSTR UnicodeSectionName;
  554. UnicodeSectionName = ConvertAtoW (SectionName);
  555. SectionPtr = AddInfSectionToTableW (Inf, UnicodeSectionName);
  556. FreeConvertedStr (SectionName);
  557. return SectionPtr;
  558. }
  559. PINFSECTION
  560. AddInfSectionToTableW (
  561. IN HINF Inf,
  562. IN PCWSTR SectionName
  563. )
  564. /*++
  565. Routine Description:
  566. Creates a new section in our linked list structure if necessary.
  567. The return structure can be used to add lines to the section.
  568. Arguments:
  569. Inf - Specifies the INF to add the section to
  570. SectionName - Specifies the name of the new section
  571. Return Value:
  572. A pointer to the new INF section struct, or NULL if an
  573. error occurred.
  574. --*/
  575. {
  576. PINFSECTION NewSection;
  577. PINFFILE InfFile = (PINFFILE) Inf;
  578. //
  579. // Return early if this section already exists
  580. //
  581. NewSection = FindInfSectionInTableW (InfFile, SectionName);
  582. if (NewSection) {
  583. return NewSection;
  584. }
  585. //
  586. // Allocate a section struct
  587. //
  588. NewSection = (PINFSECTION) PmGetAlignedMemory (
  589. InfFile->InfPool,
  590. sizeof (INFSECTION)
  591. );
  592. if (!NewSection) {
  593. return NULL;
  594. }
  595. //
  596. // Fill in members of the struct and link
  597. //
  598. ZeroMemory (NewSection, sizeof (INFSECTION));
  599. NewSection->Name = PmDuplicateStringW (
  600. InfFile->InfPool,
  601. SectionName
  602. );
  603. if (!NewSection->Name) {
  604. return NULL;
  605. }
  606. NewSection->Prev = InfFile->LastInfSection;
  607. if (NewSection->Prev) {
  608. NewSection->Prev->Next = NewSection;
  609. } else {
  610. InfFile->FirstInfSection = NewSection;
  611. }
  612. InfFile->LastInfSection = NewSection;
  613. return NewSection;
  614. }
  615. PINFLINE
  616. AddInfLineToTableA (
  617. IN HINF Inf,
  618. IN PINFSECTION SectionPtr,
  619. IN PCSTR Key, OPTIONAL
  620. IN PCSTR Data,
  621. IN DWORD LineFlags
  622. )
  623. {
  624. PCWSTR UnicodeKey;
  625. PCWSTR UnicodeData;
  626. PINFLINE Line;
  627. if (Key) {
  628. UnicodeKey = ConvertAtoW (Key);
  629. } else {
  630. UnicodeKey = NULL;
  631. }
  632. UnicodeData = ConvertAtoW (Data);
  633. Line = AddInfLineToTableW (Inf, SectionPtr, UnicodeKey, UnicodeData, LineFlags);
  634. if (Key) {
  635. FreeConvertedStr (UnicodeKey);
  636. }
  637. FreeConvertedStr (UnicodeData);
  638. return Line;
  639. }
  640. PINFLINE
  641. AddInfLineToTableW (
  642. IN HINF Inf,
  643. IN PINFSECTION SectionPtr,
  644. IN PCWSTR Key, OPTIONAL
  645. IN PCWSTR Data,
  646. IN DWORD LineFlags
  647. )
  648. /*++
  649. Routine Description:
  650. Adds a line to the specified section. The caller specifies the
  651. full formatted data, and an optional key. The caller does NOT
  652. supply the equals sign between the key and data.
  653. Arguments:
  654. InfFile - Specifies the table to add the INF line to
  655. SectionName - Specifies the name of the section to add the line to
  656. Key - If specified, supplies the left-hand side of the equals line
  657. Data - Specifies the text for the line, or the right-hand side of
  658. the key = value expression.
  659. LineFlags - Specifies the flags for the INF line (see LINEFLAG_*)
  660. Return Value:
  661. TRUE if the line was added to the structure, or FALSE if not.
  662. --*/
  663. {
  664. PINFLINE NewLine;
  665. PINFFILE InfFile = (PINFFILE) Inf;
  666. //
  667. // Allocate line struct
  668. //
  669. NewLine = (PINFLINE) PmGetAlignedMemory (
  670. InfFile->InfPool,
  671. sizeof (INFLINE)
  672. );
  673. if (!NewLine) {
  674. return NULL;
  675. }
  676. //
  677. // Fill in members of the struct and link
  678. //
  679. ZeroMemory (NewLine, sizeof (INFLINE));
  680. if (Key) {
  681. NewLine->Key = PmDuplicateStringW (
  682. InfFile->InfPool,
  683. Key
  684. );
  685. if (!NewLine->Key) {
  686. return NULL;
  687. }
  688. }
  689. NewLine->Data = PmDuplicateStringW (
  690. InfFile->InfPool,
  691. Data
  692. );
  693. if (!NewLine->Data) {
  694. return NULL;
  695. }
  696. NewLine->Next = NULL;
  697. NewLine->Prev = SectionPtr->LastLine;
  698. NewLine->Section = SectionPtr;
  699. NewLine->LineFlags = LineFlags;
  700. if (NewLine->Prev) {
  701. NewLine->Prev->Next = NewLine;
  702. } else {
  703. SectionPtr->FirstLine = NewLine;
  704. }
  705. SectionPtr->LastLine = NewLine;
  706. SectionPtr->LineCount++;
  707. return NewLine;
  708. }
  709. PINFSECTION
  710. FindInfSectionInTableA (
  711. IN HINF Inf,
  712. IN PCSTR SectionName
  713. )
  714. {
  715. PINFSECTION InfSectionPtr;
  716. PCWSTR UnicodeSectionName;
  717. UnicodeSectionName = ConvertAtoW (SectionName);
  718. InfSectionPtr = FindInfSectionInTableW (Inf, UnicodeSectionName);
  719. FreeConvertedStr (UnicodeSectionName);
  720. return InfSectionPtr;
  721. }
  722. PINFSECTION
  723. FindInfSectionInTableW (
  724. IN HINF Inf,
  725. IN PCWSTR SectionName
  726. )
  727. /*++
  728. Routine Description:
  729. Scans the INF for a specific section. This routine scans
  730. the INF structures sequentially and does a case-insensitive
  731. comparison.
  732. Arguments:
  733. Inf - Specifies the INF to search
  734. SectionName - Specifies the name of the section to find
  735. Return Value:
  736. A pointer to the matching INF section struct, or NULL if
  737. the section was not found.
  738. --*/
  739. {
  740. PINFSECTION Section;
  741. PINFFILE InfFile = (PINFFILE) Inf;
  742. Section = InfFile->FirstInfSection;
  743. while (Section) {
  744. if (StringIMatchW (Section->Name, SectionName)) {
  745. return Section;
  746. }
  747. Section = Section->Next;
  748. }
  749. return NULL;
  750. }
  751. PINFSECTION
  752. GetFirstInfSectionInTable (
  753. IN HINF Inf
  754. )
  755. {
  756. PINFFILE InfFile = (PINFFILE) Inf;
  757. if (InfFile) {
  758. return InfFile->FirstInfSection;
  759. }
  760. return NULL;
  761. }
  762. PINFSECTION
  763. GetNextInfSectionInTable (
  764. IN PINFSECTION Section
  765. )
  766. {
  767. if (Section) {
  768. return Section->Next;
  769. }
  770. return NULL;
  771. }
  772. PINFLINE
  773. FindLineInInfSectionA (
  774. IN HINF Inf,
  775. IN PINFSECTION Section,
  776. IN PCSTR Key
  777. )
  778. {
  779. PCWSTR UnicodeKey;
  780. PINFLINE LinePtr;
  781. UnicodeKey = ConvertAtoW (Key);
  782. LinePtr = FindLineInInfSectionW (Inf, Section, UnicodeKey);
  783. FreeConvertedStr (UnicodeKey);
  784. return LinePtr;
  785. }
  786. PINFLINE
  787. FindLineInInfSectionW (
  788. IN HINF Inf,
  789. IN PINFSECTION Section,
  790. IN PCWSTR Key
  791. )
  792. /*++
  793. Routine Description:
  794. Scans the specified INF section for a specific key. This routine
  795. scans the INF line structures sequentially and does a case-insensitive
  796. comparison.
  797. Arguments:
  798. Inf - Specifies the INF to search
  799. Section - Specifies the section to search
  800. Key - Specifies the key to find
  801. Return Value:
  802. A pointer to the matching INF line struct, or NULL if
  803. the section was not found.
  804. --*/
  805. {
  806. PINFLINE Line;
  807. Line = Section->FirstLine;
  808. while (Line) {
  809. if (Line->Key && StringIMatchW (Line->Key, Key)) {
  810. return Line;
  811. }
  812. Line = Line->Next;
  813. }
  814. return NULL;
  815. }
  816. PINFLINE
  817. GetFirstLineInSectionStruct (
  818. IN PINFSECTION Section
  819. )
  820. /*++
  821. Routine Description:
  822. GetFirstLineInSectionStruct returns the first INFLINE pointer for the
  823. section, or NULL if no lines exist. Call GetNextLineInSection to
  824. continue enumeration.
  825. This routine does not return lines consisting only of comments.
  826. Arguments:
  827. Section - Specifies the section structure to enumerate lines frmo
  828. Return Value:
  829. A pointer to the first INFLINE struct, or NULL if no lines exist.
  830. --*/
  831. {
  832. if (!Section->FirstLine) {
  833. return NULL;
  834. }
  835. if (Section->FirstLine->LineFlags & LINEFLAG_ALL_COMMENTS) {
  836. return GetNextLineInSection (Section->FirstLine);
  837. }
  838. return Section->FirstLine;
  839. }
  840. PINFLINE
  841. GetNextLineInSection (
  842. IN PINFLINE PrevLine
  843. )
  844. /*++
  845. Routine Description:
  846. GetNextLineInSection returns the next INFLINE pointer for the
  847. section, based on the previous line, or NULL if no lines exist.
  848. This routine does not return lines with comments.
  849. Arguments:
  850. PrevLine - Specifies previous line (returned from
  851. GetFirstLineInSectionStruct or GetFirstLineInSectionStr).
  852. Return Value:
  853. This routine does not return lines consisting only of comments.
  854. --*/
  855. {
  856. while (PrevLine) {
  857. PrevLine = PrevLine->Next;
  858. if (!PrevLine || !(PrevLine->LineFlags & LINEFLAG_ALL_COMMENTS)) {
  859. break;
  860. }
  861. }
  862. return PrevLine;
  863. }
  864. PINFLINE
  865. GetFirstLineInSectionStrA (
  866. IN HINF Inf,
  867. IN PCSTR Section
  868. )
  869. /*++
  870. Routine Description:
  871. GetFirstLineInSectionStruct returns the first INFLINE pointer for the
  872. section, or NULL if no lines exist. Call GetNextLineInSection to
  873. continue enumeration.
  874. Arguments:
  875. Inf - Specifies the INF that has the section
  876. Section - Specifies the name of the section in the INF
  877. Return Value:
  878. A pointer to the first INFLINE struct, or NULL if no lines exist.
  879. --*/
  880. {
  881. PCWSTR UnicodeSection;
  882. PINFLINE LinePtr;
  883. UnicodeSection = ConvertAtoW (Section);
  884. LinePtr = GetFirstLineInSectionStrW (Inf, UnicodeSection);
  885. FreeConvertedStr (UnicodeSection);
  886. return LinePtr;
  887. }
  888. PINFLINE
  889. GetFirstLineInSectionStrW (
  890. IN HINF Inf,
  891. IN PCWSTR Section
  892. )
  893. /*++
  894. Routine Description:
  895. GetFirstLineInSectionStruct returns the first INFLINE pointer for the
  896. section, or NULL if no lines exist. Call GetNextLineInSection to
  897. continue enumeration.
  898. Arguments:
  899. Inf - Specifies the INF that has the section
  900. Section - Specifies the name of the section in the INF
  901. Return Value:
  902. A pointer to the first INFLINE struct, or NULL if no lines exist.
  903. --*/
  904. {
  905. PINFSECTION SectionPtr;
  906. PINFFILE Table = (PINFFILE) Inf;
  907. SectionPtr = FindInfSectionInTableW (Table, Section);
  908. if (!SectionPtr) {
  909. return NULL;
  910. }
  911. return GetFirstLineInSectionStruct (SectionPtr);
  912. }
  913. INT
  914. pGetInfFileByte (
  915. IN HANDLE File,
  916. IN DWORD Pos
  917. )
  918. /*++
  919. Routine Description:
  920. Returns the byte at the specified position, or -1 if the file could
  921. not be read at that position.
  922. Two buffers are used to allow fast relative access. Memory-mapped
  923. files were NOT used because problems were introduced when the
  924. swap file started filling up during GUI mode.
  925. Arguments:
  926. File - Specifies the file to read
  927. Pos - Specifies the 32-bit file offset to read (zero-based, in bytes)
  928. Return Value:
  929. The byte at the specified position, or -1 if an error was encountered.
  930. (Errors are usually caused by reading past the end of the file.)
  931. --*/
  932. {
  933. DWORD Read;
  934. PBYTE BufSwap;
  935. //
  936. // If we read the buffer previously, then return data in our buffer
  937. //
  938. if (Pos >= g_Buf1Start && Pos < g_Buf1End) {
  939. return g_Buf1[Pos - g_Buf1Start];
  940. }
  941. if (Pos >= g_Buf2Start && Pos < g_Buf2End) {
  942. return g_Buf2[Pos - g_Buf2Start];
  943. }
  944. //
  945. // Buffer not available; move buffer 2 to buffer 1, then read buffer 2
  946. //
  947. g_Buf1Start = g_Buf2Start;
  948. g_Buf1End = g_Buf2End;
  949. BufSwap = g_Buf1;
  950. g_Buf1 = g_Buf2;
  951. g_Buf2 = BufSwap;
  952. g_Buf2Start = Pos - (Pos % 256);
  953. SetFilePointer (File, (LONG)g_Buf2Start, NULL, FILE_BEGIN);
  954. if (!ReadFile (File, g_Buf2, INF_BUFFER_SIZE, &Read, NULL)) {
  955. return -1;
  956. }
  957. g_Buf2End = g_Buf2Start + Read;
  958. if (Pos >= g_Buf2Start && Pos < g_Buf2End) {
  959. return g_Buf2[Pos - g_Buf2Start];
  960. }
  961. return -1;
  962. }
  963. WCHAR
  964. pGetInfFileWchar (
  965. IN HANDLE File,
  966. IN DWORD Pos,
  967. OUT PBOOL Error
  968. )
  969. /*++
  970. Routine Description:
  971. Returns the WCHAR at the specified position, or 0 if the file could
  972. not be read at that position.
  973. Two buffers are used to allow fast relative access. Memory-mapped
  974. files were NOT used because problems were introduced when the
  975. swap file started filling up during GUI mode.
  976. Arguments:
  977. File - Specifies the file to read
  978. Pos - Specifies the 32-bit file offset to read (zero-based, in bytes)
  979. Error - Receives TRUE if an error was encountered, or FALSE if an
  980. error was not encountered.
  981. Return Value:
  982. The WCHAR at the specified position, or 0 if an error was encountered.
  983. (Errors are usually caused by reading past the end of the file.)
  984. If an error was encountered, the Error variable is also set to TRUE.
  985. --*/
  986. {
  987. INT c;
  988. WCHAR ch;
  989. c = pGetInfFileByte (File, Pos);
  990. if (c == -1 || c == 26) {
  991. *Error = TRUE;
  992. return (WORD) c;
  993. }
  994. ch = (WORD) c;
  995. c = pGetInfFileByte (File, Pos + 1);
  996. if (c == -1 || c == 26) {
  997. *Error = TRUE;
  998. return 0;
  999. }
  1000. // pGetInfFileByte return a byte value or -1.
  1001. // Since we checked for -1 the next cast is valid.
  1002. ch += (WORD)(c * 256);
  1003. *Error = FALSE;
  1004. return ch;
  1005. }
  1006. PCSTR
  1007. pGetInfLineA (
  1008. IN HANDLE File,
  1009. IN DWORD StartPos,
  1010. OUT PDWORD EndPosPtr, OPTIONAL
  1011. IN OUT PGROWBUFFER LineBuf
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Returns a DBCS string supplying the line. This string can be
  1016. any length and is nul-terminated. It does not include the \r or
  1017. \n characters.
  1018. If supplied, the EndPosPtr is updated to point to the start of
  1019. the next line.
  1020. Arguments:
  1021. File - Specifies the file to read
  1022. StartPos - Specifies the 32-bit file offset to read (zero-based, in bytes)
  1023. EndPosPtr - If specified, receives the 32-bit file offset of the next
  1024. line, or equal to the file size for the last line.
  1025. LineBuf - Specifies a reused GROWBUFFER that the caller initializes
  1026. and pGetInfLineA uses for line allocation. The caller is
  1027. responsible for cleanup.
  1028. Return Value:
  1029. A pointer to the DBCS string supplying the full line (with the \r, \n or
  1030. \r\n sequence stripped), or NULL if an error occurs.
  1031. --*/
  1032. {
  1033. DWORD EndPos;
  1034. INT c;
  1035. PBYTE Data;
  1036. DWORD Pos;
  1037. DWORD ByteLen = 0;
  1038. EndPos = StartPos;
  1039. for (;;) {
  1040. c = pGetInfFileByte (File, EndPos);
  1041. if (c == -1 || c == 26) {
  1042. break;
  1043. }
  1044. if (IsDBCSLeadByte ((BYTE) c)) {
  1045. EndPos++;
  1046. c = pGetInfFileByte (File, EndPos);
  1047. if (c == -1 || c == 26) {
  1048. break;
  1049. }
  1050. ByteLen++;
  1051. } else {
  1052. if (c == '\r' || c == '\n') {
  1053. EndPos++;
  1054. if (c == '\r') {
  1055. c = pGetInfFileByte (File, EndPos);
  1056. if (c == '\n') {
  1057. EndPos++;
  1058. }
  1059. }
  1060. break;
  1061. }
  1062. }
  1063. EndPos++;
  1064. ByteLen++;
  1065. }
  1066. //
  1067. // NOTE: If you make a change here, make one below in W version
  1068. //
  1069. // Ctrl+Z ends the file
  1070. if (c == 26) {
  1071. EndPos = GetFileSize (File, NULL);
  1072. }
  1073. // Allocate buffer, caller frees
  1074. LineBuf->End = 0;
  1075. Data = GbGrow (LineBuf, ByteLen + 2);
  1076. if (!Data) {
  1077. return NULL;
  1078. }
  1079. // We've been successful -- copy end pos to caller's variable
  1080. if (EndPosPtr) {
  1081. *EndPosPtr = EndPos;
  1082. }
  1083. // End of file condition: zero-length, but not a blank line
  1084. if (!ByteLen && c != '\r' && c != '\n') {
  1085. return NULL;
  1086. }
  1087. // Copy line to buffer
  1088. for (Pos = 0 ; Pos < ByteLen ; Pos++) {
  1089. Data[Pos] = (BYTE) pGetInfFileByte (File, StartPos);
  1090. StartPos++;
  1091. }
  1092. Data[Pos] = 0;
  1093. Data[Pos + 1] = 0;
  1094. return (PCSTR) Data;
  1095. }
  1096. PCWSTR
  1097. pGetInfLineW (
  1098. IN HANDLE File,
  1099. IN DWORD StartPos,
  1100. OUT PDWORD EndPosPtr, OPTIONAL
  1101. IN OUT PGROWBUFFER LineBuf
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Returns a UNICODE string supplying the line. This string can be
  1106. any length and is nul-terminated. It does not include the \r or
  1107. \n characters.
  1108. If supplied, the EndPosPtr is updated to point to the start of
  1109. the next line.
  1110. Arguments:
  1111. File - Specifies the file to read
  1112. StartPos - Specifies the 32-bit file offset to read (zero-based, in bytes)
  1113. EndPosPtr - If specified, receives the 32-bit file offset of the next
  1114. line, or equal to the file size for the last line.
  1115. LineBuf - Specifies a reused GROWBUFFER that the caller initializes
  1116. and pGetInfLineA uses for line allocation. The caller is
  1117. responsible for cleanup.
  1118. Return Value:
  1119. A pointer to the UNICODE string supplying the full line (with the \r, \n or
  1120. \r\n sequence stripped), or NULL if an error occurs.
  1121. --*/
  1122. {
  1123. DWORD EndPos;
  1124. PBYTE Data;
  1125. DWORD Pos;
  1126. DWORD ByteLen = 0;
  1127. WCHAR ch;
  1128. BOOL Error;
  1129. EndPos = StartPos;
  1130. for (;;) {
  1131. ch = pGetInfFileWchar (File, EndPos, &Error);
  1132. if (Error) {
  1133. break;
  1134. }
  1135. if (ch == L'\r' || ch == L'\n') {
  1136. EndPos += 2;
  1137. if (ch == L'\r') {
  1138. ch = pGetInfFileWchar (File, EndPos, &Error);
  1139. if (ch == '\n') {
  1140. EndPos += 2;
  1141. }
  1142. }
  1143. break;
  1144. }
  1145. EndPos += 2;
  1146. ByteLen += 2;
  1147. }
  1148. //
  1149. // NOTE: If you make a change here, make one above in A version
  1150. //
  1151. // Ctrl+Z ends the file
  1152. if (ch == 26) {
  1153. EndPos = GetFileSize (File, NULL);
  1154. }
  1155. // Allocate buffer
  1156. LineBuf->End = 0;
  1157. Data = GbGrow (LineBuf, ByteLen + 2);
  1158. if (!Data) {
  1159. return NULL;
  1160. }
  1161. // We've been successful -- copy end pos to caller's variable
  1162. if (EndPosPtr) {
  1163. *EndPosPtr = EndPos;
  1164. }
  1165. // End of file condition: zero-length, but not a blank line
  1166. if (!ByteLen && ch != L'\r' && ch != L'\n') {
  1167. return NULL;
  1168. }
  1169. // Copy to buffer
  1170. for (Pos = 0 ; Pos < ByteLen ; Pos++) {
  1171. Data[Pos] = (BYTE) pGetInfFileByte (File, StartPos);
  1172. StartPos++;
  1173. }
  1174. Data[Pos] = 0;
  1175. Data[Pos + 1] = 0;
  1176. if (EndPosPtr) {
  1177. *EndPosPtr = EndPos;
  1178. }
  1179. return (PCWSTR) Data;
  1180. }
  1181. PCWSTR
  1182. pGetNextInfLine (
  1183. IN HANDLE File,
  1184. IN PGROWBUFFER LineBuf,
  1185. IN OUT PDWORD Pos,
  1186. IN BOOL UnicodeMode
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. Returns a string supplying the line. This string can be any length and
  1191. is nul-terminated. It does not include the \r or \n characters.
  1192. Arguments:
  1193. File - Specifies the file to read
  1194. LineBuf - Specifies a reused GROWBUFFER that the caller initializes
  1195. and pGetInfLineA uses for line allocation. The caller is
  1196. responsible for cleanup.
  1197. Pos - Specifies the byte offset to the start of the line. Receives
  1198. the byte offset to the next line.
  1199. UnicodeMode - Specifies TRUE if the file being read is a UNICODE file,
  1200. or FALSE if the file being read is a DBCS file.
  1201. Return Value:
  1202. A pointer to the string supplying the full line (with the \r, \n or
  1203. \r\n sequence stripped), or NULL if an error occurs.
  1204. --*/
  1205. {
  1206. PCSTR AnsiStr = NULL;
  1207. PCWSTR UnicodeStr = NULL;
  1208. PCWSTR FinalStr;
  1209. BOOL Converted = FALSE;
  1210. //
  1211. // Obtain the text from the file
  1212. //
  1213. if (UnicodeMode) {
  1214. UnicodeStr = pGetInfLineW (File, *Pos, Pos, LineBuf);
  1215. if (!UnicodeStr) {
  1216. return NULL;
  1217. }
  1218. } else {
  1219. AnsiStr = pGetInfLineA (File, *Pos, Pos, LineBuf);
  1220. if (!AnsiStr) {
  1221. return NULL;
  1222. }
  1223. }
  1224. if (AnsiStr) {
  1225. UnicodeStr = ConvertAtoW (AnsiStr);
  1226. if (!UnicodeStr) {
  1227. return NULL;
  1228. }
  1229. Converted = TRUE;
  1230. }
  1231. FinalStr = UnicodeStr;
  1232. //
  1233. // Copy converted string into line buffer
  1234. //
  1235. if (Converted) {
  1236. LineBuf->End = 0;
  1237. Converted = GbMultiSzAppendW (LineBuf, FinalStr);
  1238. FreeConvertedStr (FinalStr);
  1239. if (!Converted) {
  1240. return NULL;
  1241. }
  1242. }
  1243. return (PCWSTR) LineBuf->Buf;
  1244. }
  1245. BOOL
  1246. DeleteLineInInfSection (
  1247. IN HINF Inf,
  1248. IN PINFLINE InfLine
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. DeleteLineInInfSection removes the specified InfLine from its section,
  1253. cleaning up memory used by the line.
  1254. Arguments:
  1255. Inf - Specifies the INF to modify
  1256. InfLine - Specifies the line to delete
  1257. Return Value:
  1258. TRUE if the line was deleted successfully, or FALSE if an error
  1259. occurred.
  1260. --*/
  1261. {
  1262. PINFFILE InfFile = (PINFFILE) Inf;
  1263. if (InfLine->Prev) {
  1264. InfLine->Prev->Next = InfLine->Next;
  1265. } else {
  1266. InfLine->Section->FirstLine = InfLine->Next;
  1267. }
  1268. if (InfLine->Next) {
  1269. InfLine->Next->Prev = InfLine->Prev;
  1270. } else {
  1271. InfLine->Section->LastLine = InfLine->Prev;
  1272. }
  1273. if (InfLine->Key) {
  1274. PmReleaseMemory (InfFile->InfPool, (PVOID) InfLine->Key);
  1275. }
  1276. if (InfLine->Data) {
  1277. PmReleaseMemory (InfFile->InfPool, (PVOID) InfLine->Data);
  1278. }
  1279. InfLine->Section->LineCount--;
  1280. PmReleaseMemory (InfFile->InfPool, (PVOID) InfLine);
  1281. return TRUE;
  1282. }
  1283. BOOL
  1284. DeleteSectionInInfFile (
  1285. IN HINF Inf,
  1286. IN PINFSECTION Section
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. DeleteSectionInInfFile removes the specified section from the INF
  1291. data structure, removing all lines cleaning up
  1292. memory used by the section.
  1293. Arguments:
  1294. InfFile - Specifies the table owning the INF line
  1295. Section - Specifies the section to delete
  1296. Return Value:
  1297. TRUE if the section was deleted successfully, or FALSE if an error
  1298. occurred.
  1299. --*/
  1300. {
  1301. PINFLINE InfLine;
  1302. PINFLINE DelInfLine;
  1303. PINFFILE InfFile = (PINFFILE) Inf;
  1304. InfLine = Section->FirstLine;
  1305. while (InfLine) {
  1306. DelInfLine = InfLine;
  1307. InfLine = InfLine->Next;
  1308. if (!DeleteLineInInfSection (InfFile, DelInfLine)) {
  1309. return FALSE;
  1310. }
  1311. }
  1312. if (Section->Prev) {
  1313. Section->Prev->Next = Section->Next;
  1314. } else {
  1315. InfFile->FirstInfSection = Section->Next;
  1316. }
  1317. if (Section->Next) {
  1318. Section->Next->Prev = Section->Prev;
  1319. } else {
  1320. InfFile->LastInfSection = Section->Prev;
  1321. }
  1322. PmReleaseMemory (InfFile->InfPool, (PVOID) Section->Name);
  1323. PmReleaseMemory (InfFile->InfPool, (PVOID) Section);
  1324. return TRUE;
  1325. }
  1326. UINT
  1327. GetInfSectionLineCount (
  1328. IN PINFSECTION Section
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. GetInfSectionLineCount returns the number of lines in the specified
  1333. INF section.
  1334. Arguments:
  1335. Section - Specifies the section to query
  1336. Return Value:
  1337. The number of lines, or zero if the section has no lines.
  1338. --*/
  1339. {
  1340. return Section->LineCount;
  1341. }