1 // SoftEther UT-VPN SourceCode
\r
3 // Copyright (C) 2004-2010 SoftEther Corporation.
\r
4 // Copyright (C) 2004-2010 University of Tsukuba, Japan.
\r
5 // Copyright (C) 2003-2010 Daiyuu Nobori.
\r
6 // All Rights Reserved.
\r
8 // http://utvpn.tsukuba.ac.jp/
\r
10 // This program is free software; you can redistribute it and/or
\r
11 // modify it under the terms of the GNU General Public License
\r
12 // version 2 as published by the Free Software Foundation.
\r
14 // This program is distributed in the hope that it will be useful,
\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
17 // GNU General Public License for more details.
\r
19 // You should have received a copy of the GNU General Public License version 2
\r
20 // along with this program; if not, write to the Free Software
\r
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。
\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の
\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
\r
29 // この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
\r
30 // ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
\r
31 // および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
\r
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
\r
34 // および、試験または研究のために利用が行われることを想定して配布
\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
\r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
\r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。
\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
\r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の
\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
\r
58 // 公益保護にご協力いただきますようお願い申し上げます。
\r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
\r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
\r
65 // 日本国内の脆弱性情報届出受付公的機関:
\r
67 // http://www.ipa.go.jp/security/vuln/report/
\r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/
\r
72 // -----------------------------------------------
\r
75 // 新規リリース by SoftEther
\r
76 // -----------------------------------------------
\r
90 #include <Mayaqua/Mayaqua.h>
\r
93 void BackupCfg(FOLDER *f, char *original)
\r
95 wchar_t *original_w = CopyStrToUni(original);
\r
97 BackupCfgW(f, original_w);
\r
101 void BackupCfgW(FOLDER *f, wchar_t *original)
\r
103 wchar_t dirname[MAX_PATH];
\r
104 wchar_t filename[MAX_PATH];
\r
105 wchar_t fullpath[MAX_PATH];
\r
108 if (f == NULL || filename == NULL)
\r
114 UniFormat(dirname, sizeof(dirname), L"@backup.%s", original[0] == L'@' ? original + 1 : original);
\r
118 UniFormat(filename, sizeof(filename), L"%04u%02u%02u%02u_%s",
\r
119 st.wYear, st.wMonth, st.wDay, st.wHour, original[0] == L'@' ? original + 1 : original);
\r
121 // このファイル名が存在するかどうかチェックする
\r
122 if (IsFileExistsW(filename))
\r
131 UniFormat(fullpath, sizeof(fullpath), L"%s/%s", dirname, filename);
\r
132 CfgSaveW(f, fullpath);
\r
136 void FreeCfgRw(CFG_RW *rw)
\r
144 if (rw->Io != NULL)
\r
149 DeleteLock(rw->lock);
\r
150 Free(rw->FileNameW);
\r
151 Free(rw->FileName);
\r
156 UINT SaveCfgRw(CFG_RW *rw, FOLDER *f)
\r
160 if (rw == NULL || f == NULL)
\r
167 if (rw->Io != NULL)
\r
173 if (CfgSaveExW2(rw, f, rw->FileNameW, &ret))
\r
175 if (rw->DontBackup == false)
\r
177 BackupCfgW(f, rw->FileNameW);
\r
185 rw->Io = FileOpenW(rw->FileNameW, false);
\r
193 CFG_RW *NewCfgRw(FOLDER **root, char *cfg_name)
\r
195 return NewCfgRwEx(root, cfg_name, false);
\r
197 CFG_RW *NewCfgRwW(FOLDER **root, wchar_t *cfg_name)
\r
199 return NewCfgRwExW(root, cfg_name, false);
\r
201 CFG_RW *NewCfgRwEx(FOLDER **root, char *cfg_name, bool dont_backup)
\r
203 wchar_t *cfg_name_w = CopyStrToUni(cfg_name);
\r
204 CFG_RW *ret = NewCfgRwExW(root, cfg_name_w, dont_backup);
\r
210 CFG_RW *NewCfgRwExW(FOLDER **root, wchar_t *cfg_name, bool dont_backup)
\r
215 if (cfg_name == NULL || root == NULL)
\r
220 f = CfgReadW(cfg_name);
\r
223 rw = ZeroMalloc(sizeof(CFG_RW));
\r
224 rw->lock = NewLock();
\r
225 rw->FileNameW = CopyUniStr(cfg_name);
\r
226 rw->FileName = CopyUniToStr(cfg_name);
\r
227 rw->Io = FileCreateW(cfg_name);
\r
229 rw->DontBackup = dont_backup;
\r
234 rw = ZeroMalloc(sizeof(CFG_RW));
\r
235 rw->FileNameW = CopyUniStr(cfg_name);
\r
236 rw->FileName = CopyUniToStr(cfg_name);
\r
237 rw->Io = FileOpenW(cfg_name, false);
\r
238 rw->lock = NewLock();
\r
242 rw->DontBackup = dont_backup;
\r
248 bool FileCopy(char *src, char *dst)
\r
253 if (src == NULL || dst == NULL)
\r
266 ret = DumpBuf(b, dst);
\r
272 bool FileCopyW(wchar_t *src, wchar_t *dst)
\r
277 if (src == NULL || dst == NULL)
\r
282 b = ReadDumpW(src);
\r
290 ret = DumpBufW(b, dst);
\r
298 void CfgSave(FOLDER *f, char *name)
\r
300 CfgSaveEx(NULL, f, name);
\r
302 void CfgSaveW(FOLDER *f, wchar_t *name)
\r
304 CfgSaveExW(NULL, f, name);
\r
306 bool CfgSaveEx(CFG_RW *rw, FOLDER *f, char *name)
\r
308 wchar_t *name_w = CopyStrToUni(name);
\r
309 bool ret = CfgSaveExW(rw, f, name_w);
\r
315 bool CfgSaveExW(CFG_RW *rw, FOLDER *f, wchar_t *name)
\r
317 return CfgSaveExW2(rw, f, name, NULL);
\r
319 bool CfgSaveExW2(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size)
\r
321 wchar_t tmp[MAX_SIZE];
\r
323 UCHAR hash[SHA1_SIZE];
\r
327 UINT dummy_int = 0;
\r
329 if (name == NULL || f == NULL)
\r
333 if (written_size == NULL)
\r
335 written_size = &dummy_int;
\r
338 // 同じディレクトリにある SAVE_BINARY_FILE_NAME_SWITCH ファイルがあるかどうか確認
\r
339 if (IsFileExistsW(SAVE_BINARY_FILE_NAME_SWITCH))
\r
345 b = CfgFolderToBuf(f, text);
\r
351 Hash(hash, b->Buf, b->Size, true);
\r
353 // 最後に書き込んだ内容と書き込む内容を比較する
\r
356 if (Cmp(hash, rw->LashHash, SHA1_SIZE) == 0)
\r
363 Copy(rw->LashHash, hash, SHA1_SIZE);
\r
367 if (ret || OS_IS_UNIX(GetOsInfo()->OsType))
\r
370 UniFormat(tmp, sizeof(tmp), L"%s.log", name);
\r
371 // 現在存在するファイルを一時ファイルにコピー
\r
372 FileCopyW(name, tmp);
\r
375 o = FileCreateW(name);
\r
378 if (FileWrite(o, b->Buf, b->Size) == false)
\r
383 FileRenameW(tmp, name);
\r
387 Zero(rw->LashHash, sizeof(rw->LashHash));
\r
401 FileRenameW(tmp, name);
\r
405 Zero(rw->LashHash, sizeof(rw->LashHash));
\r
410 *written_size = b->Size;
\r
419 FOLDER *CfgRead(char *name)
\r
421 wchar_t *name_w = CopyStrToUni(name);
\r
422 FOLDER *ret = CfgReadW(name_w);
\r
428 FOLDER *CfgReadW(wchar_t *name)
\r
430 wchar_t tmp[MAX_SIZE];
\r
431 wchar_t newfile[MAX_SIZE];
\r
437 bool delete_new = false;
\r
438 bool binary_file = false;
\r
439 bool invalid_file = false;
\r
448 UniFormat(newfile, sizeof(newfile), L"%s.new", name);
\r
450 UniFormat(tmp, sizeof(tmp), L"%s.log", name);
\r
452 // 新しいファイルが存在していれば読み込む
\r
453 o = FileOpenW(newfile, false);
\r
457 o = FileOpenW(tmp, false);
\r
465 // 一時的なファイルが無い場合は本来のファイルを読む
\r
466 o = FileOpenW(name, false);
\r
470 // 一時的なファイルのサイズが 0 の場合も本来のファイルを読み込む
\r
471 if (FileSize(o) == 0)
\r
473 invalid_file = true;
\r
479 o = FileOpenW(name, false);
\r
489 size = FileSize(o);
\r
490 buf = Malloc(size);
\r
491 FileRead(o, buf, size);
\r
493 WriteBuf(b, buf, size);
\r
502 FileDeleteW(newfile);
\r
505 // バッファの先頭 8 文字が "SEVPN_DB" の場合はバイナリファイル
\r
506 ReadBuf(b, header, sizeof(header));
\r
507 if (Cmp(header, TAG_BINARY, 8) == 0)
\r
509 UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
\r
510 binary_file = true;
\r
513 ReadBuf(b, hash1, sizeof(hash1));
\r
515 Hash(hash2, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
\r
517 if (Cmp(hash1, hash2, SHA1_SIZE) != 0)
\r
520 invalid_file = true;
\r
530 SeekBuf(b, 8 + SHA1_SIZE, 0);
\r
534 if (binary_file == false)
\r
537 f = CfgBufTextToFolder(b);
\r
542 f = CfgBufBinToFolder(b);
\r
549 FileDeleteW(newfile);
\r
555 void CfgTest2(FOLDER *f, UINT n)
\r
564 Debug("\nCFG Test Begin\n");
\r
566 root = CfgCreateFolder(NULL, TAG_ROOT);
\r
569 b = CfgFolderToBufText(root);
\r
570 //Print("%s\n", b->Buf);
\r
573 CfgDeleteFolder(root);
\r
575 DumpBuf(b, "test1.config");
\r
577 root = CfgBufTextToFolder(b);
\r
581 b = CfgFolderToBufText(root);
\r
582 // Print("%s\n", b->Buf);
\r
583 DumpBuf(b, "test2.config");
\r
586 CfgSave(root, "test.txt");
\r
588 CfgDeleteFolder(root);
\r
590 Debug("\nCFG Test End\n");
\r
595 char *CfgReadNextLine(BUF *b)
\r
607 tmp = (char *)b->Buf + b->Current;
\r
608 if ((b->Size - b->Current) == 0)
\r
616 if (tmp[len] == 13 || tmp[len] == 10)
\r
618 if (tmp[len] == 13)
\r
620 if (len < (b->Size - b->Current))
\r
628 if (len >= (b->Size - b->Current))
\r
635 buf = ZeroMalloc(len + 1);
\r
636 ReadBuf(b, buf, len);
\r
639 if (StrLen(buf) >= 1)
\r
641 if (buf[StrLen(buf) - 1] == 13)
\r
643 buf[StrLen(buf) - 1] = 0;
\r
651 bool CfgReadNextTextBUF(BUF *b, FOLDER *current)
\r
662 if (b == NULL || current == NULL)
\r
670 buf = CfgReadNextLine(b);
\r
677 token = ParseToken(buf, "\t ");
\r
684 if (token->NumTokens >= 1)
\r
686 if (!StrCmpi(token->Token[0], TAG_DECLARE))
\r
688 if (token->NumTokens >= 2)
\r
691 name = CfgUnescape(token->Token[1]);
\r
694 f = CfgCreateFolder(current, name);
\r
699 if (CfgReadNextTextBUF(b, f) == false)
\r
708 if (!StrCmpi(token->Token[0], "}"))
\r
713 if (token->NumTokens >= 3)
\r
715 name = CfgUnescape(token->Token[1]);
\r
716 data = token->Token[2];
\r
718 if (!StrCmpi(token->Token[0], TAG_STRING))
\r
723 string = CfgUnescape(data);
\r
724 uni_size = CalcUtf8ToUni(string, StrLen(string));
\r
727 uni = Malloc(uni_size);
\r
728 Utf8ToUni(uni, uni_size, string, StrLen(string));
\r
729 CfgAddUniStr(current, name, uni);
\r
734 if (!StrCmpi(token->Token[0], TAG_INT))
\r
737 CfgAddInt(current, name, ToInt(data));
\r
739 if (!StrCmpi(token->Token[0], TAG_INT64))
\r
742 CfgAddInt64(current, name, ToInt64(data));
\r
744 if (!StrCmpi(token->Token[0], TAG_BOOL))
\r
748 if (!StrCmpi(data, TAG_TRUE))
\r
752 else if (ToInt(data) != 0)
\r
756 CfgAddBool(current, name, b);
\r
758 if (!StrCmpi(token->Token[0], TAG_BYTE))
\r
761 char *unescaped_b64 = CfgUnescape(data);
\r
762 void *tmp = Malloc(StrLen(unescaped_b64) * 4 + 64);
\r
763 int size = B64_Decode(tmp, unescaped_b64, StrLen(unescaped_b64));
\r
764 CfgAddByte(current, name, tmp, size);
\r
766 Free(unescaped_b64);
\r
781 // ストリームテキストをフォルダに変換
\r
782 FOLDER *CfgBufTextToFolder(BUF *b)
\r
791 // root フォルダから再帰的に読み込む
\r
792 c = CfgCreateFolder(NULL, "tmp");
\r
797 if (CfgReadNextTextBUF(b, c) == false)
\r
804 f = CfgGetFolder(c, TAG_ROOT);
\r
807 // root フォルダが見つからない
\r
808 CfgDeleteFolder(c);
\r
812 // tmp フォルダから root への参照を削除
\r
813 Delete(c->Folders, f);
\r
817 CfgDeleteFolder(c);
\r
824 void CfgReadNextFolderBin(BUF *b, FOLDER *parent)
\r
826 char name[MAX_SIZE];
\r
833 if (b == NULL || parent == NULL)
\r
839 ReadBufStr(b, name, sizeof(name));
\r
840 f = CfgCreateFolder(parent, name);
\r
844 for (i = 0;i < n;i++)
\r
847 CfgReadNextFolderBin(b, f);
\r
852 for (i = 0;i < n;i++)
\r
857 ReadBufStr(b, name, sizeof(name));
\r
859 type = ReadBufInt(b);
\r
863 case ITEM_TYPE_INT:
\r
865 CfgAddInt(f, name, ReadBufInt(b));
\r
868 case ITEM_TYPE_INT64:
\r
870 CfgAddInt64(f, name, ReadBufInt64(b));
\r
873 case ITEM_TYPE_BYTE:
\r
875 size = ReadBufInt(b);
\r
876 buf = ZeroMalloc(size);
\r
877 ReadBuf(b, buf, size);
\r
878 CfgAddByte(f, name, buf, size);
\r
882 case ITEM_TYPE_STRING:
\r
884 size = ReadBufInt(b);
\r
885 buf = ZeroMalloc(size + 1);
\r
886 ReadBuf(b, buf, size);
\r
887 string = ZeroMalloc(CalcUtf8ToUni(buf, StrLen(buf)) + 4);
\r
888 Utf8ToUni(string, 0, buf, StrLen(buf));
\r
889 CfgAddUniStr(f, name, string);
\r
894 case ITEM_TYPE_BOOL:
\r
896 CfgAddBool(f, name, ReadBufInt(b) == 0 ? false : true);
\r
903 FOLDER *CfgBufBinToFolder(BUF *b)
\r
913 c = CfgCreateFolder(NULL, "tmp");
\r
916 CfgReadNextFolderBin(b, c);
\r
919 f = CfgGetFolder(c, TAG_ROOT);
\r
923 CfgDeleteFolder(c);
\r
927 Delete(c->Folders, f);
\r
930 CfgDeleteFolder(c);
\r
936 BUF *CfgFolderToBufBin(FOLDER *f)
\r
939 UCHAR hash[SHA1_SIZE];
\r
949 WriteBuf(b, TAG_BINARY, 8);
\r
952 Zero(hash, sizeof(hash));
\r
953 WriteBuf(b, hash, sizeof(hash));
\r
956 CfgOutputFolderBin(b, f);
\r
959 Hash(((UCHAR *)b->Buf) + 8, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
\r
964 // フォルダをストリームテキストに変換
\r
965 BUF *CfgFolderToBufText(FOLDER *f)
\r
967 return CfgFolderToBufTextEx(f, false);
\r
969 BUF *CfgFolderToBufTextEx(FOLDER *f, bool no_banner)
\r
982 if (no_banner == false)
\r
984 WriteBuf(b, TAG_CPYRIGHT, StrLen(TAG_CPYRIGHT));
\r
988 CfgOutputFolderText(b, f, 0);
\r
993 // フォルダ内容を出力 (フォルダを列挙)
\r
994 bool CfgEnumFolderProc(FOLDER *f, void *param)
\r
998 if (f == NULL || param == NULL)
\r
1003 p = (CFG_ENUM_PARAM *)param;
\r
1005 CfgOutputFolderText(p->b, f, p->depth);
\r
1011 bool CfgEnumItemProc(ITEM *t, void *param)
\r
1013 CFG_ENUM_PARAM *p;
\r
1015 if (t == NULL || param == NULL)
\r
1020 p = (CFG_ENUM_PARAM *)param;
\r
1021 CfgAddItemText(p->b, t, p->depth);
\r
1026 // フォルダ内容を出力 (再帰、バイナリ)
\r
1027 void CfgOutputFolderBin(BUF *b, FOLDER *f)
\r
1031 if (b == NULL || f == NULL)
\r
1037 WriteBufStr(b, f->Name);
\r
1040 WriteBufInt(b, LIST_NUM(f->Folders));
\r
1043 for (i = 0;i < LIST_NUM(f->Folders);i++)
\r
1045 FOLDER *sub = LIST_DATA(f->Folders, i);
\r
1046 CfgOutputFolderBin(b, sub);
\r
1048 if ((i % 100) == 99)
\r
1055 WriteBufInt(b, LIST_NUM(f->Items));
\r
1058 for (i = 0;i < LIST_NUM(f->Items);i++)
\r
1062 ITEM *t = LIST_DATA(f->Items, i);
\r
1065 WriteBufStr(b, t->Name);
\r
1068 WriteBufInt(b, t->Type);
\r
1072 case ITEM_TYPE_INT:
\r
1074 WriteBufInt(b, *((UINT *)t->Buf));
\r
1077 case ITEM_TYPE_INT64:
\r
1079 WriteBufInt64(b, *((UINT64 *)t->Buf));
\r
1082 case ITEM_TYPE_BYTE:
\r
1084 WriteBufInt(b, t->size);
\r
1086 WriteBuf(b, t->Buf, t->size);
\r
1089 case ITEM_TYPE_STRING:
\r
1091 utf8_size = CalcUniToUtf8((wchar_t *)t->Buf) + 1;
\r
1092 utf8 = ZeroMalloc(utf8_size);
\r
1093 UniToUtf8(utf8, utf8_size, (wchar_t *)t->Buf);
\r
1094 WriteBufInt(b, StrLen(utf8));
\r
1095 WriteBuf(b, utf8, StrLen(utf8));
\r
1099 case ITEM_TYPE_BOOL:
\r
1101 if (*((bool *)t->Buf) == false)
\r
1103 WriteBufInt(b, 0);
\r
1107 WriteBufInt(b, 1);
\r
1114 // フォルダ内容を出力 (再帰、テキスト)
\r
1115 void CfgOutputFolderText(BUF *b, FOLDER *f, UINT depth)
\r
1119 if (b == NULL || f == NULL)
\r
1125 CfgAddDeclare(b, f->Name, depth);
\r
1128 Zero(&p, sizeof(CFG_ENUM_PARAM));
\r
1134 CfgEnumItem(f, CfgEnumItemProc, &p);
\r
1136 if (LIST_NUM(f->Folders) != 0 && LIST_NUM(f->Items) != 0)
\r
1138 WriteBuf(b, "\r\n", 2);
\r
1142 CfgEnumFolder(f, CfgEnumFolderProc, &p);
\r
1145 CfgAddEnd(b, depth);
\r
1147 //WriteBuf(b, "\r\n", 2);
\r
1151 void CfgAddItemText(BUF *b, ITEM *t, UINT depth)
\r
1161 if (b == NULL || t == NULL)
\r
1170 case ITEM_TYPE_INT:
\r
1171 data = Malloc(32);
\r
1172 ToStr(data, *((UINT *)t->Buf));
\r
1175 case ITEM_TYPE_INT64:
\r
1176 data = Malloc(64);
\r
1177 ToStr64(data, *((UINT64 *)t->Buf));
\r
1180 case ITEM_TYPE_BYTE:
\r
1181 data = ZeroMalloc(t->size * 4 + 32);
\r
1182 len = B64_Encode(data, t->Buf, t->size);
\r
1186 case ITEM_TYPE_STRING:
\r
1188 utf8_size = CalcUniToUtf8(string);
\r
1190 utf8 = ZeroMalloc(utf8_size);
\r
1192 UniToUtf8(utf8, utf8_size, string);
\r
1197 case ITEM_TYPE_BOOL:
\r
1199 data = Malloc(size);
\r
1200 if (*((bool *)t->Buf) == false)
\r
1202 StrCpy(data, size, TAG_FALSE);
\r
1206 StrCpy(data, size, TAG_TRUE);
\r
1216 CfgAddData(b, t->Type, t->Name, data, sub, depth);
\r
1227 void CfgAddData(BUF *b, UINT type, char *name, char *data, char *sub, UINT depth)
\r
1232 char *sub2 = NULL;
\r
1235 if (b == NULL || type == 0 || name == NULL || data == NULL)
\r
1240 name2 = CfgEscape(name);
\r
1241 data2 = CfgEscape(data);
\r
1244 sub2 = CfgEscape(sub);
\r
1247 tmp_size = StrLen(name2) + StrLen(data2) + 2 + 64 + 1;
\r
1248 tmp = Malloc(tmp_size);
\r
1252 StrCpy(tmp, tmp_size, CfgTypeToStr(type));
\r
1253 StrCat(tmp, tmp_size, " ");
\r
1254 StrCat(tmp, tmp_size, name2);
\r
1255 StrCat(tmp, tmp_size, " ");
\r
1256 StrCat(tmp, tmp_size, data2);
\r
1257 StrCat(tmp, tmp_size, " ");
\r
1258 StrCat(tmp, tmp_size, sub2);
\r
1262 StrCpy(tmp, tmp_size, CfgTypeToStr(type));
\r
1263 StrCat(tmp, tmp_size, " ");
\r
1264 StrCat(tmp, tmp_size, name2);
\r
1265 StrCat(tmp, tmp_size, " ");
\r
1266 StrCat(tmp, tmp_size, data2);
\r
1275 CfgAddLine(b, tmp, depth);
\r
1279 // データ種類文字列を整数値に変換
\r
1280 UINT CfgStrToType(char *str)
\r
1282 if (!StrCmpi(str, TAG_INT)) return ITEM_TYPE_INT;
\r
1283 if (!StrCmpi(str, TAG_INT64)) return ITEM_TYPE_INT64;
\r
1284 if (!StrCmpi(str, TAG_BYTE)) return ITEM_TYPE_BYTE;
\r
1285 if (!StrCmpi(str, TAG_STRING)) return ITEM_TYPE_STRING;
\r
1286 if (!StrCmpi(str, TAG_BOOL)) return ITEM_TYPE_BOOL;
\r
1291 char *CfgTypeToStr(UINT type)
\r
1295 case ITEM_TYPE_INT:
\r
1297 case ITEM_TYPE_INT64:
\r
1299 case ITEM_TYPE_BYTE:
\r
1301 case ITEM_TYPE_STRING:
\r
1302 return TAG_STRING;
\r
1303 case ITEM_TYPE_BOOL:
\r
1310 void CfgAddEnd(BUF *b, UINT depth)
\r
1318 CfgAddLine(b, "}", depth);
\r
1319 // CfgAddLine(b, TAG_END, depth);
\r
1323 void CfgAddDeclare(BUF *b, char *name, UINT depth)
\r
1329 if (b == NULL || name == NULL)
\r
1334 name2 = CfgEscape(name);
\r
1336 tmp_size = StrLen(name2) + 2 + StrLen(TAG_DECLARE);
\r
1337 tmp = Malloc(tmp_size);
\r
1339 Format(tmp, 0, "%s %s", TAG_DECLARE, name2);
\r
1340 CfgAddLine(b, tmp, depth);
\r
1341 CfgAddLine(b, "{", depth);
\r
1347 void CfgAddLine(BUF *b, char *str, UINT depth)
\r
1356 for (i = 0;i < depth;i++)
\r
1358 WriteBuf(b, "\t", 1);
\r
1360 WriteBuf(b, str, StrLen(str));
\r
1361 WriteBuf(b, "\r\n", 2);
\r
1365 BUF *CfgFolderToBuf(FOLDER *f, bool textmode)
\r
1367 return CfgFolderToBufEx(f, textmode, false);
\r
1369 BUF *CfgFolderToBufEx(FOLDER *f, bool textmode, bool no_banner)
\r
1379 return CfgFolderToBufTextEx(f, no_banner);
\r
1383 return CfgFolderToBufBin(f);;
\r
1388 char *CfgUnescape(char *str)
\r
1401 len = StrLen(str);
\r
1402 tmp = ZeroMalloc(len + 1);
\r
1404 if (len == 1 && str[0] == '$')
\r
1411 for (i = 0;i < len;i++)
\r
1413 if (str[i] != '$')
\r
1415 tmp[wp++] = str[i];
\r
1421 tmp2[2] = str[i + 1];
\r
1422 tmp2[3] = str[i + 2];
\r
1425 code = ToInt(tmp2);
\r
1426 tmp[wp++] = (char)code;
\r
1430 ret = Malloc(StrLen(tmp) + 1);
\r
1431 StrCpy(ret, StrLen(tmp) + 1, tmp);
\r
1437 char *CfgEscape(char *str)
\r
1450 len = StrLen(str);
\r
1451 tmp = ZeroMalloc(len * 3 + 2);
\r
1455 StrCpy(tmp, (len * 3 + 2), "$");
\r
1461 for (i = 0;i < len;i++)
\r
1463 if (CfgCheckCharForName(str[i]))
\r
1465 tmp[wp++] = str[i];
\r
1470 Format(tmp2, sizeof(tmp2), "%02X", (UINT)str[i]);
\r
1471 tmp[wp++] = tmp2[0];
\r
1472 tmp[wp++] = tmp2[1];
\r
1476 ret = Malloc(StrLen(tmp) + 1);
\r
1477 StrCpy(ret, 0, tmp);
\r
1482 // 名前に使用することができる文字かどうかチェック
\r
1483 bool CfgCheckCharForName(char c)
\r
1485 if (c >= 0 && c <= 31)
\r
1489 if (c == ' ' || c == '\t')
\r
1501 bool CfgGetStr(FOLDER *f, char *name, char *str, UINT size)
\r
1506 if (f == NULL || name == NULL || str == NULL)
\r
1513 // unicode 文字列を一時的に取得する
\r
1514 tmp_size = size * 4 + 10; // 一応これくらいとっておく
\r
1515 tmp = Malloc(tmp_size);
\r
1516 if (CfgGetUniStr(f, name, tmp, tmp_size) == false)
\r
1524 UniToStr(str, size, tmp);
\r
1530 // unicode_string 型の値の取得
\r
1531 bool CfgGetUniStr(FOLDER *f, char *name, wchar_t *str, UINT size)
\r
1535 if (f == NULL || name == NULL || str == NULL)
\r
1542 t = CfgFindItem(f, name);
\r
1547 if (t->Type != ITEM_TYPE_STRING)
\r
1551 UniStrCpy(str, size, t->Buf);
\r
1556 bool CfgIsFolder(FOLDER *f, char *name)
\r
1559 if (f == NULL || name == NULL)
\r
1564 return (CfgGetFolder(f, name) == NULL) ? false : true;
\r
1568 bool CfgIsItem(FOLDER *f, char *name)
\r
1572 if (f == NULL || name == NULL)
\r
1577 t = CfgFindItem(f, name);
\r
1586 // byte[] 型を BUF で取得
\r
1587 BUF *CfgGetBuf(FOLDER *f, char *name)
\r
1592 if (f == NULL || name == NULL)
\r
1597 t = CfgFindItem(f, name);
\r
1604 WriteBuf(b, t->Buf, t->size);
\r
1611 UINT CfgGetByte(FOLDER *f, char *name, void *buf, UINT size)
\r
1615 if (f == NULL || name == NULL || buf == NULL)
\r
1620 t = CfgFindItem(f, name);
\r
1625 if (t->Type != ITEM_TYPE_BYTE)
\r
1629 if (t->size <= size)
\r
1631 Copy(buf, t->Buf, t->size);
\r
1636 Copy(buf, t->Buf, size);
\r
1642 UINT64 CfgGetInt64(FOLDER *f, char *name)
\r
1647 if (f == NULL || name == NULL)
\r
1652 t = CfgFindItem(f, name);
\r
1657 if (t->Type != ITEM_TYPE_INT64)
\r
1661 if (t->size != sizeof(UINT64))
\r
1666 ret = (UINT64 *)t->Buf;
\r
1671 bool CfgGetBool(FOLDER *f, char *name)
\r
1676 if (f == NULL || name == NULL)
\r
1681 t = CfgFindItem(f, name);
\r
1686 if (t->Type != ITEM_TYPE_BOOL)
\r
1690 if (t->size != sizeof(bool))
\r
1695 ret = (bool *)t->Buf;
\r
1696 if (*ret == false)
\r
1707 UINT CfgGetInt(FOLDER *f, char *name)
\r
1712 if (f == NULL || name == NULL)
\r
1717 t = CfgFindItem(f, name);
\r
1722 if (t->Type != ITEM_TYPE_INT)
\r
1726 if (t->size != sizeof(UINT))
\r
1731 ret = (UINT *)t->Buf;
\r
1736 ITEM *CfgFindItem(FOLDER *parent, char *name)
\r
1740 if (parent == NULL || name == NULL)
\r
1745 tt.Name = ZeroMalloc(StrLen(name) + 1);
\r
1746 StrCpy(tt.Name, 0, name);
\r
1747 t = Search(parent->Items, &tt);
\r
1754 FOLDER *CfgGetFolder(FOLDER *parent, char *name)
\r
1756 return CfgFindFolder(parent, name);
\r
1760 FOLDER *CfgFindFolder(FOLDER *parent, char *name)
\r
1764 if (parent == NULL || name == NULL)
\r
1769 ff.Name = ZeroMalloc(StrLen(name) + 1);
\r
1770 StrCpy(ff.Name, 0, name);
\r
1771 f = Search(parent->Folders, &ff);
\r
1778 ITEM *CfgAddStr(FOLDER *f, char *name, char *str)
\r
1784 if (f == NULL || name == NULL || str == NULL)
\r
1790 tmp_size = CalcStrToUni(str);
\r
1791 if (tmp_size == 0)
\r
1795 tmp = Malloc(tmp_size);
\r
1796 StrToUni(tmp, tmp_size, str);
\r
1797 t = CfgAddUniStr(f, name, tmp);
\r
1803 // unicode_string 型の追加
\r
1804 ITEM *CfgAddUniStr(FOLDER *f, char *name, wchar_t *str)
\r
1807 if (f == NULL || name == NULL || str == NULL)
\r
1812 return CfgCreateItem(f, name, ITEM_TYPE_STRING, str, UniStrSize(str));
\r
1816 ITEM *CfgAddBuf(FOLDER *f, char *name, BUF *b)
\r
1819 if (f == NULL || name == NULL || b == NULL)
\r
1823 return CfgAddByte(f, name, b->Buf, b->Size);
\r
1827 ITEM *CfgAddByte(FOLDER *f, char *name, void *buf, UINT size)
\r
1830 if (f == NULL || name == NULL || buf == NULL)
\r
1834 return CfgCreateItem(f, name, ITEM_TYPE_BYTE, buf, size);
\r
1838 ITEM *CfgAddInt64(FOLDER *f, char *name, UINT64 i)
\r
1841 if (f == NULL || name == NULL)
\r
1845 return CfgCreateItem(f, name, ITEM_TYPE_INT64, &i, sizeof(UINT64));
\r
1849 bool CfgGetIp(FOLDER *f, char *name, struct IP *ip)
\r
1851 char tmp[MAX_SIZE];
\r
1853 if (f == NULL || name == NULL || ip == NULL)
\r
1858 Zero(ip, sizeof(IP));
\r
1860 if (CfgGetStr(f, name, tmp, sizeof(tmp)) == false)
\r
1865 if (StrToIP(ip, tmp) == false)
\r
1872 UINT CfgGetIp32(FOLDER *f, char *name)
\r
1876 if (f == NULL || name == NULL)
\r
1881 if (CfgGetIp(f, name, &p) == false)
\r
1886 return IPToUINT(&p);
\r
1888 bool CfgGetIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
\r
1892 Zero(addr, sizeof(IPV6_ADDR));
\r
1893 if (f == NULL || name == NULL || addr == NULL)
\r
1898 if (CfgGetIp(f, name, &ip) == false)
\r
1903 if (IsIP6(&ip) == false)
\r
1908 if (IPToIPv6Addr(addr, &ip) == false)
\r
1917 ITEM *CfgAddIp(FOLDER *f, char *name, struct IP *ip)
\r
1919 char tmp[MAX_SIZE];
\r
1921 if (f == NULL || name == NULL || ip == NULL)
\r
1926 IPToStr(tmp, sizeof(tmp), ip);
\r
1928 return CfgAddStr(f, name, tmp);
\r
1930 ITEM *CfgAddIp32(FOLDER *f, char *name, UINT ip)
\r
1934 if (f == NULL || name == NULL)
\r
1941 return CfgAddIp(f, name, &p);
\r
1943 ITEM *CfgAddIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
\r
1947 if (f == NULL || name == NULL || addr == NULL)
\r
1952 IPv6AddrToIP(&ip, addr);
\r
1954 return CfgAddIp(f, name, &ip);
\r
1958 ITEM *CfgAddInt(FOLDER *f, char *name, UINT i)
\r
1961 if (f == NULL || name == NULL)
\r
1965 return CfgCreateItem(f, name, ITEM_TYPE_INT, &i, sizeof(UINT));
\r
1969 ITEM *CfgAddBool(FOLDER *f, char *name, bool b)
\r
1973 if (f == NULL || name == NULL)
\r
1979 return CfgCreateItem(f, name, ITEM_TYPE_BOOL, &b, sizeof(bool));
\r
1983 int CmpItemName(void *p1, void *p2)
\r
1986 if (p1 == NULL || p2 == NULL)
\r
1990 f1 = *(ITEM **)p1;
\r
1991 f2 = *(ITEM **)p2;
\r
1992 if (f1 == NULL || f2 == NULL)
\r
1996 return StrCmpi(f1->Name, f2->Name);
\r
2000 int CmpFolderName(void *p1, void *p2)
\r
2003 if (p1 == NULL || p2 == NULL)
\r
2007 f1 = *(FOLDER **)p1;
\r
2008 f2 = *(FOLDER **)p2;
\r
2009 if (f1 == NULL || f2 == NULL)
\r
2013 return StrCmpi(f1->Name, f2->Name);
\r
2017 void CfgEnumItem(FOLDER *f, ENUM_ITEM proc, void *param)
\r
2021 if (f == NULL || proc == NULL)
\r
2026 for (i = 0;i < LIST_NUM(f->Items);i++)
\r
2028 ITEM *tt = LIST_DATA(f->Items, i);
\r
2029 if (proc(tt, param) == false)
\r
2036 // フォルダを列挙してトークンリストに格納
\r
2037 TOKEN_LIST *CfgEnumFolderToTokenList(FOLDER *f)
\r
2039 TOKEN_LIST *t, *ret;
\r
2047 t = ZeroMalloc(sizeof(TOKEN_LIST));
\r
2048 t->NumTokens = LIST_NUM(f->Folders);
\r
2049 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
\r
2051 for (i = 0;i < t->NumTokens;i++)
\r
2053 FOLDER *ff = LIST_DATA(f->Folders, i);
\r
2054 t->Token[i] = CopyStr(ff->Name);
\r
2057 ret = UniqueToken(t);
\r
2063 // アイテムを列挙してトークンリストに格納
\r
2064 TOKEN_LIST *CfgEnumItemToTokenList(FOLDER *f)
\r
2066 TOKEN_LIST *t, *ret;
\r
2074 t = ZeroMalloc(sizeof(TOKEN_LIST));
\r
2075 t->NumTokens = LIST_NUM(f->Items);
\r
2076 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
\r
2078 for (i = 0;i < t->NumTokens;i++)
\r
2080 FOLDER *ff = LIST_DATA(f->Items, i);
\r
2081 t->Token[i] = CopyStr(ff->Name);
\r
2084 ret = UniqueToken(t);
\r
2091 void CfgEnumFolder(FOLDER *f, ENUM_FOLDER proc, void *param)
\r
2095 if (f == NULL || proc == NULL)
\r
2100 for (i = 0;i < LIST_NUM(f->Folders);i++)
\r
2102 FOLDER *ff = LIST_DATA(f->Folders, i);
\r
2103 if (proc(ff, param) == false)
\r
2108 if ((i % 100) == 99)
\r
2116 ITEM *CfgCreateItem(FOLDER *parent, char *name, UINT type, void *buf, UINT size)
\r
2120 #ifdef CHECK_CFG_NAME_EXISTS
\r
2122 #endif // CHECK_CFG_NAME_EXISTS
\r
2124 if (parent == NULL || name == NULL || type == 0 || buf == NULL)
\r
2129 name_size = StrLen(name) + 1;
\r
2131 #ifdef CHECK_CFG_NAME_EXISTS
\r
2133 // すでに同名のアイテムが無いかどうか確認
\r
2134 tt.Name = ZeroMalloc(name_size);
\r
2135 StrCpy(tt.Name, 0, name);
\r
2136 t = Search(parent->Items, &tt);
\r
2144 #endif // CHECK_CFG_NAME_EXISTS
\r
2146 t = ZeroMalloc(sizeof(ITEM));
\r
2147 t->Buf = Malloc(size);
\r
2148 Copy(t->Buf, buf, size);
\r
2149 t->Name = ZeroMalloc(name_size);
\r
2150 StrCpy(t->Name, 0, name);
\r
2153 t->Parent = parent;
\r
2156 Insert(parent->Items, t);
\r
2162 void CfgDeleteItem(ITEM *t)
\r
2171 Delete(t->Parent->Items, t);
\r
2181 void CfgDeleteFolder(FOLDER *f)
\r
2193 num = LIST_NUM(f->Folders);
\r
2194 ff = Malloc(sizeof(FOLDER *) * num);
\r
2195 Copy(ff, f->Folders->p, sizeof(FOLDER *) * num);
\r
2196 for (i = 0;i < num;i++)
\r
2198 CfgDeleteFolder(ff[i]);
\r
2203 num = LIST_NUM(f->Items);
\r
2204 tt = Malloc(sizeof(ITEM *) * num);
\r
2205 Copy(tt, f->Items->p, sizeof(ITEM *) * num);
\r
2206 for (i = 0;i < num;i++)
\r
2208 CfgDeleteItem(tt[i]);
\r
2215 if (f->Parent != NULL)
\r
2217 Delete(f->Parent->Folders, f);
\r
2220 ReleaseList(f->Folders);
\r
2221 ReleaseList(f->Items);
\r
2228 FOLDER *CfgCreateRoot()
\r
2230 return CfgCreateFolder(NULL, TAG_ROOT);
\r
2234 FOLDER *CfgCreateFolder(FOLDER *parent, char *name)
\r
2244 size = StrLen(name) + 1;
\r
2246 #ifdef CHECK_CFG_NAME_EXISTS
\r
2249 if (parent != NULL)
\r
2252 ff.Name = ZeroMalloc(size);
\r
2253 StrCpy(ff.Name, 0, name);
\r
2254 f = Search(parent->Folders, &ff);
\r
2258 // 既に同じ名前のフォルダが存在する
\r
2263 #endif // CHECK_CFG_NAME_EXISTS
\r
2265 f = ZeroMalloc(sizeof(FOLDER));
\r
2266 f->Items = NewListFast(CmpItemName);
\r
2267 f->Folders = NewListFast(CmpFolderName);
\r
2268 f->Name = ZeroMalloc(size);
\r
2269 StrCpy(f->Name, 0, name);
\r
2270 f->Parent = parent;
\r
2273 if (f->Parent != NULL)
\r
2275 Insert(f->Parent->Folders, f);
\r