Coverage Report

Created: 2024-05-20 06:11

/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
    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 = 0;
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 = NULL;
429
0
  char* value = NULL;
430
0
  char* separator = NULL;
431
0
  char* beg = NULL;
432
0
  char* end = NULL;
433
0
  wIniFileSection* section = NULL;
434
435
0
  WINPR_ASSERT(ini);
436
437
0
  while (IniFile_Load_HasNextLine(ini))
438
0
  {
439
0
    char* line = IniFile_Load_GetNextLine(ini);
440
441
0
    if (line[0] == ';')
442
0
      continue;
443
444
0
    if (line[0] == '[')
445
0
    {
446
0
      beg = &line[1];
447
0
      end = strchr(line, ']');
448
449
0
      if (!end)
450
0
        return -1;
451
452
0
      *end = '\0';
453
0
      IniFile_AddToSection(ini, beg);
454
0
      section = ini->sections[ini->nSections - 1];
455
0
    }
456
0
    else
457
0
    {
458
0
      separator = strchr(line, '=');
459
460
0
      if (separator == NULL)
461
0
        return -1;
462
463
0
      end = separator;
464
465
0
      while ((&end[-1] > line) && ((end[-1] == ' ') || (end[-1] == '\t')))
466
0
        end--;
467
468
0
      *end = '\0';
469
0
      name = line;
470
0
      beg = separator + 1;
471
472
0
      while (*beg && ((*beg == ' ') || (*beg == '\t')))
473
0
        beg++;
474
475
0
      if (*beg == '"')
476
0
        beg++;
477
478
0
      end = &line[ini->lineLength];
479
480
0
      while ((end > beg) && ((end[-1] == ' ') || (end[-1] == '\t')))
481
0
        end--;
482
483
0
      if (end[-1] == '"')
484
0
        end[-1] = '\0';
485
486
0
      value = beg;
487
488
0
      if (!IniFile_AddKey(section, name, value))
489
0
        return -1;
490
0
    }
491
0
  }
492
493
0
  return 1;
494
0
}
495
496
static BOOL IniFile_SetFilename(wIniFile* ini, const char* name)
497
0
{
498
0
  WINPR_ASSERT(ini);
499
0
  free(ini->filename);
500
0
  ini->filename = NULL;
501
502
0
  if (!name)
503
0
    return TRUE;
504
0
  ini->filename = _strdup(name);
505
0
  return ini->filename != NULL;
506
0
}
507
508
int IniFile_ReadBuffer(wIniFile* ini, const char* buffer)
509
0
{
510
0
  BOOL status = 0;
511
512
0
  WINPR_ASSERT(ini);
513
514
0
  if (!buffer)
515
0
    return -1;
516
517
0
  ini->readOnly = TRUE;
518
0
  status = IniFile_Load_String(ini, buffer);
519
520
0
  if (!status)
521
0
    return -1;
522
523
0
  return IniFile_Load(ini);
524
0
}
525
526
int IniFile_ReadFile(wIniFile* ini, const char* filename)
527
0
{
528
0
  WINPR_ASSERT(ini);
529
530
0
  ini->readOnly = TRUE;
531
0
  if (!IniFile_SetFilename(ini, filename))
532
0
    return -1;
533
0
  if (!ini->filename)
534
0
    return -1;
535
536
0
  if (!IniFile_Load_File(ini, filename))
537
0
    return -1;
538
539
0
  return IniFile_Load(ini);
540
0
}
541
542
char** IniFile_GetSectionNames(wIniFile* ini, size_t* count)
543
0
{
544
0
  WINPR_ASSERT(ini);
545
546
0
  if (!count)
547
0
    return NULL;
548
549
0
  if (ini->nSections > INT_MAX)
550
0
    return NULL;
551
552
0
  size_t length = (sizeof(char*) * ini->nSections) + sizeof(char);
553
554
0
  for (size_t index = 0; index < ini->nSections; index++)
555
0
  {
556
0
    wIniFileSection* section = ini->sections[index];
557
0
    const size_t nameLength = strlen(section->name);
558
0
    length += (nameLength + 1);
559
0
  }
560
561
0
  char** sectionNames = (char**)calloc(length, sizeof(char*));
562
563
0
  if (!sectionNames)
564
0
    return NULL;
565
566
0
  char* p = (char*)&((BYTE*)sectionNames)[sizeof(char*) * ini->nSections];
567
568
0
  for (size_t index = 0; index < ini->nSections; index++)
569
0
  {
570
0
    sectionNames[index] = p;
571
0
    wIniFileSection* section = ini->sections[index];
572
0
    const size_t nameLength = strlen(section->name);
573
0
    CopyMemory(p, section->name, nameLength + 1);
574
0
    p += (nameLength + 1);
575
0
  }
576
577
0
  *p = '\0';
578
0
  *count = ini->nSections;
579
0
  return sectionNames;
580
0
}
581
582
char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, size_t* count)
583
0
{
584
0
  WINPR_ASSERT(ini);
585
586
0
  if (!section || !count)
587
0
    return NULL;
588
589
0
  wIniFileSection* pSection = IniFile_GetSection(ini, section);
590
591
0
  if (!pSection)
592
0
    return NULL;
593
594
0
  if (pSection->nKeys > INT_MAX)
595
0
    return NULL;
596
597
0
  size_t length = (sizeof(char*) * pSection->nKeys) + sizeof(char);
598
599
0
  for (size_t index = 0; index < pSection->nKeys; index++)
600
0
  {
601
0
    wIniFileKey* pKey = pSection->keys[index];
602
0
    const size_t nameLength = strlen(pKey->name);
603
0
    length += (nameLength + 1);
604
0
  }
605
606
0
  char** keyNames = (char**)calloc(length, sizeof(char*));
607
608
0
  if (!keyNames)
609
0
    return NULL;
610
611
0
  char* p = (char*)&((BYTE*)keyNames)[sizeof(char*) * pSection->nKeys];
612
613
0
  for (size_t index = 0; index < pSection->nKeys; index++)
614
0
  {
615
0
    keyNames[index] = p;
616
0
    wIniFileKey* pKey = pSection->keys[index];
617
0
    const size_t nameLength = strlen(pKey->name);
618
0
    CopyMemory(p, pKey->name, nameLength + 1);
619
0
    p += (nameLength + 1);
620
0
  }
621
622
0
  *p = '\0';
623
0
  *count = pSection->nKeys;
624
0
  return keyNames;
625
0
}
626
627
const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
628
0
{
629
0
  const char* value = NULL;
630
0
  wIniFileKey* pKey = NULL;
631
0
  wIniFileSection* pSection = NULL;
632
633
0
  WINPR_ASSERT(ini);
634
635
0
  pSection = IniFile_GetSection(ini, section);
636
637
0
  if (!pSection)
638
0
    return NULL;
639
640
0
  pKey = IniFile_GetKey(pSection, key);
641
642
0
  if (!pKey)
643
0
    return NULL;
644
645
0
  value = (const char*)pKey->value;
646
0
  return value;
647
0
}
648
649
int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
650
0
{
651
0
  int err = 0;
652
0
  long value = 0;
653
0
  wIniFileKey* pKey = NULL;
654
0
  wIniFileSection* pSection = NULL;
655
656
0
  WINPR_ASSERT(ini);
657
658
0
  pSection = IniFile_GetSection(ini, section);
659
660
0
  if (!pSection)
661
0
    return 0;
662
663
0
  pKey = IniFile_GetKey(pSection, key);
664
665
0
  if (!pKey)
666
0
    return 0;
667
668
0
  err = errno;
669
0
  errno = 0;
670
0
  value = strtol(pKey->value, NULL, 0);
671
0
  if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
672
0
  {
673
0
    errno = err;
674
0
    return 0;
675
0
  }
676
0
  return (int)value;
677
0
}
678
679
int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key,
680
                              const char* value)
681
0
{
682
0
  wIniFileKey* pKey = NULL;
683
684
0
  WINPR_ASSERT(ini);
685
0
  wIniFileSection* pSection = IniFile_GetSection(ini, section);
686
687
0
  if (!pSection)
688
0
    pSection = IniFile_AddToSection(ini, section);
689
690
0
  if (!pSection)
691
0
    return -1;
692
693
0
  pKey = IniFile_AddKey(pSection, key, value);
694
695
0
  if (!pKey)
696
0
    return -1;
697
698
0
  return 1;
699
0
}
700
701
int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value)
702
0
{
703
0
  char strVal[128] = { 0 };
704
0
  wIniFileKey* pKey = NULL;
705
0
  wIniFileSection* pSection = NULL;
706
707
0
  WINPR_ASSERT(ini);
708
709
0
  sprintf_s(strVal, sizeof(strVal), "%d", value);
710
0
  pSection = IniFile_GetSection(ini, section);
711
712
0
  if (!pSection)
713
0
    pSection = IniFile_AddToSection(ini, section);
714
715
0
  if (!pSection)
716
0
    return -1;
717
718
0
  pKey = IniFile_AddKey(pSection, key, strVal);
719
720
0
  if (!pKey)
721
0
    return -1;
722
723
0
  return 1;
724
0
}
725
726
char* IniFile_WriteBuffer(wIniFile* ini)
727
0
{
728
0
  size_t offset = 0;
729
0
  size_t size = 0;
730
0
  char* buffer = NULL;
731
732
0
  WINPR_ASSERT(ini);
733
734
0
  for (size_t i = 0; i < ini->nSections; i++)
735
0
  {
736
0
    wIniFileSection* section = ini->sections[i];
737
0
    size += (strlen(section->name) + 3);
738
739
0
    for (size_t j = 0; j < section->nKeys; j++)
740
0
    {
741
0
      wIniFileKey* key = section->keys[j];
742
0
      size += (strlen(key->name) + strlen(key->value) + 2);
743
0
    }
744
745
0
    size += 1;
746
0
  }
747
748
0
  size += 1;
749
0
  buffer = calloc(size + 1, sizeof(char));
750
751
0
  if (!buffer)
752
0
    return NULL;
753
754
0
  offset = 0;
755
756
0
  for (size_t i = 0; i < ini->nSections; i++)
757
0
  {
758
0
    wIniFileSection* section = ini->sections[i];
759
0
    sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name);
760
0
    offset += (strlen(section->name) + 3);
761
762
0
    for (size_t j = 0; j < section->nKeys; j++)
763
0
    {
764
0
      wIniFileKey* key = section->keys[j];
765
0
      sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value);
766
0
      offset += (strlen(key->name) + strlen(key->value) + 2);
767
0
    }
768
769
0
    sprintf_s(&buffer[offset], size - offset, "\n");
770
0
    offset += 1;
771
0
  }
772
773
0
  return buffer;
774
0
}
775
776
int IniFile_WriteFile(wIniFile* ini, const char* filename)
777
0
{
778
0
  int ret = -1;
779
780
0
  WINPR_ASSERT(ini);
781
782
0
  char* buffer = IniFile_WriteBuffer(ini);
783
784
0
  if (!buffer)
785
0
    return -1;
786
787
0
  const size_t length = strlen(buffer);
788
0
  ini->readOnly = FALSE;
789
790
0
  if (!filename)
791
0
    filename = ini->filename;
792
793
0
  FILE* fp = IniFile_Open_File(ini, filename);
794
0
  if (!fp)
795
0
    goto fail;
796
797
0
  if (fwrite((void*)buffer, length, 1, fp) != 1)
798
0
    goto fail;
799
800
0
  ret = 1;
801
802
0
fail:
803
0
  IniFile_Close_File(fp);
804
0
  free(buffer);
805
0
  return ret;
806
0
}
807
808
void IniFile_Free(wIniFile* ini)
809
0
{
810
0
  if (!ini)
811
0
    return;
812
813
0
  IniFile_SetFilename(ini, NULL);
814
815
0
  for (size_t index = 0; index < ini->nSections; index++)
816
0
    IniFile_Section_Free(ini->sections[index]);
817
818
0
  free(ini->sections);
819
0
  free(ini->buffer);
820
0
  free(ini);
821
0
}
822
823
wIniFile* IniFile_New(void)
824
0
{
825
0
  wIniFile* ini = (wIniFile*)calloc(1, sizeof(wIniFile));
826
827
0
  if (!ini)
828
0
    goto fail;
829
830
0
  if (!IniFile_SectionResize(ini, 64))
831
0
    goto fail;
832
833
0
  return ini;
834
835
0
fail:
836
0
  WINPR_PRAGMA_DIAG_PUSH
837
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
838
0
  IniFile_Free(ini);
839
0
  WINPR_PRAGMA_DIAG_POP
840
0
  return NULL;
841
0
}
842
843
wIniFile* IniFile_Clone(const wIniFile* ini)
844
0
{
845
0
  if (!ini)
846
0
    return NULL;
847
848
0
  wIniFile* copy = IniFile_New();
849
0
  if (!copy)
850
0
    goto fail;
851
852
0
  copy->lineLength = ini->lineLength;
853
0
  if (!IniFile_SetFilename(copy, ini->filename))
854
0
    goto fail;
855
856
0
  if (ini->buffersize > 0)
857
0
  {
858
0
    if (!IniFile_BufferResize(copy, ini->buffersize))
859
0
      goto fail;
860
0
    memcpy(copy->buffer, ini->buffer, copy->buffersize);
861
0
  }
862
863
0
  copy->readOnly = ini->readOnly;
864
865
0
  for (size_t x = 0; x < ini->nSections; x++)
866
0
  {
867
0
    const wIniFileSection* cur = ini->sections[x];
868
0
    if (!cur)
869
0
      goto fail;
870
871
0
    wIniFileSection* scopy = IniFile_AddToSection(copy, cur->name);
872
0
    if (!scopy)
873
0
      goto fail;
874
875
0
    for (size_t y = 0; y < cur->nKeys; y++)
876
0
    {
877
0
      const wIniFileKey* key = cur->keys[y];
878
0
      if (!key)
879
0
        goto fail;
880
881
0
      IniFile_AddKey(scopy, key->name, key->value);
882
0
    }
883
0
  }
884
0
  return copy;
885
886
0
fail:
887
0
  IniFile_Free(copy);
888
0
  return NULL;
889
0
}