Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/utils/ini.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * .ini config file
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
#include <winpr/assert.h>
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include <errno.h>
28
#include <winpr/wtypes.h>
29
#include <winpr/crt.h>
30
#include <winpr/file.h>
31
32
#include <winpr/ini.h>
33
34
typedef struct
35
{
36
  char* name;
37
  char* value;
38
} wIniFileKey;
39
40
typedef struct
41
{
42
  char* name;
43
  size_t nKeys;
44
  size_t cKeys;
45
  wIniFileKey** keys;
46
} wIniFileSection;
47
48
struct s_wIniFile
49
{
50
  char* line;
51
  char* nextLine;
52
  size_t lineLength;
53
  char* tokctx;
54
  char* buffer;
55
  size_t buffersize;
56
  char* filename;
57
  BOOL readOnly;
58
  size_t nSections;
59
  size_t cSections;
60
  wIniFileSection** sections;
61
};
62
63
static BOOL IniFile_Load_NextLine(wIniFile* ini, char* str)
64
0
{
65
0
  size_t length = 0;
66
67
0
  WINPR_ASSERT(ini);
68
69
0
  ini->nextLine = strtok_s(str, "\n", &ini->tokctx);
70
71
0
  if (ini->nextLine)
72
0
    length = strlen(ini->nextLine);
73
74
0
  if (length > 0)
75
0
  {
76
0
    if (ini->nextLine[length - 1] == '\r')
77
0
    {
78
0
      ini->nextLine[length - 1] = '\0';
79
0
      length--;
80
0
    }
81
82
0
    if (length < 1)
83
0
      ini->nextLine = NULL;
84
0
  }
85
86
0
  return (ini->nextLine) ? TRUE : FALSE;
87
0
}
88
89
static BOOL IniFile_BufferResize(wIniFile* ini, size_t size)
90
0
{
91
0
  WINPR_ASSERT(ini);
92
0
  if (size > ini->buffersize)
93
0
  {
94
0
    const size_t diff = size - ini->buffersize;
95
0
    char* tmp = realloc(ini->buffer, size);
96
0
    if (!tmp)
97
0
      return FALSE;
98
99
0
    memset(&tmp[ini->buffersize], 0, diff * sizeof(char));
100
0
    ini->buffer = tmp;
101
0
    ini->buffersize = size;
102
0
  }
103
0
  return TRUE;
104
0
}
105
106
static BOOL IniFile_Load_String(wIniFile* ini, const char* iniString)
107
0
{
108
0
  size_t fileSize;
109
110
0
  WINPR_ASSERT(ini);
111
112
0
  if (!iniString)
113
0
    return FALSE;
114
115
0
  ini->line = NULL;
116
0
  ini->nextLine = NULL;
117
0
  fileSize = strlen(iniString);
118
119
0
  if (fileSize < 1)
120
0
    return FALSE;
121
122
0
  if (!IniFile_BufferResize(ini, fileSize + 2))
123
0
    return FALSE;
124
125
0
  CopyMemory(ini->buffer, iniString, fileSize);
126
0
  ini->buffer[fileSize] = '\n';
127
0
  IniFile_Load_NextLine(ini, ini->buffer);
128
0
  return TRUE;
129
0
}
130
131
static void IniFile_Close_File(FILE* fp)
132
0
{
133
0
  if (fp)
134
0
    fclose(fp);
135
0
}
136
137
static FILE* IniFile_Open_File(wIniFile* ini, const char* filename)
138
0
{
139
0
  WINPR_ASSERT(ini);
140
141
0
  if (!filename)
142
0
    return FALSE;
143
144
0
  if (ini->readOnly)
145
0
    return winpr_fopen(filename, "rb");
146
0
  else
147
0
    return winpr_fopen(filename, "w+b");
148
0
}
149
150
static BOOL IniFile_Load_File(wIniFile* ini, const char* filename)
151
0
{
152
0
  BOOL rc = FALSE;
153
0
  INT64 fileSize;
154
155
0
  WINPR_ASSERT(ini);
156
157
0
  FILE* fp = IniFile_Open_File(ini, filename);
158
0
  if (!fp)
159
0
    return FALSE;
160
161
0
  if (_fseeki64(fp, 0, SEEK_END) < 0)
162
0
    goto out_file;
163
164
0
  fileSize = _ftelli64(fp);
165
166
0
  if (fileSize < 0)
167
0
    goto out_file;
168
169
0
  if (_fseeki64(fp, 0, SEEK_SET) < 0)
170
0
    goto out_file;
171
172
0
  ini->line = NULL;
173
0
  ini->nextLine = NULL;
174
175
0
  if (fileSize < 1)
176
0
    goto out_file;
177
178
0
  if (fileSize > SIZE_MAX)
179
0
    goto out_file;
180
181
0
  if (!IniFile_BufferResize(ini, (size_t)fileSize + 2))
182
0
    goto out_file;
183
184
0
  if (fread(ini->buffer, (size_t)fileSize, 1ul, fp) != 1)
185
0
    goto out_file;
186
187
0
  ini->buffer[fileSize] = '\n';
188
0
  IniFile_Load_NextLine(ini, ini->buffer);
189
0
  rc = TRUE;
190
191
0
out_file:
192
0
  IniFile_Close_File(fp);
193
0
  return rc;
194
0
}
195
196
static BOOL IniFile_Load_HasNextLine(wIniFile* ini)
197
0
{
198
0
  WINPR_ASSERT(ini);
199
200
0
  return (ini->nextLine) ? TRUE : FALSE;
201
0
}
202
203
static char* IniFile_Load_GetNextLine(wIniFile* ini)
204
0
{
205
0
  WINPR_ASSERT(ini);
206
207
0
  ini->line = ini->nextLine;
208
0
  ini->lineLength = strlen(ini->line);
209
0
  IniFile_Load_NextLine(ini, NULL);
210
0
  return ini->line;
211
0
}
212
213
static void IniFile_Key_Free(wIniFileKey* key)
214
0
{
215
0
  if (!key)
216
0
    return;
217
218
0
  free(key->name);
219
0
  free(key->value);
220
0
  free(key);
221
0
}
222
223
static wIniFileKey* IniFile_Key_New(const char* name, const char* value)
224
0
{
225
0
  if (!name || !value)
226
0
    return NULL;
227
228
0
  wIniFileKey* key = calloc(1, sizeof(wIniFileKey));
229
230
0
  if (key)
231
0
  {
232
0
    key->name = _strdup(name);
233
0
    key->value = _strdup(value);
234
235
0
    if (!key->name || !key->value)
236
0
    {
237
0
      IniFile_Key_Free(key);
238
0
      return NULL;
239
0
    }
240
0
  }
241
242
0
  return key;
243
0
}
244
245
static void IniFile_Section_Free(wIniFileSection* section)
246
0
{
247
0
  if (!section)
248
0
    return;
249
250
0
  free(section->name);
251
252
0
  for (size_t index = 0; index < section->nKeys; index++)
253
0
  {
254
0
    IniFile_Key_Free(section->keys[index]);
255
0
  }
256
257
0
  free(section->keys);
258
0
  free(section);
259
0
}
260
261
static BOOL IniFile_SectionKeysResize(wIniFileSection* section, size_t count)
262
0
{
263
0
  WINPR_ASSERT(section);
264
265
0
  if (section->nKeys + count >= section->cKeys)
266
0
  {
267
0
    const size_t new_size = section->cKeys + count + 1024;
268
0
    const size_t diff = new_size - section->cKeys;
269
0
    wIniFileKey** new_keys =
270
0
        (wIniFileKey**)realloc(section->keys, sizeof(wIniFileKey*) * new_size);
271
272
0
    if (!new_keys)
273
0
      return FALSE;
274
275
0
    memset(&new_keys[section->cKeys], 0, diff * sizeof(wIniFileKey*));
276
0
    section->cKeys = new_size;
277
0
    section->keys = new_keys;
278
0
  }
279
0
  return TRUE;
280
0
}
281
282
static wIniFileSection* IniFile_Section_New(const char* name)
283
0
{
284
0
  if (!name)
285
0
    return NULL;
286
287
0
  wIniFileSection* section = calloc(1, sizeof(wIniFileSection));
288
289
0
  if (!section)
290
0
    goto fail;
291
292
0
  section->name = _strdup(name);
293
294
0
  if (!section->name)
295
0
    goto fail;
296
297
0
  if (!IniFile_SectionKeysResize(section, 64))
298
0
    goto fail;
299
300
0
  return section;
301
302
0
fail:
303
0
  IniFile_Section_Free(section);
304
0
  return NULL;
305
0
}
306
307
static wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
308
0
{
309
0
  wIniFileSection* section = NULL;
310
311
0
  WINPR_ASSERT(ini);
312
313
0
  if (!name)
314
0
    return NULL;
315
316
0
  for (size_t index = 0; index < ini->nSections; index++)
317
0
  {
318
0
    if (_stricmp(name, ini->sections[index]->name) == 0)
319
0
    {
320
0
      section = ini->sections[index];
321
0
      break;
322
0
    }
323
0
  }
324
325
0
  return section;
326
0
}
327
328
static BOOL IniFile_SectionResize(wIniFile* ini, size_t count)
329
0
{
330
0
  WINPR_ASSERT(ini);
331
332
0
  if (ini->nSections + count >= ini->cSections)
333
0
  {
334
0
    const size_t new_size = ini->cSections + count + 1024;
335
0
    const size_t diff = new_size - ini->cSections;
336
0
    wIniFileSection** new_sect =
337
0
        (wIniFileSection**)realloc(ini->sections, sizeof(wIniFileSection*) * new_size);
338
339
0
    if (!new_sect)
340
0
      return FALSE;
341
342
0
    memset(&new_sect[ini->cSections], 0, diff * sizeof(wIniFileSection*));
343
0
    ini->cSections = new_size;
344
0
    ini->sections = new_sect;
345
0
  }
346
0
  return TRUE;
347
0
}
348
349
static wIniFileSection* IniFile_AddToSection(wIniFile* ini, const char* name)
350
0
{
351
0
  WINPR_ASSERT(ini);
352
353
0
  if (!name)
354
0
    return NULL;
355
356
0
  wIniFileSection* section = IniFile_GetSection(ini, name);
357
358
0
  if (!section)
359
0
  {
360
0
    if (!IniFile_SectionResize(ini, 1))
361
0
      return NULL;
362
363
0
    section = IniFile_Section_New(name);
364
0
    if (!section)
365
0
      return NULL;
366
0
    ini->sections[ini->nSections++] = section;
367
0
  }
368
369
0
  return section;
370
0
}
371
372
static wIniFileKey* IniFile_GetKey(wIniFileSection* section, const char* name)
373
0
{
374
0
  wIniFileKey* key = NULL;
375
376
0
  WINPR_ASSERT(section);
377
378
0
  if (!name)
379
0
    return NULL;
380
381
0
  for (size_t index = 0; index < section->nKeys; index++)
382
0
  {
383
0
    if (_stricmp(name, section->keys[index]->name) == 0)
384
0
    {
385
0
      key = section->keys[index];
386
0
      break;
387
0
    }
388
0
  }
389
390
0
  return key;
391
0
}
392
393
static wIniFileKey* IniFile_AddKey(wIniFileSection* section, const char* name, const char* value)
394
0
{
395
0
  WINPR_ASSERT(section);
396
397
0
  if (!name || !value)
398
0
    return NULL;
399
400
0
  wIniFileKey* key = IniFile_GetKey(section, name);
401
402
0
  if (!key)
403
0
  {
404
0
    if (!IniFile_SectionKeysResize(section, 1))
405
0
      return NULL;
406
407
0
    key = IniFile_Key_New(name, value);
408
409
0
    if (!key)
410
0
      return NULL;
411
412
0
    section->keys[section->nKeys++] = key;
413
0
  }
414
0
  else
415
0
  {
416
0
    free(key->value);
417
0
    key->value = _strdup(value);
418
419
0
    if (!key->value)
420
0
      return NULL;
421
0
  }
422
423
0
  return key;
424
0
}
425
426
static int IniFile_Load(wIniFile* ini)
427
0
{
428
0
  char* name;
429
0
  char* value;
430
0
  char* separator;
431
0
  char *beg, *end;
432
0
  wIniFileSection* section = NULL;
433
434
0
  WINPR_ASSERT(ini);
435
436
0
  while (IniFile_Load_HasNextLine(ini))
437
0
  {
438
0
    char* line = IniFile_Load_GetNextLine(ini);
439
440
0
    if (line[0] == ';')
441
0
      continue;
442
443
0
    if (line[0] == '[')
444
0
    {
445
0
      beg = &line[1];
446
0
      end = strchr(line, ']');
447
448
0
      if (!end)
449
0
        return -1;
450
451
0
      *end = '\0';
452
0
      IniFile_AddToSection(ini, beg);
453
0
      section = ini->sections[ini->nSections - 1];
454
0
    }
455
0
    else
456
0
    {
457
0
      separator = strchr(line, '=');
458
459
0
      if (separator == NULL)
460
0
        return -1;
461
462
0
      end = separator;
463
464
0
      while ((&end[-1] > line) && ((end[-1] == ' ') || (end[-1] == '\t')))
465
0
        end--;
466
467
0
      *end = '\0';
468
0
      name = line;
469
0
      beg = separator + 1;
470
471
0
      while (*beg && ((*beg == ' ') || (*beg == '\t')))
472
0
        beg++;
473
474
0
      if (*beg == '"')
475
0
        beg++;
476
477
0
      end = &line[ini->lineLength];
478
479
0
      while ((end > beg) && ((end[-1] == ' ') || (end[-1] == '\t')))
480
0
        end--;
481
482
0
      if (end[-1] == '"')
483
0
        end[-1] = '\0';
484
485
0
      value = beg;
486
487
0
      if (!IniFile_AddKey(section, name, value))
488
0
        return -1;
489
0
    }
490
0
  }
491
492
0
  return 1;
493
0
}
494
495
static BOOL IniFile_SetFilename(wIniFile* ini, const char* name)
496
0
{
497
0
  WINPR_ASSERT(ini);
498
0
  free(ini->filename);
499
0
  ini->filename = NULL;
500
501
0
  if (!name)
502
0
    return TRUE;
503
0
  ini->filename = _strdup(name);
504
0
  return ini->filename != NULL;
505
0
}
506
507
int IniFile_ReadBuffer(wIniFile* ini, const char* buffer)
508
0
{
509
0
  BOOL status;
510
511
0
  WINPR_ASSERT(ini);
512
513
0
  if (!buffer)
514
0
    return -1;
515
516
0
  ini->readOnly = TRUE;
517
0
  status = IniFile_Load_String(ini, buffer);
518
519
0
  if (!status)
520
0
    return -1;
521
522
0
  return IniFile_Load(ini);
523
0
}
524
525
int IniFile_ReadFile(wIniFile* ini, const char* filename)
526
0
{
527
0
  WINPR_ASSERT(ini);
528
529
0
  ini->readOnly = TRUE;
530
0
  if (!IniFile_SetFilename(ini, filename))
531
0
    return -1;
532
0
  if (!ini->filename)
533
0
    return -1;
534
535
0
  if (!IniFile_Load_File(ini, filename))
536
0
    return -1;
537
538
0
  return IniFile_Load(ini);
539
0
}
540
541
char** IniFile_GetSectionNames(wIniFile* ini, size_t* count)
542
0
{
543
0
  WINPR_ASSERT(ini);
544
545
0
  if (!count)
546
0
    return NULL;
547
548
0
  if (ini->nSections > INT_MAX)
549
0
    return NULL;
550
551
0
  size_t length = (sizeof(char*) * ini->nSections) + sizeof(char);
552
553
0
  for (size_t index = 0; index < ini->nSections; index++)
554
0
  {
555
0
    wIniFileSection* section = ini->sections[index];
556
0
    const size_t nameLength = strlen(section->name);
557
0
    length += (nameLength + 1);
558
0
  }
559
560
0
  char** sectionNames = (char**)calloc(length, sizeof(char*));
561
562
0
  if (!sectionNames)
563
0
    return NULL;
564
565
0
  char* p = (char*)&((BYTE*)sectionNames)[sizeof(char*) * ini->nSections];
566
567
0
  for (size_t index = 0; index < ini->nSections; index++)
568
0
  {
569
0
    sectionNames[index] = p;
570
0
    wIniFileSection* section = ini->sections[index];
571
0
    const size_t nameLength = strlen(section->name);
572
0
    CopyMemory(p, section->name, nameLength + 1);
573
0
    p += (nameLength + 1);
574
0
  }
575
576
0
  *p = '\0';
577
0
  *count = ini->nSections;
578
0
  return sectionNames;
579
0
}
580
581
char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, size_t* count)
582
0
{
583
0
  WINPR_ASSERT(ini);
584
585
0
  if (!section || !count)
586
0
    return NULL;
587
588
0
  wIniFileSection* pSection = IniFile_GetSection(ini, section);
589
590
0
  if (!pSection)
591
0
    return NULL;
592
593
0
  if (pSection->nKeys > INT_MAX)
594
0
    return NULL;
595
596
0
  size_t length = (sizeof(char*) * pSection->nKeys) + sizeof(char);
597
598
0
  for (size_t index = 0; index < pSection->nKeys; index++)
599
0
  {
600
0
    wIniFileKey* pKey = pSection->keys[index];
601
0
    const size_t nameLength = strlen(pKey->name);
602
0
    length += (nameLength + 1);
603
0
  }
604
605
0
  char** keyNames = (char**)calloc(length, sizeof(char*));
606
607
0
  if (!keyNames)
608
0
    return NULL;
609
610
0
  char* p = (char*)&((BYTE*)keyNames)[sizeof(char*) * pSection->nKeys];
611
612
0
  for (size_t index = 0; index < pSection->nKeys; index++)
613
0
  {
614
0
    keyNames[index] = p;
615
0
    wIniFileKey* pKey = pSection->keys[index];
616
0
    const size_t nameLength = strlen(pKey->name);
617
0
    CopyMemory(p, pKey->name, nameLength + 1);
618
0
    p += (nameLength + 1);
619
0
  }
620
621
0
  *p = '\0';
622
0
  *count = pSection->nKeys;
623
0
  return keyNames;
624
0
}
625
626
const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
627
0
{
628
0
  const char* value = NULL;
629
0
  wIniFileKey* pKey = NULL;
630
0
  wIniFileSection* pSection = NULL;
631
632
0
  WINPR_ASSERT(ini);
633
634
0
  pSection = IniFile_GetSection(ini, section);
635
636
0
  if (!pSection)
637
0
    return NULL;
638
639
0
  pKey = IniFile_GetKey(pSection, key);
640
641
0
  if (!pKey)
642
0
    return NULL;
643
644
0
  value = (const char*)pKey->value;
645
0
  return value;
646
0
}
647
648
int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
649
0
{
650
0
  int err;
651
0
  long value = 0;
652
0
  wIniFileKey* pKey = NULL;
653
0
  wIniFileSection* pSection = NULL;
654
655
0
  WINPR_ASSERT(ini);
656
657
0
  pSection = IniFile_GetSection(ini, section);
658
659
0
  if (!pSection)
660
0
    return 0;
661
662
0
  pKey = IniFile_GetKey(pSection, key);
663
664
0
  if (!pKey)
665
0
    return 0;
666
667
0
  err = errno;
668
0
  errno = 0;
669
0
  value = strtol(pKey->value, NULL, 0);
670
0
  if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
671
0
  {
672
0
    errno = err;
673
0
    return 0;
674
0
  }
675
0
  return (int)value;
676
0
}
677
678
int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key,
679
                              const char* value)
680
0
{
681
0
  wIniFileKey* pKey = NULL;
682
683
0
  WINPR_ASSERT(ini);
684
0
  wIniFileSection* pSection = IniFile_GetSection(ini, section);
685
686
0
  if (!pSection)
687
0
    pSection = IniFile_AddToSection(ini, section);
688
689
0
  if (!pSection)
690
0
    return -1;
691
692
0
  pKey = IniFile_AddKey(pSection, key, value);
693
694
0
  if (!pKey)
695
0
    return -1;
696
697
0
  return 1;
698
0
}
699
700
int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value)
701
0
{
702
0
  char strVal[128] = { 0 };
703
0
  wIniFileKey* pKey = NULL;
704
0
  wIniFileSection* pSection = NULL;
705
706
0
  WINPR_ASSERT(ini);
707
708
0
  sprintf_s(strVal, sizeof(strVal), "%d", value);
709
0
  pSection = IniFile_GetSection(ini, section);
710
711
0
  if (!pSection)
712
0
    pSection = IniFile_AddToSection(ini, section);
713
714
0
  if (!pSection)
715
0
    return -1;
716
717
0
  pKey = IniFile_AddKey(pSection, key, strVal);
718
719
0
  if (!pKey)
720
0
    return -1;
721
722
0
  return 1;
723
0
}
724
725
char* IniFile_WriteBuffer(wIniFile* ini)
726
0
{
727
0
  size_t offset = 0;
728
0
  size_t size = 0;
729
0
  char* buffer = NULL;
730
731
0
  WINPR_ASSERT(ini);
732
733
0
  for (size_t i = 0; i < ini->nSections; i++)
734
0
  {
735
0
    wIniFileSection* section = ini->sections[i];
736
0
    size += (strlen(section->name) + 3);
737
738
0
    for (size_t j = 0; j < section->nKeys; j++)
739
0
    {
740
0
      wIniFileKey* key = section->keys[j];
741
0
      size += (strlen(key->name) + strlen(key->value) + 2);
742
0
    }
743
744
0
    size += 1;
745
0
  }
746
747
0
  size += 1;
748
0
  buffer = calloc(size + 1, sizeof(char));
749
750
0
  if (!buffer)
751
0
    return NULL;
752
753
0
  offset = 0;
754
755
0
  for (size_t i = 0; i < ini->nSections; i++)
756
0
  {
757
0
    wIniFileSection* section = ini->sections[i];
758
0
    sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name);
759
0
    offset += (strlen(section->name) + 3);
760
761
0
    for (size_t j = 0; j < section->nKeys; j++)
762
0
    {
763
0
      wIniFileKey* key = section->keys[j];
764
0
      sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value);
765
0
      offset += (strlen(key->name) + strlen(key->value) + 2);
766
0
    }
767
768
0
    sprintf_s(&buffer[offset], size - offset, "\n");
769
0
    offset += 1;
770
0
  }
771
772
0
  return buffer;
773
0
}
774
775
int IniFile_WriteFile(wIniFile* ini, const char* filename)
776
0
{
777
0
  int ret = -1;
778
779
0
  WINPR_ASSERT(ini);
780
781
0
  char* buffer = IniFile_WriteBuffer(ini);
782
783
0
  if (!buffer)
784
0
    return -1;
785
786
0
  const size_t length = strlen(buffer);
787
0
  ini->readOnly = FALSE;
788
789
0
  if (!filename)
790
0
    filename = ini->filename;
791
792
0
  FILE* fp = IniFile_Open_File(ini, filename);
793
0
  if (!fp)
794
0
    goto fail;
795
796
0
  if (fwrite((void*)buffer, length, 1, fp) != 1)
797
0
    goto fail;
798
799
0
  ret = 1;
800
801
0
fail:
802
0
  IniFile_Close_File(fp);
803
0
  free(buffer);
804
0
  return ret;
805
0
}
806
807
void IniFile_Free(wIniFile* ini)
808
0
{
809
0
  if (!ini)
810
0
    return;
811
812
0
  IniFile_SetFilename(ini, NULL);
813
814
0
  for (size_t index = 0; index < ini->nSections; index++)
815
0
    IniFile_Section_Free(ini->sections[index]);
816
817
0
  free(ini->sections);
818
0
  free(ini->buffer);
819
0
  free(ini);
820
0
}
821
822
wIniFile* IniFile_New(void)
823
0
{
824
0
  wIniFile* ini = (wIniFile*)calloc(1, sizeof(wIniFile));
825
826
0
  if (!ini)
827
0
    goto fail;
828
829
0
  if (!IniFile_SectionResize(ini, 64))
830
0
    goto fail;
831
832
0
  return ini;
833
834
0
fail:
835
0
  IniFile_Free(ini);
836
0
  return NULL;
837
0
}
838
839
wIniFile* IniFile_Clone(const wIniFile* ini)
840
0
{
841
0
  if (!ini)
842
0
    return NULL;
843
844
0
  wIniFile* copy = IniFile_New();
845
0
  if (!copy)
846
0
    goto fail;
847
848
0
  copy->lineLength = ini->lineLength;
849
0
  if (!IniFile_SetFilename(copy, ini->filename))
850
0
    goto fail;
851
852
0
  if (ini->buffersize > 0)
853
0
  {
854
0
    if (!IniFile_BufferResize(copy, ini->buffersize))
855
0
      goto fail;
856
0
    memcpy(copy->buffer, ini->buffer, copy->buffersize);
857
0
  }
858
859
0
  copy->readOnly = ini->readOnly;
860
861
0
  for (size_t x = 0; x < ini->nSections; x++)
862
0
  {
863
0
    const wIniFileSection* cur = ini->sections[x];
864
0
    if (!cur)
865
0
      goto fail;
866
867
0
    wIniFileSection* scopy = IniFile_AddToSection(copy, cur->name);
868
0
    if (!scopy)
869
0
      goto fail;
870
871
0
    for (size_t y = 0; y < cur->nKeys; y++)
872
0
    {
873
0
      const wIniFileKey* key = cur->keys[y];
874
0
      if (!key)
875
0
        goto fail;
876
877
0
      IniFile_AddKey(scopy, key->name, key->value);
878
0
    }
879
0
  }
880
0
  return copy;
881
882
0
fail:
883
0
  IniFile_Free(copy);
884
0
  return NULL;
885
0
}