20 #include <winpr/config.h>
21 #include <winpr/assert.h>
28 #include <winpr/wtypes.h>
29 #include <winpr/crt.h>
30 #include <winpr/file.h>
32 #include <winpr/ini.h>
60 wIniFileSection** sections;
63 static BOOL IniFile_Load_NextLine(wIniFile* ini,
char* str)
69 ini->nextLine = strtok_s(str,
"\n", &ini->tokctx);
72 length = strlen(ini->nextLine);
76 if (ini->nextLine[length - 1] ==
'\r')
78 ini->nextLine[length - 1] =
'\0';
86 return (ini->nextLine) ? TRUE : FALSE;
89 static BOOL IniFile_BufferResize(wIniFile* ini,
size_t size)
92 if (size > ini->buffersize)
94 const size_t diff = size - ini->buffersize;
95 char* tmp = realloc(ini->buffer, size);
99 memset(&tmp[ini->buffersize], 0, diff *
sizeof(
char));
101 ini->buffersize = size;
106 static BOOL IniFile_Load_String(wIniFile* ini,
const char* iniString)
116 ini->nextLine = NULL;
117 fileSize = strlen(iniString);
122 if (!IniFile_BufferResize(ini, fileSize + 2))
125 CopyMemory(ini->buffer, iniString, fileSize);
126 ini->buffer[fileSize] =
'\n';
127 IniFile_Load_NextLine(ini, ini->buffer);
131 static void IniFile_Close_File(FILE* fp)
137 static FILE* IniFile_Open_File(wIniFile* ini,
const char* filename)
145 return winpr_fopen(filename,
"rb");
147 return winpr_fopen(filename,
"w+b");
150 static BOOL IniFile_Load_File(wIniFile* ini,
const char* filename)
156 FILE* fp = IniFile_Open_File(ini, filename);
160 if (_fseeki64(fp, 0, SEEK_END) < 0)
163 const INT64 fileSize = _ftelli64(fp);
168 if (_fseeki64(fp, 0, SEEK_SET) < 0)
172 ini->nextLine = NULL;
177 if (!IniFile_BufferResize(ini, (
size_t)fileSize + 2))
180 if (fread(ini->buffer, (
size_t)fileSize, 1ul, fp) != 1)
183 ini->buffer[fileSize] =
'\n';
184 IniFile_Load_NextLine(ini, ini->buffer);
188 IniFile_Close_File(fp);
192 static BOOL IniFile_Load_HasNextLine(wIniFile* ini)
196 return (ini->nextLine) ? TRUE : FALSE;
199 static char* IniFile_Load_GetNextLine(wIniFile* ini)
203 ini->line = ini->nextLine;
204 ini->lineLength = strlen(ini->line);
205 IniFile_Load_NextLine(ini, NULL);
209 static void IniFile_Key_Free(wIniFileKey* key)
219 static wIniFileKey* IniFile_Key_New(
const char* name,
const char* value)
224 wIniFileKey* key = calloc(1,
sizeof(wIniFileKey));
228 key->name = _strdup(name);
229 key->value = _strdup(value);
231 if (!key->name || !key->value)
233 IniFile_Key_Free(key);
241 static void IniFile_Section_Free(wIniFileSection* section)
248 for (
size_t index = 0; index < section->nKeys; index++)
250 IniFile_Key_Free(section->keys[index]);
257 static BOOL IniFile_SectionKeysResize(wIniFileSection* section,
size_t count)
259 WINPR_ASSERT(section);
261 if (section->nKeys + count >= section->cKeys)
263 const size_t new_size = section->cKeys + count + 1024;
264 const size_t diff = new_size - section->cKeys;
265 wIniFileKey** new_keys =
266 (wIniFileKey**)realloc(section->keys,
sizeof(wIniFileKey*) * new_size);
271 memset(&new_keys[section->cKeys], 0, diff *
sizeof(wIniFileKey*));
272 section->cKeys = new_size;
273 section->keys = new_keys;
278 static wIniFileSection* IniFile_Section_New(
const char* name)
283 wIniFileSection* section = calloc(1,
sizeof(wIniFileSection));
288 section->name = _strdup(name);
293 if (!IniFile_SectionKeysResize(section, 64))
299 IniFile_Section_Free(section);
303 static wIniFileSection* IniFile_GetSection(wIniFile* ini,
const char* name)
305 wIniFileSection* section = NULL;
312 for (
size_t index = 0; index < ini->nSections; index++)
314 if (_stricmp(name, ini->sections[index]->name) == 0)
316 section = ini->sections[index];
324 static BOOL IniFile_SectionResize(wIniFile* ini,
size_t count)
328 if (ini->nSections + count >= ini->cSections)
330 const size_t new_size = ini->cSections + count + 1024;
331 const size_t diff = new_size - ini->cSections;
332 wIniFileSection** new_sect =
333 (wIniFileSection**)realloc(ini->sections,
sizeof(wIniFileSection*) * new_size);
338 memset(&new_sect[ini->cSections], 0, diff *
sizeof(wIniFileSection*));
339 ini->cSections = new_size;
340 ini->sections = new_sect;
345 static wIniFileSection* IniFile_AddToSection(wIniFile* ini,
const char* name)
352 wIniFileSection* section = IniFile_GetSection(ini, name);
356 if (!IniFile_SectionResize(ini, 1))
359 section = IniFile_Section_New(name);
362 ini->sections[ini->nSections++] = section;
368 static wIniFileKey* IniFile_GetKey(wIniFileSection* section,
const char* name)
370 wIniFileKey* key = NULL;
372 WINPR_ASSERT(section);
377 for (
size_t index = 0; index < section->nKeys; index++)
379 if (_stricmp(name, section->keys[index]->name) == 0)
381 key = section->keys[index];
389 static wIniFileKey* IniFile_AddKey(wIniFileSection* section,
const char* name,
const char* value)
391 WINPR_ASSERT(section);
396 wIniFileKey* key = IniFile_GetKey(section, name);
400 if (!IniFile_SectionKeysResize(section, 1))
403 key = IniFile_Key_New(name, value);
408 section->keys[section->nKeys++] = key;
413 key->value = _strdup(value);
422 static int IniFile_Load(wIniFile* ini)
426 char* separator = NULL;
429 wIniFileSection* section = NULL;
433 while (IniFile_Load_HasNextLine(ini))
435 char* line = IniFile_Load_GetNextLine(ini);
443 end = strchr(line,
']');
449 IniFile_AddToSection(ini, beg);
450 section = ini->sections[ini->nSections - 1];
454 separator = strchr(line,
'=');
456 if (separator == NULL)
461 while ((&end[-1] > line) && ((end[-1] ==
' ') || (end[-1] ==
'\t')))
468 while (*beg && ((*beg ==
' ') || (*beg ==
'\t')))
474 end = &line[ini->lineLength];
476 while ((end > beg) && ((end[-1] ==
' ') || (end[-1] ==
'\t')))
484 if (!IniFile_AddKey(section, name, value))
492 static BOOL IniFile_SetFilename(wIniFile* ini,
const char* name)
496 ini->filename = NULL;
500 ini->filename = _strdup(name);
501 return ini->filename != NULL;
504 int IniFile_ReadBuffer(wIniFile* ini,
const char* buffer)
513 ini->readOnly = TRUE;
514 status = IniFile_Load_String(ini, buffer);
519 return IniFile_Load(ini);
522 int IniFile_ReadFile(wIniFile* ini,
const char* filename)
526 ini->readOnly = TRUE;
527 if (!IniFile_SetFilename(ini, filename))
532 if (!IniFile_Load_File(ini, filename))
535 return IniFile_Load(ini);
538 char** IniFile_GetSectionNames(wIniFile* ini,
size_t* count)
545 if (ini->nSections > INT_MAX)
548 size_t length = (
sizeof(
char*) * ini->nSections) +
sizeof(char);
550 for (
size_t index = 0; index < ini->nSections; index++)
552 wIniFileSection* section = ini->sections[index];
553 const size_t nameLength = strlen(section->name);
554 length += (nameLength + 1);
557 char** sectionNames = (
char**)calloc(length,
sizeof(
char*));
562 char* p = (
char*)&((BYTE*)sectionNames)[
sizeof(
char*) * ini->nSections];
564 for (
size_t index = 0; index < ini->nSections; index++)
566 sectionNames[index] = p;
567 wIniFileSection* section = ini->sections[index];
568 const size_t nameLength = strlen(section->name);
569 CopyMemory(p, section->name, nameLength + 1);
570 p += (nameLength + 1);
574 *count = ini->nSections;
578 char** IniFile_GetSectionKeyNames(wIniFile* ini,
const char* section,
size_t* count)
582 if (!section || !count)
585 wIniFileSection* pSection = IniFile_GetSection(ini, section);
590 if (pSection->nKeys > INT_MAX)
593 size_t length = (
sizeof(
char*) * pSection->nKeys) +
sizeof(char);
595 for (
size_t index = 0; index < pSection->nKeys; index++)
597 wIniFileKey* pKey = pSection->keys[index];
598 const size_t nameLength = strlen(pKey->name);
599 length += (nameLength + 1);
602 char** keyNames = (
char**)calloc(length,
sizeof(
char*));
607 char* p = (
char*)&((BYTE*)keyNames)[
sizeof(
char*) * pSection->nKeys];
609 for (
size_t index = 0; index < pSection->nKeys; index++)
612 wIniFileKey* pKey = pSection->keys[index];
613 const size_t nameLength = strlen(pKey->name);
614 CopyMemory(p, pKey->name, nameLength + 1);
615 p += (nameLength + 1);
619 *count = pSection->nKeys;
623 const char* IniFile_GetKeyValueString(wIniFile* ini,
const char* section,
const char* key)
625 const char* value = NULL;
626 wIniFileKey* pKey = NULL;
627 wIniFileSection* pSection = NULL;
631 pSection = IniFile_GetSection(ini, section);
636 pKey = IniFile_GetKey(pSection, key);
641 value = (
const char*)pKey->value;
645 int IniFile_GetKeyValueInt(wIniFile* ini,
const char* section,
const char* key)
649 wIniFileKey* pKey = NULL;
650 wIniFileSection* pSection = NULL;
654 pSection = IniFile_GetSection(ini, section);
659 pKey = IniFile_GetKey(pSection, key);
666 value = strtol(pKey->value, NULL, 0);
667 if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
675 int IniFile_SetKeyValueString(wIniFile* ini,
const char* section,
const char* key,
678 wIniFileKey* pKey = NULL;
681 wIniFileSection* pSection = IniFile_GetSection(ini, section);
684 pSection = IniFile_AddToSection(ini, section);
689 pKey = IniFile_AddKey(pSection, key, value);
697 int IniFile_SetKeyValueInt(wIniFile* ini,
const char* section,
const char* key,
int value)
699 char strVal[128] = { 0 };
700 wIniFileKey* pKey = NULL;
701 wIniFileSection* pSection = NULL;
705 (void)sprintf_s(strVal,
sizeof(strVal),
"%d", value);
706 pSection = IniFile_GetSection(ini, section);
709 pSection = IniFile_AddToSection(ini, section);
714 pKey = IniFile_AddKey(pSection, key, strVal);
722 char* IniFile_WriteBuffer(wIniFile* ini)
730 for (
size_t i = 0; i < ini->nSections; i++)
732 wIniFileSection* section = ini->sections[i];
733 size += (strlen(section->name) + 3);
735 for (
size_t j = 0; j < section->nKeys; j++)
737 wIniFileKey* key = section->keys[j];
738 size += (strlen(key->name) + strlen(key->value) + 2);
745 buffer = calloc(size + 1,
sizeof(
char));
752 for (
size_t i = 0; i < ini->nSections; i++)
754 wIniFileSection* section = ini->sections[i];
755 (void)sprintf_s(&buffer[offset], size - offset,
"[%s]\n", section->name);
756 offset += (strlen(section->name) + 3);
758 for (
size_t j = 0; j < section->nKeys; j++)
760 wIniFileKey* key = section->keys[j];
761 (void)sprintf_s(&buffer[offset], size - offset,
"%s=%s\n", key->name, key->value);
762 offset += (strlen(key->name) + strlen(key->value) + 2);
765 (void)sprintf_s(&buffer[offset], size - offset,
"\n");
772 int IniFile_WriteFile(wIniFile* ini,
const char* filename)
778 char* buffer = IniFile_WriteBuffer(ini);
783 const size_t length = strlen(buffer);
784 ini->readOnly = FALSE;
787 filename = ini->filename;
789 FILE* fp = IniFile_Open_File(ini, filename);
793 if (fwrite((
void*)buffer, length, 1, fp) != 1)
799 IniFile_Close_File(fp);
804 void IniFile_Free(wIniFile* ini)
809 IniFile_SetFilename(ini, NULL);
811 for (
size_t index = 0; index < ini->nSections; index++)
812 IniFile_Section_Free(ini->sections[index]);
819 wIniFile* IniFile_New(
void)
821 wIniFile* ini = (wIniFile*)calloc(1,
sizeof(wIniFile));
826 if (!IniFile_SectionResize(ini, 64))
832 WINPR_PRAGMA_DIAG_PUSH
833 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
835 WINPR_PRAGMA_DIAG_POP
839 wIniFile* IniFile_Clone(
const wIniFile* ini)
844 wIniFile* copy = IniFile_New();
848 copy->lineLength = ini->lineLength;
849 if (!IniFile_SetFilename(copy, ini->filename))
852 if (ini->buffersize > 0)
854 if (!IniFile_BufferResize(copy, ini->buffersize))
856 memcpy(copy->buffer, ini->buffer, copy->buffersize);
859 copy->readOnly = ini->readOnly;
861 for (
size_t x = 0; x < ini->nSections; x++)
863 const wIniFileSection* cur = ini->sections[x];
867 wIniFileSection* scopy = IniFile_AddToSection(copy, cur->name);
871 for (
size_t y = 0; y < cur->nKeys; y++)
873 const wIniFileKey* key = cur->keys[y];
877 IniFile_AddKey(scopy, key->name, key->value);