1 // SoftEther VPN Source Code - Stable Edition Repository
2 // Mayaqua Kernel
3 //
4 // SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0.
5 //
6 // Copyright (c) Daiyuu Nobori.
7 // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
8 // Copyright (c) SoftEther Corporation.
9 // Copyright (c) all contributors on SoftEther VPN project in GitHub.
10 //
11 // All Rights Reserved.
12 //
13 // http://www.softether.org/
14 //
15 // This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project.
16 // Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN
17 //
18 // License: The Apache License, Version 2.0
19 // https://www.apache.org/licenses/LICENSE-2.0
20 //
21 // DISCLAIMER
22 // ==========
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 // SOFTWARE.
31 //
32 // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
33 // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
34 // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
35 // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
36 // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
37 // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
38 // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
39 // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
40 // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
41 // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
42 // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
43 // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
44 // LAW OR COURT RULE.
45 //
46 // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
47 // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
48 // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
49 // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
50 // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
51 // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
52 // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
53 // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
54 // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
55 // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
56 // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
57 // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
58 // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
59 // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
60 // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
61 // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
62 // STATEMENT FOR WARNING AND DISCLAIMER.
63 //
64 // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
65 // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
66 // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
67 //
68 //
69 // SOURCE CODE CONTRIBUTION
70 // ------------------------
71 //
72 // Your contribution to SoftEther VPN Project is much appreciated.
73 // Please send patches to us through GitHub.
74 // Read the SoftEther VPN Patch Acceptance Policy in advance:
75 // http://www.softether.org/5-download/src/9.patch
76 //
77 //
78 // DEAR SECURITY EXPERTS
79 // ---------------------
80 //
81 // If you find a bug or a security vulnerability please kindly inform us
82 // about the problem immediately so that we can fix the security problem
83 // to protect a lot of users around the world as soon as possible.
84 //
85 // Our e-mail address for security reports is:
86 // softether-vpn-security [at] softether.org
87 //
88 // Please note that the above e-mail address is not a technical support
89 // inquiry address. If you need technical assistance, please visit
90 // http://www.softether.org/ and ask your question on the users forum.
91 //
92 // Thank you for your cooperation.
93 //
94 //
95 // NO MEMORY OR RESOURCE LEAKS
96 // ---------------------------
97 //
98 // The memory-leaks and resource-leaks verification under the stress
99 // test has been passed before release this source code.
100
101
102 // Cfg.c
103 // Configuration information manipulation module
104
105 #include <GlobalConst.h>
106
107 #define CFG_C
108
109 #include <stdio.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <wchar.h>
113 #include <stdarg.h>
114 #include <time.h>
115 #include <errno.h>
116 #include <Mayaqua/Mayaqua.h>
117
118 // Create a backup of the configuration file
BackupCfgWEx(CFG_RW * rw,FOLDER * f,wchar_t * original,UINT revision_number)119 void BackupCfgWEx(CFG_RW *rw, FOLDER *f, wchar_t *original, UINT revision_number)
120 {
121 wchar_t dirname[MAX_PATH];
122 wchar_t filename[MAX_PATH];
123 wchar_t fullpath[MAX_PATH];
124 wchar_t datestr[MAX_PATH];
125 SYSTEMTIME st;
126 // Validate arguments
127 if (f == NULL || rw == NULL)
128 {
129 return;
130 }
131
132 // Determine the directory name
133 UniFormat(dirname, sizeof(dirname), L"$backup.%s", original[0] == L'$' ? original + 1 : original);
134
135 // Determine the file name
136 LocalTime(&st);
137 UniFormat(datestr, sizeof(datestr), L"%04u%02u%02u%02u_%s",
138 st.wYear, st.wMonth, st.wDay, st.wHour, original[0] == L'$' ? original + 1 : original);
139
140 if (revision_number == INFINITE)
141 {
142 UniStrCpy(filename, sizeof(filename), datestr);
143 }
144 else
145 {
146 UniFormat(filename, sizeof(filename), L"%08u_%s",
147 revision_number, original[0] == L'$' ? original + 1 : original);
148 }
149
150 // Don't save if the date and time has not been changed
151 if (UniStrCmpi(datestr, rw->LastSavedDateStr) == 0)
152 {
153 return;
154 }
155
156 UniStrCpy(rw->LastSavedDateStr, sizeof(rw->LastSavedDateStr), datestr);
157
158 // Check the existence of file name
159 if (IsFileExistsW(filename))
160 {
161 return;
162 }
163
164 // Create the directory
165 MakeDirW(dirname);
166
167 // Save the file
168 UniFormat(fullpath, sizeof(fullpath), L"%s/%s", dirname, filename);
169 CfgSaveW(f, fullpath);
170 }
171
172 // Close the configuration file R/W
FreeCfgRw(CFG_RW * rw)173 void FreeCfgRw(CFG_RW *rw)
174 {
175 // Validate arguments
176 if (rw == NULL)
177 {
178 return;
179 }
180
181 if (rw->Io != NULL)
182 {
183 FileClose(rw->Io);
184 }
185
186 DeleteLock(rw->lock);
187 Free(rw->FileNameW);
188 Free(rw->FileName);
189 Free(rw);
190 }
191
192 // Writing to the configuration file
SaveCfgRw(CFG_RW * rw,FOLDER * f)193 UINT SaveCfgRw(CFG_RW *rw, FOLDER *f)
194 {
195 return SaveCfgRwEx(rw, f, INFINITE);
196 }
SaveCfgRwEx(CFG_RW * rw,FOLDER * f,UINT revision_number)197 UINT SaveCfgRwEx(CFG_RW *rw, FOLDER *f, UINT revision_number)
198 {
199 UINT ret = 0;
200 // Validate arguments
201 if (rw == NULL || f == NULL)
202 {
203 return 0;
204 }
205
206 Lock(rw->lock);
207 {
208 if (rw->Io != NULL)
209 {
210 FileClose(rw->Io);
211 rw->Io = NULL;
212 }
213
214 if (CfgSaveExW2(rw, f, rw->FileNameW, &ret))
215 {
216 if (rw->DontBackup == false)
217 {
218 BackupCfgWEx(rw, f, rw->FileNameW, revision_number);
219 }
220 }
221 else
222 {
223 ret = 0;
224 }
225
226 rw->Io = FileOpenW(rw->FileNameW, false);
227 }
228 Unlock(rw->lock);
229
230 return ret;
231 }
232
233 // Creating a configuration file R/W
NewCfgRw(FOLDER ** root,char * cfg_name)234 CFG_RW *NewCfgRw(FOLDER **root, char *cfg_name)
235 {
236 return NewCfgRwEx(root, cfg_name, false);
237 }
NewCfgRwW(FOLDER ** root,wchar_t * cfg_name)238 CFG_RW *NewCfgRwW(FOLDER **root, wchar_t *cfg_name)
239 {
240 return NewCfgRwExW(root, cfg_name, false);
241 }
NewCfgRwEx(FOLDER ** root,char * cfg_name,bool dont_backup)242 CFG_RW *NewCfgRwEx(FOLDER **root, char *cfg_name, bool dont_backup)
243 {
244 wchar_t *cfg_name_w = CopyStrToUni(cfg_name);
245 CFG_RW *ret = NewCfgRwExW(root, cfg_name_w, dont_backup);
246
247 Free(cfg_name_w);
248
249 return ret;
250 }
NewCfgRwExW(FOLDER ** root,wchar_t * cfg_name,bool dont_backup)251 CFG_RW *NewCfgRwExW(FOLDER **root, wchar_t *cfg_name, bool dont_backup)
252 {
253 return NewCfgRwEx2W(root, cfg_name, dont_backup, NULL);
254 }
NewCfgRwEx2A(FOLDER ** root,char * cfg_name_a,bool dont_backup,char * template_name_a)255 CFG_RW *NewCfgRwEx2A(FOLDER **root, char *cfg_name_a, bool dont_backup, char *template_name_a)
256 {
257 CFG_RW *ret;
258 wchar_t *cfg_name_w = CopyStrToUni(cfg_name_a);
259 wchar_t *template_name_w = CopyStrToUni(template_name_a);
260
261 ret = NewCfgRwEx2W(root, cfg_name_w, dont_backup, template_name_w);
262
263 Free(cfg_name_w);
264 Free(template_name_w);
265
266 return ret;
267 }
NewCfgRwEx2W(FOLDER ** root,wchar_t * cfg_name,bool dont_backup,wchar_t * template_name)268 CFG_RW *NewCfgRwEx2W(FOLDER **root, wchar_t *cfg_name, bool dont_backup, wchar_t *template_name)
269 {
270 CFG_RW *rw;
271 FOLDER *f;
272 bool loaded_from_template = false;
273 // Validate arguments
274 if (cfg_name == NULL || root == NULL)
275 {
276 return NULL;
277 }
278
279 f = CfgReadW(cfg_name);
280 if (f == NULL)
281 {
282 // Load from template
283 if (UniIsEmptyStr(template_name) == false)
284 {
285 f = CfgReadW(template_name);
286 if (f != NULL)
287 {
288 loaded_from_template = true;
289
290 goto LABEL_CONTIUNE;
291 }
292 }
293
294 rw = ZeroMalloc(sizeof(CFG_RW));
295 rw->lock = NewLock();
296 rw->FileNameW = CopyUniStr(cfg_name);
297 rw->FileName = CopyUniToStr(cfg_name);
298 rw->Io = FileCreateW(cfg_name);
299 *root = NULL;
300 rw->DontBackup = dont_backup;
301
302 return rw;
303 }
304
305 LABEL_CONTIUNE:
306 rw = ZeroMalloc(sizeof(CFG_RW));
307 rw->FileNameW = CopyUniStr(cfg_name);
308 rw->FileName = CopyUniToStr(cfg_name);
309 if (loaded_from_template == false)
310 {
311 rw->Io = FileOpenW(cfg_name, false);
312 }
313 else
314 {
315 rw->Io = FileCreateW(cfg_name);
316 }
317 rw->lock = NewLock();
318
319 *root = f;
320
321 rw->DontBackup = dont_backup;
322
323 return rw;
324 }
325
326 // Copy a file
FileCopy(char * src,char * dst)327 bool FileCopy(char *src, char *dst)
328 {
329 BUF *b;
330 bool ret = false;
331 // Validate arguments
332 if (src == NULL || dst == NULL)
333 {
334 return false;
335 }
336
337 b = ReadDump(src);
338 if (b == NULL)
339 {
340 return false;
341 }
342
343 SeekBuf(b, 0, 0);
344
345 ret = DumpBuf(b, dst);
346
347 FreeBuf(b);
348
349 return ret;
350 }
FileCopyW(wchar_t * src,wchar_t * dst)351 bool FileCopyW(wchar_t *src, wchar_t *dst)
352 {
353 return FileCopyExW(src, dst, true);
354 }
FileCopyExW(wchar_t * src,wchar_t * dst,bool read_lock)355 bool FileCopyExW(wchar_t *src, wchar_t *dst, bool read_lock)
356 {
357 BUF *b;
358 bool ret = false;
359 // Validate arguments
360 if (src == NULL || dst == NULL)
361 {
362 return false;
363 }
364
365 b = ReadDumpExW(src, false);
366 if (b == NULL)
367 {
368 return false;
369 }
370
371 SeekBuf(b, 0, 0);
372
373 ret = DumpBufW(b, dst);
374
375 FreeBuf(b);
376
377 return ret;
378 }
FileCopyExWithEofW(wchar_t * src,wchar_t * dst,bool read_lock)379 bool FileCopyExWithEofW(wchar_t *src, wchar_t *dst, bool read_lock)
380 {
381 BUF *b;
382 bool ret = false;
383 // Validate arguments
384 if (src == NULL || dst == NULL)
385 {
386 return false;
387 }
388
389 b = ReadDumpExW(src, false);
390 if (b == NULL)
391 {
392 return false;
393 }
394
395 SeekBuf(b, b->Size, 0);
396
397 WriteBufChar(b, 0x1A);
398
399 SeekBuf(b, 0, 0);
400
401 ret = DumpBufW(b, dst);
402
403 FreeBuf(b);
404
405 return ret;
406 }
407
408 // Save the settings to a file
CfgSave(FOLDER * f,char * name)409 void CfgSave(FOLDER *f, char *name)
410 {
411 CfgSaveEx(NULL, f, name);
412 }
CfgSaveW(FOLDER * f,wchar_t * name)413 void CfgSaveW(FOLDER *f, wchar_t *name)
414 {
415 CfgSaveExW(NULL, f, name);
416 }
CfgSaveEx(CFG_RW * rw,FOLDER * f,char * name)417 bool CfgSaveEx(CFG_RW *rw, FOLDER *f, char *name)
418 {
419 wchar_t *name_w = CopyStrToUni(name);
420 bool ret = CfgSaveExW(rw, f, name_w);
421
422 Free(name_w);
423
424 return ret;
425 }
CfgSaveExW(CFG_RW * rw,FOLDER * f,wchar_t * name)426 bool CfgSaveExW(CFG_RW *rw, FOLDER *f, wchar_t *name)
427 {
428 return CfgSaveExW2(rw, f, name, NULL);
429 }
CfgSaveExW2(CFG_RW * rw,FOLDER * f,wchar_t * name,UINT * written_size)430 bool CfgSaveExW2(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size)
431 {
432 return CfgSaveExW3(rw, f, name, written_size, IsFileExistsW(SAVE_BINARY_FILE_NAME_SWITCH));
433 }
CfgSaveExW3(CFG_RW * rw,FOLDER * f,wchar_t * name,UINT * written_size,bool write_binary)434 bool CfgSaveExW3(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size, bool write_binary)
435 {
436 wchar_t tmp[MAX_SIZE];
437 bool text = !write_binary;
438 UCHAR hash[SHA1_SIZE];
439 BUF *b;
440 IO *o;
441 bool ret = true;
442 UINT dummy_int = 0;
443 // Validate arguments
444 if (name == NULL || f == NULL)
445 {
446 return false;
447 }
448 if (written_size == NULL)
449 {
450 written_size = &dummy_int;
451 }
452
453 // Convert to buffer
454 b = CfgFolderToBuf(f, text);
455 if (b == NULL)
456 {
457 return false;
458 }
459 // Hash the contents
460 Hash(hash, b->Buf, b->Size, true);
461
462 // Compare the contents to be written with the content which was written last
463 if (rw != NULL)
464 {
465 if (Cmp(hash, rw->LashHash, SHA1_SIZE) == 0)
466 {
467 // Contents are not changed
468 ret = false;
469 }
470 else
471 {
472 Copy(rw->LashHash, hash, SHA1_SIZE);
473 }
474 }
475
476 if (ret || OS_IS_UNIX(GetOsInfo()->OsType))
477 {
478 // Generate a temporary file name
479 UniFormat(tmp, sizeof(tmp), L"%s.log", name);
480 // Copy the file that currently exist to a temporary file
481 // with appending the EOF
482 FileCopyExWithEofW(name, tmp, true);
483
484 // Save the new file
485 o = FileCreateW(name);
486 if (o != NULL)
487 {
488 if (FileWrite(o, b->Buf, b->Size) == false)
489 {
490 // File saving failure
491 FileClose(o);
492 FileDeleteW(name);
493 FileRenameW(tmp, name);
494
495 if (rw != NULL)
496 {
497 Zero(rw->LashHash, sizeof(rw->LashHash));
498 }
499 }
500 else
501 {
502 // Successful saving file
503 FileClose(o);
504
505 // Delete the temporary file
506 FileDeleteW(tmp);
507 }
508 }
509 else
510 {
511 // File saving failure
512 FileRenameW(tmp, name);
513
514 if (rw != NULL)
515 {
516 Zero(rw->LashHash, sizeof(rw->LashHash));
517 }
518 }
519 }
520
521 *written_size = b->Size;
522
523 // Release memory
524 FreeBuf(b);
525
526 return ret;
527 }
528
529 // Read the settings from the file
CfgRead(char * name)530 FOLDER *CfgRead(char *name)
531 {
532 wchar_t *name_w = CopyStrToUni(name);
533 FOLDER *ret = CfgReadW(name_w);
534
535 Free(name_w);
536
537 return ret;
538 }
CfgReadW(wchar_t * name)539 FOLDER *CfgReadW(wchar_t *name)
540 {
541 wchar_t tmp[MAX_SIZE];
542 wchar_t newfile[MAX_SIZE];
543 BUF *b;
544 IO *o;
545 UINT size;
546 void *buf;
547 FOLDER *f;
548 bool delete_new = false;
549 bool binary_file = false;
550 bool invalid_file = false;
551 UCHAR header[8];
552 bool has_eof = false;
553 // Validate arguments
554 if (name == NULL)
555 {
556 return NULL;
557 }
558
559 // Generate a new file name
560 UniFormat(newfile, sizeof(newfile), L"%s.new", name);
561 // Generate a temporary file name
562 UniFormat(tmp, sizeof(tmp), L"%s.log", name);
563
564 // Read the new file if it exists
565 o = FileOpenW(newfile, false);
566 if (o == NULL)
567 {
568 UINT size;
569 // Read the temporary file
570 o = FileOpenW(tmp, false);
571
572 if (o != NULL)
573 {
574 // Check the EOF
575 size = FileSize(o);
576 if (size >= 2)
577 {
578 char c;
579
580 if (FileSeek(o, FILE_BEGIN, size - 1) && FileRead(o, &c, 1) && c == 0x1A && FileSeek(o, FILE_BEGIN, 0))
581 {
582 // EOF ok
583 has_eof = true;
584 }
585 else
586 {
587 // No EOF: file is corrupted
588 FileClose(o);
589 o = NULL;
590 }
591 }
592 }
593 }
594 else
595 {
596 delete_new = true;
597 }
598 if (o == NULL)
599 {
600 // Read the original file if there is no temporary file
601 o = FileOpenW(name, false);
602 }
603 else
604 {
605 // Read the original file too if the size of temporary file is 0
606 if (FileSize(o) == 0)
607 {
608 invalid_file = true;
609 }
610
611 if (invalid_file)
612 {
613 FileClose(o);
614 o = FileOpenW(name, false);
615 }
616 }
617 if (o == NULL)
618 {
619 // Failed to read
620 return NULL;
621 }
622
623 // Read into the buffer
624 size = FileSize(o);
625 if (has_eof)
626 {
627 // Ignore EOF
628 size -= 1;
629 }
630 buf = Malloc(size);
631 FileRead(o, buf, size);
632 b = NewBuf();
633 WriteBuf(b, buf, size);
634 SeekBuf(b, 0, 0);
635
636 // Close the file
637 FileClose(o);
638
639 if (delete_new)
640 {
641 // Delete the new file
642 FileDeleteW(newfile);
643 }
644
645 // If the beginning 8 character of the buffer is "SEVPN_DB", it is binary file
646 ReadBuf(b, header, sizeof(header));
647 if (Cmp(header, TAG_BINARY, 8) == 0)
648 {
649 UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
650 binary_file = true;
651
652 // Check the hash
653 ReadBuf(b, hash1, sizeof(hash1));
654
655 Hash(hash2, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
656
657 if (Cmp(hash1, hash2, SHA1_SIZE) != 0)
658 {
659 // Corrupted file
660 invalid_file = true;
661 FreeBuf(b);
662 return NULL;
663 }
664 }
665
666 SeekBuf(b, 0, 0);
667
668 if (binary_file)
669 {
670 SeekBuf(b, 8 + SHA1_SIZE, 0);
671 }
672
673 // Convert the buffer into a folder
674 if (binary_file == false)
675 {
676 // Text mode
677 f = CfgBufTextToFolder(b);
678 }
679 else
680 {
681 // Binary mode
682 f = CfgBufBinToFolder(b);
683 }
684
685 // Memory release
686 Free(buf);
687 FreeBuf(b);
688
689 FileDeleteW(newfile);
690
691 return f;
692 }
693
694 // Test of Cfg
CfgTest2(FOLDER * f,UINT n)695 void CfgTest2(FOLDER *f, UINT n)
696 {
697 }
698
CfgTest()699 void CfgTest()
700 {
701 #if 0
702 FOLDER *root;
703 BUF *b;
704 Debug("\nCFG Test Begin\n");
705
706 root = CfgCreateFolder(NULL, TAG_ROOT);
707 CfgTest2(root, 5);
708
709 b = CfgFolderToBufText(root);
710 //Print("%s\n", b->Buf);
711 SeekBuf(b, 0, 0);
712
713 CfgDeleteFolder(root);
714
715 DumpBuf(b, "test1.config");
716
717 root = CfgBufTextToFolder(b);
718
719 FreeBuf(b);
720
721 b = CfgFolderToBufText(root);
722 // Print("%s\n", b->Buf);
723 DumpBuf(b, "test2.config");
724 FreeBuf(b);
725
726 CfgSave(root, "test.txt");
727
728 CfgDeleteFolder(root);
729
730 Debug("\nCFG Test End\n");
731 #endif
732 }
733
734 // Read one line
CfgReadNextLine(BUF * b)735 char *CfgReadNextLine(BUF *b)
736 {
737 char *tmp;
738 char *buf;
739 UINT len;
740 // Validate arguments
741 if (b == NULL)
742 {
743 return NULL;
744 }
745
746 // Examine the number of characters up to the next newline
747 tmp = (char *)b->Buf + b->Current;
748 if ((b->Size - b->Current) == 0)
749 {
750 // Read to the end
751 return NULL;
752 }
753 len = 0;
754 while (true)
755 {
756 if (tmp[len] == 13 || tmp[len] == 10)
757 {
758 if (tmp[len] == 13)
759 {
760 if (len < (b->Size - b->Current))
761 {
762 len++;
763 }
764 }
765 break;
766 }
767 len++;
768 if (len >= (b->Size - b->Current))
769 {
770 break;
771 }
772 }
773
774 // Read ahead only 'len' bytes
775 buf = ZeroMalloc(len + 1);
776 ReadBuf(b, buf, len);
777 SeekBuf(b, 1, 1);
778
779 if (StrLen(buf) >= 1)
780 {
781 if (buf[StrLen(buf) - 1] == 13)
782 {
783 buf[StrLen(buf) - 1] = 0;
784 }
785 }
786
787 return buf;
788 }
789
790 // Read the text stream
CfgReadNextTextBUF(BUF * b,FOLDER * current)791 bool CfgReadNextTextBUF(BUF *b, FOLDER *current)
792 {
793 char *buf;
794 TOKEN_LIST *token;
795 char *name;
796 char *string;
797 char *data;
798 bool ret;
799 FOLDER *f;
800
801 // Validate arguments
802 if (b == NULL || current == NULL)
803 {
804 return false;
805 }
806
807 ret = true;
808
809 // Read one line
810 buf = CfgReadNextLine(b);
811 if (buf == NULL)
812 {
813 return false;
814 }
815
816 // Analyze this line
817 token = ParseToken(buf, "\t ");
818 if (token == NULL)
819 {
820 Free(buf);
821 return false;
822 }
823
824 if (token->NumTokens >= 1)
825 {
826 if (!StrCmpi(token->Token[0], TAG_DECLARE))
827 {
828 if (token->NumTokens >= 2)
829 {
830 // declare
831 name = CfgUnescape(token->Token[1]);
832
833 // Create a folder
834 f = CfgCreateFolder(current, name);
835
836 // Read the next folder
837 while (true)
838 {
839 if (CfgReadNextTextBUF(b, f) == false)
840 {
841 break;
842 }
843 }
844
845 Free(name);
846 }
847 }
848 if (!StrCmpi(token->Token[0], "}"))
849 {
850 // end
851 ret = false;
852 }
853 if (token->NumTokens >= 3)
854 {
855 name = CfgUnescape(token->Token[1]);
856 data = token->Token[2];
857
858 if (!StrCmpi(token->Token[0], TAG_STRING))
859 {
860 // string
861 wchar_t *uni;
862 UINT uni_size;
863 string = CfgUnescape(data);
864 uni_size = CalcUtf8ToUni(string, StrLen(string));
865 if (uni_size != 0)
866 {
867 uni = Malloc(uni_size);
868 Utf8ToUni(uni, uni_size, string, StrLen(string));
869 CfgAddUniStr(current, name, uni);
870 Free(uni);
871 }
872 Free(string);
873 }
874 if (!StrCmpi(token->Token[0], TAG_INT))
875 {
876 // uint
877 CfgAddInt(current, name, ToInt(data));
878 }
879 if (!StrCmpi(token->Token[0], TAG_INT64))
880 {
881 // uint64
882 CfgAddInt64(current, name, ToInt64(data));
883 }
884 if (!StrCmpi(token->Token[0], TAG_BOOL))
885 {
886 // bool
887 bool b = false;
888 if (!StrCmpi(data, TAG_TRUE))
889 {
890 b = true;
891 }
892 else if (ToInt(data) != 0)
893 {
894 b = true;
895 }
896 CfgAddBool(current, name, b);
897 }
898 if (!StrCmpi(token->Token[0], TAG_BYTE))
899 {
900 // byte
901 char *unescaped_b64 = CfgUnescape(data);
902 void *tmp = Malloc(StrLen(unescaped_b64) * 4 + 64);
903 int size = B64_Decode(tmp, unescaped_b64, StrLen(unescaped_b64));
904 CfgAddByte(current, name, tmp, size);
905 Free(tmp);
906 Free(unescaped_b64);
907 }
908
909 Free(name);
910 }
911 }
912
913 // Release of the token
914 FreeToken(token);
915
916 Free(buf);
917
918 return ret;
919 }
920
921 // Convert the stream text to a folder
CfgBufTextToFolder(BUF * b)922 FOLDER *CfgBufTextToFolder(BUF *b)
923 {
924 FOLDER *f, *c;
925 // Validate arguments
926 if (b == NULL)
927 {
928 return NULL;
929 }
930
931 // Read recursively from the root folder
932 c = CfgCreateFolder(NULL, "tmp");
933
934 while (true)
935 {
936 // Read the text stream
937 if (CfgReadNextTextBUF(b, c) == false)
938 {
939 break;
940 }
941 }
942
943 // Getting root folder
944 f = CfgGetFolder(c, TAG_ROOT);
945 if (f == NULL)
946 {
947 // Root folder is not found
948 CfgDeleteFolder(c);
949 return NULL;
950 }
951
952 // Remove the reference from tmp folder to the root
953 Delete(c->Folders, f);
954 f->Parent = NULL;
955
956 // Delete the tmp folder
957 CfgDeleteFolder(c);
958
959 // Return the root folder
960 return f;
961 }
962
963 // Read the next folder
CfgReadNextFolderBin(BUF * b,FOLDER * parent)964 void CfgReadNextFolderBin(BUF *b, FOLDER *parent)
965 {
966 char name[MAX_SIZE];
967 FOLDER *f;
968 UINT n, i;
969 UINT size;
970 UCHAR *buf;
971 wchar_t *string;
972 // Validate arguments
973 if (b == NULL || parent == NULL)
974 {
975 return;
976 }
977
978 // Folder name
979 ReadBufStr(b, name, sizeof(name));
980 f = CfgCreateFolder(parent, name);
981
982 // The number of the subfolder
983 n = ReadBufInt(b);
984 for (i = 0;i < n;i++)
985 {
986 // Subfolder
987 CfgReadNextFolderBin(b, f);
988 }
989
990 // The number of items
991 n = ReadBufInt(b);
992 for (i = 0;i < n;i++)
993 {
994 UINT type;
995
996 // Name
997 ReadBufStr(b, name, sizeof(name));
998 // Type
999 type = ReadBufInt(b);
1000
1001 switch (type)
1002 {
1003 case ITEM_TYPE_INT:
1004 // int
1005 CfgAddInt(f, name, ReadBufInt(b));
1006 break;
1007
1008 case ITEM_TYPE_INT64:
1009 // int64
1010 CfgAddInt64(f, name, ReadBufInt64(b));
1011 break;
1012
1013 case ITEM_TYPE_BYTE:
1014 // data
1015 size = ReadBufInt(b);
1016 buf = ZeroMalloc(size);
1017 ReadBuf(b, buf, size);
1018 CfgAddByte(f, name, buf, size);
1019 Free(buf);
1020 break;
1021
1022 case ITEM_TYPE_STRING:
1023 // string
1024 size = ReadBufInt(b);
1025 buf = ZeroMalloc(size + 1);
1026 ReadBuf(b, buf, size);
1027 string = ZeroMalloc(CalcUtf8ToUni(buf, StrLen(buf)) + 4);
1028 Utf8ToUni(string, 0, buf, StrLen(buf));
1029 CfgAddUniStr(f, name, string);
1030 Free(string);
1031 Free(buf);
1032 break;
1033
1034 case ITEM_TYPE_BOOL:
1035 // bool
1036 CfgAddBool(f, name, ReadBufInt(b) == 0 ? false : true);
1037 break;
1038 }
1039 }
1040 }
1041
1042 // Convert the binary to folder
CfgBufBinToFolder(BUF * b)1043 FOLDER *CfgBufBinToFolder(BUF *b)
1044 {
1045 FOLDER *f, *c;
1046 // Validate arguments
1047 if (b == NULL)
1048 {
1049 return NULL;
1050 }
1051
1052 // Create a temporary folder
1053 c = CfgCreateFolder(NULL, "tmp");
1054
1055 // Read a binary
1056 CfgReadNextFolderBin(b, c);
1057
1058 // Get root folder
1059 f = CfgGetFolder(c, TAG_ROOT);
1060 if (f == NULL)
1061 {
1062 // Missing
1063 CfgDeleteFolder(c);
1064 return NULL;
1065 }
1066
1067 Delete(c->Folders, f);
1068 f->Parent = NULL;
1069
1070 CfgDeleteFolder(c);
1071
1072 return f;
1073 }
1074
1075 // Convert the folder to binary
CfgFolderToBufBin(FOLDER * f)1076 BUF *CfgFolderToBufBin(FOLDER *f)
1077 {
1078 BUF *b;
1079 UCHAR hash[SHA1_SIZE];
1080 // Validate arguments
1081 if (f == NULL)
1082 {
1083 return NULL;
1084 }
1085
1086 b = NewBuf();
1087
1088 // Header
1089 WriteBuf(b, TAG_BINARY, 8);
1090
1091 // Hash area
1092 Zero(hash, sizeof(hash));
1093 WriteBuf(b, hash, sizeof(hash));
1094
1095 // Output the root folder (recursive)
1096 CfgOutputFolderBin(b, f);
1097
1098 // Hash
1099 Hash(((UCHAR *)b->Buf) + 8, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
1100
1101 return b;
1102 }
1103
1104 // Convert the folder to a stream text
CfgFolderToBufText(FOLDER * f)1105 BUF *CfgFolderToBufText(FOLDER *f)
1106 {
1107 return CfgFolderToBufTextEx(f, false);
1108 }
CfgFolderToBufTextEx(FOLDER * f,bool no_banner)1109 BUF *CfgFolderToBufTextEx(FOLDER *f, bool no_banner)
1110 {
1111 BUF *b;
1112 // Validate arguments
1113 if (f == NULL)
1114 {
1115 return NULL;
1116 }
1117
1118 // Create a stream
1119 b = NewBuf();
1120
1121 // Copyright notice
1122 if (no_banner == false)
1123 {
1124 WriteBuf(b, TAG_CPYRIGHT, StrLen(TAG_CPYRIGHT));
1125 }
1126
1127 // Output the root folder (recursive)
1128 CfgOutputFolderText(b, f, 0);
1129
1130 return b;
1131 }
1132
1133 // Output the folder contents (Enumerate folders)
CfgEnumFolderProc(FOLDER * f,void * param)1134 bool CfgEnumFolderProc(FOLDER *f, void *param)
1135 {
1136 CFG_ENUM_PARAM *p;
1137 // Validate arguments
1138 if (f == NULL || param == NULL)
1139 {
1140 return false;
1141 }
1142
1143 p = (CFG_ENUM_PARAM *)param;
1144 // Output the folder contents (recursive)
1145 CfgOutputFolderText(p->b, f, p->depth);
1146
1147 return true;
1148 }
1149
1150 // Output the contents of the item (enumeration)
CfgEnumItemProc(ITEM * t,void * param)1151 bool CfgEnumItemProc(ITEM *t, void *param)
1152 {
1153 CFG_ENUM_PARAM *p;
1154 // Validate arguments
1155 if (t == NULL || param == NULL)
1156 {
1157 return false;
1158 }
1159
1160 p = (CFG_ENUM_PARAM *)param;
1161 CfgAddItemText(p->b, t, p->depth);
1162
1163 return true;
1164 }
1165
1166 // Output the folder contents (Recursive, binary)
CfgOutputFolderBin(BUF * b,FOLDER * f)1167 void CfgOutputFolderBin(BUF *b, FOLDER *f)
1168 {
1169 UINT i;
1170 // Validate arguments
1171 if (b == NULL || f == NULL)
1172 {
1173 return;
1174 }
1175
1176 // Folder name
1177 WriteBufStr(b, f->Name);
1178
1179 // The number of the subfolder
1180 WriteBufInt(b, LIST_NUM(f->Folders));
1181
1182 // Subfolder
1183 for (i = 0;i < LIST_NUM(f->Folders);i++)
1184 {
1185 FOLDER *sub = LIST_DATA(f->Folders, i);
1186 CfgOutputFolderBin(b, sub);
1187
1188 if ((i % 100) == 99)
1189 {
1190 YieldCpu();
1191 }
1192 }
1193
1194 // The number of Items
1195 WriteBufInt(b, LIST_NUM(f->Items));
1196
1197 // Item
1198 for (i = 0;i < LIST_NUM(f->Items);i++)
1199 {
1200 char *utf8;
1201 UINT utf8_size;
1202 ITEM *t = LIST_DATA(f->Items, i);
1203
1204 // Item Name
1205 WriteBufStr(b, t->Name);
1206
1207 // Type
1208 WriteBufInt(b, t->Type);
1209
1210 switch (t->Type)
1211 {
1212 case ITEM_TYPE_INT:
1213 // Integer
1214 WriteBufInt(b, *((UINT *)t->Buf));
1215 break;
1216
1217 case ITEM_TYPE_INT64:
1218 // 64-bit integer
1219 WriteBufInt64(b, *((UINT64 *)t->Buf));
1220 break;
1221
1222 case ITEM_TYPE_BYTE:
1223 // Data size
1224 WriteBufInt(b, t->size);
1225 // Data
1226 WriteBuf(b, t->Buf, t->size);
1227 break;
1228
1229 case ITEM_TYPE_STRING:
1230 // String
1231 utf8_size = CalcUniToUtf8((wchar_t *)t->Buf) + 1;
1232 utf8 = ZeroMalloc(utf8_size);
1233 UniToUtf8(utf8, utf8_size, (wchar_t *)t->Buf);
1234 WriteBufInt(b, StrLen(utf8));
1235 WriteBuf(b, utf8, StrLen(utf8));
1236 Free(utf8);
1237 break;
1238
1239 case ITEM_TYPE_BOOL:
1240 // Boolean type
1241 if (*((bool *)t->Buf) == false)
1242 {
1243 WriteBufInt(b, 0);
1244 }
1245 else
1246 {
1247 WriteBufInt(b, 1);
1248 }
1249 break;
1250 }
1251 }
1252 }
1253
1254 // Output the contents of the folder (Recursive, text)
CfgOutputFolderText(BUF * b,FOLDER * f,UINT depth)1255 void CfgOutputFolderText(BUF *b, FOLDER *f, UINT depth)
1256 {
1257 CFG_ENUM_PARAM p;
1258 // Validate arguments
1259 if (b == NULL || f == NULL)
1260 {
1261 return;
1262 }
1263
1264 // Output starting of the folder
1265 CfgAddDeclare(b, f->Name, depth);
1266 depth++;
1267
1268 Zero(&p, sizeof(CFG_ENUM_PARAM));
1269 p.depth = depth;
1270 p.b = b;
1271 p.f = f;
1272
1273 // Enumerate the list of items
1274 CfgEnumItem(f, CfgEnumItemProc, &p);
1275
1276 if (LIST_NUM(f->Folders) != 0 && LIST_NUM(f->Items) != 0)
1277 {
1278 WriteBuf(b, "\r\n", 2);
1279 }
1280
1281 // Enumerate the folder list
1282 CfgEnumFolder(f, CfgEnumFolderProc, &p);
1283 // Output the end of the folder
1284 depth--;
1285 CfgAddEnd(b, depth);
1286
1287 //WriteBuf(b, "\r\n", 2);
1288 }
1289
1290 // Output contents of the item
CfgAddItemText(BUF * b,ITEM * t,UINT depth)1291 void CfgAddItemText(BUF *b, ITEM *t, UINT depth)
1292 {
1293 char *data;
1294 char *sub = NULL;
1295 UINT len;
1296 UINT size;
1297 char *utf8;
1298 UINT utf8_size;
1299 wchar_t *string;
1300 // Validate arguments
1301 if (b == NULL || t == NULL)
1302 {
1303 return;
1304 }
1305
1306 // Process the data by its type
1307 data = NULL;
1308 switch (t->Type)
1309 {
1310 case ITEM_TYPE_INT:
1311 data = Malloc(32);
1312 ToStr(data, *((UINT *)t->Buf));
1313 break;
1314
1315 case ITEM_TYPE_INT64:
1316 data = Malloc(64);
1317 ToStr64(data, *((UINT64 *)t->Buf));
1318 break;
1319
1320 case ITEM_TYPE_BYTE:
1321 data = ZeroMalloc(t->size * 4 + 32);
1322 len = B64_Encode(data, t->Buf, t->size);
1323 data[len] = 0;
1324 break;
1325
1326 case ITEM_TYPE_STRING:
1327 string = t->Buf;
1328 utf8_size = CalcUniToUtf8(string);
1329 utf8_size++;
1330 utf8 = ZeroMalloc(utf8_size);
1331 utf8[0] = 0;
1332 UniToUtf8(utf8, utf8_size, string);
1333 size = utf8_size;
1334 data = utf8;
1335 break;
1336
1337 case ITEM_TYPE_BOOL:
1338 size = 32;
1339 data = Malloc(size);
1340 if (*((bool *)t->Buf) == false)
1341 {
1342 StrCpy(data, size, TAG_FALSE);
1343 }
1344 else
1345 {
1346 StrCpy(data, size, TAG_TRUE);
1347 }
1348 break;
1349 }
1350 if (data == NULL)
1351 {
1352 return;
1353 }
1354
1355 // Output the data line
1356 CfgAddData(b, t->Type, t->Name, data, sub, depth);
1357
1358 // Memory release
1359 Free(data);
1360 if (sub != NULL)
1361 {
1362 Free(sub);
1363 }
1364 }
1365
1366 // Output the data line
CfgAddData(BUF * b,UINT type,char * name,char * data,char * sub,UINT depth)1367 void CfgAddData(BUF *b, UINT type, char *name, char *data, char *sub, UINT depth)
1368 {
1369 char *tmp;
1370 char *name2;
1371 char *data2;
1372 char *sub2 = NULL;
1373 UINT tmp_size;
1374 // Validate arguments
1375 if (b == NULL || type == 0 || name == NULL || data == NULL)
1376 {
1377 return;
1378 }
1379
1380 name2 = CfgEscape(name);
1381 data2 = CfgEscape(data);
1382 if (sub != NULL)
1383 {
1384 sub2 = CfgEscape(sub);
1385 }
1386
1387 tmp_size = StrLen(name2) + StrLen(data2) + 2 + 64 + 1;
1388 tmp = Malloc(tmp_size);
1389
1390 if (sub2 != NULL)
1391 {
1392 StrCpy(tmp, tmp_size, CfgTypeToStr(type));
1393 StrCat(tmp, tmp_size, " ");
1394 StrCat(tmp, tmp_size, name2);
1395 StrCat(tmp, tmp_size, " ");
1396 StrCat(tmp, tmp_size, data2);
1397 StrCat(tmp, tmp_size, " ");
1398 StrCat(tmp, tmp_size, sub2);
1399 }
1400 else
1401 {
1402 StrCpy(tmp, tmp_size, CfgTypeToStr(type));
1403 StrCat(tmp, tmp_size, " ");
1404 StrCat(tmp, tmp_size, name2);
1405 StrCat(tmp, tmp_size, " ");
1406 StrCat(tmp, tmp_size, data2);
1407 }
1408
1409 Free(name2);
1410 Free(data2);
1411 if (sub2 != NULL)
1412 {
1413 Free(sub2);
1414 }
1415 CfgAddLine(b, tmp, depth);
1416 Free(tmp);
1417 }
1418
1419 // Convert the data type string to an integer value
CfgStrToType(char * str)1420 UINT CfgStrToType(char *str)
1421 {
1422 if (!StrCmpi(str, TAG_INT)) return ITEM_TYPE_INT;
1423 if (!StrCmpi(str, TAG_INT64)) return ITEM_TYPE_INT64;
1424 if (!StrCmpi(str, TAG_BYTE)) return ITEM_TYPE_BYTE;
1425 if (!StrCmpi(str, TAG_STRING)) return ITEM_TYPE_STRING;
1426 if (!StrCmpi(str, TAG_BOOL)) return ITEM_TYPE_BOOL;
1427 return 0;
1428 }
1429
1430 // Convert the type of data to a string
CfgTypeToStr(UINT type)1431 char *CfgTypeToStr(UINT type)
1432 {
1433 switch (type)
1434 {
1435 case ITEM_TYPE_INT:
1436 return TAG_INT;
1437 case ITEM_TYPE_INT64:
1438 return TAG_INT64;
1439 case ITEM_TYPE_BYTE:
1440 return TAG_BYTE;
1441 case ITEM_TYPE_STRING:
1442 return TAG_STRING;
1443 case ITEM_TYPE_BOOL:
1444 return TAG_BOOL;
1445 }
1446 return NULL;
1447 }
1448
1449 // Outputs the End line
CfgAddEnd(BUF * b,UINT depth)1450 void CfgAddEnd(BUF *b, UINT depth)
1451 {
1452 // Validate arguments
1453 if (b == NULL)
1454 {
1455 return;
1456 }
1457
1458 CfgAddLine(b, "}", depth);
1459 // CfgAddLine(b, TAG_END, depth);
1460 }
1461
1462 // Outputs the Declare lines
CfgAddDeclare(BUF * b,char * name,UINT depth)1463 void CfgAddDeclare(BUF *b, char *name, UINT depth)
1464 {
1465 char *tmp;
1466 char *name2;
1467 UINT tmp_size;
1468 // Validate arguments
1469 if (b == NULL || name == NULL)
1470 {
1471 return;
1472 }
1473
1474 name2 = CfgEscape(name);
1475
1476 tmp_size = StrLen(name2) + 2 + StrLen(TAG_DECLARE);
1477 tmp = Malloc(tmp_size);
1478
1479 Format(tmp, 0, "%s %s", TAG_DECLARE, name2);
1480 CfgAddLine(b, tmp, depth);
1481 CfgAddLine(b, "{", depth);
1482 Free(tmp);
1483 Free(name2);
1484 }
1485
1486 // Outputs one line
CfgAddLine(BUF * b,char * str,UINT depth)1487 void CfgAddLine(BUF *b, char *str, UINT depth)
1488 {
1489 UINT i;
1490 // Validate arguments
1491 if (b == NULL)
1492 {
1493 return;
1494 }
1495
1496 for (i = 0;i < depth;i++)
1497 {
1498 WriteBuf(b, "\t", 1);
1499 }
1500 WriteBuf(b, str, StrLen(str));
1501 WriteBuf(b, "\r\n", 2);
1502 }
1503
1504 // Convert the folder to a stream
CfgFolderToBuf(FOLDER * f,bool textmode)1505 BUF *CfgFolderToBuf(FOLDER *f, bool textmode)
1506 {
1507 return CfgFolderToBufEx(f, textmode, false);
1508 }
CfgFolderToBufEx(FOLDER * f,bool textmode,bool no_banner)1509 BUF *CfgFolderToBufEx(FOLDER *f, bool textmode, bool no_banner)
1510 {
1511 // Validate arguments
1512 if (f == NULL)
1513 {
1514 return NULL;
1515 }
1516
1517 if (textmode)
1518 {
1519 return CfgFolderToBufTextEx(f, no_banner);
1520 }
1521 else
1522 {
1523 return CfgFolderToBufBin(f);;
1524 }
1525 }
1526
1527 // Escape restoration of the string
CfgUnescape(char * str)1528 char *CfgUnescape(char *str)
1529 {
1530 char *tmp;
1531 char *ret;
1532 char tmp2[16];
1533 UINT len, wp, i;
1534 UINT code;
1535 // Validate arguments
1536 if (str == NULL)
1537 {
1538 return NULL;
1539 }
1540
1541 len = StrLen(str);
1542 tmp = ZeroMalloc(len + 1);
1543 wp = 0;
1544 if (len == 1 && str[0] == '$')
1545 {
1546 // Empty character
1547 tmp[0] = 0;
1548 }
1549 else
1550 {
1551 for (i = 0;i < len;i++)
1552 {
1553 if (str[i] != '$')
1554 {
1555 tmp[wp++] = str[i];
1556 }
1557 else
1558 {
1559 tmp2[0] = '0';
1560 tmp2[1] = 'x';
1561 tmp2[2] = str[i + 1];
1562 tmp2[3] = str[i + 2];
1563 i += 2;
1564 tmp2[4] = 0;
1565 code = ToInt(tmp2);
1566 tmp[wp++] = (char)code;
1567 }
1568 }
1569 }
1570 ret = Malloc(StrLen(tmp) + 1);
1571 StrCpy(ret, StrLen(tmp) + 1, tmp);
1572 Free(tmp);
1573 return ret;
1574 }
1575
1576 // Escape the string
CfgEscape(char * str)1577 char *CfgEscape(char *str)
1578 {
1579 char *tmp;
1580 char *ret;
1581 char tmp2[16];
1582 UINT len;
1583 UINT wp, i;
1584 // Validate arguments
1585 if (str == NULL)
1586 {
1587 return NULL;
1588 }
1589
1590 len = StrLen(str);
1591 tmp = ZeroMalloc(len * 3 + 2);
1592 if (len == 0)
1593 {
1594 // Empty character
1595 StrCpy(tmp, (len * 3 + 2), "$");
1596 }
1597 else
1598 {
1599 // Non null character
1600 wp = 0;
1601 for (i = 0;i < len;i++)
1602 {
1603 if (CfgCheckCharForName(str[i]))
1604 {
1605 tmp[wp++] = str[i];
1606 }
1607 else
1608 {
1609 tmp[wp++] = '$';
1610 Format(tmp2, sizeof(tmp2), "%02X", (UINT)str[i]);
1611 tmp[wp++] = tmp2[0];
1612 tmp[wp++] = tmp2[1];
1613 }
1614 }
1615 }
1616 ret = Malloc(StrLen(tmp) + 1);
1617 StrCpy(ret, 0, tmp);
1618 Free(tmp);
1619 return ret;
1620 }
1621
1622 // Check if the character can be used in the name
CfgCheckCharForName(char c)1623 bool CfgCheckCharForName(char c)
1624 {
1625 if (c >= 0 && c <= 31)
1626 {
1627 return false;
1628 }
1629 if (c == ' ' || c == '\t')
1630 {
1631 return false;
1632 }
1633 if (c == '$')
1634 {
1635 return false;
1636 }
1637 return true;
1638 }
1639
1640 // Get the string type value
CfgGetStr(FOLDER * f,char * name,char * str,UINT size)1641 bool CfgGetStr(FOLDER *f, char *name, char *str, UINT size)
1642 {
1643 wchar_t *tmp;
1644 UINT tmp_size;
1645 // Validate arguments
1646 if (f == NULL || name == NULL || str == NULL)
1647 {
1648 return false;
1649 }
1650
1651 str[0] = 0;
1652
1653 // Get unicode string temporarily
1654 tmp_size = size * 4 + 10; // Just to make sure, a quantity of this amount is secured.
1655 tmp = Malloc(tmp_size);
1656 if (CfgGetUniStr(f, name, tmp, tmp_size) == false)
1657 {
1658 // Failure
1659 Free(tmp);
1660 return false;
1661 }
1662
1663 // Copy to the ANSI string
1664 UniToStr(str, size, tmp);
1665 Free(tmp);
1666
1667 return true;
1668 }
1669
1670 // Get the value of the unicode_string type
CfgGetUniStr(FOLDER * f,char * name,wchar_t * str,UINT size)1671 bool CfgGetUniStr(FOLDER *f, char *name, wchar_t *str, UINT size)
1672 {
1673 ITEM *t;
1674 // Validate arguments
1675 if (f == NULL || name == NULL || str == NULL)
1676 {
1677 return false;
1678 }
1679
1680 str[0] = 0;
1681
1682 t = CfgFindItem(f, name);
1683 if (t == NULL)
1684 {
1685 return false;
1686 }
1687 if (t->Type != ITEM_TYPE_STRING)
1688 {
1689 return false;
1690 }
1691 UniStrCpy(str, size, t->Buf);
1692 return true;
1693 }
1694
1695 // Check for the existence of a folder
CfgIsFolder(FOLDER * f,char * name)1696 bool CfgIsFolder(FOLDER *f, char *name)
1697 {
1698 // Validate arguments
1699 if (f == NULL || name == NULL)
1700 {
1701 return false;
1702 }
1703
1704 return (CfgGetFolder(f, name) == NULL) ? false : true;
1705 }
1706
1707 // Check for the existence of item
CfgIsItem(FOLDER * f,char * name)1708 bool CfgIsItem(FOLDER *f, char *name)
1709 {
1710 ITEM *t;
1711 // Validate arguments
1712 if (f == NULL || name == NULL)
1713 {
1714 return false;
1715 }
1716
1717 t = CfgFindItem(f, name);
1718 if (t == NULL)
1719 {
1720 return false;
1721 }
1722
1723 return true;
1724 }
1725
1726 // Get the byte[] type as a BUF
CfgGetBuf(FOLDER * f,char * name)1727 BUF *CfgGetBuf(FOLDER *f, char *name)
1728 {
1729 ITEM *t;
1730 BUF *b;
1731 // Validate arguments
1732 if (f == NULL || name == NULL)
1733 {
1734 return NULL;
1735 }
1736
1737 t = CfgFindItem(f, name);
1738 if (t == NULL)
1739 {
1740 return NULL;
1741 }
1742
1743 b = NewBuf();
1744 WriteBuf(b, t->Buf, t->size);
1745 SeekBuf(b, 0, 0);
1746
1747 return b;
1748 }
1749
1750 // Get the value of type byte[]
CfgGetByte(FOLDER * f,char * name,void * buf,UINT size)1751 UINT CfgGetByte(FOLDER *f, char *name, void *buf, UINT size)
1752 {
1753 ITEM *t;
1754 // Validate arguments
1755 if (f == NULL || name == NULL || buf == NULL)
1756 {
1757 return 0;
1758 }
1759
1760 t = CfgFindItem(f, name);
1761 if (t == NULL)
1762 {
1763 return 0;
1764 }
1765 if (t->Type != ITEM_TYPE_BYTE)
1766 {
1767 return 0;
1768 }
1769 if (t->size <= size)
1770 {
1771 Copy(buf, t->Buf, t->size);
1772 return t->size;
1773 }
1774 else
1775 {
1776 Copy(buf, t->Buf, size);
1777 return t->size;
1778 }
1779 }
1780
1781 // Get the value of type int64
CfgGetInt64(FOLDER * f,char * name)1782 UINT64 CfgGetInt64(FOLDER *f, char *name)
1783 {
1784 ITEM *t;
1785 UINT64 *ret;
1786 // Validate arguments
1787 if (f == NULL || name == NULL)
1788 {
1789 return 0;
1790 }
1791
1792 t = CfgFindItem(f, name);
1793 if (t == NULL)
1794 {
1795 return 0;
1796 }
1797 if (t->Type != ITEM_TYPE_INT64)
1798 {
1799 return 0;
1800 }
1801 if (t->size != sizeof(UINT64))
1802 {
1803 return 0;
1804 }
1805
1806 ret = (UINT64 *)t->Buf;
1807 return *ret;
1808 }
1809
1810 // Get the value of the bool type
CfgGetBool(FOLDER * f,char * name)1811 bool CfgGetBool(FOLDER *f, char *name)
1812 {
1813 ITEM *t;
1814 bool *ret;
1815 // Validate arguments
1816 if (f == NULL || name == NULL)
1817 {
1818 return 0;
1819 }
1820
1821 t = CfgFindItem(f, name);
1822 if (t == NULL)
1823 {
1824 return 0;
1825 }
1826 if (t->Type != ITEM_TYPE_BOOL)
1827 {
1828 return 0;
1829 }
1830 if (t->size != sizeof(bool))
1831 {
1832 return 0;
1833 }
1834
1835 ret = (bool *)t->Buf;
1836 if (*ret == false)
1837 {
1838 return false;
1839 }
1840 else
1841 {
1842 return true;
1843 }
1844 }
1845
1846 // Get the value of the int type
CfgGetInt(FOLDER * f,char * name)1847 UINT CfgGetInt(FOLDER *f, char *name)
1848 {
1849 ITEM *t;
1850 UINT *ret;
1851 // Validate arguments
1852 if (f == NULL || name == NULL)
1853 {
1854 return 0;
1855 }
1856
1857 t = CfgFindItem(f, name);
1858 if (t == NULL)
1859 {
1860 return 0;
1861 }
1862 if (t->Type != ITEM_TYPE_INT)
1863 {
1864 return 0;
1865 }
1866 if (t->size != sizeof(UINT))
1867 {
1868 return 0;
1869 }
1870
1871 ret = (UINT *)t->Buf;
1872 return *ret;
1873 }
1874
1875 // Search for an item
CfgFindItem(FOLDER * parent,char * name)1876 ITEM *CfgFindItem(FOLDER *parent, char *name)
1877 {
1878 ITEM *t, tt;
1879 // Validate arguments
1880 if (parent == NULL || name == NULL)
1881 {
1882 return NULL;
1883 }
1884
1885 tt.Name = ZeroMalloc(StrLen(name) + 1);
1886 StrCpy(tt.Name, 0, name);
1887 t = Search(parent->Items, &tt);
1888 Free(tt.Name);
1889
1890 return t;
1891 }
1892
1893 // Get a folder
CfgGetFolder(FOLDER * parent,char * name)1894 FOLDER *CfgGetFolder(FOLDER *parent, char *name)
1895 {
1896 return CfgFindFolder(parent, name);
1897 }
1898
1899 // Search a folder
CfgFindFolder(FOLDER * parent,char * name)1900 FOLDER *CfgFindFolder(FOLDER *parent, char *name)
1901 {
1902 FOLDER *f, ff;
1903 // Validate arguments
1904 if (parent == NULL || name == NULL)
1905 {
1906 return NULL;
1907 }
1908
1909 ff.Name = ZeroMalloc(StrLen(name) + 1);
1910 StrCpy(ff.Name, 0, name);
1911 f = Search(parent->Folders, &ff);
1912 Free(ff.Name);
1913
1914 return f;
1915 }
1916
1917 // Adding a string type
CfgAddStr(FOLDER * f,char * name,char * str)1918 ITEM *CfgAddStr(FOLDER *f, char *name, char *str)
1919 {
1920 wchar_t *tmp;
1921 UINT tmp_size;
1922 ITEM *t;
1923 // Validate arguments
1924 if (f == NULL || name == NULL || str == NULL)
1925 {
1926 return NULL;
1927 }
1928
1929 // Convert to a Unicode string
1930 tmp_size = CalcStrToUni(str);
1931 if (tmp_size == 0)
1932 {
1933 return NULL;
1934 }
1935 tmp = Malloc(tmp_size);
1936 StrToUni(tmp, tmp_size, str);
1937 t = CfgAddUniStr(f, name, tmp);
1938 Free(tmp);
1939
1940 return t;
1941 }
1942
1943 // Add unicode_string type
CfgAddUniStr(FOLDER * f,char * name,wchar_t * str)1944 ITEM *CfgAddUniStr(FOLDER *f, char *name, wchar_t *str)
1945 {
1946 // Validate arguments
1947 if (f == NULL || name == NULL || str == NULL)
1948 {
1949 return NULL;
1950 }
1951
1952 return CfgCreateItem(f, name, ITEM_TYPE_STRING, str, UniStrSize(str));
1953 }
1954
1955 // Add a binary
CfgAddBuf(FOLDER * f,char * name,BUF * b)1956 ITEM *CfgAddBuf(FOLDER *f, char *name, BUF *b)
1957 {
1958 // Validate arguments
1959 if (f == NULL || name == NULL || b == NULL)
1960 {
1961 return NULL;
1962 }
1963 return CfgAddByte(f, name, b->Buf, b->Size);
1964 }
1965
1966 // Add byte type
CfgAddByte(FOLDER * f,char * name,void * buf,UINT size)1967 ITEM *CfgAddByte(FOLDER *f, char *name, void *buf, UINT size)
1968 {
1969 // Validate arguments
1970 if (f == NULL || name == NULL || buf == NULL)
1971 {
1972 return NULL;
1973 }
1974 return CfgCreateItem(f, name, ITEM_TYPE_BYTE, buf, size);
1975 }
1976
1977 // Add a 64-bit integer type
CfgAddInt64(FOLDER * f,char * name,UINT64 i)1978 ITEM *CfgAddInt64(FOLDER *f, char *name, UINT64 i)
1979 {
1980 // Validate arguments
1981 if (f == NULL || name == NULL)
1982 {
1983 return NULL;
1984 }
1985 return CfgCreateItem(f, name, ITEM_TYPE_INT64, &i, sizeof(UINT64));
1986 }
1987
1988 // Get an IP address type
CfgGetIp(FOLDER * f,char * name,struct IP * ip)1989 bool CfgGetIp(FOLDER *f, char *name, struct IP *ip)
1990 {
1991 char tmp[MAX_SIZE];
1992 // Validate arguments
1993 if (f == NULL || name == NULL || ip == NULL)
1994 {
1995 return false;
1996 }
1997
1998 Zero(ip, sizeof(IP));
1999
2000 if (CfgGetStr(f, name, tmp, sizeof(tmp)) == false)
2001 {
2002 return false;
2003 }
2004
2005 if (StrToIP(ip, tmp) == false)
2006 {
2007 return false;
2008 }
2009
2010 return true;
2011 }
CfgGetIp32(FOLDER * f,char * name)2012 UINT CfgGetIp32(FOLDER *f, char *name)
2013 {
2014 IP p;
2015 // Validate arguments
2016 if (f == NULL || name == NULL)
2017 {
2018 return 0;
2019 }
2020
2021 if (CfgGetIp(f, name, &p) == false)
2022 {
2023 return 0;
2024 }
2025
2026 return IPToUINT(&p);
2027 }
CfgGetIp6Addr(FOLDER * f,char * name,IPV6_ADDR * addr)2028 bool CfgGetIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
2029 {
2030 IP ip;
2031 // Validate arguments
2032 Zero(addr, sizeof(IPV6_ADDR));
2033 if (f == NULL || name == NULL || addr == NULL)
2034 {
2035 return false;
2036 }
2037
2038 if (CfgGetIp(f, name, &ip) == false)
2039 {
2040 return false;
2041 }
2042
2043 if (IsIP6(&ip) == false)
2044 {
2045 return false;
2046 }
2047
2048 if (IPToIPv6Addr(addr, &ip) == false)
2049 {
2050 return false;
2051 }
2052
2053 return true;
2054 }
2055
2056 // Add an IP address type
CfgAddIp(FOLDER * f,char * name,struct IP * ip)2057 ITEM *CfgAddIp(FOLDER *f, char *name, struct IP *ip)
2058 {
2059 char tmp[MAX_SIZE];
2060 // Validate arguments
2061 if (f == NULL || name == NULL || ip == NULL)
2062 {
2063 return NULL;
2064 }
2065
2066 IPToStr(tmp, sizeof(tmp), ip);
2067
2068 return CfgAddStr(f, name, tmp);
2069 }
CfgAddIp32(FOLDER * f,char * name,UINT ip)2070 ITEM *CfgAddIp32(FOLDER *f, char *name, UINT ip)
2071 {
2072 IP p;
2073 // Validate arguments
2074 if (f == NULL || name == NULL)
2075 {
2076 return NULL;
2077 }
2078
2079 UINTToIP(&p, ip);
2080
2081 return CfgAddIp(f, name, &p);
2082 }
CfgAddIp6Addr(FOLDER * f,char * name,IPV6_ADDR * addr)2083 ITEM *CfgAddIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
2084 {
2085 IP ip;
2086 // Validate arguments
2087 if (f == NULL || name == NULL || addr == NULL)
2088 {
2089 return NULL;
2090 }
2091
2092 IPv6AddrToIP(&ip, addr);
2093
2094 return CfgAddIp(f, name, &ip);
2095 }
2096
2097 // Add an integer type
CfgAddInt(FOLDER * f,char * name,UINT i)2098 ITEM *CfgAddInt(FOLDER *f, char *name, UINT i)
2099 {
2100 // Validate arguments
2101 if (f == NULL || name == NULL)
2102 {
2103 return NULL;
2104 }
2105 return CfgCreateItem(f, name, ITEM_TYPE_INT, &i, sizeof(UINT));
2106 }
2107
2108 // Adding a bool type
CfgAddBool(FOLDER * f,char * name,bool b)2109 ITEM *CfgAddBool(FOLDER *f, char *name, bool b)
2110 {
2111 bool v;
2112 // Validate arguments
2113 if (f == NULL || name == NULL)
2114 {
2115 return NULL;
2116 }
2117
2118 v = b ? 1 : 0;
2119 return CfgCreateItem(f, name, ITEM_TYPE_BOOL, &b, sizeof(bool));
2120 }
2121
2122 // Comparison function of the item names
CmpItemName(void * p1,void * p2)2123 int CmpItemName(void *p1, void *p2)
2124 {
2125 ITEM *f1, *f2;
2126 if (p1 == NULL || p2 == NULL)
2127 {
2128 return 0;
2129 }
2130 f1 = *(ITEM **)p1;
2131 f2 = *(ITEM **)p2;
2132 if (f1 == NULL || f2 == NULL)
2133 {
2134 return 0;
2135 }
2136 return StrCmpi(f1->Name, f2->Name);
2137 }
2138
2139 // Comparison function of the folder names
CmpFolderName(void * p1,void * p2)2140 int CmpFolderName(void *p1, void *p2)
2141 {
2142 FOLDER *f1, *f2;
2143 if (p1 == NULL || p2 == NULL)
2144 {
2145 return 0;
2146 }
2147 f1 = *(FOLDER **)p1;
2148 f2 = *(FOLDER **)p2;
2149 if (f1 == NULL || f2 == NULL)
2150 {
2151 return 0;
2152 }
2153 return StrCmpi(f1->Name, f2->Name);
2154 }
2155
2156 // Enumeration of items
CfgEnumItem(FOLDER * f,ENUM_ITEM proc,void * param)2157 void CfgEnumItem(FOLDER *f, ENUM_ITEM proc, void *param)
2158 {
2159 UINT i;
2160 // Validate arguments
2161 if (f == NULL || proc == NULL)
2162 {
2163 return;
2164 }
2165
2166 for (i = 0;i < LIST_NUM(f->Items);i++)
2167 {
2168 ITEM *tt = LIST_DATA(f->Items, i);
2169 if (proc(tt, param) == false)
2170 {
2171 break;
2172 }
2173 }
2174 }
2175
2176 // Enumerate the folders and store it in the token list
CfgEnumFolderToTokenList(FOLDER * f)2177 TOKEN_LIST *CfgEnumFolderToTokenList(FOLDER *f)
2178 {
2179 TOKEN_LIST *t, *ret;
2180 UINT i;
2181 // Validate arguments
2182 if (f == NULL)
2183 {
2184 return NULL;
2185 }
2186
2187 t = ZeroMalloc(sizeof(TOKEN_LIST));
2188 t->NumTokens = LIST_NUM(f->Folders);
2189 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
2190
2191 for (i = 0;i < t->NumTokens;i++)
2192 {
2193 FOLDER *ff = LIST_DATA(f->Folders, i);
2194 t->Token[i] = CopyStr(ff->Name);
2195 }
2196
2197 ret = UniqueToken(t);
2198 FreeToken(t);
2199
2200 return ret;
2201 }
2202
2203 // Enumerate items and store these to the token list
CfgEnumItemToTokenList(FOLDER * f)2204 TOKEN_LIST *CfgEnumItemToTokenList(FOLDER *f)
2205 {
2206 TOKEN_LIST *t, *ret;
2207 UINT i;
2208 // Validate arguments
2209 if (f == NULL)
2210 {
2211 return NULL;
2212 }
2213
2214 t = ZeroMalloc(sizeof(TOKEN_LIST));
2215 t->NumTokens = LIST_NUM(f->Items);
2216 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
2217
2218 for (i = 0;i < t->NumTokens;i++)
2219 {
2220 FOLDER *ff = LIST_DATA(f->Items, i);
2221 t->Token[i] = CopyStr(ff->Name);
2222 }
2223
2224 ret = UniqueToken(t);
2225 FreeToken(t);
2226
2227 return ret;
2228 }
2229
2230 // Folder enumeration
CfgEnumFolder(FOLDER * f,ENUM_FOLDER proc,void * param)2231 void CfgEnumFolder(FOLDER *f, ENUM_FOLDER proc, void *param)
2232 {
2233 UINT i;
2234 // Validate arguments
2235 if (f == NULL || proc == NULL)
2236 {
2237 return;
2238 }
2239
2240 for (i = 0;i < LIST_NUM(f->Folders);i++)
2241 {
2242 FOLDER *ff = LIST_DATA(f->Folders, i);
2243 if (proc(ff, param) == false)
2244 {
2245 break;
2246 }
2247
2248 if ((i % 100) == 99)
2249 {
2250 YieldCpu();
2251 }
2252 }
2253 }
2254
2255 // Create an item
CfgCreateItem(FOLDER * parent,char * name,UINT type,void * buf,UINT size)2256 ITEM *CfgCreateItem(FOLDER *parent, char *name, UINT type, void *buf, UINT size)
2257 {
2258 UINT name_size;
2259 ITEM *t;
2260 #ifdef CHECK_CFG_NAME_EXISTS
2261 ITEM tt;
2262 #endif // CHECK_CFG_NAME_EXISTS
2263 // Validate arguments
2264 if (parent == NULL || name == NULL || type == 0 || buf == NULL)
2265 {
2266 return NULL;
2267 }
2268
2269 name_size = StrLen(name) + 1;
2270
2271 #ifdef CHECK_CFG_NAME_EXISTS
2272
2273 // Check whether there are any items with the same name already
2274 tt.Name = ZeroMalloc(name_size);
2275 StrCpy(tt.Name, 0, name);
2276 t = Search(parent->Items, &tt);
2277 Free(tt.Name);
2278 if (t != NULL)
2279 {
2280 // Duplicated
2281 return NULL;
2282 }
2283
2284 #endif // CHECK_CFG_NAME_EXISTS
2285
2286 t = ZeroMalloc(sizeof(ITEM));
2287 t->Buf = Malloc(size);
2288 Copy(t->Buf, buf, size);
2289 t->Name = ZeroMalloc(name_size);
2290 StrCpy(t->Name, 0, name);
2291 t->Type = type;
2292 t->size = size;
2293 t->Parent = parent;
2294
2295 // Add to the parent list
2296 Insert(parent->Items, t);
2297
2298 return t;
2299 }
2300
2301 // Delete the item
CfgDeleteItem(ITEM * t)2302 void CfgDeleteItem(ITEM *t)
2303 {
2304 // Validate arguments
2305 if (t == NULL)
2306 {
2307 return;
2308 }
2309
2310 // Remove from the parent list
2311 Delete(t->Parent->Items, t);
2312
2313 // Memory release
2314 Free(t->Buf);
2315 Free(t->Name);
2316 Free(t);
2317 }
2318
2319
2320 // Delete the folder
CfgDeleteFolder(FOLDER * f)2321 void CfgDeleteFolder(FOLDER *f)
2322 {
2323 FOLDER **ff;
2324 ITEM **tt;
2325 UINT num, i;
2326 // Validate arguments
2327 if (f == NULL)
2328 {
2329 return;
2330 }
2331
2332 // Remove all subfolders
2333 num = LIST_NUM(f->Folders);
2334 ff = Malloc(sizeof(FOLDER *) * num);
2335 Copy(ff, f->Folders->p, sizeof(FOLDER *) * num);
2336 for (i = 0;i < num;i++)
2337 {
2338 CfgDeleteFolder(ff[i]);
2339 }
2340 Free(ff);
2341
2342 // Remove all items
2343 num = LIST_NUM(f->Items);
2344 tt = Malloc(sizeof(ITEM *) * num);
2345 Copy(tt, f->Items->p, sizeof(ITEM *) * num);
2346 for (i = 0;i < num;i++)
2347 {
2348 CfgDeleteItem(tt[i]);
2349 }
2350 Free(tt);
2351
2352 // Memory release
2353 Free(f->Name);
2354 // Remove from the parent list
2355 if (f->Parent != NULL)
2356 {
2357 Delete(f->Parent->Folders, f);
2358 }
2359 // Release the list
2360 ReleaseList(f->Folders);
2361 ReleaseList(f->Items);
2362
2363 // Release of the memory of the body
2364 Free(f);
2365 }
2366
2367 // Creating a root
CfgCreateRoot()2368 FOLDER *CfgCreateRoot()
2369 {
2370 return CfgCreateFolder(NULL, TAG_ROOT);
2371 }
2372
2373 // Create a folder
CfgCreateFolder(FOLDER * parent,char * name)2374 FOLDER *CfgCreateFolder(FOLDER *parent, char *name)
2375 {
2376 UINT size;
2377 FOLDER *f;
2378 // Validate arguments
2379 if (name == NULL)
2380 {
2381 return NULL;
2382 }
2383
2384 size = StrLen(name) + 1;
2385
2386 #ifdef CHECK_CFG_NAME_EXISTS
2387
2388 // Check the name in the parent list
2389 if (parent != NULL)
2390 {
2391 FOLDER ff;
2392 ff.Name = ZeroMalloc(size);
2393 StrCpy(ff.Name, 0, name);
2394 f = Search(parent->Folders, &ff);
2395 Free(ff.Name);
2396 if (f != NULL)
2397 {
2398 // Folder with the same name already exists
2399 return NULL;
2400 }
2401 }
2402
2403 #endif // CHECK_CFG_NAME_EXISTS
2404
2405 f = ZeroMalloc(sizeof(FOLDER));
2406 f->Items = NewListFast(CmpItemName);
2407 f->Folders = NewListFast(CmpFolderName);
2408 f->Name = ZeroMalloc(size);
2409 StrCpy(f->Name, 0, name);
2410 f->Parent = parent;
2411
2412 // Add to parentlist
2413 if (f->Parent != NULL)
2414 {
2415 Insert(f->Parent->Folders, f);
2416 }
2417 return f;
2418 }
2419
2420
2421