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.

1936 lines
45 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. inf.c
  5. Abstract:
  6. Provides wrappers for commonly used INF file handling routines. The wrappers provide, amount
  7. other things, easy memory allocation using a user supplied GROWBUFFER or POOLHANDLE
  8. Author:
  9. 09-Jul-1997 Marc R. Whitten (marcw) - File creation.
  10. Revision History:
  11. 07-Feb-2001 ovidiut Revised the replace/append capability.
  12. 22-Oct-1998 marcw Added capability to replace/append inf files.
  13. 08-Oct-1997 jimschm OEM version of SetupGetStringField
  14. --*/
  15. #include "pch.h"
  16. #define INF_REPLACE 1
  17. #define INF_APPEND 2
  18. #define S_VERSION_A "Version"
  19. #define S_TARGETINF_A "TargetInf"
  20. #define S_VERSION_W L"Version"
  21. #define S_LANGUAGE_W L"Language"
  22. #define S_STRINGS_W L"Strings"
  23. #define S_INFDIR_A "inf"
  24. #define S_TAG_A "Tag"
  25. #define INF_INVALID_VERSION 0xffff
  26. #define INF_ANY_LANGUAGE 0
  27. VOID InitInfReplaceTable (VOID);
  28. UINT pGetLanguage (IN PCSTR File);
  29. typedef struct _tagINFMOD {
  30. struct _tagINFMOD *Next;
  31. PCSTR TargetInf;
  32. DWORD Language;
  33. DWORD Version;
  34. PCSTR Tag;
  35. BOOL ReplacementFile;
  36. PCSTR PatchInf;
  37. } INFMOD, *PINFMOD;
  38. PINFMOD g_RootInfMod;
  39. POOLHANDLE g_InfModPool;
  40. PBOOL g_UpginfsUpdated;
  41. VOID
  42. InfGlobalInit (
  43. IN BOOL Terminate
  44. )
  45. {
  46. if (!Terminate) {
  47. g_InfModPool = PoolMemInitNamedPool ("INF Modifications");
  48. } else {
  49. PoolMemDestroyPool (g_InfModPool);
  50. g_RootInfMod = NULL;
  51. }
  52. }
  53. /*++
  54. Routine Description:
  55. pAllocateSpace is a private function that allocates space using the user specified allocator.
  56. Arguments:
  57. Context - A valid INFSTRUCT which has been initialized either by a call to InitInfStruct or
  58. by using one of the static initializers (INITINFSTRUCT_GROWBUFFER or
  59. INITINFSTRUCT_POOLHANDLE)
  60. Size - The size (in bytes) to allocate.
  61. Return Value:
  62. A pointer to the successfully allocated memory or NULL if no memory could be allocated.
  63. --*/
  64. PBYTE
  65. pAllocateSpaceA (
  66. IN PINFSTRUCTA Context,
  67. IN UINT Size
  68. )
  69. {
  70. PBYTE rBytes = NULL;
  71. switch (Context -> Allocator) {
  72. case INF_USE_POOLHANDLE:
  73. //
  74. // Allocate space using Poolmem.
  75. //
  76. rBytes = PoolMemGetMemory(Context -> PoolHandle, Size);
  77. break;
  78. case INF_USE_GROWBUFFER:
  79. case INF_USE_PRIVATE_GROWBUFFER:
  80. //
  81. // Allocate space using Growbuf.
  82. //
  83. Context->GrowBuffer.End = 0;
  84. rBytes = GrowBuffer(&(Context -> GrowBuffer), Size);
  85. break;
  86. case INF_USE_PRIVATE_POOLHANDLE:
  87. //
  88. // Allocate space using private growbuffer.
  89. //
  90. if (!Context -> PoolHandle) {
  91. Context -> PoolHandle = PoolMemInitNamedPool ("INF Pool");
  92. }
  93. if (Context -> PoolHandle) {
  94. rBytes = PoolMemGetMemory(Context -> PoolHandle, Size);
  95. }
  96. break;
  97. }
  98. return rBytes;
  99. }
  100. PBYTE
  101. pAllocateSpaceW (
  102. IN PINFSTRUCTW Context,
  103. IN UINT Size
  104. )
  105. {
  106. PBYTE rBytes = NULL;
  107. switch (Context -> Allocator) {
  108. case INF_USE_POOLHANDLE:
  109. //
  110. // Allocate space using Poolmem.
  111. //
  112. rBytes = PoolMemGetMemory(Context -> PoolHandle, Size);
  113. break;
  114. case INF_USE_GROWBUFFER:
  115. case INF_USE_PRIVATE_GROWBUFFER:
  116. //
  117. // Allocate space using Growbuf.
  118. //
  119. Context->GrowBuffer.End = 0;
  120. rBytes = GrowBuffer(&(Context -> GrowBuffer), Size);
  121. break;
  122. case INF_USE_PRIVATE_POOLHANDLE:
  123. //
  124. // Allocate space using private growbuffer.
  125. //
  126. if (!Context -> PoolHandle) {
  127. Context -> PoolHandle = PoolMemInitNamedPool ("INF Pool");
  128. }
  129. if (Context -> PoolHandle) {
  130. rBytes = PoolMemGetMemory(Context -> PoolHandle, Size);
  131. }
  132. break;
  133. }
  134. return rBytes;
  135. }
  136. /*++
  137. Routine Description:
  138. This function initializes an INFSTRUCT with the user supplied allocator. It is used when
  139. user of the INF wrapper routines wishes to manage his own memory (i.e. such as when he
  140. already has a suitable allocator with sufficient scope created, etc.)
  141. There is no need to call this function if the user wishes to have the INF wrapper routines
  142. manage there own memory. Initialize your Init structure with one of either
  143. INITINFSTRUCT_POOLMEM or INITINFSTRUCT_GROWBUFFER, depending on your preference and needs
  144. for an allocator.
  145. Arguments:
  146. Context - Recieves the initialized INFSTRUCT.
  147. GrowBuffer - An optional parameter containing a user supplied and initialized GROWBUFFER.
  148. If this parameter is non-NULL, then PoolHandle should be NULL.
  149. PoolHandle - An optional parameter containing a user supplied and initialized POOLHANDLE.
  150. If this parameter is non-NULL, then GrowBuffer should be NULL.
  151. One of either GrowBuffer or PoolHandle *must* be specified.
  152. Return Value:
  153. None.
  154. --*/
  155. VOID
  156. InitInfStructA (
  157. OUT PINFSTRUCTA Context,
  158. IN PGROWBUFFER GrowBuffer, OPTIONAL
  159. IN POOLHANDLE PoolHandle OPTIONAL
  160. )
  161. {
  162. ZeroMemory(Context,sizeof(INFSTRUCTA));
  163. if (!PoolHandle && !GrowBuffer) {
  164. Context -> Allocator = INF_USE_PRIVATE_POOLHANDLE;
  165. }
  166. if (PoolHandle) {
  167. Context -> PoolHandle = PoolHandle;
  168. Context -> Allocator = INF_USE_POOLHANDLE;
  169. }
  170. if (GrowBuffer) {
  171. Context -> GrowBuffer = *GrowBuffer;
  172. Context -> Allocator = INF_USE_GROWBUFFER;
  173. }
  174. }
  175. VOID
  176. InitInfStructW (
  177. OUT PINFSTRUCTW Context,
  178. IN PGROWBUFFER GrowBuffer, OPTIONAL
  179. IN POOLHANDLE PoolHandle OPTIONAL
  180. )
  181. {
  182. ZeroMemory(Context,sizeof(INFSTRUCTW));
  183. if (!PoolHandle && !GrowBuffer) {
  184. Context -> Allocator = INF_USE_PRIVATE_POOLHANDLE;
  185. }
  186. if (PoolHandle) {
  187. Context -> PoolHandle = PoolHandle;
  188. Context -> Allocator = INF_USE_POOLHANDLE;
  189. }
  190. if (GrowBuffer) {
  191. Context -> GrowBuffer = *GrowBuffer;
  192. Context -> Allocator = INF_USE_GROWBUFFER;
  193. }
  194. }
  195. /*++
  196. Routine Description:
  197. InfCleanupInfStruct is responsible for cleaning up the data associated
  198. with an INFSTRUCT. This is a mandatory call, unless the INFSTRUCT
  199. was initialized with InitInfStruct, called with a non-NULL grow buffer or
  200. pool handle.
  201. This routine can be called no matter how the INFSTRUCT was initialized.
  202. However, it will NOT free caller-owned grow buffers or pools.
  203. Arguments:
  204. Context - Receives the properly cleaned up INFSTRUCT, ready to be
  205. reused.
  206. Return Value:
  207. none
  208. --*/
  209. VOID
  210. InfCleanUpInfStructA (
  211. IN OUT PINFSTRUCTA Context
  212. )
  213. {
  214. if (Context -> Allocator == INF_USE_PRIVATE_GROWBUFFER) {
  215. FreeGrowBuffer (&(Context -> GrowBuffer));
  216. }
  217. else if (Context -> Allocator == INF_USE_PRIVATE_POOLHANDLE && Context -> PoolHandle) {
  218. PoolMemDestroyPool(Context -> PoolHandle);
  219. }
  220. InitInfStructA (Context, NULL, NULL);
  221. }
  222. VOID
  223. InfCleanUpInfStructW (
  224. IN OUT PINFSTRUCTW Context
  225. )
  226. {
  227. if (Context -> Allocator == INF_USE_PRIVATE_GROWBUFFER) {
  228. FreeGrowBuffer (&(Context -> GrowBuffer));
  229. }
  230. else if (Context -> Allocator == INF_USE_PRIVATE_POOLHANDLE && Context -> PoolHandle) {
  231. PoolMemDestroyPool(Context -> PoolHandle);
  232. }
  233. InitInfStructW (Context, NULL, NULL);
  234. }
  235. /*++
  236. Routine Description:
  237. InfResetInfStruct resets the pool so memory can be recycled. The intent is
  238. to allow a caller to reset the INFSTRUCT in order to release the memory
  239. obtained from getting INF fields. This is useful in a loop of InfFindFirstLine/
  240. InfFindNextLine, where two or more fields are processed for each line.
  241. If only one field is processed in an InfFindFirstLine/InfFindNextLine loop,
  242. a grow buffer should be used instead.
  243. This routine empties the active pool block, a block that is 8K by default. If
  244. more than the block size has been allocated, other memory blocks besides the
  245. active block will exist. Because only the active block is reset, the pool will
  246. grow.
  247. If the caller expects more than the block size during one iteration, it should call
  248. InfCleanupInfStruct to free the pool completely.
  249. Arguments:
  250. Context - Specifies the struct to reset
  251. Return Value:
  252. none
  253. --*/
  254. VOID
  255. InfResetInfStructA (
  256. IN OUT PINFSTRUCTA Context
  257. )
  258. {
  259. switch (Context -> Allocator) {
  260. case INF_USE_POOLHANDLE:
  261. case INF_USE_PRIVATE_POOLHANDLE:
  262. if (Context->PoolHandle) {
  263. PoolMemEmptyPool (Context->PoolHandle);
  264. }
  265. break;
  266. }
  267. }
  268. VOID
  269. InfResetInfStructW (
  270. IN OUT PINFSTRUCTW Context
  271. )
  272. {
  273. switch (Context -> Allocator) {
  274. case INF_USE_POOLHANDLE:
  275. case INF_USE_PRIVATE_POOLHANDLE:
  276. if (Context->PoolHandle) {
  277. PoolMemEmptyPool (Context->PoolHandle);
  278. }
  279. break;
  280. }
  281. }
  282. VOID
  283. pDeleteNode (
  284. IN PINFMOD Node
  285. )
  286. {
  287. if (Node) {
  288. if (Node->TargetInf) {
  289. PoolMemReleaseMemory (g_InfModPool, (PVOID)Node->TargetInf);
  290. }
  291. if (Node->PatchInf) {
  292. PoolMemReleaseMemory (g_InfModPool, (PVOID)Node->PatchInf);
  293. }
  294. PoolMemReleaseMemory (g_InfModPool, Node);
  295. }
  296. }
  297. PINFMOD
  298. pCreateInfMod (
  299. IN PCSTR TargetInf,
  300. IN DWORD Language,
  301. IN DWORD Version,
  302. IN PCSTR Tag, OPTIONAL
  303. IN BOOL ReplacementFile,
  304. IN PCSTR PatchInf
  305. )
  306. {
  307. PINFMOD node;
  308. node = (PINFMOD) PoolMemGetAlignedMemory (g_InfModPool, sizeof (INFMOD));
  309. if (node) {
  310. node->Next = NULL;
  311. node->TargetInf = PoolMemDuplicateString (g_InfModPool, TargetInf);
  312. node->Language = Language;
  313. node->Version = Version;
  314. node->Tag = Tag ? PoolMemDuplicateString (g_InfModPool, Tag) : NULL;
  315. node->ReplacementFile = ReplacementFile;
  316. node->PatchInf = PoolMemDuplicateString (g_InfModPool, PatchInf);
  317. }
  318. return node;
  319. }
  320. BOOL
  321. pAddReplacementInfToTable (
  322. IN PSTR InfToPatch,
  323. IN UINT Version,
  324. IN UINT Language,
  325. IN PCSTR Tag, OPTIONAL
  326. IN DWORD Operation,
  327. IN PCSTR PatchInf
  328. )
  329. {
  330. PINFMOD node;
  331. node = pCreateInfMod (InfToPatch, Language, Version, Tag, Operation & INF_REPLACE, PatchInf);
  332. if (!node) {
  333. return FALSE;
  334. }
  335. node->Next = g_RootInfMod;
  336. g_RootInfMod = node;
  337. return TRUE;
  338. }
  339. BOOL
  340. pGetInfModificationList (
  341. IN PCSTR TargetInf,
  342. IN UINT TargetLanguage,
  343. IN UINT TargetVersion,
  344. IN PCSTR Tag, OPTIONAL
  345. OUT PCSTR* TargetReplacementFile, OPTIONAL
  346. OUT PGROWBUFFER TargetAppendList OPTIONAL
  347. )
  348. {
  349. PINFMOD node;
  350. UINT version;
  351. PCSTR patchInf;
  352. BOOL b = FALSE;
  353. if (TargetReplacementFile) {
  354. *TargetReplacementFile = NULL;
  355. }
  356. if (TargetAppendList) {
  357. TargetAppendList->End = 0;
  358. }
  359. if (TargetVersion == INF_INVALID_VERSION) {
  360. return FALSE;
  361. }
  362. version = TargetVersion;
  363. patchInf = NULL;
  364. for (node = g_RootInfMod; node; node = node->Next) {
  365. if (node->Version > version &&
  366. (node->Language == TargetLanguage || node->Language == INF_ANY_LANGUAGE) &&
  367. (!Tag || !node->Tag || StringIMatchA (node->Tag, Tag)) &&
  368. StringIMatchA (node->TargetInf, TargetInf)
  369. ) {
  370. if (node->ReplacementFile) {
  371. //
  372. // rev the version#; new minimum version will be that of the replacement file
  373. //
  374. version = node->Version;
  375. patchInf = node->PatchInf;
  376. b = TRUE;
  377. }
  378. }
  379. }
  380. if (TargetReplacementFile) {
  381. *TargetReplacementFile = patchInf;
  382. }
  383. //
  384. // for append nodes, add to the list only those that have a higher version than the
  385. // target or the replacement file
  386. //
  387. for (node = g_RootInfMod; node; node = node->Next) {
  388. if (node->Version > version &&
  389. (node->Language == TargetLanguage || node->Language == INF_ANY_LANGUAGE) &&
  390. (!Tag || !node->Tag || StringIMatchA (node->Tag, Tag)) &&
  391. StringIMatchA (node->TargetInf, TargetInf) &&
  392. !node->ReplacementFile
  393. ) {
  394. if (TargetAppendList) {
  395. MultiSzAppendA (TargetAppendList, node->PatchInf);
  396. }
  397. b = TRUE;
  398. }
  399. }
  400. if (TargetAppendList && TargetAppendList->End) {
  401. MultiSzAppendA (TargetAppendList, "");
  402. }
  403. return b;
  404. }
  405. VOID
  406. pDestroyInfModList (
  407. IN PINFMOD List
  408. )
  409. {
  410. PINFMOD node, next;
  411. node = List;
  412. while (node) {
  413. next = node->Next;
  414. pDeleteNode (node);
  415. node = next;
  416. }
  417. }
  418. /*++
  419. Routine Description:
  420. InfOpenInfFileA and InfOpenInfFileW are wrappers for the SetupOpenInfFile function.
  421. They cut down the number of parameters necessary to open an INF file by supplying
  422. the most common options for non-user specified parameters.
  423. A call to one of these functions is equivelant to
  424. SetupOpenInfFile(<FileName>,NULL,INF_STYLE_WIN4,NULL)
  425. Arguments:
  426. FileName - Contains the name of the INF file to open. See the help for SetupOpenInfFile
  427. for special details concerning this parameter.
  428. Return Value:
  429. If the INF file is successfully opened, a valid HINF is returned, otherwise,
  430. INVALID_HANDLE_VALUE is returned. See the documentation for SetupOpenInfFile for more
  431. details.
  432. --*/
  433. HINF
  434. RealInfOpenInfFileA (
  435. IN PCSTR FileSpec /*,*/
  436. ALLOCATION_TRACKING_DEF
  437. )
  438. {
  439. PCSTR p;
  440. HINF rInf;
  441. UINT language;
  442. static BOOL firstCall = TRUE;
  443. GROWBUFFER AppendList = GROWBUF_INIT;
  444. MULTISZ_ENUM e;
  445. UINT version;
  446. PCSTR replacementFile;
  447. CHAR windir[MAX_MBCHAR_PATH];
  448. CHAR buf[MAX_MBCHAR_PATH];
  449. PCSTR tag;
  450. PCSTR fullPath = NULL;
  451. MYASSERT(FileSpec);
  452. if (firstCall || (g_UpginfsUpdated != NULL && *g_UpginfsUpdated)) {
  453. //
  454. // Generate the necessary memdb sections for the replace/adds.
  455. //
  456. InitInfReplaceTable ();
  457. firstCall = FALSE;
  458. if (g_UpginfsUpdated) {
  459. *g_UpginfsUpdated = FALSE;
  460. }
  461. }
  462. //
  463. // if FileSpec is incomplete, make the full path first
  464. //
  465. if (!_mbschr (FileSpec, '\\')) {
  466. if (GetWindowsDirectoryA (windir, MAX_MBCHAR_PATH)) {
  467. WIN32_FIND_DATAA fd;
  468. p = JoinPathsA (windir, S_INFDIR_A);
  469. fullPath = JoinPathsA (p, FileSpec);
  470. FreePathStringA (p);
  471. if (!DoesFileExistExA (fullPath, &fd) ||
  472. (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  473. ) {
  474. FreePathStringA (fullPath);
  475. if (GetSystemDirectoryA (windir, MAX_MBCHAR_PATH)) {
  476. fullPath = JoinPathsA (windir, FileSpec);
  477. if (!DoesFileExistExA (fullPath, &fd) ||
  478. (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  479. ) {
  480. FreePathStringA (fullPath);
  481. fullPath = NULL;
  482. }
  483. }
  484. }
  485. }
  486. if (fullPath) {
  487. FileSpec = fullPath;
  488. }
  489. }
  490. //
  491. // gather info we'll need to determine if there are infs to replace/append
  492. // this inf.
  493. //
  494. p = GetFileNameFromPathA (FileSpec);
  495. language = pGetLanguage (FileSpec);
  496. version = GetPrivateProfileIntA (
  497. S_VERSION_A,
  498. S_VERSION_A,
  499. INF_INVALID_VERSION,
  500. FileSpec
  501. );
  502. if (GetPrivateProfileStringA (
  503. S_VERSION_A,
  504. S_TAG_A,
  505. TEXT(""),
  506. buf,
  507. MAX_MBCHAR_PATH,
  508. FileSpec
  509. )) {
  510. tag = buf;
  511. } else {
  512. tag = NULL;
  513. }
  514. if (!pGetInfModificationList (p, language, version, tag, &replacementFile, &AppendList)) {
  515. replacementFile = FileSpec;
  516. } else {
  517. if (replacementFile) {
  518. LOGA ((LOG_INFORMATION, "Using replacement file %s for %s", replacementFile, FileSpec));
  519. } else {
  520. replacementFile = FileSpec;
  521. }
  522. }
  523. //
  524. // Open the main inf.
  525. //
  526. rInf = SetupOpenInfFileA (
  527. replacementFile,
  528. NULL,
  529. INF_STYLE_WIN4 | INF_STYLE_OLDNT,
  530. NULL
  531. );
  532. //
  533. // Append language and non-language-specific .add files.
  534. //
  535. if (rInf != INVALID_HANDLE_VALUE) {
  536. if (EnumFirstMultiSzA (&e, (PCSTR) AppendList.Buf)) {
  537. do {
  538. if (!SetupOpenAppendInfFileA (e.CurrentString, rInf, NULL)) {
  539. DEBUGMSGA ((
  540. DBG_ERROR,
  541. "Unable to append %s to %s.",
  542. e.CurrentString,
  543. FileSpec
  544. ));
  545. } else {
  546. LOGA ((LOG_INFORMATION, "Using append file %s for %s", e.CurrentString, FileSpec));
  547. }
  548. } while (EnumNextMultiSzA (&e));
  549. }
  550. }
  551. FreeGrowBuffer (&AppendList);
  552. if (rInf != INVALID_HANDLE_VALUE) {
  553. DebugRegisterAllocation (INF_HANDLE, (PVOID) rInf, File, Line);
  554. }
  555. if (fullPath) {
  556. FreePathStringA (fullPath);
  557. }
  558. return rInf;
  559. }
  560. HINF
  561. RealInfOpenInfFileW (
  562. IN PCWSTR FileSpec /*,*/
  563. ALLOCATION_TRACKING_DEF
  564. )
  565. {
  566. PCSTR AnsiFileSpec;
  567. HINF rInf;
  568. AnsiFileSpec = ConvertWtoA (FileSpec);
  569. MYASSERT (AnsiFileSpec);
  570. rInf = InfOpenInfFileA (AnsiFileSpec);
  571. FreeConvertedStr (AnsiFileSpec);
  572. return rInf;
  573. }
  574. VOID
  575. InfCloseInfFile (
  576. HINF Inf
  577. )
  578. {
  579. DebugUnregisterAllocation (INF_HANDLE, Inf);
  580. SetupCloseInfFile (Inf);
  581. }
  582. /*++
  583. Routine Description:
  584. InfOpenInfInAllSourcesA and InfOpenInfInAllSourcesW are special inf open routines that
  585. are capable of opening multiple versions of the same inf file that may be spread out across
  586. installation directories. The first INF file found will be opened with a call to
  587. SetupOpenInfFile. Additional files will be opened with SetupOpenAppendInfFile.
  588. Arguments:
  589. InfSpecifier - Contains the source directory indepent portion of the path to a particular inf file.
  590. For files located in the root of the source directory, this will simply be the name
  591. of the file. For files located in a sub-directory of the source directory, this will
  592. be a partial path.
  593. SourceCount - Contains the number of source directories
  594. SourceDirectories - Contains an array of all the source directories.
  595. Return Value:
  596. If any INF file is successfully opened, a valid HINF is returned, otherwise,
  597. INVALID_HANDLE_VALUE is returned. See the documentation for SetupOpenInfFile for more
  598. details.
  599. --*/
  600. HINF
  601. InfOpenInfInAllSourcesA (
  602. IN PCSTR InfSpecifier,
  603. IN DWORD SourceCount,
  604. IN PCSTR * SourceDirectories
  605. )
  606. {
  607. DWORD index;
  608. HINF rInf = INVALID_HANDLE_VALUE;
  609. PSTR curPath;
  610. MYASSERT(InfSpecifier && SourceDirectories);
  611. //
  612. // Open all available inf files in the source directories.
  613. //
  614. for (index = 0;index < SourceCount; index++) {
  615. //
  616. // Create a path to the INF in the current source directory.
  617. //
  618. curPath = JoinPathsA(SourceDirectories[index],InfSpecifier);
  619. //
  620. // See if the INF file exists there...
  621. //
  622. if (DoesFileExistA (curPath)) {
  623. //
  624. // Open the INF file.
  625. //
  626. rInf = InfOpenInfFileA(curPath);
  627. if (rInf == INVALID_HANDLE_VALUE) {
  628. LOGA ((LOG_ERROR, "Error opening INF %s.", curPath));
  629. }
  630. }
  631. //
  632. // Free this string.
  633. //
  634. FreePathStringA(curPath);
  635. if (rInf != INVALID_HANDLE_VALUE) {
  636. //
  637. // done
  638. //
  639. break;
  640. }
  641. }
  642. return rInf;
  643. }
  644. HINF
  645. InfOpenInfInAllSourcesW (
  646. IN PCWSTR InfSpecifier,
  647. IN DWORD SourceCount,
  648. IN PCWSTR *SourceDirectories
  649. )
  650. {
  651. DWORD index;
  652. HINF rInf = INVALID_HANDLE_VALUE;
  653. PWSTR curPath;
  654. MYASSERT(InfSpecifier && SourceDirectories);
  655. //
  656. // Open all available inf files in the source directories.
  657. //
  658. for (index = 0;index < SourceCount; index++) {
  659. //
  660. // Create a path to the INF in the current source directory.
  661. //
  662. curPath = JoinPathsW(SourceDirectories[index],InfSpecifier);
  663. //
  664. // See if the INF file exists there...
  665. //
  666. if (DoesFileExistW (curPath)) {
  667. //
  668. // Open the INF file.
  669. //
  670. rInf = InfOpenInfFileW(curPath);
  671. if (rInf == INVALID_HANDLE_VALUE) {
  672. LOGW ((LOG_ERROR, "OpenInfInAllSources: Error opening INF %s.", curPath));
  673. }
  674. }
  675. //
  676. // Free this string.
  677. //
  678. FreePathStringW(curPath);
  679. if (rInf != INVALID_HANDLE_VALUE) {
  680. //
  681. // done
  682. //
  683. break;
  684. }
  685. }
  686. return rInf;
  687. }
  688. /*++
  689. Routine Description:
  690. InfGetLineTextA and InfGetLineTextW are wrappers for the SetupGetLineText function.
  691. They both reduce the number of parameters required to get the line text and
  692. take care of allocating and filling a buffer with the data returned from the API.
  693. Arguments:
  694. Context - A valid InfStruct. The INFCONTEXT member of the structure must point to a valid
  695. line to retrieve (i.e. through the use of InfFindFirstLine/InfFindNextLine.
  696. Return Value:
  697. A pointer to the allocated line or NULL if there was an error. Consult GetLastError() for
  698. extended error information.
  699. --*/
  700. PSTR
  701. InfGetLineTextA (
  702. IN OUT PINFSTRUCTA Context
  703. )
  704. {
  705. PSTR rLine = NULL;
  706. UINT requiredSize;
  707. //
  708. // Get the size necessary for holding the field.
  709. //
  710. if (SetupGetLineTextA(
  711. &(Context -> Context),
  712. NULL,
  713. NULL,
  714. NULL,
  715. NULL,
  716. 0,
  717. &requiredSize
  718. )) {
  719. //
  720. // Create a string big enough.
  721. //
  722. rLine = (PSTR) pAllocateSpaceA(Context,requiredSize);
  723. if (rLine) {
  724. //
  725. // Get the field.
  726. //
  727. if (!SetupGetLineTextA(
  728. &(Context -> Context),
  729. NULL,
  730. NULL,
  731. NULL,
  732. rLine,
  733. requiredSize,
  734. NULL
  735. )) {
  736. //
  737. // If we did not successfully get the field, reset the string to NULL.
  738. //
  739. DEBUGMSGA((DBG_ERROR,"InfGetLineTextA: Error retrieving field from INF file."));
  740. rLine = NULL;
  741. }
  742. }
  743. }
  744. return rLine;
  745. }
  746. PWSTR
  747. InfGetLineTextW (
  748. IN OUT PINFSTRUCTW Context
  749. )
  750. {
  751. PWSTR rLine = NULL;
  752. UINT requiredSize;
  753. //
  754. // Get the size necessary for holding the field.
  755. //
  756. if (SetupGetLineTextW(
  757. &(Context -> Context),
  758. NULL,
  759. NULL,
  760. NULL,
  761. NULL,
  762. 0,
  763. &requiredSize
  764. )) {
  765. //
  766. // Create a string big enough.
  767. //
  768. rLine = (PWSTR) pAllocateSpaceW(Context,requiredSize*sizeof(WCHAR));
  769. if (rLine) {
  770. //
  771. // Get the field.
  772. //
  773. if (!SetupGetLineTextW(
  774. &(Context -> Context),
  775. NULL,
  776. NULL,
  777. NULL,
  778. rLine,
  779. requiredSize,
  780. NULL
  781. )) {
  782. //
  783. // If we did not successfully get the field, reset the string to NULL.
  784. //
  785. DEBUGMSGW((DBG_ERROR,"InfGetLineTextW: Error retrieving field from INF file."));
  786. rLine = NULL;
  787. }
  788. }
  789. }
  790. return rLine;
  791. }
  792. /*++
  793. Routine Description:
  794. InfGetMultiSzFieldA and InfGetMultiSzFieldW are wrappers for the SetupGetMultiSzField function.
  795. They both reduce the number of parameters required to get the line text and
  796. take care of allocating and filling a buffer with the data returned from the API.
  797. Arguments:
  798. Context - A valid InfStruct. The INFCONTEXT member of the structure must point to a valid
  799. line to retrieve (i.e. through the use of InfFindFirstLine/InfFindNextLine.
  800. FieldIndex - The index within the line to retrieve a string field.
  801. Return Value:
  802. A pointer to the allocated fields or NULL if there was an error. Consult GetLastError() for
  803. extended error information.
  804. --*/
  805. PSTR
  806. InfGetMultiSzFieldA (
  807. IN OUT PINFSTRUCTA Context,
  808. IN UINT FieldIndex
  809. )
  810. {
  811. UINT requiredSize;
  812. PSTR rFields = NULL;
  813. //
  814. // Get the size necessary for holding the field.
  815. //
  816. if (SetupGetMultiSzFieldA(
  817. &(Context -> Context),
  818. FieldIndex,
  819. NULL,
  820. 0,
  821. &requiredSize
  822. )) {
  823. //
  824. // Create a string big enough.
  825. //
  826. rFields = (PSTR) pAllocateSpaceA(Context,requiredSize);
  827. if (rFields) {
  828. //
  829. // Get the field.
  830. //
  831. if (!SetupGetMultiSzFieldA(
  832. &(Context -> Context),
  833. FieldIndex,
  834. rFields,
  835. requiredSize,
  836. NULL
  837. )) {
  838. //
  839. // If we did not successfully get the field, reset the string to NULL.
  840. //
  841. DEBUGMSGA((DBG_ERROR,"InfGetMultiSzFieldA: Error retrieving field from INF file."));
  842. rFields = NULL;
  843. }
  844. }
  845. }
  846. return rFields;
  847. }
  848. PWSTR
  849. InfGetMultiSzFieldW (
  850. IN OUT PINFSTRUCTW Context,
  851. IN UINT FieldIndex
  852. )
  853. {
  854. UINT requiredSize;
  855. PWSTR rFields = NULL;
  856. //
  857. // Get the size necessary for holding the field.
  858. //
  859. if (SetupGetMultiSzFieldW(
  860. &(Context -> Context),
  861. FieldIndex,
  862. NULL,
  863. 0,
  864. &requiredSize
  865. )) {
  866. //
  867. // Create a string big enough.
  868. //
  869. rFields = (PWSTR) pAllocateSpaceW(Context,requiredSize*sizeof(WCHAR));
  870. if (rFields) {
  871. //
  872. // Get the field.
  873. //
  874. if (!SetupGetMultiSzFieldW(
  875. &(Context -> Context),
  876. FieldIndex,
  877. rFields,
  878. requiredSize,
  879. NULL
  880. )) {
  881. //
  882. // If we did not successfully get the field, reset the string to NULL.
  883. //
  884. DEBUGMSGW((DBG_ERROR,"InfGetMultiSzFieldW: Error retrieving field from INF file."));
  885. rFields = NULL;
  886. }
  887. }
  888. }
  889. return rFields;
  890. }
  891. /*++
  892. Routine Description:
  893. InfGetStringFieldA and InfGetStringFieldW are wrappers for the SetupGetStringField function.
  894. They both reduce the number of parameters required to get the line text and
  895. take care of allocating and filling a buffer with the data returned from the API.
  896. Arguments:
  897. Context - A valid InfStruct. The INFCONTEXT member of the structure must point to a valid
  898. line to retrieve (i.e. through the use of InfFindFirstLine/InfFindNextLine.
  899. FieldIndex - The index within the line to retrieve a string field.
  900. Return Value:
  901. A pointer to the allocated line or NULL if there was an error. Consult GetLastError() for
  902. extended error information.
  903. --*/
  904. PSTR
  905. InfGetStringFieldA (
  906. IN OUT PINFSTRUCTA Context,
  907. IN UINT FieldIndex
  908. )
  909. {
  910. UINT requiredSize;
  911. PSTR rField = NULL;
  912. //
  913. // Get the size necessary for holding the field.
  914. //
  915. if (SetupGetStringFieldA(
  916. &(Context -> Context),
  917. FieldIndex,
  918. NULL,
  919. 0,
  920. &requiredSize
  921. )) {
  922. //
  923. // Create a string big enough.
  924. //
  925. rField = (PSTR) pAllocateSpaceA(Context,requiredSize);
  926. if (rField) {
  927. //
  928. // Get the field.
  929. //
  930. if (!SetupGetStringFieldA(
  931. &(Context -> Context),
  932. FieldIndex,
  933. rField,
  934. requiredSize,
  935. NULL
  936. )) {
  937. //
  938. // If we did not successfully get the field, reset the string to NULL.
  939. //
  940. DEBUGMSGA((DBG_ERROR,"InfGetStringFieldA: Error retrieving field from INF file."));
  941. rField = NULL;
  942. }
  943. }
  944. }
  945. return rField;
  946. }
  947. PWSTR
  948. InfGetStringFieldW (
  949. IN OUT PINFSTRUCTW Context,
  950. IN UINT FieldIndex
  951. )
  952. {
  953. UINT requiredSize;
  954. PWSTR rField = NULL;
  955. //
  956. // Get the size necessary for holding the field.
  957. //
  958. if (SetupGetStringFieldW(
  959. &(Context -> Context),
  960. FieldIndex,
  961. NULL,
  962. 0,
  963. &requiredSize
  964. )) {
  965. //
  966. // Create a string big enough.
  967. //
  968. rField = (PWSTR) pAllocateSpaceW(Context,requiredSize*sizeof(WCHAR));
  969. if (rField) {
  970. //
  971. // Get the field.
  972. //
  973. if (!SetupGetStringFieldW(
  974. &(Context -> Context),
  975. FieldIndex,
  976. rField,
  977. requiredSize,
  978. NULL
  979. )) {
  980. //
  981. // If we did not successfully get the field, reset the string to NULL.
  982. //
  983. DEBUGMSGW((DBG_ERROR,"InfGetStringFieldW: Error retrieving field from INF file."));
  984. rField = NULL;
  985. }
  986. }
  987. }
  988. return rField;
  989. }
  990. /*++
  991. Routine Description:
  992. InfGetIntField is a wrapper for SetupGetIntField. It is virtually identical to this function
  993. except that it takes care of getting the INFCONTEXT out of the INFSTRUCT structure.
  994. Arguments:
  995. Context - A valid InfStruct. The INFCONTEXT member of the structure must point to a valid
  996. line to retrieve (i.e. through the use of InfFindFirstLine/InfFindNextLine.
  997. FieldIndex - The index within the line from which to retrieve the field.
  998. Value - Recieves the value of the requested Int field.
  999. Return Value:
  1000. TRUE if the field was successfully retrieved, FALSE otherwise. Use GetLastError() To receive
  1001. extended error information.
  1002. --*/
  1003. BOOL
  1004. InfGetIntFieldA (
  1005. IN PINFSTRUCTA Context,
  1006. IN UINT FieldIndex,
  1007. IN PINT Value
  1008. )
  1009. {
  1010. return SetupGetIntField (&(Context -> Context), FieldIndex, Value);
  1011. }
  1012. BOOL
  1013. InfGetIntFieldW (
  1014. IN PINFSTRUCTW Context,
  1015. IN UINT FieldIndex,
  1016. IN PINT Value
  1017. )
  1018. {
  1019. return SetupGetIntField (&(Context -> Context), FieldIndex, Value);
  1020. }
  1021. /*++
  1022. Routine Description:
  1023. InfGetBinaryField is a wrapper for the SetupGetBinaryField function. It reduces
  1024. the number of parameters required to get the line text and takes care of
  1025. allocating and filling a buffer with the data returned from the API.
  1026. Arguments:
  1027. Context - A valid InfStruct. The INFCONTEXT member of the structure must point to a valid
  1028. line to retrieve (i.e. through the use of InfFindFirstLine/InfFindNextLine.
  1029. FieldIndex - the index within the line of the desired binary information.
  1030. Return Value:
  1031. A pointer to the allocated line or NULL if there was an error. Consult GetLastError() for
  1032. extended error information.
  1033. --*/
  1034. PBYTE
  1035. InfGetBinaryFieldA (
  1036. IN PINFSTRUCTA Context,
  1037. IN UINT FieldIndex
  1038. )
  1039. {
  1040. UINT requiredSize;
  1041. PBYTE rField = NULL;
  1042. //
  1043. // Get the size necessary for holding the field.
  1044. //
  1045. if (SetupGetBinaryField(
  1046. &(Context -> Context),
  1047. FieldIndex,
  1048. NULL,
  1049. 0,
  1050. &requiredSize
  1051. )) {
  1052. //
  1053. // Create a string big enough.
  1054. //
  1055. rField = pAllocateSpaceA(Context,requiredSize);
  1056. if (rField) {
  1057. //
  1058. // Get the field.
  1059. //
  1060. if (!SetupGetBinaryField(
  1061. &(Context -> Context),
  1062. FieldIndex,
  1063. rField,
  1064. requiredSize,
  1065. NULL
  1066. )) {
  1067. //
  1068. // If we did not successfully get the field, reset the string to NULL.
  1069. //
  1070. DEBUGMSGA((DBG_ERROR,"InfGetBinaryFieldA: Error retrieving field from INF file."));
  1071. rField = NULL;
  1072. }
  1073. }
  1074. }
  1075. return rField;
  1076. }
  1077. PBYTE
  1078. InfGetBinaryFieldW (
  1079. IN PINFSTRUCTW Context,
  1080. IN UINT FieldIndex
  1081. )
  1082. {
  1083. UINT requiredSize;
  1084. PBYTE rField = NULL;
  1085. //
  1086. // Get the size necessary for holding the field.
  1087. //
  1088. if (SetupGetBinaryField(
  1089. &(Context -> Context),
  1090. FieldIndex,
  1091. NULL,
  1092. 0,
  1093. &requiredSize
  1094. )) {
  1095. //
  1096. // Create a string big enough.
  1097. //
  1098. rField = pAllocateSpaceW(Context,requiredSize);
  1099. if (rField) {
  1100. //
  1101. // Get the field.
  1102. //
  1103. if (!SetupGetBinaryField(
  1104. &(Context -> Context),
  1105. FieldIndex,
  1106. rField,
  1107. requiredSize,
  1108. NULL
  1109. )) {
  1110. //
  1111. // If we did not successfully get the field, reset the string to NULL.
  1112. //
  1113. DEBUGMSGW((DBG_ERROR,"InfGetBinaryFieldW: Error retrieving field from INF file."));
  1114. rField = NULL;
  1115. }
  1116. }
  1117. }
  1118. return rField;
  1119. }
  1120. /*++
  1121. Routine Description:
  1122. InfGetIndexByLine is a straight wrapper for SetupGetLineByIndex. The only
  1123. difference is the use of an PINFSTRUCT instead of a PINFCONTEXT.
  1124. Arguments:
  1125. InfHandle - Contains a valid HINF.
  1126. Section - Contains the name of the section within the InfFile.
  1127. Index - Contains the index within the section of the line in question.
  1128. Context - A valid InfStruct that is updated with the result of these calls.
  1129. Return Value:
  1130. TRUE if the function was called successfully, FALSE otherwise.
  1131. --*/
  1132. BOOL
  1133. InfGetLineByIndexA (
  1134. IN HINF InfHandle,
  1135. IN PCSTR Section,
  1136. IN DWORD Index,
  1137. OUT PINFSTRUCTA Context
  1138. )
  1139. {
  1140. return SetupGetLineByIndexA(InfHandle,Section,Index,&(Context -> Context));
  1141. }
  1142. BOOL
  1143. InfGetLineByIndexW (
  1144. IN HINF InfHandle,
  1145. IN PCWSTR Section,
  1146. IN DWORD Index,
  1147. OUT PINFSTRUCTW Context
  1148. )
  1149. {
  1150. return SetupGetLineByIndexW(InfHandle,Section,Index,&(Context -> Context));
  1151. }
  1152. /*++
  1153. Routine Description:
  1154. InfFindFirstLineA and InfFindFirstLineW are wrappers for the SetupFindFirstLine function.
  1155. They are virtually identical except that they operate on INFSTRUCTs instead of INFCONTEXTS.
  1156. Arguments:
  1157. InfHandle - Contains a valid HINF.
  1158. Section - Contains the name of the section within the InfFile.
  1159. Key - An optional parameter containing the name of the key within the section to find.
  1160. If NULL, these routines will return the first line in the section.
  1161. Context - A valid InfStruct that is updated with the result of these calls.
  1162. Return Value:
  1163. TRUE if lines exist in the section, FALSE otherwise.
  1164. --*/
  1165. BOOL
  1166. InfFindFirstLineA (
  1167. IN HINF InfHandle,
  1168. IN PCSTR Section,
  1169. IN PCSTR Key, OPTIONAL
  1170. OUT PINFSTRUCTA Context
  1171. )
  1172. {
  1173. if (Key) {
  1174. Context->KeyName = (PCSTR) pAllocateSpaceA (Context, SizeOfStringA (Key));
  1175. StringCopyA ((PSTR)Context->KeyName, Key);
  1176. } else {
  1177. Context->KeyName = NULL;
  1178. }
  1179. return SetupFindFirstLineA (
  1180. InfHandle,
  1181. Section,
  1182. Context->KeyName,
  1183. &(Context -> Context)
  1184. );
  1185. }
  1186. BOOL
  1187. InfFindFirstLineW (
  1188. IN HINF InfHandle,
  1189. IN PCWSTR Section,
  1190. IN PCWSTR Key, OPTIONAL
  1191. OUT PINFSTRUCTW Context
  1192. )
  1193. {
  1194. if (Key) {
  1195. Context->KeyName = (PCWSTR) pAllocateSpaceW (Context, SizeOfStringW (Key));
  1196. StringCopyW ((PWSTR)Context->KeyName, Key);
  1197. } else {
  1198. Context->KeyName = NULL;
  1199. }
  1200. return SetupFindFirstLineW (
  1201. InfHandle,
  1202. Section,
  1203. Context->KeyName,
  1204. &(Context -> Context)
  1205. );
  1206. }
  1207. /*++
  1208. Routine Description:
  1209. InfFindNextLineA and InfFindNextLineW are wrappers for the SetupFindNextMatchLine function.
  1210. They are virtually identical except that they operate on INFSTRUCTs instead of INFCONTEXTS and
  1211. need only one INFSTRUCT parameter.
  1212. Arguments:
  1213. Context - A valid InfStruct that is updated with the result of these calls.
  1214. Return Value:
  1215. TRUE if there is another line in the section, FALSE otherwise.
  1216. --*/
  1217. BOOL
  1218. InfFindNextLineA (
  1219. IN OUT PINFSTRUCTA Context
  1220. )
  1221. {
  1222. return SetupFindNextMatchLineA (&(Context -> Context), Context->KeyName, &(Context -> Context));
  1223. }
  1224. BOOL
  1225. InfFindNextLineW (
  1226. IN OUT PINFSTRUCTW Context
  1227. )
  1228. {
  1229. return SetupFindNextMatchLineW (&(Context -> Context), Context->KeyName, &(Context -> Context));
  1230. }
  1231. UINT
  1232. InfGetFieldCountA (
  1233. IN PINFSTRUCTA Context
  1234. )
  1235. {
  1236. return SetupGetFieldCount(&(Context -> Context));
  1237. }
  1238. UINT
  1239. InfGetFieldCountW (
  1240. IN PINFSTRUCTW Context
  1241. )
  1242. {
  1243. return SetupGetFieldCount(&(Context -> Context));
  1244. }
  1245. PCSTR
  1246. InfGetOemStringFieldA (
  1247. IN PINFSTRUCTA Context,
  1248. IN UINT Field
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. InfGetOemStringField returns a string field in the OEM character set.
  1253. This routine is used when accessing txtsetup.sif. It is implemented
  1254. only in the A version because UNICODE does not have a concept of OEM
  1255. characters.
  1256. Arguments:
  1257. Context - Specifies the initialized INF structure that points to the
  1258. line to read from
  1259. Field - Specifies the field number
  1260. Return Value:
  1261. A pointer to the OEM string, or NULL if an error occurred.
  1262. --*/
  1263. {
  1264. PCSTR Text;
  1265. PSTR OemText;
  1266. INT Size;
  1267. Text = InfGetStringFieldA (Context, Field);
  1268. if (!Text) {
  1269. return NULL;
  1270. }
  1271. Size = SizeOfStringA (Text);
  1272. OemText = (PSTR) pAllocateSpaceA (Context, Size);
  1273. if (!OemText) {
  1274. return NULL;
  1275. }
  1276. //
  1277. // We leave Text allocated because the caller will free everything
  1278. // when they clean up Context. Note the assumption that the conversion
  1279. // doesn't change string length.
  1280. //
  1281. OemToCharBuffA (Text, OemText, Size);
  1282. return OemText;
  1283. }
  1284. BOOL
  1285. SetupGetOemStringFieldA (
  1286. IN PINFCONTEXT Context,
  1287. IN DWORD Index,
  1288. IN PTSTR ReturnBuffer, OPTIONAL
  1289. IN DWORD ReturnBufferSize,
  1290. OUT PDWORD RequiredSize OPTIONAL
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. SetupGetOemStringFieldA is a SetupGetStringField that converts the
  1295. return text to the OEM character set.
  1296. Arguments:
  1297. Context - Specifies the initialized INF structure that points to the
  1298. line to read from
  1299. Index - Specifies the field number
  1300. ReturnBuffer - Specifies the buffer to fill the text into
  1301. ReturnBufferSize - Specifies the size of ReturnBuffer in bytes
  1302. RequiredSize - Receives the size of the buffer needed
  1303. Return Value:
  1304. TRUE if successful, FALSE if failure.
  1305. --*/
  1306. {
  1307. PSTR OemBuf;
  1308. INT Size;
  1309. if (!SetupGetStringFieldA (
  1310. Context,
  1311. Index,
  1312. ReturnBuffer,
  1313. ReturnBufferSize,
  1314. RequiredSize
  1315. )) {
  1316. return FALSE;
  1317. }
  1318. if (!ReturnBuffer) {
  1319. return TRUE;
  1320. }
  1321. Size = SizeOfStringA (ReturnBuffer);
  1322. OemBuf = (PSTR) MemAlloc (g_hHeap, 0, Size);
  1323. OemToCharBuffA (ReturnBuffer, OemBuf, Size);
  1324. StringCopyA (ReturnBuffer, OemBuf);
  1325. MemFree (g_hHeap, 0, OemBuf);
  1326. return TRUE;
  1327. }
  1328. UINT
  1329. pGetLanguage (
  1330. IN PCSTR File
  1331. )
  1332. {
  1333. HINF inf = INVALID_HANDLE_VALUE;
  1334. PINFSECTION section;
  1335. PINFLINE line;
  1336. PWSTR start, end;
  1337. UINT rLanguage = INF_INVALID_VERSION;
  1338. WCHAR envvar[MAX_MBCHAR_PATH];
  1339. *envvar = 0;
  1340. //
  1341. // Use the infparse rourtines to get this information. They
  1342. // are more reliable than the *privateprofile* apis.
  1343. //
  1344. inf = OpenInfFileExA (File, "version, strings", FALSE);
  1345. if (inf == INVALID_HANDLE_VALUE) {
  1346. return rLanguage;
  1347. }
  1348. section = FindInfSectionInTableW (inf, S_VERSION_W);
  1349. if (section) {
  1350. line = FindLineInInfSectionW (inf, section, S_LANGUAGE_W);
  1351. if (line && line->Data) {
  1352. start = wcschr (line->Data, L'%');
  1353. if (start) {
  1354. end = wcschr (start + 1, L'%');
  1355. if (end) {
  1356. StringCopyABW(envvar, start+1, end);
  1357. }
  1358. }
  1359. else {
  1360. if (*line->Data == L'*') {
  1361. rLanguage = INF_ANY_LANGUAGE;
  1362. }
  1363. else {
  1364. rLanguage = _wcsnum (line->Data);
  1365. }
  1366. }
  1367. }
  1368. }
  1369. if (*envvar) {
  1370. //
  1371. // Get the data from the strings section.
  1372. //
  1373. section = FindInfSectionInTableW (inf, S_STRINGS_W);
  1374. if (section) {
  1375. line = FindLineInInfSectionW (inf, section, envvar);
  1376. if (line && line->Data) {
  1377. if (*line->Data == L'*') {
  1378. rLanguage = INF_ANY_LANGUAGE;
  1379. }
  1380. else {
  1381. rLanguage = _wcsnum (line->Data);
  1382. }
  1383. }
  1384. }
  1385. }
  1386. if (inf != INVALID_HANDLE_VALUE) {
  1387. CloseInfFile (inf);
  1388. }
  1389. return rLanguage;
  1390. }
  1391. VOID
  1392. InitInfReplaceTable (
  1393. VOID
  1394. )
  1395. {
  1396. CHAR systemPath[MAX_MBCHAR_PATH];
  1397. CHAR buffer[MAX_MBCHAR_PATH];
  1398. PSTR upginfsDir;
  1399. BOOL validFile;
  1400. TREE_ENUMA e;
  1401. INT version;
  1402. INT language;
  1403. DWORD operation;
  1404. BOOL bReplace, bAdd;
  1405. CHAR buf[MAX_MBCHAR_PATH];
  1406. PCSTR tag;
  1407. // pDestroyInfModList (g_RootInfMod);
  1408. PoolMemEmptyPool (g_InfModPool);
  1409. g_RootInfMod = NULL;
  1410. //
  1411. // Look in the special directory %windir%\upginfs for anything to add
  1412. // to our list.
  1413. //
  1414. if (GetWindowsDirectoryA (systemPath, MAX_MBCHAR_PATH)) {
  1415. upginfsDir = JoinPathsA (systemPath, S_UPGINFSDIR);
  1416. if (EnumFirstFileInTreeA (&e, upginfsDir, NULL, FALSE)) {
  1417. do {
  1418. //
  1419. // we only care about *.rep and *.add files. Ignore everything
  1420. // else.
  1421. //
  1422. if (e.Directory) {
  1423. continue;
  1424. }
  1425. bReplace = IsPatternMatchA ("*.rep", e.Name);
  1426. bAdd = IsPatternMatchA ("*.add", e.Name);
  1427. if (bAdd || bReplace) {
  1428. __try {
  1429. validFile = FALSE;
  1430. operation = bReplace ? INF_REPLACE : INF_APPEND;
  1431. GetPrivateProfileStringA (
  1432. S_VERSION_A,
  1433. S_TARGETINF_A,
  1434. "",
  1435. buffer,
  1436. MAX_MBCHAR_PATH,
  1437. e.FullPath
  1438. );
  1439. if (!*buffer) {
  1440. __leave;
  1441. }
  1442. version = GetPrivateProfileIntA (
  1443. S_VERSION_A,
  1444. S_VERSION_A,
  1445. INF_INVALID_VERSION,
  1446. e.FullPath
  1447. );
  1448. //
  1449. // version is ALWAYS needed
  1450. //
  1451. if (version == INF_INVALID_VERSION) {
  1452. __leave;
  1453. }
  1454. language = pGetLanguage (e.FullPath);
  1455. if (language == INF_INVALID_VERSION) {
  1456. __leave;
  1457. }
  1458. if (GetPrivateProfileStringA (
  1459. S_VERSION_A,
  1460. S_TAG_A,
  1461. TEXT(""),
  1462. buf,
  1463. MAX_MBCHAR_PATH,
  1464. e.FullPath
  1465. )) {
  1466. tag = buf;
  1467. } else {
  1468. tag = NULL;
  1469. }
  1470. validFile = TRUE;
  1471. }
  1472. __finally {
  1473. if (!validFile || !pAddReplacementInfToTable (buffer, version, language, tag, operation, e.FullPath)) {
  1474. DEBUGMSGA ((DBG_WARNING,"Invalid Replace or Add file found in %s.",upginfsDir));
  1475. }
  1476. }
  1477. } else {
  1478. DEBUGMSGA ((
  1479. DBG_WARNING,
  1480. "Non .rep or .add file found in %s directory! Unexpected.",
  1481. upginfsDir
  1482. ));
  1483. }
  1484. } while (EnumNextFileInTreeA (&e));
  1485. }
  1486. ELSE_DEBUGMSGA ((DBG_VERBOSE, "InfInitialize: No infs in %s directory.", upginfsDir));
  1487. FreePathStringA (upginfsDir);
  1488. }
  1489. }