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.

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