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