20#include <winpr/config.h>
21#include <winpr/assert.h>
28#include <winpr/wtypes.h>
30#include <winpr/file.h>
60 wIniFileSection** sections;
63static BOOL IniFile_Load_NextLine(wIniFile* ini,
char* str)
69 ini->nextLine = strtok_s(str,
"\n", &ini->tokctx);
74 size_t length = strlen(ini->nextLine);
78 if (ini->nextLine[length - 1] ==
'\r')
80 ini->nextLine[length - 1] =
'\0';
87 ini->nextLine =
nullptr;
91static BOOL IniFile_BufferResize(wIniFile* ini,
size_t size)
94 if (size > ini->buffersize)
96 const size_t diff = size - ini->buffersize;
97 char* tmp = realloc(ini->buffer, size);
101 memset(&tmp[ini->buffersize], 0, diff *
sizeof(
char));
103 ini->buffersize = size;
108static BOOL IniFile_Load_String(wIniFile* ini,
const char* iniString)
118 ini->nextLine =
nullptr;
119 fileSize = strlen(iniString);
124 if (!IniFile_BufferResize(ini, fileSize + 2))
127 CopyMemory(ini->buffer, iniString, fileSize);
128 ini->buffer[fileSize] =
'\n';
129 IniFile_Load_NextLine(ini, ini->buffer);
133static void IniFile_Close_File(FILE* fp)
139static FILE* IniFile_Open_File(wIniFile* ini,
const char* filename)
147 return winpr_fopen(filename,
"rb");
149 return winpr_fopen(filename,
"w+b");
152static BOOL IniFile_Load_File(wIniFile* ini,
const char* filename)
158 FILE* fp = IniFile_Open_File(ini, filename);
162 if (_fseeki64(fp, 0, SEEK_END) < 0)
166 const INT64 fileSize = _ftelli64(fp);
170 if (_fseeki64(fp, 0, SEEK_SET) < 0)
174 ini->nextLine =
nullptr;
179 if (!IniFile_BufferResize(ini, (
size_t)fileSize + 2))
182 if (fread(ini->buffer, (
size_t)fileSize, 1ul, fp) != 1)
185 ini->buffer[fileSize] =
'\n';
186 ini->buffer[fileSize + 1] =
'\0';
188 IniFile_Load_NextLine(ini, ini->buffer);
192 IniFile_Close_File(fp);
196static BOOL IniFile_Load_HasNextLine(wIniFile* ini)
200 return (ini->nextLine !=
nullptr);
203static char* IniFile_Load_GetNextLine(wIniFile* ini)
207 ini->line = ini->nextLine;
208 ini->lineLength = strlen(ini->line);
209 IniFile_Load_NextLine(ini,
nullptr);
213static void IniFile_Key_Free(wIniFileKey* key)
223static wIniFileKey* IniFile_Key_New(
const char* name,
const char* value)
228 wIniFileKey* key = calloc(1,
sizeof(wIniFileKey));
232 key->name = _strdup(name);
233 key->value = _strdup(value);
235 if (!key->name || !key->value)
237 IniFile_Key_Free(key);
245static void IniFile_Section_Free(wIniFileSection* section)
252 for (
size_t index = 0; index < section->nKeys; index++)
254 IniFile_Key_Free(section->keys[index]);
257 free((
void*)section->keys);
261static BOOL IniFile_SectionKeysResize(wIniFileSection* section,
size_t count)
263 WINPR_ASSERT(section);
265 if (section->nKeys + count >= section->cKeys)
267 const size_t new_size = section->cKeys + count + 1024;
268 const size_t diff = new_size - section->cKeys;
269 wIniFileKey** new_keys =
270 (wIniFileKey**)realloc((
void*)section->keys,
sizeof(wIniFileKey*) * new_size);
275 memset((
void*)&new_keys[section->cKeys], 0, diff *
sizeof(wIniFileKey*));
276 section->cKeys = new_size;
277 section->keys = new_keys;
282static wIniFileSection* IniFile_Section_New(
const char* name)
287 wIniFileSection* section = calloc(1,
sizeof(wIniFileSection));
292 section->name = _strdup(name);
297 if (!IniFile_SectionKeysResize(section, 64))
303 IniFile_Section_Free(section);
307static wIniFileSection* IniFile_GetSection(wIniFile* ini,
const char* name)
309 wIniFileSection* section =
nullptr;
316 for (
size_t index = 0; index < ini->nSections; index++)
318 if (_stricmp(name, ini->sections[index]->name) == 0)
320 section = ini->sections[index];
328static BOOL IniFile_SectionResize(wIniFile* ini,
size_t count)
332 if (ini->nSections + count >= ini->cSections)
334 const size_t new_size = ini->cSections + count + 1024;
335 const size_t diff = new_size - ini->cSections;
336 wIniFileSection** new_sect =
337 (wIniFileSection**)realloc((
void*)ini->sections,
sizeof(wIniFileSection*) * new_size);
342 memset((
void*)&new_sect[ini->cSections], 0, diff *
sizeof(wIniFileSection*));
343 ini->cSections = new_size;
344 ini->sections = new_sect;
349static wIniFileSection* IniFile_AddToSection(wIniFile* ini,
const char* name)
356 wIniFileSection* section = IniFile_GetSection(ini, name);
360 if (!IniFile_SectionResize(ini, 1))
363 section = IniFile_Section_New(name);
366 ini->sections[ini->nSections++] = section;
372static wIniFileKey* IniFile_GetKey(wIniFileSection* section,
const char* name)
374 wIniFileKey* key =
nullptr;
376 WINPR_ASSERT(section);
381 for (
size_t index = 0; index < section->nKeys; index++)
383 if (_stricmp(name, section->keys[index]->name) == 0)
385 key = section->keys[index];
393static wIniFileKey* IniFile_AddKey(wIniFileSection* section,
const char* name,
const char* value)
395 WINPR_ASSERT(section);
400 wIniFileKey* key = IniFile_GetKey(section, name);
404 if (!IniFile_SectionKeysResize(section, 1))
407 key = IniFile_Key_New(name, value);
412 section->keys[section->nKeys++] = key;
417 key->value = _strdup(value);
426static int IniFile_Load(wIniFile* ini)
428 char* name =
nullptr;
429 char* value =
nullptr;
430 char* separator =
nullptr;
433 wIniFileSection* section =
nullptr;
437 while (IniFile_Load_HasNextLine(ini))
439 char* line = IniFile_Load_GetNextLine(ini);
447 end = strchr(line,
']');
453 IniFile_AddToSection(ini, beg);
454 section = ini->sections[ini->nSections - 1];
458 separator = strchr(line,
'=');
460 if (separator ==
nullptr)
465 while ((&end[-1] > line) && ((end[-1] ==
' ') || (end[-1] ==
'\t')))
472 while (*beg && ((*beg ==
' ') || (*beg ==
'\t')))
478 end = &line[ini->lineLength];
480 while ((end > beg) && ((end[-1] ==
' ') || (end[-1] ==
'\t')))
488 if (!IniFile_AddKey(section, name, value))
496static BOOL IniFile_SetFilename(wIniFile* ini,
const char* name)
500 ini->filename =
nullptr;
504 ini->filename = _strdup(name);
505 return ini->filename !=
nullptr;
508int IniFile_ReadBuffer(wIniFile* ini,
const char* buffer)
517 ini->readOnly = TRUE;
518 status = IniFile_Load_String(ini, buffer);
523 return IniFile_Load(ini);
526int IniFile_ReadFile(wIniFile* ini,
const char* filename)
530 ini->readOnly = TRUE;
531 if (!IniFile_SetFilename(ini, filename))
536 if (!IniFile_Load_File(ini, filename))
539 return IniFile_Load(ini);
542char** IniFile_GetSectionNames(wIniFile* ini,
size_t* count)
549 if (ini->nSections > INT_MAX)
552 size_t length = (
sizeof(
char*) * ini->nSections) +
sizeof(char);
554 for (
size_t index = 0; index < ini->nSections; index++)
556 wIniFileSection* section = ini->sections[index];
557 const size_t nameLength = strlen(section->name);
558 length += (nameLength + 1);
561 char** sectionNames = (
char**)calloc(length,
sizeof(
char*));
566 char* p = (
char*)&((BYTE*)sectionNames)[
sizeof(
char*) * ini->nSections];
568 for (
size_t index = 0; index < ini->nSections; index++)
570 sectionNames[index] = p;
571 wIniFileSection* section = ini->sections[index];
572 const size_t nameLength = strlen(section->name);
573 CopyMemory(p, section->name, nameLength + 1);
574 p += (nameLength + 1);
578 *count = ini->nSections;
582char** IniFile_GetSectionKeyNames(wIniFile* ini,
const char* section,
size_t* count)
586 if (!section || !count)
589 wIniFileSection* pSection = IniFile_GetSection(ini, section);
594 if (pSection->nKeys > INT_MAX)
597 size_t length = (
sizeof(
char*) * pSection->nKeys) +
sizeof(char);
599 for (
size_t index = 0; index < pSection->nKeys; index++)
601 wIniFileKey* pKey = pSection->keys[index];
602 const size_t nameLength = strlen(pKey->name);
603 length += (nameLength + 1);
606 char** keyNames = (
char**)calloc(length,
sizeof(
char*));
611 char* p = (
char*)&((BYTE*)keyNames)[
sizeof(
char*) * pSection->nKeys];
613 for (
size_t index = 0; index < pSection->nKeys; index++)
616 wIniFileKey* pKey = pSection->keys[index];
617 const size_t nameLength = strlen(pKey->name);
618 CopyMemory(p, pKey->name, nameLength + 1);
619 p += (nameLength + 1);
623 *count = pSection->nKeys;
627const char* IniFile_GetKeyValueString(wIniFile* ini,
const char* section,
const char* key)
629 const char* value =
nullptr;
630 wIniFileKey* pKey =
nullptr;
631 wIniFileSection* pSection =
nullptr;
635 pSection = IniFile_GetSection(ini, section);
640 pKey = IniFile_GetKey(pSection, key);
645 value = (
const char*)pKey->value;
649int IniFile_GetKeyValueInt(wIniFile* ini,
const char* section,
const char* key)
653 wIniFileKey* pKey =
nullptr;
654 wIniFileSection* pSection =
nullptr;
658 pSection = IniFile_GetSection(ini, section);
663 pKey = IniFile_GetKey(pSection, key);
670 value = strtol(pKey->value,
nullptr, 0);
671 if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
679int IniFile_SetKeyValueString(wIniFile* ini,
const char* section,
const char* key,
682 wIniFileKey* pKey =
nullptr;
685 wIniFileSection* pSection = IniFile_GetSection(ini, section);
688 pSection = IniFile_AddToSection(ini, section);
693 pKey = IniFile_AddKey(pSection, key, value);
701int IniFile_SetKeyValueInt(wIniFile* ini,
const char* section,
const char* key,
int value)
703 char strVal[128] = WINPR_C_ARRAY_INIT;
704 wIniFileKey* pKey =
nullptr;
705 wIniFileSection* pSection =
nullptr;
709 (void)sprintf_s(strVal,
sizeof(strVal),
"%d", value);
710 pSection = IniFile_GetSection(ini, section);
713 pSection = IniFile_AddToSection(ini, section);
718 pKey = IniFile_AddKey(pSection, key, strVal);
726char* IniFile_WriteBuffer(wIniFile* ini)
730 char* buffer =
nullptr;
734 for (
size_t i = 0; i < ini->nSections; i++)
736 wIniFileSection* section = ini->sections[i];
737 size += (strlen(section->name) + 3);
739 for (
size_t j = 0; j < section->nKeys; j++)
741 wIniFileKey* key = section->keys[j];
742 size += (strlen(key->name) + strlen(key->value) + 2);
749 buffer = calloc(size + 1,
sizeof(
char));
756 for (
size_t i = 0; i < ini->nSections; i++)
758 wIniFileSection* section = ini->sections[i];
759 (void)sprintf_s(&buffer[offset], size - offset,
"[%s]\n", section->name);
760 offset += (strlen(section->name) + 3);
762 for (
size_t j = 0; j < section->nKeys; j++)
764 wIniFileKey* key = section->keys[j];
765 (void)sprintf_s(&buffer[offset], size - offset,
"%s=%s\n", key->name, key->value);
766 offset += (strlen(key->name) + strlen(key->value) + 2);
769 (void)sprintf_s(&buffer[offset], size - offset,
"\n");
776int IniFile_WriteFile(wIniFile* ini,
const char* filename)
782 char* buffer = IniFile_WriteBuffer(ini);
787 const size_t length = strlen(buffer);
788 ini->readOnly = FALSE;
791 filename = ini->filename;
793 FILE* fp = IniFile_Open_File(ini, filename);
797 if (fwrite((
void*)buffer, length, 1, fp) != 1)
803 IniFile_Close_File(fp);
808void IniFile_Free(wIniFile* ini)
813 IniFile_SetFilename(ini,
nullptr);
815 for (
size_t index = 0; index < ini->nSections; index++)
816 IniFile_Section_Free(ini->sections[index]);
818 free((
void*)ini->sections);
823wIniFile* IniFile_New(
void)
825 wIniFile* ini = (wIniFile*)calloc(1,
sizeof(wIniFile));
830 if (!IniFile_SectionResize(ini, 64))
836 WINPR_PRAGMA_DIAG_PUSH
837 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
839 WINPR_PRAGMA_DIAG_POP
843wIniFile* IniFile_Clone(
const wIniFile* ini)
848 wIniFile* copy = IniFile_New();
852 copy->lineLength = ini->lineLength;
853 if (!IniFile_SetFilename(copy, ini->filename))
856 if (ini->buffersize > 0)
858 if (!IniFile_BufferResize(copy, ini->buffersize))
860 memcpy(copy->buffer, ini->buffer, copy->buffersize);
863 copy->readOnly = ini->readOnly;
865 for (
size_t x = 0; x < ini->nSections; x++)
867 const wIniFileSection* cur = ini->sections[x];
871 wIniFileSection* scopy = IniFile_AddToSection(copy, cur->name);
875 for (
size_t y = 0; y < cur->nKeys; y++)
877 const wIniFileKey* key = cur->keys[y];
881 IniFile_AddKey(scopy, key->name, key->value);