|
|
/*++
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 ); }
|