Coverage Report

Created: 2025-07-01 06:46

/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 = 0;
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
    (void)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 NULL;
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
154
0
  WINPR_ASSERT(ini);
155
156
0
  FILE* fp = IniFile_Open_File(ini, filename);
157
0
  if (!fp)
158
0
    return FALSE;
159
160
0
  if (_fseeki64(fp, 0, SEEK_END) < 0)
161
0
    goto out_file;
162
163
0
  const INT64 fileSize = _ftelli64(fp);
164
165
0
  if (fileSize < 0)
166
0
    goto out_file;
167
168
0
  if (_fseeki64(fp, 0, SEEK_SET) < 0)
169
0
    goto out_file;
170
171
0
  ini->line = NULL;
172
0
  ini->nextLine = NULL;
173
174
0
  if (fileSize < 1)
175
0
    goto out_file;
176
177
0
  if (!IniFile_BufferResize(ini, (size_t)fileSize + 2))
178
0
    goto out_file;
179
180
0
  if (fread(ini->buffer, (size_t)fileSize, 1ul, fp) != 1)
181
0
    goto out_file;
182
183
0
  ini->buffer[fileSize] = '\n';
184
0
  ini->buffer[fileSize + 1] = '\0';
185
0
  IniFile_Load_NextLine(ini, ini->buffer);
186
0
  rc = TRUE;
187
188
0
out_file:
189
0
  IniFile_Close_File(fp);
190
0
  return rc;
191
0
}
192
193
static BOOL IniFile_Load_HasNextLine(wIniFile* ini)
194
0
{
195
0
  WINPR_ASSERT(ini);
196
197
0
  return (ini->nextLine) ? TRUE : FALSE;
198
0
}
199
200
static char* IniFile_Load_GetNextLine(wIniFile* ini)
201
0
{
202
0
  WINPR_ASSERT(ini);
203
204
0
  ini->line = ini->nextLine;
205
0
  ini->lineLength = strlen(ini->line);
206
0
  IniFile_Load_NextLine(ini, NULL);
207
0
  return ini->line;
208
0
}
209
210
static void IniFile_Key_Free(wIniFileKey* key)
211
0
{
212
0
  if (!key)
213
0
    return;
214
215
0
  free(key->name);
216
0
  free(key->value);
217
0
  free(key);
218
0
}
219
220
static wIniFileKey* IniFile_Key_New(const char* name, const char* value)
221
0
{
222
0
  if (!name || !value)
223
0
    return NULL;
224
225
0
  wIniFileKey* key = calloc(1, sizeof(wIniFileKey));
226
227
0
  if (key)
228
0
  {
229
0
    key->name = _strdup(name);
230
0
    key->value = _strdup(value);
231
232
0
    if (!key->name || !key->value)
233
0
    {
234
0
      IniFile_Key_Free(key);
235
0
      return NULL;
236
0
    }
237
0
  }
238
239
0
  return key;
240
0
}
241
242
static void IniFile_Section_Free(wIniFileSection* section)
243
0
{
244
0
  if (!section)
245
0
    return;
246
247
0
  free(section->name);
248
249
0
  for (size_t index = 0; index < section->nKeys; index++)
250
0
  {
251
0
    IniFile_Key_Free(section->keys[index]);
252
0
  }
253
254
0
  free((void*)section->keys);
255
0
  free(section);
256
0
}
257
258
static BOOL IniFile_SectionKeysResize(wIniFileSection* section, size_t count)
259
0
{
260
0
  WINPR_ASSERT(section);
261
262
0
  if (section->nKeys + count >= section->cKeys)
263
0
  {
264
0
    const size_t new_size = section->cKeys + count + 1024;
265
0
    const size_t diff = new_size - section->cKeys;
266
0
    wIniFileKey** new_keys =
267
0
        (wIniFileKey**)realloc((void*)section->keys, sizeof(wIniFileKey*) * new_size);
268
269
0
    if (!new_keys)
270
0
      return FALSE;
271
272
0
    memset((void*)&new_keys[section->cKeys], 0, diff * sizeof(wIniFileKey*));
273
0
    section->cKeys = new_size;
274
0
    section->keys = new_keys;
275
0
  }
276
0
  return TRUE;
277
0
}
278
279
static wIniFileSection* IniFile_Section_New(const char* name)
280
0
{
281
0
  if (!name)
282
0
    return NULL;
283
284
0
  wIniFileSection* section = calloc(1, sizeof(wIniFileSection));
285
286
0
  if (!section)
287
0
    goto fail;
288
289
0
  section->name = _strdup(name);
290
291
0
  if (!section->name)
292
0
    goto fail;
293
294
0
  if (!IniFile_SectionKeysResize(section, 64))
295
0
    goto fail;
296
297
0
  return section;
298
299
0
fail:
300
0
  IniFile_Section_Free(section);
301
0
  return NULL;
302
0
}
303
304
static wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
305
0
{
306
0
  wIniFileSection* section = NULL;
307
308
0
  WINPR_ASSERT(ini);
309
310
0
  if (!name)
311
0
    return NULL;
312
313
0
  for (size_t index = 0; index < ini->nSections; index++)
314
0
  {
315
0
    if (_stricmp(name, ini->sections[index]->name) == 0)
316
0
    {
317
0
      section = ini->sections[index];
318
0
      break;
319
0
    }
320
0
  }
321
322
0
  return section;
323
0
}
324
325
static BOOL IniFile_SectionResize(wIniFile* ini, size_t count)
326
0
{
327
0
  WINPR_ASSERT(ini);
328
329
0
  if (ini->nSections + count >= ini->cSections)
330
0
  {
331
0
    const size_t new_size = ini->cSections + count + 1024;
332
0
    const size_t diff = new_size - ini->cSections;
333
0
    wIniFileSection** new_sect =
334
0
        (wIniFileSection**)realloc((void*)ini->sections, sizeof(wIniFileSection*) * new_size);
335
336
0
    if (!new_sect)
337
0
      return FALSE;
338
339
0
    memset((void*)&new_sect[ini->cSections], 0, diff * sizeof(wIniFileSection*));
340
0
    ini->cSections = new_size;
341
0
    ini->sections = new_sect;
342
0
  }
343
0
  return TRUE;
344
0
}
345
346
static wIniFileSection* IniFile_AddToSection(wIniFile* ini, const char* name)
347
0
{
348
0
  WINPR_ASSERT(ini);
349
350
0
  if (!name)
351
0
    return NULL;
352
353
0
  wIniFileSection* section = IniFile_GetSection(ini, name);
354
355
0
  if (!section)
356
0
  {
357
0
    if (!IniFile_SectionResize(ini, 1))
358
0
      return NULL;
359
360
0
    section = IniFile_Section_New(name);
361
0
    if (!section)
362
0
      return NULL;
363
0
    ini->sections[ini->nSections++] = section;
364
0
  }
365
366
0
  return section;
367
0
}
368
369
static wIniFileKey* IniFile_GetKey(wIniFileSection* section, const char* name)
370
0
{
371
0
  wIniFileKey* key = NULL;
372
373
0
  WINPR_ASSERT(section);
374
375
0
  if (!name)
376
0
    return NULL;
377
378
0
  for (size_t index = 0; index < section->nKeys; index++)
379
0
  {
380
0
    if (_stricmp(name, section->keys[index]->name) == 0)
381
0
    {
382
0
      key = section->keys[index];
383
0
      break;
384
0
    }
385
0
  }
386
387
0
  return key;
388
0
}
389
390
static wIniFileKey* IniFile_AddKey(wIniFileSection* section, const char* name, const char* value)
391
0
{
392
0
  WINPR_ASSERT(section);
393
394
0
  if (!name || !value)
395
0
    return NULL;
396
397
0
  wIniFileKey* key = IniFile_GetKey(section, name);
398
399
0
  if (!key)
400
0
  {
401
0
    if (!IniFile_SectionKeysResize(section, 1))
402
0
      return NULL;
403
404
0
    key = IniFile_Key_New(name, value);
405
406
0
    if (!key)
407
0
      return NULL;
408
409
0
    section->keys[section->nKeys++] = key;
410
0
  }
411
0
  else
412
0
  {
413
0
    free(key->value);
414
0
    key->value = _strdup(value);
415
416
0
    if (!key->value)
417
0
      return NULL;
418
0
  }
419
420
0
  return key;
421
0
}
422
423
static int IniFile_Load(wIniFile* ini)
424
0
{
425
0
  char* name = NULL;
426
0
  char* value = NULL;
427
0
  char* separator = NULL;
428
0
  char* beg = NULL;
429
0
  char* end = NULL;
430
0
  wIniFileSection* section = NULL;
431
432
0
  WINPR_ASSERT(ini);
433
434
0
  while (IniFile_Load_HasNextLine(ini))
435
0
  {
436
0
    char* line = IniFile_Load_GetNextLine(ini);
437
438
0
    if (line[0] == ';')
439
0
      continue;
440
441
0
    if (line[0] == '[')
442
0
    {
443
0
      beg = &line[1];
444
0
      end = strchr(line, ']');
445
446
0
      if (!end)
447
0
        return -1;
448
449
0
      *end = '\0';
450
0
      IniFile_AddToSection(ini, beg);
451
0
      section = ini->sections[ini->nSections - 1];
452
0
    }
453
0
    else
454
0
    {
455
0
      separator = strchr(line, '=');
456
457
0
      if (separator == NULL)
458
0
        return -1;
459
460
0
      end = separator;
461
462
0
      while ((&end[-1] > line) && ((end[-1] == ' ') || (end[-1] == '\t')))
463
0
        end--;
464
465
0
      *end = '\0';
466
0
      name = line;
467
0
      beg = separator + 1;
468
469
0
      while (*beg && ((*beg == ' ') || (*beg == '\t')))
470
0
        beg++;
471
472
0
      if (*beg == '"')
473
0
        beg++;
474
475
0
      end = &line[ini->lineLength];
476
477
0
      while ((end > beg) && ((end[-1] == ' ') || (end[-1] == '\t')))
478
0
        end--;
479
480
0
      if (end[-1] == '"')
481
0
        end[-1] = '\0';
482
483
0
      value = beg;
484
485
0
      if (!IniFile_AddKey(section, name, value))
486
0
        return -1;
487
0
    }
488
0
  }
489
490
0
  return 1;
491
0
}
492
493
static BOOL IniFile_SetFilename(wIniFile* ini, const char* name)
494
0
{
495
0
  WINPR_ASSERT(ini);
496
0
  free(ini->filename);
497
0
  ini->filename = NULL;
498
499
0
  if (!name)
500
0
    return TRUE;
501
0
  ini->filename = _strdup(name);
502
0
  return ini->filename != NULL;
503
0
}
504
505
int IniFile_ReadBuffer(wIniFile* ini, const char* buffer)
506
0
{
507
0
  BOOL status = 0;
508
509
0
  WINPR_ASSERT(ini);
510
511
0
  if (!buffer)
512
0
    return -1;
513
514
0
  ini->readOnly = TRUE;
515
0
  status = IniFile_Load_String(ini, buffer);
516
517
0
  if (!status)
518
0
    return -1;
519
520
0
  return IniFile_Load(ini);
521
0
}
522
523
int IniFile_ReadFile(wIniFile* ini, const char* filename)
524
0
{
525
0
  WINPR_ASSERT(ini);
526
527
0
  ini->readOnly = TRUE;
528
0
  if (!IniFile_SetFilename(ini, filename))
529
0
    return -1;
530
0
  if (!ini->filename)
531
0
    return -1;
532
533
0
  if (!IniFile_Load_File(ini, filename))
534
0
    return -1;
535
536
0
  return IniFile_Load(ini);
537
0
}
538
539
char** IniFile_GetSectionNames(wIniFile* ini, size_t* count)
540
0
{
541
0
  WINPR_ASSERT(ini);
542
543
0
  if (!count)
544
0
    return NULL;
545
546
0
  if (ini->nSections > INT_MAX)
547
0
    return NULL;
548
549
0
  size_t length = (sizeof(char*) * ini->nSections) + sizeof(char);
550
551
0
  for (size_t index = 0; index < ini->nSections; index++)
552
0
  {
553
0
    wIniFileSection* section = ini->sections[index];
554
0
    const size_t nameLength = strlen(section->name);
555
0
    length += (nameLength + 1);
556
0
  }
557
558
0
  char** sectionNames = (char**)calloc(length, sizeof(char*));
559
560
0
  if (!sectionNames)
561
0
    return NULL;
562
563
0
  char* p = (char*)&((BYTE*)sectionNames)[sizeof(char*) * ini->nSections];
564
565
0
  for (size_t index = 0; index < ini->nSections; index++)
566
0
  {
567
0
    sectionNames[index] = p;
568
0
    wIniFileSection* section = ini->sections[index];
569
0
    const size_t nameLength = strlen(section->name);
570
0
    CopyMemory(p, section->name, nameLength + 1);
571
0
    p += (nameLength + 1);
572
0
  }
573
574
0
  *p = '\0';
575
0
  *count = ini->nSections;
576
0
  return sectionNames;
577
0
}
578
579
char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, size_t* count)
580
0
{
581
0
  WINPR_ASSERT(ini);
582
583
0
  if (!section || !count)
584
0
    return NULL;
585
586
0
  wIniFileSection* pSection = IniFile_GetSection(ini, section);
587
588
0
  if (!pSection)
589
0
    return NULL;
590
591
0
  if (pSection->nKeys > INT_MAX)
592
0
    return NULL;
593
594
0
  size_t length = (sizeof(char*) * pSection->nKeys) + sizeof(char);
595
596
0
  for (size_t index = 0; index < pSection->nKeys; index++)
597
0
  {
598
0
    wIniFileKey* pKey = pSection->keys[index];
599
0
    const size_t nameLength = strlen(pKey->name);
600
0
    length += (nameLength + 1);
601
0
  }
602
603
0
  char** keyNames = (char**)calloc(length, sizeof(char*));
604
605
0
  if (!keyNames)
606
0
    return NULL;
607
608
0
  char* p = (char*)&((BYTE*)keyNames)[sizeof(char*) * pSection->nKeys];
609
610
0
  for (size_t index = 0; index < pSection->nKeys; index++)
611
0
  {
612
0
    keyNames[index] = p;
613
0
    wIniFileKey* pKey = pSection->keys[index];
614
0
    const size_t nameLength = strlen(pKey->name);
615
0
    CopyMemory(p, pKey->name, nameLength + 1);
616
0
    p += (nameLength + 1);
617
0
  }
618
619
0
  *p = '\0';
620
0
  *count = pSection->nKeys;
621
0
  return keyNames;
622
0
}
623
624
const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
625
0
{
626
0
  const char* value = NULL;
627
0
  wIniFileKey* pKey = NULL;
628
0
  wIniFileSection* pSection = NULL;
629
630
0
  WINPR_ASSERT(ini);
631
632
0
  pSection = IniFile_GetSection(ini, section);
633
634
0
  if (!pSection)
635
0
    return NULL;
636
637
0
  pKey = IniFile_GetKey(pSection, key);
638
639
0
  if (!pKey)
640
0
    return NULL;
641
642
0
  value = (const char*)pKey->value;
643
0
  return value;
644
0
}
645
646
int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
647
0
{
648
0
  int err = 0;
649
0
  long value = 0;
650
0
  wIniFileKey* pKey = NULL;
651
0
  wIniFileSection* pSection = NULL;
652
653
0
  WINPR_ASSERT(ini);
654
655
0
  pSection = IniFile_GetSection(ini, section);
656
657
0
  if (!pSection)
658
0
    return 0;
659
660
0
  pKey = IniFile_GetKey(pSection, key);
661
662
0
  if (!pKey)
663
0
    return 0;
664
665
0
  err = errno;
666
0
  errno = 0;
667
0
  value = strtol(pKey->value, NULL, 0);
668
0
  if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
669
0
  {
670
0
    errno = err;
671
0
    return 0;
672
0
  }
673
0
  return (int)value;
674
0
}
675
676
int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key,
677
                              const char* value)
678
0
{
679
0
  wIniFileKey* pKey = NULL;
680
681
0
  WINPR_ASSERT(ini);
682
0
  wIniFileSection* pSection = IniFile_GetSection(ini, section);
683
684
0
  if (!pSection)
685
0
    pSection = IniFile_AddToSection(ini, section);
686
687
0
  if (!pSection)
688
0
    return -1;
689
690
0
  pKey = IniFile_AddKey(pSection, key, value);
691
692
0
  if (!pKey)
693
0
    return -1;
694
695
0
  return 1;
696
0
}
697
698
int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value)
699
0
{
700
0
  char strVal[128] = { 0 };
701
0
  wIniFileKey* pKey = NULL;
702
0
  wIniFileSection* pSection = NULL;
703
704
0
  WINPR_ASSERT(ini);
705
706
0
  (void)sprintf_s(strVal, sizeof(strVal), "%d", value);
707
0
  pSection = IniFile_GetSection(ini, section);
708
709
0
  if (!pSection)
710
0
    pSection = IniFile_AddToSection(ini, section);
711
712
0
  if (!pSection)
713
0
    return -1;
714
715
0
  pKey = IniFile_AddKey(pSection, key, strVal);
716
717
0
  if (!pKey)
718
0
    return -1;
719
720
0
  return 1;
721
0
}
722
723
char* IniFile_WriteBuffer(wIniFile* ini)
724
0
{
725
0
  size_t offset = 0;
726
0
  size_t size = 0;
727
0
  char* buffer = NULL;
728
729
0
  WINPR_ASSERT(ini);
730
731
0
  for (size_t i = 0; i < ini->nSections; i++)
732
0
  {
733
0
    wIniFileSection* section = ini->sections[i];
734
0
    size += (strlen(section->name) + 3);
735
736
0
    for (size_t j = 0; j < section->nKeys; j++)
737
0
    {
738
0
      wIniFileKey* key = section->keys[j];
739
0
      size += (strlen(key->name) + strlen(key->value) + 2);
740
0
    }
741
742
0
    size += 1;
743
0
  }
744
745
0
  size += 1;
746
0
  buffer = calloc(size + 1, sizeof(char));
747
748
0
  if (!buffer)
749
0
    return NULL;
750
751
0
  offset = 0;
752
753
0
  for (size_t i = 0; i < ini->nSections; i++)
754
0
  {
755
0
    wIniFileSection* section = ini->sections[i];
756
0
    (void)sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name);
757
0
    offset += (strlen(section->name) + 3);
758
759
0
    for (size_t j = 0; j < section->nKeys; j++)
760
0
    {
761
0
      wIniFileKey* key = section->keys[j];
762
0
      (void)sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value);
763
0
      offset += (strlen(key->name) + strlen(key->value) + 2);
764
0
    }
765
766
0
    (void)sprintf_s(&buffer[offset], size - offset, "\n");
767
0
    offset += 1;
768
0
  }
769
770
0
  return buffer;
771
0
}
772
773
int IniFile_WriteFile(wIniFile* ini, const char* filename)
774
0
{
775
0
  int ret = -1;
776
777
0
  WINPR_ASSERT(ini);
778
779
0
  char* buffer = IniFile_WriteBuffer(ini);
780
781
0
  if (!buffer)
782
0
    return -1;
783
784
0
  const size_t length = strlen(buffer);
785
0
  ini->readOnly = FALSE;
786
787
0
  if (!filename)
788
0
    filename = ini->filename;
789
790
0
  FILE* fp = IniFile_Open_File(ini, filename);
791
0
  if (!fp)
792
0
    goto fail;
793
794
0
  if (fwrite((void*)buffer, length, 1, fp) != 1)
795
0
    goto fail;
796
797
0
  ret = 1;
798
799
0
fail:
800
0
  IniFile_Close_File(fp);
801
0
  free(buffer);
802
0
  return ret;
803
0
}
804
805
void IniFile_Free(wIniFile* ini)
806
0
{
807
0
  if (!ini)
808
0
    return;
809
810
0
  IniFile_SetFilename(ini, NULL);
811
812
0
  for (size_t index = 0; index < ini->nSections; index++)
813
0
    IniFile_Section_Free(ini->sections[index]);
814
815
0
  free((void*)ini->sections);
816
0
  free(ini->buffer);
817
0
  free(ini);
818
0
}
819
820
wIniFile* IniFile_New(void)
821
0
{
822
0
  wIniFile* ini = (wIniFile*)calloc(1, sizeof(wIniFile));
823
824
0
  if (!ini)
825
0
    goto fail;
826
827
0
  if (!IniFile_SectionResize(ini, 64))
828
0
    goto fail;
829
830
0
  return ini;
831
832
0
fail:
833
0
  WINPR_PRAGMA_DIAG_PUSH
834
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
835
0
  IniFile_Free(ini);
836
0
  WINPR_PRAGMA_DIAG_POP
837
0
  return NULL;
838
0
}
839
840
wIniFile* IniFile_Clone(const wIniFile* ini)
841
0
{
842
0
  if (!ini)
843
0
    return NULL;
844
845
0
  wIniFile* copy = IniFile_New();
846
0
  if (!copy)
847
0
    goto fail;
848
849
0
  copy->lineLength = ini->lineLength;
850
0
  if (!IniFile_SetFilename(copy, ini->filename))
851
0
    goto fail;
852
853
0
  if (ini->buffersize > 0)
854
0
  {
855
0
    if (!IniFile_BufferResize(copy, ini->buffersize))
856
0
      goto fail;
857
0
    memcpy(copy->buffer, ini->buffer, copy->buffersize);
858
0
  }
859
860
0
  copy->readOnly = ini->readOnly;
861
862
0
  for (size_t x = 0; x < ini->nSections; x++)
863
0
  {
864
0
    const wIniFileSection* cur = ini->sections[x];
865
0
    if (!cur)
866
0
      goto fail;
867
868
0
    wIniFileSection* scopy = IniFile_AddToSection(copy, cur->name);
869
0
    if (!scopy)
870
0
      goto fail;
871
872
0
    for (size_t y = 0; y < cur->nKeys; y++)
873
0
    {
874
0
      const wIniFileKey* key = cur->keys[y];
875
0
      if (!key)
876
0
        goto fail;
877
878
0
      IniFile_AddKey(scopy, key->name, key->value);
879
0
    }
880
0
  }
881
0
  return copy;
882
883
0
fail:
884
0
  IniFile_Free(copy);
885
0
  return NULL;
886
0
}