1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-09-19 18:20:40 +03:00
SoftEtherVPN/src/Mayaqua/Cfg.c
Josh Soref ac865f04fc Correct Spelling (#458)
* spelling: accepts

* spelling: account

* spelling: accept

* spelling: accumulate

* spelling: adapter

* spelling: address

* spelling: additional

* spelling: aggressive

* spelling: adhered

* spelling: allowed

* spelling: ambiguous

* spelling: amount

* spelling: anonymous

* spelling: acquisition

* spelling: assemble

* spelling: associated

* spelling: assigns

* spelling: attach

* spelling: attempt

* spelling: attribute

* spelling: authenticate

* spelling: authentication

* spelling: available

* spelling: bridging

* spelling: cascade

* spelling: cancel

* spelling: check

* spelling: challenge

* spelling: changing

* spelling: characters

* spelling: cloud

* spelling: compare

* spelling: communication

* spelling: compatible

* spelling: compatibility

* spelling: completion

* spelling: complete

* spelling: computers

* spelling: configure

* spelling: configuration

* spelling: conformant

* spelling: connection

* spelling: contains

* spelling: continuously

* spelling: continue

* spelling: convert

* spelling: counters

* spelling: create

* spelling: created

* spelling: cumulate

* spelling: currently

* spelling: debugging

* spelling: decryption

* spelling: description

* spelling: default

* spelling: driver

* spelling: delete

* spelling: destination

* spelling: disabled

* spelling: different

* spelling: dynamically

* spelling: directory

* spelling: disappeared

* spelling: disable

* spelling: doesn't

* spelling: download

* spelling: dropped

* spelling: enable

* spelling: established

* spelling: ether

* spelling: except

* spelling: expired

* spelling: field

* spelling: following

* spelling: forever

* spelling: firewall

* spelling: first

* spelling: fragment

* spelling: function

* spelling: gateway

* spelling: identifier

* spelling: identify

* spelling: incoming

* spelling: information

* spelling: initialize

* spelling: injection

* spelling: inner

* spelling: instead

* spelling: installation

* spelling: inserted

* spelling: integer

* spelling: interrupt

* spelling: intuitive

* spelling: interval

* spelling: january

* spelling: keybytes

* spelling: know

* spelling: language

* spelling: length

* spelling: library

* spelling: listener

* spelling: maintain

* spelling: modified

* spelling: necessary

* spelling: number

* spelling: obsoleted

* spelling: occurred

* spelling: occurring

* spelling: occur

* spelling: original

* spelling: omittable

* spelling: omit

* spelling: opening

* spelling: operation

* spelling: packet

* spelling: parameters

* spelling: pointed

* spelling: popupmenuopen

* spelling: privilege

* spelling: product

* spelling: protection

* spelling: promiscuous

* spelling: prompt

* spelling: query

* spelling: random

* spelling: reconnection

* spelling: revocation

* spelling: received

* spelling: red hat

* spelling: registry

* spelling: release

* spelling: retrieve
2018-05-16 23:47:10 +02:00

2429 lines
45 KiB
C

// SoftEther VPN Source Code - Developer Edition Master Branch
// Mayaqua Kernel
//
// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
//
// Copyright (c) Daiyuu Nobori.
// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
// Copyright (c) SoftEther Corporation.
//
// All Rights Reserved.
//
// http://www.softether.org/
//
// Author: Daiyuu Nobori, Ph.D.
// Comments: Tetsuo Sugiyama, Ph.D.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// version 2 as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License version 2
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
//
//
// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
//
// USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS
// YOU HAVE A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY
// CRIMINAL LAWS OR CIVIL RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS
// SOFTWARE IN OTHER COUNTRIES IS COMPLETELY AT YOUR OWN RISK. THE
// SOFTETHER VPN PROJECT HAS DEVELOPED AND DISTRIBUTED THIS SOFTWARE TO
// COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING CIVIL RIGHTS INCLUDING
// PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER COUNTRIES' LAWS OR
// CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES. WE HAVE
// NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
// INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+
// COUNTRIES AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE
// WORLD, WITH DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY
// COUNTRIES' LAWS, REGULATIONS AND CIVIL RIGHTS TO MAKE THE SOFTWARE
// COMPLY WITH ALL COUNTRIES' LAWS BY THE PROJECT. EVEN IF YOU WILL BE
// SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A PUBLIC SERVANT IN YOUR
// COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE LIABLE TO
// RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
// RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT
// JUST A STATEMENT FOR WARNING AND DISCLAIMER.
//
//
// SOURCE CODE CONTRIBUTION
// ------------------------
//
// Your contribution to SoftEther VPN Project is much appreciated.
// Please send patches to us through GitHub.
// Read the SoftEther VPN Patch Acceptance Policy in advance:
// http://www.softether.org/5-download/src/9.patch
//
//
// DEAR SECURITY EXPERTS
// ---------------------
//
// If you find a bug or a security vulnerability please kindly inform us
// about the problem immediately so that we can fix the security problem
// to protect a lot of users around the world as soon as possible.
//
// Our e-mail address for security reports is:
// softether-vpn-security [at] softether.org
//
// Please note that the above e-mail address is not a technical support
// inquiry address. If you need technical assistance, please visit
// http://www.softether.org/ and ask your question on the users forum.
//
// Thank you for your cooperation.
//
//
// NO MEMORY OR RESOURCE LEAKS
// ---------------------------
//
// The memory-leaks and resource-leaks verification under the stress
// test has been passed before release this source code.
// Cfg.c
// Configuration information manipulation module
#include <GlobalConst.h>
#define CFG_C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <Mayaqua/Mayaqua.h>
// Create a backup of the configuration file
void BackupCfgWEx(CFG_RW *rw, FOLDER *f, wchar_t *original, UINT revision_number)
{
wchar_t dirname[MAX_PATH];
wchar_t filename[MAX_PATH];
wchar_t fullpath[MAX_PATH];
wchar_t datestr[MAX_PATH];
SYSTEMTIME st;
// Validate arguments
if (f == NULL || filename == NULL || rw == NULL)
{
return;
}
// Determine the directory name
UniFormat(dirname, sizeof(dirname), L"@backup.%s", original[0] == L'@' ? original + 1 : original);
// Determine the file name
LocalTime(&st);
UniFormat(datestr, sizeof(datestr), L"%04u%02u%02u%02u_%s",
st.wYear, st.wMonth, st.wDay, st.wHour, original[0] == L'@' ? original + 1 : original);
if (revision_number == INFINITE)
{
UniStrCpy(filename, sizeof(filename), datestr);
}
else
{
UniFormat(filename, sizeof(filename), L"%08u_%s",
revision_number, original[0] == L'@' ? original + 1 : original);
}
// Don't save if the date and time has not been changed
if (UniStrCmpi(datestr, rw->LastSavedDateStr) == 0)
{
return;
}
UniStrCpy(rw->LastSavedDateStr, sizeof(rw->LastSavedDateStr), datestr);
// Check the existence of file name
if (IsFileExistsW(filename))
{
return;
}
// Create the directory
MakeDirW(dirname);
// Save the file
UniFormat(fullpath, sizeof(fullpath), L"%s/%s", dirname, filename);
CfgSaveW(f, fullpath);
}
// Close the configuration file R/W
void FreeCfgRw(CFG_RW *rw)
{
// Validate arguments
if (rw == NULL)
{
return;
}
if (rw->Io != NULL)
{
FileClose(rw->Io);
}
DeleteLock(rw->lock);
Free(rw->FileNameW);
Free(rw->FileName);
Free(rw);
}
// Writing to the configuration file
UINT SaveCfgRw(CFG_RW *rw, FOLDER *f)
{
return SaveCfgRwEx(rw, f, INFINITE);
}
UINT SaveCfgRwEx(CFG_RW *rw, FOLDER *f, UINT revision_number)
{
UINT ret = 0;
// Validate arguments
if (rw == NULL || f == NULL)
{
return 0;
}
Lock(rw->lock);
{
if (rw->Io != NULL)
{
FileClose(rw->Io);
rw->Io = NULL;
}
if (CfgSaveExW2(rw, f, rw->FileNameW, &ret))
{
if (rw->DontBackup == false)
{
BackupCfgWEx(rw, f, rw->FileNameW, revision_number);
}
}
else
{
ret = 0;
}
rw->Io = FileOpenW(rw->FileNameW, false);
}
Unlock(rw->lock);
return ret;
}
// Creating a configuration file R/W
CFG_RW *NewCfgRw(FOLDER **root, char *cfg_name)
{
return NewCfgRwEx(root, cfg_name, false);
}
CFG_RW *NewCfgRwW(FOLDER **root, wchar_t *cfg_name)
{
return NewCfgRwExW(root, cfg_name, false);
}
CFG_RW *NewCfgRwEx(FOLDER **root, char *cfg_name, bool dont_backup)
{
wchar_t *cfg_name_w = CopyStrToUni(cfg_name);
CFG_RW *ret = NewCfgRwExW(root, cfg_name_w, dont_backup);
Free(cfg_name_w);
return ret;
}
CFG_RW *NewCfgRwExW(FOLDER **root, wchar_t *cfg_name, bool dont_backup)
{
return NewCfgRwEx2W(root, cfg_name, dont_backup, NULL);
}
CFG_RW *NewCfgRwEx2A(FOLDER **root, char *cfg_name_a, bool dont_backup, char *template_name_a)
{
CFG_RW *ret;
wchar_t *cfg_name_w = CopyStrToUni(cfg_name_a);
wchar_t *template_name_w = CopyStrToUni(template_name_a);
ret = NewCfgRwEx2W(root, cfg_name_w, dont_backup, template_name_w);
Free(cfg_name_w);
Free(template_name_w);
return ret;
}
CFG_RW *NewCfgRwEx2W(FOLDER **root, wchar_t *cfg_name, bool dont_backup, wchar_t *template_name)
{
CFG_RW *rw;
FOLDER *f;
bool loaded_from_template = false;
// Validate arguments
if (cfg_name == NULL || root == NULL)
{
return NULL;
}
f = CfgReadW(cfg_name);
if (f == NULL)
{
// Load from template
if (UniIsEmptyStr(template_name) == false)
{
f = CfgReadW(template_name);
if (f != NULL)
{
loaded_from_template = true;
goto LABEL_CONTINUE;
}
}
rw = ZeroMalloc(sizeof(CFG_RW));
rw->lock = NewLock();
rw->FileNameW = CopyUniStr(cfg_name);
rw->FileName = CopyUniToStr(cfg_name);
rw->Io = FileCreateW(cfg_name);
*root = NULL;
rw->DontBackup = dont_backup;
return rw;
}
LABEL_CONTINUE:
rw = ZeroMalloc(sizeof(CFG_RW));
rw->FileNameW = CopyUniStr(cfg_name);
rw->FileName = CopyUniToStr(cfg_name);
if (loaded_from_template == false)
{
rw->Io = FileOpenW(cfg_name, false);
}
else
{
rw->Io = FileCreateW(cfg_name);
}
rw->lock = NewLock();
*root = f;
rw->DontBackup = dont_backup;
return rw;
}
// Copy a file
bool FileCopy(char *src, char *dst)
{
BUF *b;
bool ret = false;
// Validate arguments
if (src == NULL || dst == NULL)
{
return false;
}
b = ReadDump(src);
if (b == NULL)
{
return false;
}
SeekBuf(b, 0, 0);
ret = DumpBuf(b, dst);
FreeBuf(b);
return ret;
}
bool FileCopyW(wchar_t *src, wchar_t *dst)
{
return FileCopyExW(src, dst, true);
}
bool FileCopyExW(wchar_t *src, wchar_t *dst, bool read_lock)
{
BUF *b;
bool ret = false;
// Validate arguments
if (src == NULL || dst == NULL)
{
return false;
}
b = ReadDumpExW(src, false);
if (b == NULL)
{
return false;
}
SeekBuf(b, 0, 0);
ret = DumpBufW(b, dst);
FreeBuf(b);
return ret;
}
bool FileCopyExWithEofW(wchar_t *src, wchar_t *dst, bool read_lock)
{
BUF *b;
bool ret = false;
// Validate arguments
if (src == NULL || dst == NULL)
{
return false;
}
b = ReadDumpExW(src, false);
if (b == NULL)
{
return false;
}
SeekBuf(b, b->Size, 0);
WriteBufChar(b, 0x1A);
SeekBuf(b, 0, 0);
ret = DumpBufW(b, dst);
FreeBuf(b);
return ret;
}
// Save the settings to a file
void CfgSave(FOLDER *f, char *name)
{
CfgSaveEx(NULL, f, name);
}
void CfgSaveW(FOLDER *f, wchar_t *name)
{
CfgSaveExW(NULL, f, name);
}
bool CfgSaveEx(CFG_RW *rw, FOLDER *f, char *name)
{
wchar_t *name_w = CopyStrToUni(name);
bool ret = CfgSaveExW(rw, f, name_w);
Free(name_w);
return ret;
}
bool CfgSaveExW(CFG_RW *rw, FOLDER *f, wchar_t *name)
{
return CfgSaveExW2(rw, f, name, NULL);
}
bool CfgSaveExW2(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size)
{
return CfgSaveExW3(rw, f, name, written_size, IsFileExistsW(SAVE_BINARY_FILE_NAME_SWITCH));
}
bool CfgSaveExW3(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size, bool write_binary)
{
wchar_t tmp[MAX_SIZE];
bool text = !write_binary;
UCHAR hash[SHA1_SIZE];
BUF *b;
IO *o;
bool ret = true;
UINT dummy_int = 0;
// Validate arguments
if (name == NULL || f == NULL)
{
return false;
}
if (written_size == NULL)
{
written_size = &dummy_int;
}
// Convert to buffer
b = CfgFolderToBuf(f, text);
if (b == NULL)
{
return false;
}
// Hash the contents
Hash(hash, b->Buf, b->Size, true);
// Compare the contents to be written with the content which was written last
if (rw != NULL)
{
if (Cmp(hash, rw->LashHash, SHA1_SIZE) == 0)
{
// Contents are not changed
ret = false;
}
else
{
Copy(rw->LashHash, hash, SHA1_SIZE);
}
}
if (ret || OS_IS_UNIX(GetOsInfo()->OsType))
{
// Generate a temporary file name
UniFormat(tmp, sizeof(tmp), L"%s.log", name);
// Copy the file that currently exist to a temporary file
// with appending the EOF
FileCopyExWithEofW(name, tmp, true);
// Save the new file
o = FileCreateW(name);
if (o != NULL)
{
if (FileWrite(o, b->Buf, b->Size) == false)
{
// File saving failure
FileClose(o);
FileDeleteW(name);
FileRenameW(tmp, name);
if (rw != NULL)
{
Zero(rw->LashHash, sizeof(rw->LashHash));
}
}
else
{
// Successful saving file
FileClose(o);
// Delete the temporary file
FileDeleteW(tmp);
}
}
else
{
// File saving failure
FileRenameW(tmp, name);
if (rw != NULL)
{
Zero(rw->LashHash, sizeof(rw->LashHash));
}
}
}
*written_size = b->Size;
// Release memory
FreeBuf(b);
return ret;
}
// Read the settings from the file
FOLDER *CfgRead(char *name)
{
wchar_t *name_w = CopyStrToUni(name);
FOLDER *ret = CfgReadW(name_w);
Free(name_w);
return ret;
}
FOLDER *CfgReadW(wchar_t *name)
{
wchar_t tmp[MAX_SIZE];
wchar_t newfile[MAX_SIZE];
BUF *b;
IO *o;
UINT size;
void *buf;
FOLDER *f;
bool delete_new = false;
bool binary_file = false;
bool invalid_file = false;
UCHAR header[8];
bool has_eof = false;
// Validate arguments
if (name == NULL)
{
return NULL;
}
// Generate a new file name
UniFormat(newfile, sizeof(newfile), L"%s.new", name);
// Generate a temporary file name
UniFormat(tmp, sizeof(tmp), L"%s.log", name);
// Read the new file if it exists
o = FileOpenW(newfile, false);
if (o == NULL)
{
UINT size;
// Read the temporary file
o = FileOpenW(tmp, false);
if (o != NULL)
{
// Check the EOF
size = FileSize(o);
if (size >= 2)
{
char c;
if (FileSeek(o, FILE_BEGIN, size - 1) && FileRead(o, &c, 1) && c == 0x1A && FileSeek(o, FILE_BEGIN, 0))
{
// EOF ok
has_eof = true;
}
else
{
// No EOF: file is corrupted
FileClose(o);
o = NULL;
}
}
}
}
else
{
delete_new = true;
}
if (o == NULL)
{
// Read the original file if there is no temporary file
o = FileOpenW(name, false);
}
else
{
// Read the original file too if the size of temporary file is 0
if (FileSize(o) == 0)
{
invalid_file = true;
}
if (invalid_file)
{
FileClose(o);
o = FileOpenW(name, false);
}
}
if (o == NULL)
{
// Failed to read
return NULL;
}
// Read into the buffer
size = FileSize(o);
if (has_eof)
{
// Ignore EOF
size -= 1;
}
buf = Malloc(size);
FileRead(o, buf, size);
b = NewBuf();
WriteBuf(b, buf, size);
SeekBuf(b, 0, 0);
// Close the file
FileClose(o);
if (delete_new)
{
// Delete the new file
FileDeleteW(newfile);
}
// If the beginning 8 character of the buffer is "SEVPN_DB", it is binary file
ReadBuf(b, header, sizeof(header));
if (Cmp(header, TAG_BINARY, 8) == 0)
{
UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
binary_file = true;
// Check the hash
ReadBuf(b, hash1, sizeof(hash1));
Hash(hash2, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
if (Cmp(hash1, hash2, SHA1_SIZE) != 0)
{
// Corrupted file
invalid_file = true;
FreeBuf(b);
return NULL;
}
}
SeekBuf(b, 0, 0);
if (binary_file)
{
SeekBuf(b, 8 + SHA1_SIZE, 0);
}
// Convert the buffer into a folder
if (binary_file == false)
{
// Text mode
f = CfgBufTextToFolder(b);
}
else
{
// Binary mode
f = CfgBufBinToFolder(b);
}
// Memory release
Free(buf);
FreeBuf(b);
FileDeleteW(newfile);
return f;
}
// Test of Cfg
void CfgTest2(FOLDER *f, UINT n)
{
}
void CfgTest()
{
#if 0
FOLDER *root;
BUF *b;
Debug("\nCFG Test Begin\n");
root = CfgCreateFolder(NULL, TAG_ROOT);
CfgTest2(root, 5);
b = CfgFolderToBufText(root);
//Print("%s\n", b->Buf);
SeekBuf(b, 0, 0);
CfgDeleteFolder(root);
DumpBuf(b, "test1.config");
root = CfgBufTextToFolder(b);
FreeBuf(b);
b = CfgFolderToBufText(root);
// Print("%s\n", b->Buf);
DumpBuf(b, "test2.config");
FreeBuf(b);
CfgSave(root, "test.txt");
CfgDeleteFolder(root);
Debug("\nCFG Test End\n");
#endif
}
// Read one line
char *CfgReadNextLine(BUF *b)
{
char *tmp;
char *buf;
UINT len;
// Validate arguments
if (b == NULL)
{
return NULL;
}
// Examine the number of characters up to the next newline
tmp = (char *)b->Buf + b->Current;
if ((b->Size - b->Current) == 0)
{
// Read to the end
return NULL;
}
len = 0;
while (true)
{
if (tmp[len] == 13 || tmp[len] == 10)
{
if (tmp[len] == 13)
{
if (len < (b->Size - b->Current))
{
len++;
}
}
break;
}
len++;
if (len >= (b->Size - b->Current))
{
break;
}
}
// Read ahead only 'len' bytes
buf = ZeroMalloc(len + 1);
ReadBuf(b, buf, len);
SeekBuf(b, 1, 1);
if (StrLen(buf) >= 1)
{
if (buf[StrLen(buf) - 1] == 13)
{
buf[StrLen(buf) - 1] = 0;
}
}
return buf;
}
// Read the text stream
bool CfgReadNextTextBUF(BUF *b, FOLDER *current)
{
char *buf;
TOKEN_LIST *token;
char *name;
char *string;
char *data;
bool ret;
FOLDER *f;
// Validate arguments
if (b == NULL || current == NULL)
{
return false;
}
ret = true;
// Read one line
buf = CfgReadNextLine(b);
if (buf == NULL)
{
return false;
}
// Analyze this line
token = ParseToken(buf, "\t ");
if (token == NULL)
{
Free(buf);
return false;
}
if (token->NumTokens >= 1)
{
if (!StrCmpi(token->Token[0], TAG_DECLARE))
{
if (token->NumTokens >= 2)
{
// declare
name = CfgUnescape(token->Token[1]);
// Create a folder
f = CfgCreateFolder(current, name);
// Read the next folder
while (true)
{
if (CfgReadNextTextBUF(b, f) == false)
{
break;
}
}
Free(name);
}
}
if (!StrCmpi(token->Token[0], "}"))
{
// end
ret = false;
}
if (token->NumTokens >= 3)
{
name = CfgUnescape(token->Token[1]);
data = token->Token[2];
if (!StrCmpi(token->Token[0], TAG_STRING))
{
// string
wchar_t *uni;
UINT uni_size;
string = CfgUnescape(data);
uni_size = CalcUtf8ToUni(string, StrLen(string));
if (uni_size != 0)
{
uni = Malloc(uni_size);
Utf8ToUni(uni, uni_size, string, StrLen(string));
CfgAddUniStr(current, name, uni);
Free(uni);
}
Free(string);
}
if (!StrCmpi(token->Token[0], TAG_INT))
{
// uint
CfgAddInt(current, name, ToInt(data));
}
if (!StrCmpi(token->Token[0], TAG_INT64))
{
// uint64
CfgAddInt64(current, name, ToInt64(data));
}
if (!StrCmpi(token->Token[0], TAG_BOOL))
{
// bool
bool b = false;
if (!StrCmpi(data, TAG_TRUE))
{
b = true;
}
else if (ToInt(data) != 0)
{
b = true;
}
CfgAddBool(current, name, b);
}
if (!StrCmpi(token->Token[0], TAG_BYTE))
{
// byte
char *unescaped_b64 = CfgUnescape(data);
void *tmp = Malloc(StrLen(unescaped_b64) * 4 + 64);
int size = B64_Decode(tmp, unescaped_b64, StrLen(unescaped_b64));
CfgAddByte(current, name, tmp, size);
Free(tmp);
Free(unescaped_b64);
}
Free(name);
}
}
// Release of the token
FreeToken(token);
Free(buf);
return ret;
}
// Convert the stream text to a folder
FOLDER *CfgBufTextToFolder(BUF *b)
{
FOLDER *f, *c;
// Validate arguments
if (b == NULL)
{
return NULL;
}
// Read recursively from the root folder
c = CfgCreateFolder(NULL, "tmp");
while (true)
{
// Read the text stream
if (CfgReadNextTextBUF(b, c) == false)
{
break;
}
}
// Getting root folder
f = CfgGetFolder(c, TAG_ROOT);
if (f == NULL)
{
// Root folder is not found
CfgDeleteFolder(c);
return NULL;
}
// Remove the reference from tmp folder to the root
Delete(c->Folders, f);
f->Parent = NULL;
// Delete the tmp folder
CfgDeleteFolder(c);
// Return the root folder
return f;
}
// Read the next folder
void CfgReadNextFolderBin(BUF *b, FOLDER *parent)
{
char name[MAX_SIZE];
FOLDER *f;
UINT n, i;
UINT size;
UCHAR *buf;
wchar_t *string;
// Validate arguments
if (b == NULL || parent == NULL)
{
return;
}
// Folder name
ReadBufStr(b, name, sizeof(name));
f = CfgCreateFolder(parent, name);
// The number of the subfolder
n = ReadBufInt(b);
for (i = 0;i < n;i++)
{
// Subfolder
CfgReadNextFolderBin(b, f);
}
// The number of items
n = ReadBufInt(b);
for (i = 0;i < n;i++)
{
UINT type;
// Name
ReadBufStr(b, name, sizeof(name));
// Type
type = ReadBufInt(b);
switch (type)
{
case ITEM_TYPE_INT:
// int
CfgAddInt(f, name, ReadBufInt(b));
break;
case ITEM_TYPE_INT64:
// int64
CfgAddInt64(f, name, ReadBufInt64(b));
break;
case ITEM_TYPE_BYTE:
// data
size = ReadBufInt(b);
buf = ZeroMalloc(size);
ReadBuf(b, buf, size);
CfgAddByte(f, name, buf, size);
Free(buf);
break;
case ITEM_TYPE_STRING:
// string
size = ReadBufInt(b);
buf = ZeroMalloc(size + 1);
ReadBuf(b, buf, size);
string = ZeroMalloc(CalcUtf8ToUni(buf, StrLen(buf)) + 4);
Utf8ToUni(string, 0, buf, StrLen(buf));
CfgAddUniStr(f, name, string);
Free(string);
Free(buf);
break;
case ITEM_TYPE_BOOL:
// bool
CfgAddBool(f, name, ReadBufInt(b) == 0 ? false : true);
break;
}
}
}
// Convert the binary to folder
FOLDER *CfgBufBinToFolder(BUF *b)
{
FOLDER *f, *c;
// Validate arguments
if (b == NULL)
{
return NULL;
}
// Create a temporary folder
c = CfgCreateFolder(NULL, "tmp");
// Read a binary
CfgReadNextFolderBin(b, c);
// Get root folder
f = CfgGetFolder(c, TAG_ROOT);
if (f == NULL)
{
// Missing
CfgDeleteFolder(c);
return NULL;
}
Delete(c->Folders, f);
f->Parent = NULL;
CfgDeleteFolder(c);
return f;
}
// Convert the folder to binary
BUF *CfgFolderToBufBin(FOLDER *f)
{
BUF *b;
UCHAR hash[SHA1_SIZE];
// Validate arguments
if (f == NULL)
{
return NULL;
}
b = NewBuf();
// Header
WriteBuf(b, TAG_BINARY, 8);
// Hash area
Zero(hash, sizeof(hash));
WriteBuf(b, hash, sizeof(hash));
// Output the root folder (recursive)
CfgOutputFolderBin(b, f);
// Hash
Hash(((UCHAR *)b->Buf) + 8, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
return b;
}
// Convert the folder to a stream text
BUF *CfgFolderToBufText(FOLDER *f)
{
return CfgFolderToBufTextEx(f, false);
}
BUF *CfgFolderToBufTextEx(FOLDER *f, bool no_banner)
{
BUF *b;
// Validate arguments
if (f == NULL)
{
return NULL;
}
// Create a stream
b = NewBuf();
// Copyright notice
if (no_banner == false)
{
WriteBuf(b, TAG_CPYRIGHT, StrLen(TAG_CPYRIGHT));
}
// Output the root folder (recursive)
CfgOutputFolderText(b, f, 0);
return b;
}
// Output the folder contents (Enumerate folders)
bool CfgEnumFolderProc(FOLDER *f, void *param)
{
CFG_ENUM_PARAM *p;
// Validate arguments
if (f == NULL || param == NULL)
{
return false;
}
p = (CFG_ENUM_PARAM *)param;
// Output the folder contents (recursive)
CfgOutputFolderText(p->b, f, p->depth);
return true;
}
// Output the contents of the item (enumeration)
bool CfgEnumItemProc(ITEM *t, void *param)
{
CFG_ENUM_PARAM *p;
// Validate arguments
if (t == NULL || param == NULL)
{
return false;
}
p = (CFG_ENUM_PARAM *)param;
CfgAddItemText(p->b, t, p->depth);
return true;
}
// Output the folder contents (Recursive, binary)
void CfgOutputFolderBin(BUF *b, FOLDER *f)
{
UINT i;
// Validate arguments
if (b == NULL || f == NULL)
{
return;
}
// Folder name
WriteBufStr(b, f->Name);
// The number of the subfolder
WriteBufInt(b, LIST_NUM(f->Folders));
// Subfolder
for (i = 0;i < LIST_NUM(f->Folders);i++)
{
FOLDER *sub = LIST_DATA(f->Folders, i);
CfgOutputFolderBin(b, sub);
if ((i % 100) == 99)
{
YieldCpu();
}
}
// The number of Items
WriteBufInt(b, LIST_NUM(f->Items));
// Item
for (i = 0;i < LIST_NUM(f->Items);i++)
{
char *utf8;
UINT utf8_size;
ITEM *t = LIST_DATA(f->Items, i);
// Item Name
WriteBufStr(b, t->Name);
// Type
WriteBufInt(b, t->Type);
switch (t->Type)
{
case ITEM_TYPE_INT:
// Integer
WriteBufInt(b, *((UINT *)t->Buf));
break;
case ITEM_TYPE_INT64:
// 64-bit integer
WriteBufInt64(b, *((UINT64 *)t->Buf));
break;
case ITEM_TYPE_BYTE:
// Data size
WriteBufInt(b, t->size);
// Data
WriteBuf(b, t->Buf, t->size);
break;
case ITEM_TYPE_STRING:
// String
utf8_size = CalcUniToUtf8((wchar_t *)t->Buf) + 1;
utf8 = ZeroMalloc(utf8_size);
UniToUtf8(utf8, utf8_size, (wchar_t *)t->Buf);
WriteBufInt(b, StrLen(utf8));
WriteBuf(b, utf8, StrLen(utf8));
Free(utf8);
break;
case ITEM_TYPE_BOOL:
// Boolean type
if (*((bool *)t->Buf) == false)
{
WriteBufInt(b, 0);
}
else
{
WriteBufInt(b, 1);
}
break;
}
}
}
// Output the contents of the folder (Recursive, text)
void CfgOutputFolderText(BUF *b, FOLDER *f, UINT depth)
{
CFG_ENUM_PARAM p;
// Validate arguments
if (b == NULL || f == NULL)
{
return;
}
// Output starting of the folder
CfgAddDeclare(b, f->Name, depth);
depth++;
Zero(&p, sizeof(CFG_ENUM_PARAM));
p.depth = depth;
p.b = b;
p.f = f;
// Enumerate the list of items
CfgEnumItem(f, CfgEnumItemProc, &p);
if (LIST_NUM(f->Folders) != 0 && LIST_NUM(f->Items) != 0)
{
WriteBuf(b, "\r\n", 2);
}
// Enumerate the folder list
CfgEnumFolder(f, CfgEnumFolderProc, &p);
// Output the end of the folder
depth--;
CfgAddEnd(b, depth);
//WriteBuf(b, "\r\n", 2);
}
// Output contents of the item
void CfgAddItemText(BUF *b, ITEM *t, UINT depth)
{
char *data;
char *sub = NULL;
UINT len;
UINT size;
char *utf8;
UINT utf8_size;
wchar_t *string;
// Validate arguments
if (b == NULL || t == NULL)
{
return;
}
// Process the data by its type
data = NULL;
switch (t->Type)
{
case ITEM_TYPE_INT:
data = Malloc(32);
ToStr(data, *((UINT *)t->Buf));
break;
case ITEM_TYPE_INT64:
data = Malloc(64);
ToStr64(data, *((UINT64 *)t->Buf));
break;
case ITEM_TYPE_BYTE:
data = ZeroMalloc(t->size * 4 + 32);
len = B64_Encode(data, t->Buf, t->size);
data[len] = 0;
break;
case ITEM_TYPE_STRING:
string = t->Buf;
utf8_size = CalcUniToUtf8(string);
utf8_size++;
utf8 = ZeroMalloc(utf8_size);
utf8[0] = 0;
UniToUtf8(utf8, utf8_size, string);
size = utf8_size;
data = utf8;
break;
case ITEM_TYPE_BOOL:
size = 32;
data = Malloc(size);
if (*((bool *)t->Buf) == false)
{
StrCpy(data, size, TAG_FALSE);
}
else
{
StrCpy(data, size, TAG_TRUE);
}
break;
}
if (data == NULL)
{
return;
}
// Output the data line
CfgAddData(b, t->Type, t->Name, data, sub, depth);
// Memory release
Free(data);
if (sub != NULL)
{
Free(sub);
}
}
// Output the data line
void CfgAddData(BUF *b, UINT type, char *name, char *data, char *sub, UINT depth)
{
char *tmp;
char *name2;
char *data2;
char *sub2 = NULL;
UINT tmp_size;
// Validate arguments
if (b == NULL || type == 0 || name == NULL || data == NULL)
{
return;
}
name2 = CfgEscape(name);
data2 = CfgEscape(data);
if (sub != NULL)
{
sub2 = CfgEscape(sub);
}
tmp_size = StrLen(name2) + StrLen(data2) + 2 + 64 + 1;
tmp = Malloc(tmp_size);
if (sub2 != NULL)
{
StrCpy(tmp, tmp_size, CfgTypeToStr(type));
StrCat(tmp, tmp_size, " ");
StrCat(tmp, tmp_size, name2);
StrCat(tmp, tmp_size, " ");
StrCat(tmp, tmp_size, data2);
StrCat(tmp, tmp_size, " ");
StrCat(tmp, tmp_size, sub2);
}
else
{
StrCpy(tmp, tmp_size, CfgTypeToStr(type));
StrCat(tmp, tmp_size, " ");
StrCat(tmp, tmp_size, name2);
StrCat(tmp, tmp_size, " ");
StrCat(tmp, tmp_size, data2);
}
Free(name2);
Free(data2);
if (sub2 != NULL)
{
Free(sub2);
}
CfgAddLine(b, tmp, depth);
Free(tmp);
}
// Convert the data type string to an integer value
UINT CfgStrToType(char *str)
{
if (!StrCmpi(str, TAG_INT)) return ITEM_TYPE_INT;
if (!StrCmpi(str, TAG_INT64)) return ITEM_TYPE_INT64;
if (!StrCmpi(str, TAG_BYTE)) return ITEM_TYPE_BYTE;
if (!StrCmpi(str, TAG_STRING)) return ITEM_TYPE_STRING;
if (!StrCmpi(str, TAG_BOOL)) return ITEM_TYPE_BOOL;
return 0;
}
// Convert the type of data to a string
char *CfgTypeToStr(UINT type)
{
switch (type)
{
case ITEM_TYPE_INT:
return TAG_INT;
case ITEM_TYPE_INT64:
return TAG_INT64;
case ITEM_TYPE_BYTE:
return TAG_BYTE;
case ITEM_TYPE_STRING:
return TAG_STRING;
case ITEM_TYPE_BOOL:
return TAG_BOOL;
}
return NULL;
}
// Outputs the End line
void CfgAddEnd(BUF *b, UINT depth)
{
// Validate arguments
if (b == NULL)
{
return;
}
CfgAddLine(b, "}", depth);
// CfgAddLine(b, TAG_END, depth);
}
// Outputs the Declare lines
void CfgAddDeclare(BUF *b, char *name, UINT depth)
{
char *tmp;
char *name2;
UINT tmp_size;
// Validate arguments
if (b == NULL || name == NULL)
{
return;
}
name2 = CfgEscape(name);
tmp_size = StrLen(name2) + 2 + StrLen(TAG_DECLARE);
tmp = Malloc(tmp_size);
Format(tmp, 0, "%s %s", TAG_DECLARE, name2);
CfgAddLine(b, tmp, depth);
CfgAddLine(b, "{", depth);
Free(tmp);
Free(name2);
}
// Outputs one line
void CfgAddLine(BUF *b, char *str, UINT depth)
{
UINT i;
// Validate arguments
if (b == NULL)
{
return;
}
for (i = 0;i < depth;i++)
{
WriteBuf(b, "\t", 1);
}
WriteBuf(b, str, StrLen(str));
WriteBuf(b, "\r\n", 2);
}
// Convert the folder to a stream
BUF *CfgFolderToBuf(FOLDER *f, bool textmode)
{
return CfgFolderToBufEx(f, textmode, false);
}
BUF *CfgFolderToBufEx(FOLDER *f, bool textmode, bool no_banner)
{
// Validate arguments
if (f == NULL)
{
return NULL;
}
if (textmode)
{
return CfgFolderToBufTextEx(f, no_banner);
}
else
{
return CfgFolderToBufBin(f);;
}
}
// Escape restoration of the string
char *CfgUnescape(char *str)
{
char *tmp;
char *ret;
char tmp2[16];
UINT len, wp, i;
UINT code;
// Validate arguments
if (str == NULL)
{
return NULL;
}
len = StrLen(str);
tmp = ZeroMalloc(len + 1);
wp = 0;
if (len == 1 && str[0] == '$')
{
// Empty character
tmp[0] = 0;
}
else
{
for (i = 0;i < len;i++)
{
if (str[i] != '$')
{
tmp[wp++] = str[i];
}
else
{
tmp2[0] = '0';
tmp2[1] = 'x';
tmp2[2] = str[i + 1];
tmp2[3] = str[i + 2];
i += 2;
tmp2[4] = 0;
code = ToInt(tmp2);
tmp[wp++] = (char)code;
}
}
}
ret = Malloc(StrLen(tmp) + 1);
StrCpy(ret, StrLen(tmp) + 1, tmp);
Free(tmp);
return ret;
}
// Escape the string
char *CfgEscape(char *str)
{
char *tmp;
char *ret;
char tmp2[16];
UINT len;
UINT wp, i;
// Validate arguments
if (str == NULL)
{
return NULL;
}
len = StrLen(str);
tmp = ZeroMalloc(len * 3 + 2);
if (len == 0)
{
// Empty character
StrCpy(tmp, (len * 3 + 2), "$");
}
else
{
// Non null character
wp = 0;
for (i = 0;i < len;i++)
{
if (CfgCheckCharForName(str[i]))
{
tmp[wp++] = str[i];
}
else
{
tmp[wp++] = '$';
Format(tmp2, sizeof(tmp2), "%02X", (UINT)str[i]);
tmp[wp++] = tmp2[0];
tmp[wp++] = tmp2[1];
}
}
}
ret = Malloc(StrLen(tmp) + 1);
StrCpy(ret, 0, tmp);
Free(tmp);
return ret;
}
// Check if the character can be used in the name
bool CfgCheckCharForName(char c)
{
if (c >= 0 && c <= 31)
{
return false;
}
if (c == ' ' || c == '\t')
{
return false;
}
if (c == '$')
{
return false;
}
return true;
}
// Get the string type value
bool CfgGetStr(FOLDER *f, char *name, char *str, UINT size)
{
wchar_t *tmp;
UINT tmp_size;
// Validate arguments
if (f == NULL || name == NULL || str == NULL)
{
return false;
}
str[0] = 0;
// Get unicode string temporarily
tmp_size = size * 4 + 10; // Just to make sure, a quantity of this amount is secured.
tmp = Malloc(tmp_size);
if (CfgGetUniStr(f, name, tmp, tmp_size) == false)
{
// Failure
Free(tmp);
return false;
}
// Copy to the ANSI string
UniToStr(str, size, tmp);
Free(tmp);
return true;
}
// Get the value of the unicode_string type
bool CfgGetUniStr(FOLDER *f, char *name, wchar_t *str, UINT size)
{
ITEM *t;
// Validate arguments
if (f == NULL || name == NULL || str == NULL)
{
return false;
}
str[0] = 0;
t = CfgFindItem(f, name);
if (t == NULL)
{
return false;
}
if (t->Type != ITEM_TYPE_STRING)
{
return false;
}
UniStrCpy(str, size, t->Buf);
return true;
}
// Check for the existence of item
bool CfgIsItem(FOLDER *f, char *name)
{
ITEM *t;
// Validate arguments
if (f == NULL || name == NULL)
{
return false;
}
t = CfgFindItem(f, name);
if (t == NULL)
{
return false;
}
return true;
}
// Get the byte[] type as a BUF
BUF *CfgGetBuf(FOLDER *f, char *name)
{
ITEM *t;
BUF *b;
// Validate arguments
if (f == NULL || name == NULL)
{
return NULL;
}
t = CfgFindItem(f, name);
if (t == NULL)
{
return NULL;
}
b = NewBuf();
WriteBuf(b, t->Buf, t->size);
SeekBuf(b, 0, 0);
return b;
}
// Get the value of type byte[]
UINT CfgGetByte(FOLDER *f, char *name, void *buf, UINT size)
{
ITEM *t;
// Validate arguments
if (f == NULL || name == NULL || buf == NULL)
{
return 0;
}
t = CfgFindItem(f, name);
if (t == NULL)
{
return 0;
}
if (t->Type != ITEM_TYPE_BYTE)
{
return 0;
}
if (t->size <= size)
{
Copy(buf, t->Buf, t->size);
return t->size;
}
else
{
Copy(buf, t->Buf, size);
return t->size;
}
}
// Get the value of type int64
UINT64 CfgGetInt64(FOLDER *f, char *name)
{
ITEM *t;
UINT64 *ret;
// Validate arguments
if (f == NULL || name == NULL)
{
return 0;
}
t = CfgFindItem(f, name);
if (t == NULL)
{
return 0;
}
if (t->Type != ITEM_TYPE_INT64)
{
return 0;
}
if (t->size != sizeof(UINT64))
{
return 0;
}
ret = (UINT64 *)t->Buf;
return *ret;
}
// Get the value of the bool type
bool CfgGetBool(FOLDER *f, char *name)
{
ITEM *t;
bool *ret;
// Validate arguments
if (f == NULL || name == NULL)
{
return 0;
}
t = CfgFindItem(f, name);
if (t == NULL)
{
return 0;
}
if (t->Type != ITEM_TYPE_BOOL)
{
return 0;
}
if (t->size != sizeof(bool))
{
return 0;
}
ret = (bool *)t->Buf;
if (*ret == false)
{
return false;
}
else
{
return true;
}
}
// Get the value of the int type
UINT CfgGetInt(FOLDER *f, char *name)
{
ITEM *t;
UINT *ret;
// Validate arguments
if (f == NULL || name == NULL)
{
return 0;
}
t = CfgFindItem(f, name);
if (t == NULL)
{
return 0;
}
if (t->Type != ITEM_TYPE_INT)
{
return 0;
}
if (t->size != sizeof(UINT))
{
return 0;
}
ret = (UINT *)t->Buf;
return *ret;
}
// Search for an item
ITEM *CfgFindItem(FOLDER *parent, char *name)
{
ITEM *t, tt;
// Validate arguments
if (parent == NULL || name == NULL)
{
return NULL;
}
tt.Name = ZeroMalloc(StrLen(name) + 1);
StrCpy(tt.Name, 0, name);
t = Search(parent->Items, &tt);
Free(tt.Name);
return t;
}
// Get a folder
FOLDER *CfgGetFolder(FOLDER *parent, char *name)
{
return CfgFindFolder(parent, name);
}
// Search a folder
FOLDER *CfgFindFolder(FOLDER *parent, char *name)
{
FOLDER *f, ff;
// Validate arguments
if (parent == NULL || name == NULL)
{
return NULL;
}
ff.Name = ZeroMalloc(StrLen(name) + 1);
StrCpy(ff.Name, 0, name);
f = Search(parent->Folders, &ff);
Free(ff.Name);
return f;
}
// Adding a string type
ITEM *CfgAddStr(FOLDER *f, char *name, char *str)
{
wchar_t *tmp;
UINT tmp_size;
ITEM *t;
// Validate arguments
if (f == NULL || name == NULL || str == NULL)
{
return NULL;
}
// Convert to a Unicode string
tmp_size = CalcStrToUni(str);
if (tmp_size == 0)
{
return NULL;
}
tmp = Malloc(tmp_size);
StrToUni(tmp, tmp_size, str);
t = CfgAddUniStr(f, name, tmp);
Free(tmp);
return t;
}
// Add unicode_string type
ITEM *CfgAddUniStr(FOLDER *f, char *name, wchar_t *str)
{
// Validate arguments
if (f == NULL || name == NULL || str == NULL)
{
return NULL;
}
return CfgCreateItem(f, name, ITEM_TYPE_STRING, str, UniStrSize(str));
}
// Add a binary
ITEM *CfgAddBuf(FOLDER *f, char *name, BUF *b)
{
// Validate arguments
if (f == NULL || name == NULL || b == NULL)
{
return NULL;
}
return CfgAddByte(f, name, b->Buf, b->Size);
}
// Add byte type
ITEM *CfgAddByte(FOLDER *f, char *name, void *buf, UINT size)
{
// Validate arguments
if (f == NULL || name == NULL || buf == NULL)
{
return NULL;
}
return CfgCreateItem(f, name, ITEM_TYPE_BYTE, buf, size);
}
// Add a 64-bit integer type
ITEM *CfgAddInt64(FOLDER *f, char *name, UINT64 i)
{
// Validate arguments
if (f == NULL || name == NULL)
{
return NULL;
}
return CfgCreateItem(f, name, ITEM_TYPE_INT64, &i, sizeof(UINT64));
}
// Get an IP address type
bool CfgGetIp(FOLDER *f, char *name, struct IP *ip)
{
char tmp[MAX_SIZE];
// Validate arguments
if (f == NULL || name == NULL || ip == NULL)
{
return false;
}
Zero(ip, sizeof(IP));
if (CfgGetStr(f, name, tmp, sizeof(tmp)) == false)
{
return false;
}
if (StrToIP(ip, tmp) == false)
{
return false;
}
return true;
}
UINT CfgGetIp32(FOLDER *f, char *name)
{
IP p;
// Validate arguments
if (f == NULL || name == NULL)
{
return 0;
}
if (CfgGetIp(f, name, &p) == false)
{
return 0;
}
return IPToUINT(&p);
}
bool CfgGetIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
{
IP ip;
// Validate arguments
Zero(addr, sizeof(IPV6_ADDR));
if (f == NULL || name == NULL || addr == NULL)
{
return false;
}
if (CfgGetIp(f, name, &ip) == false)
{
return false;
}
if (IsIP6(&ip) == false)
{
return false;
}
if (IPToIPv6Addr(addr, &ip) == false)
{
return false;
}
return true;
}
// Add an IP address type
ITEM *CfgAddIp(FOLDER *f, char *name, struct IP *ip)
{
char tmp[MAX_SIZE];
// Validate arguments
if (f == NULL || name == NULL || ip == NULL)
{
return NULL;
}
IPToStr(tmp, sizeof(tmp), ip);
return CfgAddStr(f, name, tmp);
}
ITEM *CfgAddIp32(FOLDER *f, char *name, UINT ip)
{
IP p;
// Validate arguments
if (f == NULL || name == NULL)
{
return NULL;
}
UINTToIP(&p, ip);
return CfgAddIp(f, name, &p);
}
ITEM *CfgAddIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
{
IP ip;
// Validate arguments
if (f == NULL || name == NULL || addr == NULL)
{
return NULL;
}
IPv6AddrToIP(&ip, addr);
return CfgAddIp(f, name, &ip);
}
// Add an integer type
ITEM *CfgAddInt(FOLDER *f, char *name, UINT i)
{
// Validate arguments
if (f == NULL || name == NULL)
{
return NULL;
}
return CfgCreateItem(f, name, ITEM_TYPE_INT, &i, sizeof(UINT));
}
// Adding a bool type
ITEM *CfgAddBool(FOLDER *f, char *name, bool b)
{
bool v;
// Validate arguments
if (f == NULL || name == NULL)
{
return NULL;
}
v = b ? 1 : 0;
return CfgCreateItem(f, name, ITEM_TYPE_BOOL, &b, sizeof(bool));
}
// Comparison function of the item names
int CmpItemName(void *p1, void *p2)
{
ITEM *f1, *f2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
f1 = *(ITEM **)p1;
f2 = *(ITEM **)p2;
if (f1 == NULL || f2 == NULL)
{
return 0;
}
return StrCmpi(f1->Name, f2->Name);
}
// Comparison function of the folder names
int CmpFolderName(void *p1, void *p2)
{
FOLDER *f1, *f2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
f1 = *(FOLDER **)p1;
f2 = *(FOLDER **)p2;
if (f1 == NULL || f2 == NULL)
{
return 0;
}
return StrCmpi(f1->Name, f2->Name);
}
// Enumeration of items
void CfgEnumItem(FOLDER *f, ENUM_ITEM proc, void *param)
{
UINT i;
// Validate arguments
if (f == NULL || proc == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(f->Items);i++)
{
ITEM *tt = LIST_DATA(f->Items, i);
if (proc(tt, param) == false)
{
break;
}
}
}
// Enumerate the folders and store it in the token list
TOKEN_LIST *CfgEnumFolderToTokenList(FOLDER *f)
{
TOKEN_LIST *t, *ret;
UINT i;
// Validate arguments
if (f == NULL)
{
return NULL;
}
t = ZeroMalloc(sizeof(TOKEN_LIST));
t->NumTokens = LIST_NUM(f->Folders);
t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff = LIST_DATA(f->Folders, i);
t->Token[i] = CopyStr(ff->Name);
}
ret = UniqueToken(t);
FreeToken(t);
return ret;
}
// Enumerate items and store these to the token list
TOKEN_LIST *CfgEnumItemToTokenList(FOLDER *f)
{
TOKEN_LIST *t, *ret;
UINT i;
// Validate arguments
if (f == NULL)
{
return NULL;
}
t = ZeroMalloc(sizeof(TOKEN_LIST));
t->NumTokens = LIST_NUM(f->Items);
t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
for (i = 0;i < t->NumTokens;i++)
{
FOLDER *ff = LIST_DATA(f->Items, i);
t->Token[i] = CopyStr(ff->Name);
}
ret = UniqueToken(t);
FreeToken(t);
return ret;
}
// Folder enumeration
void CfgEnumFolder(FOLDER *f, ENUM_FOLDER proc, void *param)
{
UINT i;
// Validate arguments
if (f == NULL || proc == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(f->Folders);i++)
{
FOLDER *ff = LIST_DATA(f->Folders, i);
if (proc(ff, param) == false)
{
break;
}
if ((i % 100) == 99)
{
YieldCpu();
}
}
}
// Create an item
ITEM *CfgCreateItem(FOLDER *parent, char *name, UINT type, void *buf, UINT size)
{
UINT name_size;
ITEM *t;
#ifdef CHECK_CFG_NAME_EXISTS
ITEM tt;
#endif // CHECK_CFG_NAME_EXISTS
// Validate arguments
if (parent == NULL || name == NULL || type == 0 || buf == NULL)
{
return NULL;
}
name_size = StrLen(name) + 1;
#ifdef CHECK_CFG_NAME_EXISTS
// Check whether there are any items with the same name already
tt.Name = ZeroMalloc(name_size);
StrCpy(tt.Name, 0, name);
t = Search(parent->Items, &tt);
Free(tt.Name);
if (t != NULL)
{
// Duplicated
return NULL;
}
#endif // CHECK_CFG_NAME_EXISTS
t = ZeroMalloc(sizeof(ITEM));
t->Buf = Malloc(size);
Copy(t->Buf, buf, size);
t->Name = ZeroMalloc(name_size);
StrCpy(t->Name, 0, name);
t->Type = type;
t->size = size;
t->Parent = parent;
// Add to the parent list
Insert(parent->Items, t);
return t;
}
// Delete the item
void CfgDeleteItem(ITEM *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
// Remove from the parent list
Delete(t->Parent->Items, t);
// Memory release
Free(t->Buf);
Free(t->Name);
Free(t);
}
// Delete the folder
void CfgDeleteFolder(FOLDER *f)
{
FOLDER **ff;
ITEM **tt;
UINT num, i;
// Validate arguments
if (f == NULL)
{
return;
}
if(f->Folders == NULL)
{
return;
}
// Remove all subfolders
num = LIST_NUM(f->Folders);
if (num != 0)
{
ff = Malloc(sizeof(FOLDER *) * num);
Copy(ff, f->Folders->p, sizeof(FOLDER *) * num);
for (i = 0;i < num;i++)
{
CfgDeleteFolder(ff[i]);
}
Free(ff);
}
// Remove all items
num = LIST_NUM(f->Items);
if (num != 0)
{
tt = Malloc(sizeof(ITEM *) * num);
Copy(tt, f->Items->p, sizeof(ITEM *) * num);
for (i = 0;i < num;i++)
{
CfgDeleteItem(tt[i]);
}
Free(tt);
}
// Memory release
Free(f->Name);
// Remove from the parent list
if (f->Parent != NULL)
{
Delete(f->Parent->Folders, f);
}
// Release the list
ReleaseList(f->Folders);
ReleaseList(f->Items);
// Release of the memory of the body
Free(f);
}
// Creating a root
FOLDER *CfgCreateRoot()
{
return CfgCreateFolder(NULL, TAG_ROOT);
}
// Create a folder
FOLDER *CfgCreateFolder(FOLDER *parent, char *name)
{
UINT size;
FOLDER *f;
// Validate arguments
if (name == NULL)
{
return NULL;
}
size = StrLen(name) + 1;
#ifdef CHECK_CFG_NAME_EXISTS
// Check the name in the parent list
if (parent != NULL)
{
FOLDER ff;
ff.Name = ZeroMalloc(size);
StrCpy(ff.Name, 0, name);
f = Search(parent->Folders, &ff);
Free(ff.Name);
if (f != NULL)
{
// Folder with the same name already exists
return NULL;
}
}
#endif // CHECK_CFG_NAME_EXISTS
f = ZeroMalloc(sizeof(FOLDER));
f->Items = NewListFast(CmpItemName);
f->Folders = NewListFast(CmpFolderName);
f->Name = ZeroMalloc(size);
StrCpy(f->Name, 0, name);
f->Parent = parent;
// Add to parentlist
if (f->Parent != NULL)
{
Insert(f->Parent->Folders, f);
}
return f;
}