1096 lines
22 KiB
C
1096 lines
22 KiB
C
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ini.c
|
|
|
|
Abstract:
|
|
|
|
Provides wrappers for commonly used INI file handling routines.
|
|
|
|
Author:
|
|
|
|
20-Oct-1999 Ovidiu Temereanca (ovidiut) - File creation.
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
// None
|
|
|
|
#define DBG_INILIB "IniLib"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define INITIAL_BUFFER_CHAR_COUNT 256
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
PMHANDLE g_IniLibPool;
|
|
INT g_IniRefs;
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
|
|
BOOL
|
|
Ini_Init (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ini_Init initializes this library.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE if the init was successful.
|
|
FALSE if not. GetLastError() returns extended error info.
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT (g_IniRefs >= 0);
|
|
|
|
g_IniRefs++;
|
|
|
|
if (g_IniRefs == 1) {
|
|
g_IniLibPool = PmCreateNamedPool ("IniLib");
|
|
}
|
|
|
|
return g_IniLibPool != NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
Ini_Exit (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ini_Exit is called to free resources used by this lib.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT (g_IniRefs > 0);
|
|
|
|
g_IniRefs--;
|
|
|
|
if (!g_IniRefs) {
|
|
|
|
if (g_IniLibPool) {
|
|
PmDestroyPool (g_IniLibPool);
|
|
g_IniLibPool = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PBYTE
|
|
pAllocateSpace (
|
|
IN DWORD Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pAllocateSpace is a private function that allocates space from the module's private pool
|
|
|
|
Arguments:
|
|
|
|
Size - The size (in bytes) to allocate.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the successfully allocated memory or NULL if no memory could be allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT (g_IniLibPool);
|
|
MYASSERT (Size);
|
|
return PmGetMemory (g_IniLibPool, Size);
|
|
}
|
|
|
|
|
|
VOID
|
|
pFreeSpace (
|
|
IN PVOID Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pFreeSpace is a private function that frees space allocated from the module's private pool
|
|
|
|
Arguments:
|
|
|
|
Buffer - Pointer to buffer to free.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT (g_IniLibPool);
|
|
PmReleaseMemory (g_IniLibPool, Buffer);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RealIniFileOpen validates the args passed in and then
|
|
initializes IniFile struct with info used in subsequent calls to INI functions.
|
|
|
|
Arguments:
|
|
|
|
IniFile - Receives INI file attributes if open is successful
|
|
|
|
IniFileSpec - Specifies the file name; if not full path,
|
|
current drive and/or dir are prefixed
|
|
|
|
FileMustExist - Specifies TRUE if file must exist for open to succeed
|
|
|
|
Return Value:
|
|
|
|
TRUE if open succeeded; IniFile is valid for subsequent calls to other INI APIs;
|
|
IniFileClose must be called when this handle is no longer needed.
|
|
FALSE if not
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
RealIniFileOpenA (
|
|
OUT PINIFILEA IniFile,
|
|
IN PCSTR IniFileSpec,
|
|
IN BOOL FileMustExist /*,*/
|
|
ALLOCATION_TRACKING_DEF /* , PCSTR File, UINT Line */
|
|
)
|
|
{
|
|
CHAR fullPath[MAX_MBCHAR_PATH];
|
|
|
|
if (!GetFullPathNameA (IniFileSpec, MAX_MBCHAR_PATH, fullPath, NULL)) {
|
|
|
|
DEBUGMSGA ((
|
|
DBG_ERROR,
|
|
"IniFileOpenA: GetFullPathNameA failed on <%s>",
|
|
IniFileSpec
|
|
));
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUGMSGA_IF ((
|
|
!StringIMatchA (IniFileSpec, fullPath),
|
|
DBG_INILIB,
|
|
"IniFileOpenA: IniFileSpec supplied: <%s>; full path defaulting to <%s>",
|
|
IniFileSpec,
|
|
fullPath
|
|
));
|
|
|
|
if (BfPathIsDirectoryA (fullPath)) {
|
|
DEBUGMSGA ((
|
|
DBG_INILIB,
|
|
"IniFileOpenA: <%s> is a directory",
|
|
fullPath
|
|
));
|
|
return FALSE;
|
|
}
|
|
if (FileMustExist && !DoesFileExistA (fullPath)) {
|
|
DEBUGMSGA ((
|
|
DBG_INILIB,
|
|
"IniFileOpenA: file not found: <%s>",
|
|
fullPath
|
|
));
|
|
return FALSE;
|
|
}
|
|
|
|
IniFile->IniFilePath = DuplicateTextExA (g_IniLibPool, fullPath, 0, NULL);
|
|
IniFile->OriginalAttributes = GetFileAttributesA (fullPath);
|
|
|
|
if (IniFile->OriginalAttributes != (DWORD)-1) {
|
|
//
|
|
// set working attributes
|
|
//
|
|
SetFileAttributesA (fullPath, FILE_ATTRIBUTE_NORMAL);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RealIniFileOpenW (
|
|
OUT PINIFILEW IniFile,
|
|
IN PCWSTR IniFileSpec,
|
|
IN BOOL FileMustExist /*,*/
|
|
ALLOCATION_TRACKING_DEF /* , PCSTR File, UINT Line */
|
|
)
|
|
{
|
|
WCHAR fullPath[MAX_MBCHAR_PATH];
|
|
|
|
if (!GetFullPathNameW (IniFileSpec, MAX_WCHAR_PATH, fullPath, NULL)) {
|
|
|
|
DEBUGMSGW ((
|
|
DBG_ERROR,
|
|
"IniFileOpenW: GetFullPathNameW failed on <%s>",
|
|
IniFileSpec
|
|
));
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUGMSGW_IF ((
|
|
!StringIMatchW (IniFileSpec, fullPath),
|
|
DBG_INILIB,
|
|
"IniFileOpenW: IniFileSpec supplied: <%s>; full path defaulting to <%s>",
|
|
IniFileSpec,
|
|
fullPath
|
|
));
|
|
|
|
if (BfPathIsDirectoryW (fullPath)) {
|
|
DEBUGMSGW ((
|
|
DBG_INILIB,
|
|
"IniFileOpenW: <%s> is a directory",
|
|
fullPath
|
|
));
|
|
return FALSE;
|
|
}
|
|
if (FileMustExist && !DoesFileExistW (fullPath)) {
|
|
DEBUGMSGW ((
|
|
DBG_INILIB,
|
|
"IniFileOpenW: file not found: <%s>",
|
|
fullPath
|
|
));
|
|
return FALSE;
|
|
}
|
|
|
|
IniFile->IniFilePath = DuplicateTextExW (g_IniLibPool, fullPath, 0, NULL);
|
|
IniFile->OriginalAttributes = GetFileAttributesW (fullPath);
|
|
|
|
if (IniFile->OriginalAttributes != (DWORD)-1) {
|
|
//
|
|
// set working attributes
|
|
//
|
|
SetFileAttributesW (fullPath, FILE_ATTRIBUTE_NORMAL);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IniFileClose frees resources and restores INI's initial attributes
|
|
|
|
Arguments:
|
|
|
|
IniFile - Specifies a handle to an open INI file
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
VOID
|
|
IniFileCloseA (
|
|
IN PINIFILEA IniFile
|
|
)
|
|
{
|
|
if (IniFile->OriginalAttributes != (DWORD)-1) {
|
|
SetFileAttributesA (IniFile->IniFilePath, IniFile->OriginalAttributes);
|
|
}
|
|
FreeTextExA (g_IniLibPool, IniFile->IniFilePath);
|
|
}
|
|
|
|
|
|
VOID
|
|
IniFileCloseW (
|
|
IN PINIFILEW IniFile
|
|
)
|
|
{
|
|
if (IniFile->OriginalAttributes != (DWORD)-1) {
|
|
SetFileAttributesW (IniFile->IniFilePath, IniFile->OriginalAttributes);
|
|
}
|
|
FreeTextExW (g_IniLibPool, IniFile->IniFilePath);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumFirstIniSection returns the first section of the given INI file, if any.
|
|
|
|
Arguments:
|
|
|
|
IniSectEnum - Receives the first section
|
|
|
|
IniFile - Specifies a handle to an open INI file
|
|
|
|
Return Value:
|
|
|
|
TRUE if there is a section
|
|
FALSE if not
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumFirstIniSectionA (
|
|
OUT PINISECT_ENUMA IniSectEnum,
|
|
IN PINIFILEA IniFile
|
|
)
|
|
{
|
|
PSTR sections;
|
|
DWORD allocatedChars;
|
|
DWORD chars;
|
|
|
|
sections = NULL;
|
|
allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
|
|
do {
|
|
if (sections) {
|
|
pFreeSpace (sections);
|
|
}
|
|
allocatedChars *= 2;
|
|
sections = (PSTR)pAllocateSpace (allocatedChars * DWSIZEOF (CHAR));
|
|
if (!sections) {
|
|
return FALSE;
|
|
}
|
|
chars = GetPrivateProfileSectionNamesA (
|
|
sections,
|
|
allocatedChars,
|
|
IniFile->IniFilePath
|
|
);
|
|
} while (chars >= allocatedChars - 2);
|
|
|
|
if (!*sections) {
|
|
pFreeSpace (sections);
|
|
return FALSE;
|
|
}
|
|
|
|
IniSectEnum->Sections = sections;
|
|
IniSectEnum->CurrentSection = sections;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumFirstIniSectionW (
|
|
OUT PINISECT_ENUMW IniSectEnum,
|
|
IN PINIFILEW IniFile
|
|
)
|
|
{
|
|
PWSTR sections;
|
|
DWORD allocatedChars;
|
|
DWORD chars;
|
|
|
|
sections = NULL;
|
|
allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
|
|
do {
|
|
if (sections) {
|
|
pFreeSpace (sections);
|
|
}
|
|
allocatedChars *= 2;
|
|
sections = (PWSTR)pAllocateSpace (allocatedChars * DWSIZEOF (WCHAR));
|
|
if (!sections) {
|
|
return FALSE;
|
|
}
|
|
chars = GetPrivateProfileSectionNamesW (
|
|
sections,
|
|
allocatedChars,
|
|
IniFile->IniFilePath
|
|
);
|
|
} while (chars >= allocatedChars - 2);
|
|
|
|
if (!*sections) {
|
|
pFreeSpace (sections);
|
|
return FALSE;
|
|
}
|
|
|
|
IniSectEnum->Sections = sections;
|
|
IniSectEnum->CurrentSection = sections;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumNextIniSection returns the next section, if any.
|
|
|
|
Arguments:
|
|
|
|
IniSectEnum - Specifies the prev section/receives the next section
|
|
|
|
Return Value:
|
|
|
|
TRUE if there is a next section
|
|
FALSE if not
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumNextIniSectionA (
|
|
IN OUT PINISECT_ENUMA IniSectEnum
|
|
)
|
|
{
|
|
if (IniSectEnum->CurrentSection && *IniSectEnum->CurrentSection != 0) {
|
|
//Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
|
|
//CurrentKeyValuePtr (because GetEndOfStringA will return a valid pointer) so...
|
|
//lint --e(613)
|
|
IniSectEnum->CurrentSection = GetEndOfStringA (IniSectEnum->CurrentSection) + 1;
|
|
if (*IniSectEnum->CurrentSection != 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
AbortIniSectionEnumA (IniSectEnum);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumNextIniSectionW (
|
|
IN OUT PINISECT_ENUMW IniSectEnum
|
|
)
|
|
{
|
|
if (IniSectEnum->CurrentSection && *IniSectEnum->CurrentSection != 0) {
|
|
//Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
|
|
//CurrentKeyValuePtr (because GetEndOfStringW will return a valid pointer) so...
|
|
//lint --e(613)
|
|
IniSectEnum->CurrentSection = GetEndOfStringW (IniSectEnum->CurrentSection) + 1;
|
|
if (*IniSectEnum->CurrentSection != 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
AbortIniSectionEnumW (IniSectEnum);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
AbortIniSectionEnum aborts section enumeration
|
|
|
|
Arguments:
|
|
|
|
IniSectEnum - Specifies the section enumeration handle/receives NULLs
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
VOID
|
|
AbortIniSectionEnumA (
|
|
IN OUT PINISECT_ENUMA IniSectEnum
|
|
)
|
|
{
|
|
pFreeSpace ((PVOID)IniSectEnum->Sections);
|
|
IniSectEnum->Sections = NULL;
|
|
IniSectEnum->CurrentSection = NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
AbortIniSectionEnumW (
|
|
IN OUT PINISECT_ENUMW IniSectEnum
|
|
)
|
|
{
|
|
pFreeSpace ((PVOID)IniSectEnum->Sections);
|
|
IniSectEnum->Sections = NULL;
|
|
IniSectEnum->CurrentSection = NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumFirstIniKeyValue returns the first key/value pair of
|
|
the given INI file/section name, if any.
|
|
|
|
Arguments:
|
|
|
|
IniKeyValueEnum - Receives the first section
|
|
|
|
IniFile - Specifies a handle to an open INI file
|
|
|
|
Section - Specifies the section to enumearte
|
|
|
|
Return Value:
|
|
|
|
TRUE if there is a key/value pair
|
|
FALSE if not
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumFirstIniKeyValueA (
|
|
OUT PINIKEYVALUE_ENUMA IniKeyValueEnum,
|
|
IN PINIFILEA IniFile,
|
|
IN PCSTR Section
|
|
)
|
|
{
|
|
PSTR buffer;
|
|
DWORD allocatedChars;
|
|
DWORD chars;
|
|
|
|
MYASSERT (Section);
|
|
if (!Section) {
|
|
return FALSE;
|
|
}
|
|
|
|
buffer = NULL;
|
|
allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
|
|
do {
|
|
if (buffer) {
|
|
pFreeSpace (buffer);
|
|
}
|
|
allocatedChars *= 2;
|
|
buffer = (PSTR)pAllocateSpace (allocatedChars * DWSIZEOF (CHAR));
|
|
if (!buffer) {
|
|
return FALSE;
|
|
}
|
|
chars = GetPrivateProfileSectionA (
|
|
Section,
|
|
buffer,
|
|
allocatedChars,
|
|
IniFile->IniFilePath
|
|
);
|
|
} while (chars >= allocatedChars - 2);
|
|
|
|
if (!*buffer) {
|
|
pFreeSpace (buffer);
|
|
return FALSE;
|
|
}
|
|
|
|
IniKeyValueEnum->KeyValuePairs = buffer;
|
|
IniKeyValueEnum->CurrentKeyValuePair = NULL;
|
|
IniKeyValueEnum->Private = NULL;
|
|
return EnumNextIniKeyValueA (IniKeyValueEnum);
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumFirstIniKeyValueW (
|
|
OUT PINIKEYVALUE_ENUMW IniKeyValueEnum,
|
|
IN PINIFILEW IniFile,
|
|
IN PCWSTR Section
|
|
)
|
|
{
|
|
PWSTR buffer;
|
|
DWORD allocatedChars;
|
|
DWORD chars;
|
|
|
|
MYASSERT (Section);
|
|
if (!Section) {
|
|
return FALSE;
|
|
}
|
|
|
|
buffer = NULL;
|
|
allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
|
|
do {
|
|
if (buffer) {
|
|
pFreeSpace (buffer);
|
|
}
|
|
allocatedChars *= 2;
|
|
buffer = (PWSTR)pAllocateSpace (allocatedChars * DWSIZEOF (WCHAR));
|
|
if (!buffer) {
|
|
return FALSE;
|
|
}
|
|
chars = GetPrivateProfileSectionW (
|
|
Section,
|
|
buffer,
|
|
allocatedChars,
|
|
IniFile->IniFilePath
|
|
);
|
|
} while (chars >= allocatedChars - 2);
|
|
|
|
if (!*buffer) {
|
|
pFreeSpace (buffer);
|
|
return FALSE;
|
|
}
|
|
|
|
IniKeyValueEnum->KeyValuePairs = buffer;
|
|
IniKeyValueEnum->Private = NULL;
|
|
return EnumNextIniKeyValueW (IniKeyValueEnum);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumNextIniKeyValue returns the first key/value pair of
|
|
the given INI file/section name, if any.
|
|
|
|
Arguments:
|
|
|
|
IniKeyValueEnum - Specifies the prev key/value pair / receives the next pair
|
|
|
|
Return Value:
|
|
|
|
TRUE if there is a next pair
|
|
FALSE if not
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
EnumNextIniKeyValueA (
|
|
IN OUT PINIKEYVALUE_ENUMA IniKeyValueEnum
|
|
)
|
|
{
|
|
//
|
|
// restore from saved position
|
|
//
|
|
IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->Private;
|
|
//
|
|
// skip commented lines
|
|
//
|
|
do {
|
|
if (IniKeyValueEnum->CurrentKeyValuePair) {
|
|
//Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
|
|
//CurrentKeyValuePtr (because GetEndOfStringA will return a valid pointer) so...
|
|
//lint --e(613)
|
|
IniKeyValueEnum->CurrentKeyValuePair = GetEndOfStringA (IniKeyValueEnum->CurrentKeyValuePair) + 1;
|
|
} else {
|
|
IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->KeyValuePairs;
|
|
}
|
|
|
|
MYASSERT (IniKeyValueEnum->CurrentKeyValuePair);
|
|
if (!(*IniKeyValueEnum->CurrentKeyValuePair)) {
|
|
AbortIniKeyValueEnumA (IniKeyValueEnum);
|
|
return FALSE;
|
|
}
|
|
IniKeyValueEnum->CurrentKey = IniKeyValueEnum->CurrentKeyValuePair;
|
|
IniKeyValueEnum->CurrentValue = _mbschr (IniKeyValueEnum->CurrentKey, '=');
|
|
} while (*IniKeyValueEnum->CurrentKeyValuePair == ';' || !IniKeyValueEnum->CurrentValue);
|
|
|
|
MYASSERT (*IniKeyValueEnum->CurrentKeyValuePair);
|
|
MYASSERT (*IniKeyValueEnum->CurrentValue == '=');
|
|
//
|
|
// remember position for next iteration
|
|
//
|
|
IniKeyValueEnum->Private = GetEndOfStringA (IniKeyValueEnum->CurrentValue);
|
|
//
|
|
// modify buffer to get KEY and VALUE
|
|
//
|
|
*(PSTR)IniKeyValueEnum->CurrentValue = 0;
|
|
IniKeyValueEnum->CurrentValue++;
|
|
TruncateTrailingSpaceA ((PSTR)IniKeyValueEnum->CurrentKey);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumNextIniKeyValueW (
|
|
IN OUT PINIKEYVALUE_ENUMW IniKeyValueEnum
|
|
)
|
|
{
|
|
//
|
|
// restore from saved position
|
|
//
|
|
IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->Private;
|
|
//
|
|
// skip commented lines
|
|
//
|
|
do {
|
|
if (IniKeyValueEnum->CurrentKeyValuePair) {
|
|
//Since CurrentKeyValuePtr is not NULL the next assignment will not put NULL in
|
|
//CurrentKeyValuePtr (because GetEndOfStringW will return a valid pointer) so...
|
|
//lint --e(613)
|
|
IniKeyValueEnum->CurrentKeyValuePair = GetEndOfStringW (IniKeyValueEnum->CurrentKeyValuePair) + 1;
|
|
} else {
|
|
IniKeyValueEnum->CurrentKeyValuePair = IniKeyValueEnum->KeyValuePairs;
|
|
}
|
|
|
|
MYASSERT (IniKeyValueEnum->CurrentKeyValuePair);
|
|
if (!(*IniKeyValueEnum->CurrentKeyValuePair)) {
|
|
AbortIniKeyValueEnumW (IniKeyValueEnum);
|
|
return FALSE;
|
|
}
|
|
IniKeyValueEnum->CurrentKey = IniKeyValueEnum->CurrentKeyValuePair;
|
|
IniKeyValueEnum->CurrentValue = wcschr (IniKeyValueEnum->CurrentKey, L'=');
|
|
} while (*IniKeyValueEnum->CurrentKeyValuePair == L';' || !IniKeyValueEnum->CurrentValue);
|
|
|
|
MYASSERT (*IniKeyValueEnum->CurrentKeyValuePair);
|
|
MYASSERT (*IniKeyValueEnum->CurrentValue == L'=');
|
|
//
|
|
// remember position for next iteration
|
|
//
|
|
IniKeyValueEnum->Private = GetEndOfStringW (IniKeyValueEnum->CurrentValue);
|
|
//
|
|
// modify buffer to get KEY and VALUE
|
|
//
|
|
*(PWSTR)IniKeyValueEnum->CurrentValue = 0;
|
|
IniKeyValueEnum->CurrentValue++;
|
|
TruncateTrailingSpaceW ((PWSTR)IniKeyValueEnum->CurrentKey);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
AbortIniKeyValueEnum aborts key/value pairs enumeration
|
|
|
|
Arguments:
|
|
|
|
IniKeyValueEnum - Specifies the key/value pair enumeration handle/receives NULLs
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
VOID
|
|
AbortIniKeyValueEnumA (
|
|
IN OUT PINIKEYVALUE_ENUMA IniKeyValueEnum
|
|
)
|
|
{
|
|
pFreeSpace ((PVOID)IniKeyValueEnum->KeyValuePairs);
|
|
IniKeyValueEnum->KeyValuePairs = NULL;
|
|
IniKeyValueEnum->CurrentKeyValuePair = NULL;
|
|
IniKeyValueEnum->CurrentKey = NULL;
|
|
IniKeyValueEnum->CurrentValue = NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
AbortIniKeyValueEnumW (
|
|
IN OUT PINIKEYVALUE_ENUMW IniKeyValueEnum
|
|
)
|
|
{
|
|
pFreeSpace ((PVOID)IniKeyValueEnum->KeyValuePairs);
|
|
IniKeyValueEnum->KeyValuePairs = NULL;
|
|
IniKeyValueEnum->CurrentKeyValuePair = NULL;
|
|
IniKeyValueEnum->CurrentKey = NULL;
|
|
IniKeyValueEnum->CurrentValue = NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IniReadValue returns the value of a specified key in a specified section
|
|
from the given INI file. The buffer returned must be freed using IniFreeReadValue
|
|
|
|
Arguments:
|
|
|
|
IniFile - Specifies a handle to an open INI file
|
|
|
|
Section - Specifies the section to read from
|
|
|
|
Key - Specifies the key
|
|
|
|
Value - Receives a pointer to an allocated buffer containing the read value,
|
|
if function is successful; optional
|
|
|
|
Chars - Receives the number of chars (not bytes) the value has,
|
|
excluding the NULL terminator; optional
|
|
|
|
Return Value:
|
|
|
|
TRUE if there is a value for the specified section/key
|
|
FALSE if not
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
IniReadValueA (
|
|
IN PINIFILEA IniFile,
|
|
IN PCSTR Section,
|
|
IN PCSTR Key,
|
|
OUT PSTR* Value, OPTIONAL
|
|
OUT PDWORD Chars OPTIONAL
|
|
)
|
|
{
|
|
PSTR buffer;
|
|
DWORD allocatedChars;
|
|
DWORD chars;
|
|
|
|
MYASSERT (Section && Key);
|
|
if (!Section || !Key) {
|
|
return FALSE;
|
|
}
|
|
|
|
buffer = NULL;
|
|
allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
|
|
do {
|
|
if (buffer) {
|
|
pFreeSpace (buffer);
|
|
}
|
|
allocatedChars *= 2;
|
|
buffer = (PSTR)pAllocateSpace (allocatedChars * DWSIZEOF (CHAR));
|
|
if (!buffer) {
|
|
return FALSE;
|
|
}
|
|
chars = GetPrivateProfileStringA (
|
|
Section,
|
|
Key,
|
|
"",
|
|
buffer,
|
|
allocatedChars,
|
|
IniFile->IniFilePath
|
|
);
|
|
} while (chars >= allocatedChars - 1);
|
|
|
|
if (Chars) {
|
|
*Chars = chars;
|
|
}
|
|
|
|
if (Value) {
|
|
if (*buffer) {
|
|
*Value = buffer;
|
|
} else {
|
|
*Value = NULL;
|
|
}
|
|
}
|
|
|
|
if (!(Value && *Value)) {
|
|
//
|
|
// buffer no longer needed
|
|
//
|
|
pFreeSpace (buffer);
|
|
}
|
|
|
|
return chars > 0;
|
|
}
|
|
|
|
BOOL
|
|
IniReadValueW (
|
|
IN PINIFILEW IniFile,
|
|
IN PCWSTR Section,
|
|
IN PCWSTR Key,
|
|
OUT PWSTR* Value, OPTIONAL
|
|
OUT PDWORD Chars OPTIONAL
|
|
)
|
|
{
|
|
PWSTR buffer;
|
|
DWORD allocatedChars;
|
|
DWORD chars;
|
|
|
|
MYASSERT (Section && Key);
|
|
if (!Section || !Key) {
|
|
return FALSE;
|
|
}
|
|
|
|
buffer = NULL;
|
|
allocatedChars = INITIAL_BUFFER_CHAR_COUNT / 2;
|
|
do {
|
|
if (buffer) {
|
|
pFreeSpace (buffer);
|
|
}
|
|
allocatedChars *= 2;
|
|
buffer = (PWSTR)pAllocateSpace (allocatedChars * DWSIZEOF (WCHAR));
|
|
if (!buffer) {
|
|
return FALSE;
|
|
}
|
|
chars = GetPrivateProfileStringW (
|
|
Section,
|
|
Key,
|
|
L"",
|
|
buffer,
|
|
allocatedChars,
|
|
IniFile->IniFilePath
|
|
);
|
|
} while (chars >= allocatedChars - 1);
|
|
|
|
if (Chars) {
|
|
*Chars = chars;
|
|
}
|
|
|
|
if (Value) {
|
|
if (*buffer) {
|
|
*Value = buffer;
|
|
} else {
|
|
*Value = NULL;
|
|
}
|
|
}
|
|
|
|
if (!(Value && *Value)) {
|
|
//
|
|
// buffer no longer needed
|
|
//
|
|
pFreeSpace (buffer);
|
|
}
|
|
|
|
return chars > 0;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IniFreeReadValue is used to free the buffer allocated by IniReadValue
|
|
and stored in Value, if specified.
|
|
|
|
Arguments:
|
|
|
|
Value - Specifies a pointer to the string to be freed
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
VOID
|
|
IniFreeReadValueA (
|
|
IN PCSTR Value
|
|
)
|
|
{
|
|
pFreeSpace ((PVOID)Value);
|
|
}
|
|
|
|
|
|
VOID
|
|
IniFreeReadValueW (
|
|
IN PCWSTR Value
|
|
)
|
|
{
|
|
pFreeSpace ((PVOID)Value);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IniWriteValue writes the key/value pair in the specified section
|
|
|
|
Arguments:
|
|
|
|
IniFile - Specifies a handle to an open INI file
|
|
|
|
Section - Specifies the section to write to
|
|
|
|
Key - Specifies the key
|
|
|
|
Value - Spcifies the value
|
|
|
|
Return Value:
|
|
|
|
TRUE if write was successful, FALSE if not
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
IniWriteValueA (
|
|
IN PINIFILEA IniFile,
|
|
IN PCSTR Section,
|
|
IN PCSTR Key,
|
|
IN PCSTR Value
|
|
)
|
|
{
|
|
return WritePrivateProfileStringA (
|
|
Section,
|
|
Key,
|
|
Value,
|
|
IniFile->IniFilePath
|
|
);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IniWriteValueW (
|
|
IN PINIFILEW IniFile,
|
|
IN PCWSTR Section,
|
|
IN PCWSTR Key,
|
|
IN PCWSTR Value
|
|
)
|
|
{
|
|
return WritePrivateProfileStringW (
|
|
Section,
|
|
Key,
|
|
Value,
|
|
IniFile->IniFilePath
|
|
);
|
|
}
|