1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-23 01:49:53 +03:00
SoftEtherVPN/src/Mayaqua/Cfg.c

2247 lines
39 KiB
C
Raw Normal View History

2017-10-19 05:48:23 +03:00
// SoftEther VPN Source Code - Developer Edition Master Branch
2014-01-04 17:00:08 +04:00
// Mayaqua Kernel
// Cfg.c
// Configuration information manipulation module
2021-04-05 05:48:25 +03:00
#include "Cfg.h"
2014-01-04 17:00:08 +04:00
2021-04-05 05:48:25 +03:00
#include "FileIO.h"
#include "Internat.h"
#include "Memory.h"
#include "Network.h"
#include "Object.h"
#include "Str.h"
2014-01-04 17:00:08 +04:00
// 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 || rw == NULL)
2014-01-04 17:00:08 +04:00
{
return;
}
// Determine the directory name
UniFormat(dirname, sizeof(dirname), L"$backup.%s", original[0] == L'$' ? original + 1 : original);
2014-01-04 17:00:08 +04:00
// 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);
2014-01-04 17:00:08 +04:00
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);
2014-01-04 17:00:08 +04:00
}
// 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 *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)
2014-10-03 19:09:23 +04:00
{
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)
2014-01-04 17:00:08 +04:00
{
CFG_RW *rw;
FOLDER *f;
2014-10-03 19:09:23 +04:00
bool loaded_from_template = false;
2014-01-04 17:00:08 +04:00
// Validate arguments
if (cfg_name == NULL || root == NULL)
{
return NULL;
}
f = CfgReadW(cfg_name);
if (f == NULL)
{
2014-10-03 19:09:23 +04:00
// Load from template
if (UniIsEmptyStr(template_name) == false)
{
f = CfgReadW(template_name);
if (f != NULL)
{
loaded_from_template = true;
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-17 00:47:10 +03:00
goto LABEL_CONTINUE;
2014-10-03 19:09:23 +04:00
}
}
2014-01-04 17:00:08 +04:00
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;
}
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-17 00:47:10 +03:00
LABEL_CONTINUE:
2014-01-04 17:00:08 +04:00
rw = ZeroMalloc(sizeof(CFG_RW));
rw->FileNameW = CopyUniStr(cfg_name);
rw->FileName = CopyUniToStr(cfg_name);
2014-10-03 19:09:23 +04:00
if (loaded_from_template == false)
{
rw->Io = FileOpenW(cfg_name, false);
}
else
{
rw->Io = FileCreateW(cfg_name);
}
2014-01-04 17:00:08 +04:00
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;
}
2016-11-27 11:43:14 +03:00
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;
}
2014-01-04 17:00:08 +04:00
// 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
Sha0(hash, b->Buf, b->Size);
2014-01-04 17:00:08 +04:00
// 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
2016-11-27 11:43:14 +03:00
// with appending the EOF
FileCopyExWithEofW(name, tmp, true);
2014-01-04 17:00:08 +04:00
// 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);
2016-11-27 11:43:14 +03:00
2014-01-04 17:00:08 +04:00
// 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;
UCHAR header[8];
2016-11-27 11:43:14 +03:00
bool has_eof = false;
2014-01-04 17:00:08 +04:00
// 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)
{
2016-11-27 11:43:14 +03:00
UINT size;
2014-01-04 17:00:08 +04:00
// Read the temporary file
o = FileOpenW(tmp, false);
2016-11-27 11:43:14 +03:00
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;
}
}
}
2014-01-04 17:00:08 +04:00
}
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)
{
FileClose(o);
o = FileOpenW(name, false);
}
}
if (o == NULL)
{
// Failed to read
return NULL;
}
// Read into the buffer
size = FileSize(o);
2016-11-27 11:43:14 +03:00
if (has_eof)
{
// Ignore EOF
size -= 1;
}
2014-01-04 17:00:08 +04:00
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));
Sha0(hash2, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE);
2014-01-04 17:00:08 +04:00
if (Cmp(hash1, hash2, SHA1_SIZE) != 0)
{
// Corrupted file
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;
}
// 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
Sha0(((UCHAR *)b->Buf) + 8, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE);
2014-01-04 17:00:08 +04:00
return b;
}
// Convert the folder to a stream text
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);
}
// 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 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)
{
// Validate arguments
if (f == NULL || name == NULL)
{
return NULL;
}
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;
}
2014-01-04 17:00:08 +04:00
// Remove all subfolders
num = LIST_NUM(f->Folders);
2018-04-21 00:03:26 +03:00
if (num != 0)
2014-01-04 17:00:08 +04:00
{
2018-04-21 00:03:26 +03:00
ff = Malloc(sizeof(FOLDER *) * num);
Copy(ff, f->Folders->p, sizeof(FOLDER *) * num);
for (i = 0;i < num;i++)
{
CfgDeleteFolder(ff[i]);
}
Free(ff);
2014-01-04 17:00:08 +04:00
}
// Remove all items
num = LIST_NUM(f->Items);
2018-04-21 00:03:26 +03:00
if (num != 0)
2014-01-04 17:00:08 +04:00
{
2018-04-21 00:03:26 +03:00
tt = Malloc(sizeof(ITEM *) * num);
Copy(tt, f->Items->p, sizeof(ITEM *) * num);
for (i = 0;i < num;i++)
{
CfgDeleteItem(tt[i]);
}
Free(tt);
2014-01-04 17:00:08 +04:00
}
// 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;
}