Coverage Report

Created: 2026-01-09 06:43

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