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.

1095 lines
23 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. ini.c
  5. Abstract:
  6. Provides wrappers for commonly used INI file handling routines.
  7. Author:
  8. 20-Oct-1999 Ovidiu Temereanca (ovidiut) - File creation.
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. //
  14. // Includes
  15. //
  16. // None
  17. #define DBG_INILIB "IniLib"
  18. //
  19. // Strings
  20. //
  21. // None
  22. //
  23. // Constants
  24. //
  25. #define INITIAL_BUFFER_CHAR_COUNT 256
  26. //
  27. // Macros
  28. //
  29. // None
  30. //
  31. // Types
  32. //
  33. // None
  34. //
  35. // Globals
  36. //
  37. PMHANDLE g_IniLibPool;
  38. INT g_IniRefs;
  39. //
  40. // Macro expansion list
  41. //
  42. // None
  43. //
  44. // Private function prototypes
  45. //
  46. // None
  47. //
  48. // Macro expansion definition
  49. //
  50. // None
  51. //
  52. // Code
  53. //
  54. BOOL
  55. Ini_Init (
  56. VOID
  57. )
  58. /*++
  59. Routine Description:
  60. Ini_Init initializes this library.
  61. Arguments:
  62. none
  63. Return Value:
  64. TRUE if the init was successful.
  65. FALSE if not. GetLastError() returns extended error info.
  66. --*/
  67. {
  68. MYASSERT (g_IniRefs >= 0);
  69. g_IniRefs++;
  70. if (g_IniRefs == 1) {
  71. g_IniLibPool = PmCreateNamedPool ("IniLib");
  72. }
  73. return g_IniLibPool != NULL;
  74. }
  75. VOID
  76. Ini_Exit (
  77. VOID
  78. )
  79. /*++
  80. Routine Description:
  81. Ini_Exit is called to free resources used by this lib.
  82. Arguments:
  83. none
  84. Return Value:
  85. none
  86. --*/
  87. {
  88. MYASSERT (g_IniRefs > 0);
  89. g_IniRefs--;
  90. if (!g_IniRefs) {
  91. if (g_IniLibPool) {
  92. PmDestroyPool (g_IniLibPool);
  93. g_IniLibPool = NULL;
  94. }
  95. }
  96. }
  97. PBYTE
  98. pAllocateSpace (
  99. IN DWORD Size
  100. )
  101. /*++
  102. Routine Description:
  103. pAllocateSpace is a private function that allocates space from the module's private pool
  104. Arguments:
  105. Size - The size (in bytes) to allocate.
  106. Return Value:
  107. A pointer to the successfully allocated memory or NULL if no memory could be allocated.
  108. --*/
  109. {
  110. MYASSERT (g_IniLibPool);
  111. MYASSERT (Size);
  112. return PmGetMemory (g_IniLibPool, Size);
  113. }
  114. VOID
  115. pFreeSpace (
  116. IN PVOID Buffer
  117. )
  118. /*++
  119. Routine Description:
  120. pFreeSpace is a private function that frees space allocated from the module's private pool
  121. Arguments:
  122. Buffer - Pointer to buffer to free.
  123. Return Value:
  124. none
  125. --*/
  126. {
  127. MYASSERT (g_IniLibPool);
  128. PmReleaseMemory (g_IniLibPool, Buffer);
  129. }
  130. /*++
  131. Routine Description:
  132. RealIniFileOpen validates the args passed in and then
  133. initializes IniFile struct with info used in subsequent calls to INI functions.
  134. Arguments:
  135. IniFile - Receives INI file attributes if open is successful
  136. IniFileSpec - Specifies the file name; if not full path,
  137. current drive and/or dir are prefixed
  138. FileMustExist - Specifies TRUE if file must exist for open to succeed
  139. Return Value:
  140. TRUE if open succeeded; IniFile is valid for subsequent calls to other INI APIs;
  141. IniFileClose must be called when this handle is no longer needed.
  142. FALSE if not
  143. --*/
  144. BOOL
  145. RealIniFileOpenA (
  146. OUT PINIFILEA IniFile,
  147. IN PCSTR IniFileSpec,
  148. IN BOOL FileMustExist /*,*/
  149. ALLOCATION_TRACKING_DEF /* , PCSTR File, UINT Line */
  150. )
  151. {
  152. CHAR fullPath[MAX_MBCHAR_PATH];
  153. if (!GetFullPathNameA (IniFileSpec, MAX_MBCHAR_PATH, fullPath, NULL)) {
  154. DEBUGMSGA ((
  155. DBG_ERROR,
  156. "IniFileOpenA: GetFullPathNameA failed on <%s>",
  157. IniFileSpec
  158. ));
  159. return FALSE;
  160. }
  161. DEBUGMSGA_IF ((
  162. !StringIMatchA (IniFileSpec, fullPath),
  163. DBG_INILIB,
  164. "IniFileOpenA: IniFileSpec supplied: <%s>; full path defaulting to <%s>",
  165. IniFileSpec,
  166. fullPath
  167. ));
  168. if (BfPathIsDirectoryA (fullPath)) {
  169. DEBUGMSGA ((
  170. DBG_INILIB,
  171. "IniFileOpenA: <%s> is a directory",
  172. fullPath
  173. ));
  174. return FALSE;
  175. }
  176. if (FileMustExist && !DoesFileExistA (fullPath)) {
  177. DEBUGMSGA ((
  178. DBG_INILIB,
  179. "IniFileOpenA: file not found: <%s>",
  180. fullPath
  181. ));
  182. return FALSE;
  183. }
  184. IniFile->IniFilePath = DuplicateTextExA (g_IniLibPool, fullPath, 0, NULL);
  185. IniFile->OriginalAttributes = GetFileAttributesA (fullPath);
  186. if (IniFile->OriginalAttributes != (DWORD)-1) {
  187. //
  188. // set working attributes
  189. //
  190. SetFileAttributesA (fullPath, FILE_ATTRIBUTE_NORMAL);
  191. }
  192. return TRUE;
  193. }
  194. BOOL
  195. RealIniFileOpenW (
  196. OUT PINIFILEW IniFile,
  197. IN PCWSTR IniFileSpec,
  198. IN BOOL FileMustExist /*,*/
  199. ALLOCATION_TRACKING_DEF /* , PCSTR File, UINT Line */
  200. )
  201. {
  202. WCHAR fullPath[MAX_MBCHAR_PATH];
  203. if (!GetFullPathNameW (IniFileSpec, MAX_WCHAR_PATH, fullPath, NULL)) {
  204. DEBUGMSGW ((
  205. DBG_ERROR,
  206. "IniFileOpenW: GetFullPathNameW failed on <%s>",
  207. IniFileSpec
  208. ));
  209. return FALSE;
  210. }
  211. DEBUGMSGW_IF ((
  212. !StringIMatchW (IniFileSpec, fullPath),
  213. DBG_INILIB,
  214. "IniFileOpenW: IniFileSpec supplied: <%s>; full path defaulting to <%s>",
  215. IniFileSpec,
  216. fullPath
  217. ));
  218. if (BfPathIsDirectoryW (fullPath)) {
  219. DEBUGMSGW ((
  220. DBG_INILIB,
  221. "IniFileOpenW: <%s> is a directory",
  222. fullPath
  223. ));
  224. return FALSE;
  225. }
  226. if (FileMustExist && !DoesFileExistW (fullPath)) {
  227. DEBUGMSGW ((
  228. DBG_INILIB,
  229. "IniFileOpenW: file not found: <%s>",
  230. fullPath
  231. ));
  232. return FALSE;
  233. }
  234. IniFile->IniFilePath = DuplicateTextExW (g_IniLibPool, fullPath, 0, NULL);
  235. IniFile->OriginalAttributes = GetFileAttributesW (fullPath);
  236. if (IniFile->OriginalAttributes != (DWORD)-1) {
  237. //
  238. // set working attributes
  239. //
  240. SetFileAttributesW (fullPath, FILE_ATTRIBUTE_NORMAL);
  241. }
  242. return TRUE;
  243. }
  244. /*++
  245. Routine Description:
  246. IniFileClose frees resources and restores INI's initial attributes
  247. Arguments:
  248. IniFile - Specifies a handle to an open INI file
  249. Return Value:
  250. none
  251. --*/
  252. VOID
  253. IniFileCloseA (
  254. IN PINIFILEA IniFile
  255. )
  256. {
  257. if (IniFile->OriginalAttributes != (DWORD)-1) {
  258. SetFileAttributesA (IniFile->IniFilePath, IniFile->OriginalAttributes);
  259. }
  260. FreeTextExA (g_IniLibPool, IniFile->IniFilePath);
  261. }
  262. VOID
  263. IniFileCloseW (
  264. IN PINIFILEW IniFile
  265. )
  266. {
  267. if (IniFile->OriginalAttributes != (DWORD)-1) {
  268. SetFileAttributesW (IniFile->IniFilePath, IniFile->OriginalAttributes);
  269. }
  270. FreeTextExW (g_IniLibPool, IniFile->IniFilePath);
  271. }
  272. /*++
  273. Routine Description:
  274. EnumFirstIniSection returns the first section of the given INI file, if any.
  275. Arguments:
  276. IniSectEnum - Receives the first section
  277. IniFile - Specifies a handle to an open INI file
  278. Return Value:
  279. TRUE if there is a section
  280. FALSE if not
  281. --*/
  282. BOOL
  283. EnumFirstIniSectionA (
  284. OUT PINISECT_ENUMA IniSectEnum,
  285. IN PINIFILEA IniFile
  286. )
  287. {
  288. PSTR sections;
  289. DWORD allocatedChars;
  290. DWORD chars;
  291. sections = NULL;
  292. allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
  293. do {
  294. if (sections) {
  295. pFreeSpace (sections);
  296. }
  297. allocatedChars *= 2;
  298. sections = (PSTR)pAllocateSpace (allocatedChars * DWSIZEOF (CHAR));
  299. if (!sections) {
  300. return FALSE;
  301. }
  302. chars = GetPrivateProfileSectionNamesA (
  303. sections,
  304. allocatedChars,
  305. IniFile->IniFilePath
  306. );
  307. } while (chars >= allocatedChars - 2);
  308. if (!*sections) {
  309. pFreeSpace (sections);
  310. return FALSE;
  311. }
  312. IniSectEnum->Sections = sections;
  313. IniSectEnum->CurrentSection = sections;
  314. return TRUE;
  315. }
  316. BOOL
  317. EnumFirstIniSectionW (
  318. OUT PINISECT_ENUMW IniSectEnum,
  319. IN PINIFILEW IniFile
  320. )
  321. {
  322. PWSTR sections;
  323. DWORD allocatedChars;
  324. DWORD chars;
  325. sections = NULL;
  326. allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
  327. do {
  328. if (sections) {
  329. pFreeSpace (sections);
  330. }
  331. allocatedChars *= 2;
  332. sections = (PWSTR)pAllocateSpace (allocatedChars * DWSIZEOF (WCHAR));
  333. if (!sections) {
  334. return FALSE;
  335. }
  336. chars = GetPrivateProfileSectionNamesW (
  337. sections,
  338. allocatedChars,
  339. IniFile->IniFilePath
  340. );
  341. } while (chars >= allocatedChars - 2);
  342. if (!*sections) {
  343. pFreeSpace (sections);
  344. return FALSE;
  345. }
  346. IniSectEnum->Sections = sections;
  347. IniSectEnum->CurrentSection = sections;
  348. return TRUE;
  349. }
  350. /*++
  351. Routine Description:
  352. EnumNextIniSection returns the next section, if any.
  353. Arguments:
  354. IniSectEnum - Specifies the prev section/receives the next section
  355. Return Value:
  356. TRUE if there is a next section
  357. FALSE if not
  358. --*/
  359. BOOL
  360. EnumNextIniSectionA (
  361. IN OUT PINISECT_ENUMA IniSectEnum
  362. )
  363. {
  364. if (IniSectEnum->CurrentSection && *IniSectEnum->CurrentSection != 0) {
  365. //Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
  366. //CurrentKeyValuePtr (because GetEndOfStringA will return a valid pointer) so...
  367. //lint --e(613)
  368. IniSectEnum->CurrentSection = GetEndOfStringA (IniSectEnum->CurrentSection) + 1;
  369. if (*IniSectEnum->CurrentSection != 0) {
  370. return TRUE;
  371. }
  372. }
  373. AbortIniSectionEnumA (IniSectEnum);
  374. return FALSE;
  375. }
  376. BOOL
  377. EnumNextIniSectionW (
  378. IN OUT PINISECT_ENUMW IniSectEnum
  379. )
  380. {
  381. if (IniSectEnum->CurrentSection && *IniSectEnum->CurrentSection != 0) {
  382. //Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
  383. //CurrentKeyValuePtr (because GetEndOfStringW will return a valid pointer) so...
  384. //lint --e(613)
  385. IniSectEnum->CurrentSection = GetEndOfStringW (IniSectEnum->CurrentSection) + 1;
  386. if (*IniSectEnum->CurrentSection != 0) {
  387. return TRUE;
  388. }
  389. }
  390. AbortIniSectionEnumW (IniSectEnum);
  391. return FALSE;
  392. }
  393. /*++
  394. Routine Description:
  395. AbortIniSectionEnum aborts section enumeration
  396. Arguments:
  397. IniSectEnum - Specifies the section enumeration handle/receives NULLs
  398. Return Value:
  399. none
  400. --*/
  401. VOID
  402. AbortIniSectionEnumA (
  403. IN OUT PINISECT_ENUMA IniSectEnum
  404. )
  405. {
  406. pFreeSpace ((PVOID)IniSectEnum->Sections);
  407. IniSectEnum->Sections = NULL;
  408. IniSectEnum->CurrentSection = NULL;
  409. }
  410. VOID
  411. AbortIniSectionEnumW (
  412. IN OUT PINISECT_ENUMW IniSectEnum
  413. )
  414. {
  415. pFreeSpace ((PVOID)IniSectEnum->Sections);
  416. IniSectEnum->Sections = NULL;
  417. IniSectEnum->CurrentSection = NULL;
  418. }
  419. /*++
  420. Routine Description:
  421. EnumFirstIniKeyValue returns the first key/value pair of
  422. the given INI file/section name, if any.
  423. Arguments:
  424. IniKeyValueEnum - Receives the first section
  425. IniFile - Specifies a handle to an open INI file
  426. Section - Specifies the section to enumearte
  427. Return Value:
  428. TRUE if there is a key/value pair
  429. FALSE if not
  430. --*/
  431. BOOL
  432. EnumFirstIniKeyValueA (
  433. OUT PINIKEYVALUE_ENUMA IniKeyValueEnum,
  434. IN PINIFILEA IniFile,
  435. IN PCSTR Section
  436. )
  437. {
  438. PSTR buffer;
  439. DWORD allocatedChars;
  440. DWORD chars;
  441. MYASSERT (Section);
  442. if (!Section) {
  443. return FALSE;
  444. }
  445. buffer = NULL;
  446. allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
  447. do {
  448. if (buffer) {
  449. pFreeSpace (buffer);
  450. }
  451. allocatedChars *= 2;
  452. buffer = (PSTR)pAllocateSpace (allocatedChars * DWSIZEOF (CHAR));
  453. if (!buffer) {
  454. return FALSE;
  455. }
  456. chars = GetPrivateProfileSectionA (
  457. Section,
  458. buffer,
  459. allocatedChars,
  460. IniFile->IniFilePath
  461. );
  462. } while (chars >= allocatedChars - 2);
  463. if (!*buffer) {
  464. pFreeSpace (buffer);
  465. return FALSE;
  466. }
  467. IniKeyValueEnum->KeyValuePairs = buffer;
  468. IniKeyValueEnum->CurrentKeyValuePair = NULL;
  469. IniKeyValueEnum->Private = NULL;
  470. return EnumNextIniKeyValueA (IniKeyValueEnum);
  471. }
  472. BOOL
  473. EnumFirstIniKeyValueW (
  474. OUT PINIKEYVALUE_ENUMW IniKeyValueEnum,
  475. IN PINIFILEW IniFile,
  476. IN PCWSTR Section
  477. )
  478. {
  479. PWSTR buffer;
  480. DWORD allocatedChars;
  481. DWORD chars;
  482. MYASSERT (Section);
  483. if (!Section) {
  484. return FALSE;
  485. }
  486. buffer = NULL;
  487. allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
  488. do {
  489. if (buffer) {
  490. pFreeSpace (buffer);
  491. }
  492. allocatedChars *= 2;
  493. buffer = (PWSTR)pAllocateSpace (allocatedChars * DWSIZEOF (WCHAR));
  494. if (!buffer) {
  495. return FALSE;
  496. }
  497. chars = GetPrivateProfileSectionW (
  498. Section,
  499. buffer,
  500. allocatedChars,
  501. IniFile->IniFilePath
  502. );
  503. } while (chars >= allocatedChars - 2);
  504. if (!*buffer) {
  505. pFreeSpace (buffer);
  506. return FALSE;
  507. }
  508. IniKeyValueEnum->KeyValuePairs = buffer;
  509. IniKeyValueEnum->Private = NULL;
  510. return EnumNextIniKeyValueW (IniKeyValueEnum);
  511. }
  512. /*++
  513. Routine Description:
  514. EnumNextIniKeyValue returns the first key/value pair of
  515. the given INI file/section name, if any.
  516. Arguments:
  517. IniKeyValueEnum - Specifies the prev key/value pair / receives the next pair
  518. Return Value:
  519. TRUE if there is a next pair
  520. FALSE if not
  521. --*/
  522. BOOL
  523. EnumNextIniKeyValueA (
  524. IN OUT PINIKEYVALUE_ENUMA IniKeyValueEnum
  525. )
  526. {
  527. //
  528. // restore from saved position
  529. //
  530. IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->Private;
  531. //
  532. // skip commented lines
  533. //
  534. do {
  535. if (IniKeyValueEnum->CurrentKeyValuePair) {
  536. //Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
  537. //CurrentKeyValuePtr (because GetEndOfStringA will return a valid pointer) so...
  538. //lint --e(613)
  539. IniKeyValueEnum->CurrentKeyValuePair = GetEndOfStringA (IniKeyValueEnum->CurrentKeyValuePair) + 1;
  540. } else {
  541. IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->KeyValuePairs;
  542. }
  543. MYASSERT (IniKeyValueEnum->CurrentKeyValuePair);
  544. if (!(*IniKeyValueEnum->CurrentKeyValuePair)) {
  545. AbortIniKeyValueEnumA (IniKeyValueEnum);
  546. return FALSE;
  547. }
  548. IniKeyValueEnum->CurrentKey = IniKeyValueEnum->CurrentKeyValuePair;
  549. IniKeyValueEnum->CurrentValue = _mbschr (IniKeyValueEnum->CurrentKey, '=');
  550. } while (*IniKeyValueEnum->CurrentKeyValuePair == ';' || !IniKeyValueEnum->CurrentValue);
  551. MYASSERT (*IniKeyValueEnum->CurrentKeyValuePair);
  552. MYASSERT (*IniKeyValueEnum->CurrentValue == '=');
  553. //
  554. // remember position for next iteration
  555. //
  556. IniKeyValueEnum->Private = GetEndOfStringA (IniKeyValueEnum->CurrentValue);
  557. //
  558. // modify buffer to get KEY and VALUE
  559. //
  560. *(PSTR)IniKeyValueEnum->CurrentValue = 0;
  561. IniKeyValueEnum->CurrentValue++;
  562. TruncateTrailingSpaceA ((PSTR)IniKeyValueEnum->CurrentKey);
  563. return TRUE;
  564. }
  565. BOOL
  566. EnumNextIniKeyValueW (
  567. IN OUT PINIKEYVALUE_ENUMW IniKeyValueEnum
  568. )
  569. {
  570. //
  571. // restore from saved position
  572. //
  573. IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->Private;
  574. //
  575. // skip commented lines
  576. //
  577. do {
  578. if (IniKeyValueEnum->CurrentKeyValuePair) {
  579. //Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
  580. //CurrentKeyValuePtr (because GetEndOfStringW will return a valid pointer) so...
  581. //lint --e(613)
  582. IniKeyValueEnum->CurrentKeyValuePair = GetEndOfStringW (IniKeyValueEnum->CurrentKeyValuePair) + 1;
  583. } else {
  584. IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->KeyValuePairs;
  585. }
  586. MYASSERT (IniKeyValueEnum->CurrentKeyValuePair);
  587. if (!(*IniKeyValueEnum->CurrentKeyValuePair)) {
  588. AbortIniKeyValueEnumW (IniKeyValueEnum);
  589. return FALSE;
  590. }
  591. IniKeyValueEnum->CurrentKey = IniKeyValueEnum->CurrentKeyValuePair;
  592. IniKeyValueEnum->CurrentValue = wcschr (IniKeyValueEnum->CurrentKey, L'=');
  593. } while (*IniKeyValueEnum->CurrentKeyValuePair == L';' || !IniKeyValueEnum->CurrentValue);
  594. MYASSERT (*IniKeyValueEnum->CurrentKeyValuePair);
  595. MYASSERT (*IniKeyValueEnum->CurrentValue == L'=');
  596. //
  597. // remember position for next iteration
  598. //
  599. IniKeyValueEnum->Private = GetEndOfStringW (IniKeyValueEnum->CurrentValue);
  600. //
  601. // modify buffer to get KEY and VALUE
  602. //
  603. *(PWSTR)IniKeyValueEnum->CurrentValue = 0;
  604. IniKeyValueEnum->CurrentValue++;
  605. TruncateTrailingSpaceW ((PWSTR)IniKeyValueEnum->CurrentKey);
  606. return TRUE;
  607. }
  608. /*++
  609. Routine Description:
  610. AbortIniKeyValueEnum aborts key/value pairs enumeration
  611. Arguments:
  612. IniKeyValueEnum - Specifies the key/value pair enumeration handle/receives NULLs
  613. Return Value:
  614. none
  615. --*/
  616. VOID
  617. AbortIniKeyValueEnumA (
  618. IN OUT PINIKEYVALUE_ENUMA IniKeyValueEnum
  619. )
  620. {
  621. pFreeSpace ((PVOID)IniKeyValueEnum->KeyValuePairs);
  622. IniKeyValueEnum->KeyValuePairs = NULL;
  623. IniKeyValueEnum->CurrentKeyValuePair = NULL;
  624. IniKeyValueEnum->CurrentKey = NULL;
  625. IniKeyValueEnum->CurrentValue = NULL;
  626. }
  627. VOID
  628. AbortIniKeyValueEnumW (
  629. IN OUT PINIKEYVALUE_ENUMW IniKeyValueEnum
  630. )
  631. {
  632. pFreeSpace ((PVOID)IniKeyValueEnum->KeyValuePairs);
  633. IniKeyValueEnum->KeyValuePairs = NULL;
  634. IniKeyValueEnum->CurrentKeyValuePair = NULL;
  635. IniKeyValueEnum->CurrentKey = NULL;
  636. IniKeyValueEnum->CurrentValue = NULL;
  637. }
  638. /*++
  639. Routine Description:
  640. IniReadValue returns the value of a specified key in a specified section
  641. from the given INI file. The buffer returned must be freed using IniFreeReadValue
  642. Arguments:
  643. IniFile - Specifies a handle to an open INI file
  644. Section - Specifies the section to read from
  645. Key - Specifies the key
  646. Value - Receives a pointer to an allocated buffer containing the read value,
  647. if function is successful; optional
  648. Chars - Receives the number of chars (not bytes) the value has,
  649. excluding the NULL terminator; optional
  650. Return Value:
  651. TRUE if there is a value for the specified section/key
  652. FALSE if not
  653. --*/
  654. BOOL
  655. IniReadValueA (
  656. IN PINIFILEA IniFile,
  657. IN PCSTR Section,
  658. IN PCSTR Key,
  659. OUT PSTR* Value, OPTIONAL
  660. OUT PDWORD Chars OPTIONAL
  661. )
  662. {
  663. PSTR buffer;
  664. DWORD allocatedChars;
  665. DWORD chars;
  666. MYASSERT (Section && Key);
  667. if (!Section || !Key) {
  668. return FALSE;
  669. }
  670. buffer = NULL;
  671. allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
  672. do {
  673. if (buffer) {
  674. pFreeSpace (buffer);
  675. }
  676. allocatedChars *= 2;
  677. buffer = (PSTR)pAllocateSpace (allocatedChars * DWSIZEOF (CHAR));
  678. if (!buffer) {
  679. return FALSE;
  680. }
  681. chars = GetPrivateProfileStringA (
  682. Section,
  683. Key,
  684. "",
  685. buffer,
  686. allocatedChars,
  687. IniFile->IniFilePath
  688. );
  689. } while (chars >= allocatedChars - 1);
  690. if (Chars) {
  691. *Chars = chars;
  692. }
  693. if (Value) {
  694. if (*buffer) {
  695. *Value = buffer;
  696. } else {
  697. *Value = NULL;
  698. }
  699. }
  700. if (!(Value && *Value)) {
  701. //
  702. // buffer no longer needed
  703. //
  704. pFreeSpace (buffer);
  705. }
  706. return chars > 0;
  707. }
  708. BOOL
  709. IniReadValueW (
  710. IN PINIFILEW IniFile,
  711. IN PCWSTR Section,
  712. IN PCWSTR Key,
  713. OUT PWSTR* Value, OPTIONAL
  714. OUT PDWORD Chars OPTIONAL
  715. )
  716. {
  717. PWSTR buffer;
  718. DWORD allocatedChars;
  719. DWORD chars;
  720. MYASSERT (Section && Key);
  721. if (!Section || !Key) {
  722. return FALSE;
  723. }
  724. buffer = NULL;
  725. allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
  726. do {
  727. if (buffer) {
  728. pFreeSpace (buffer);
  729. }
  730. allocatedChars *= 2;
  731. buffer = (PWSTR)pAllocateSpace (allocatedChars * DWSIZEOF (WCHAR));
  732. if (!buffer) {
  733. return FALSE;
  734. }
  735. chars = GetPrivateProfileStringW (
  736. Section,
  737. Key,
  738. L"",
  739. buffer,
  740. allocatedChars,
  741. IniFile->IniFilePath
  742. );
  743. } while (chars >= allocatedChars - 1);
  744. if (Chars) {
  745. *Chars = chars;
  746. }
  747. if (Value) {
  748. if (*buffer) {
  749. *Value = buffer;
  750. } else {
  751. *Value = NULL;
  752. }
  753. }
  754. if (!(Value && *Value)) {
  755. //
  756. // buffer no longer needed
  757. //
  758. pFreeSpace (buffer);
  759. }
  760. return chars > 0;
  761. }
  762. /*++
  763. Routine Description:
  764. IniFreeReadValue is used to free the buffer allocated by IniReadValue
  765. and stored in Value, if specified.
  766. Arguments:
  767. Value - Specifies a pointer to the string to be freed
  768. Return Value:
  769. none
  770. --*/
  771. VOID
  772. IniFreeReadValueA (
  773. IN PCSTR Value
  774. )
  775. {
  776. pFreeSpace ((PVOID)Value);
  777. }
  778. VOID
  779. IniFreeReadValueW (
  780. IN PCWSTR Value
  781. )
  782. {
  783. pFreeSpace ((PVOID)Value);
  784. }
  785. /*++
  786. Routine Description:
  787. IniWriteValue writes the key/value pair in the specified section
  788. Arguments:
  789. IniFile - Specifies a handle to an open INI file
  790. Section - Specifies the section to write to
  791. Key - Specifies the key
  792. Value - Spcifies the value
  793. Return Value:
  794. TRUE if write was successful, FALSE if not
  795. --*/
  796. BOOL
  797. IniWriteValueA (
  798. IN PINIFILEA IniFile,
  799. IN PCSTR Section,
  800. IN PCSTR Key,
  801. IN PCSTR Value
  802. )
  803. {
  804. return WritePrivateProfileStringA (
  805. Section,
  806. Key,
  807. Value,
  808. IniFile->IniFilePath
  809. );
  810. }
  811. BOOL
  812. IniWriteValueW (
  813. IN PINIFILEW IniFile,
  814. IN PCWSTR Section,
  815. IN PCWSTR Key,
  816. IN PCWSTR Value
  817. )
  818. {
  819. return WritePrivateProfileStringW (
  820. Section,
  821. Key,
  822. Value,
  823. IniFile->IniFilePath
  824. );
  825. }