source: lab.git/Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Cfg.c @ a1bae3e

trunk
Last change on this file since a1bae3e was a1bae3e, checked in by mitty <mitty@…>, 12 years ago
  • copy vendor drop to trunk

git-svn-id: https://lab.mitty.jp/svn/lab/trunk@147 7d2118f6-f56c-43e7-95a2-4bb3031d96e7

  • Property mode set to 100644
File size: 43.1 KB
Line 
1// SoftEther UT-VPN SourceCode
2//
3// Copyright (C) 2004-2010 SoftEther Corporation.
4// Copyright (C) 2004-2010 University of Tsukuba, Japan.
5// Copyright (C) 2003-2010 Daiyuu Nobori.
6// All Rights Reserved.
7//
8// http://utvpn.tsukuba.ac.jp/
9//
10// This program is free software; you can redistribute it and/or
11// modify it under the terms of the GNU General Public License
12// version 2 as published by the Free Software Foundation.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License version 2
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22//
23// このファイルは GPL バージョン 2 ライセンスで公開されています。
24// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
25// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
26// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
27// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
28//
29// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
30// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
31// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
32// ホストされています。
33// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
34// および、試験または研究のために利用が行われることを想定して配布
35// しています。
36// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
37// あります。
38// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
39// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
40// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
41// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
42// に組み込みさせていただきます。
43//
44// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
45// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
46//
47// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
48// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
49// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
50// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
51// ください。
52//
53// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
54// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
55// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
56// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
57// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
58// 公益保護にご協力いただきますようお願い申し上げます。
59//
60// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
61// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
62// を保護するための努力を行います。
63//
64// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
65// 日本国内の脆弱性情報届出受付公的機関:
66//         独立行政法人 情報処理推進機構
67//         http://www.ipa.go.jp/security/vuln/report/
68//
69// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
70// 連絡先: http://www.softether.co.jp/jp/contact/
71
72// -----------------------------------------------
73// [ChangeLog]
74// 2010.05.20
75//  新規リリース by SoftEther
76// -----------------------------------------------
77
78// Cfg.c
79// 設定情報操作モジュール
80
81#define CFG_C
82
83#include <stdio.h>
84#include <stdlib.h>
85#include <string.h>
86#include <wchar.h>
87#include <stdarg.h>
88#include <time.h>
89#include <errno.h>
90#include <Mayaqua/Mayaqua.h>
91
92// 設定ファイルのバックアップの作成
93void BackupCfg(FOLDER *f, char *original)
94{
95    wchar_t *original_w = CopyStrToUni(original);
96
97    BackupCfgW(f, original_w);
98
99    Free(original_w);
100}
101void BackupCfgW(FOLDER *f, wchar_t *original)
102{
103    wchar_t dirname[MAX_PATH];
104    wchar_t filename[MAX_PATH];
105    wchar_t fullpath[MAX_PATH];
106    SYSTEMTIME st;
107    // 引数チェック
108    if (f == NULL || filename == NULL)
109    {
110        return;
111    }
112
113    // ディレクトリ名を決定
114    UniFormat(dirname, sizeof(dirname), L"@backup.%s", original[0] == L'@' ? original + 1 : original);
115
116    // ファイル名を決定
117    LocalTime(&st);
118    UniFormat(filename, sizeof(filename), L"%04u%02u%02u%02u_%s",
119        st.wYear, st.wMonth, st.wDay, st.wHour, original[0] == L'@' ? original + 1 : original);
120
121    // このファイル名が存在するかどうかチェックする
122    if (IsFileExistsW(filename))
123    {
124        return;
125    }
126
127    // ディレクトリ作成
128    MakeDirW(dirname);
129
130    // ファイル保存
131    UniFormat(fullpath, sizeof(fullpath), L"%s/%s", dirname, filename);
132    CfgSaveW(f, fullpath);
133}
134
135// 設定ファイル R/W を閉じる
136void FreeCfgRw(CFG_RW *rw)
137{
138    // 引数チェック
139    if (rw == NULL)
140    {
141        return;
142    }
143
144    if (rw->Io != NULL)
145    {
146        FileClose(rw->Io);
147    }
148
149    DeleteLock(rw->lock);
150    Free(rw->FileNameW);
151    Free(rw->FileName);
152    Free(rw);
153}
154
155// 設定ファイルの書き込み
156UINT SaveCfgRw(CFG_RW *rw, FOLDER *f)
157{
158    UINT ret = 0;
159    // 引数チェック
160    if (rw == NULL || f == NULL)
161    {
162        return 0;
163    }
164
165    Lock(rw->lock);
166    {
167        if (rw->Io != NULL)
168        {
169            FileClose(rw->Io);
170            rw->Io = NULL;
171        }
172
173        if (CfgSaveExW2(rw, f, rw->FileNameW, &ret))
174        {
175            if (rw->DontBackup == false)
176            {
177                BackupCfgW(f, rw->FileNameW);
178            }
179        }
180        else
181        {
182            ret = 0;
183        }
184
185        rw->Io = FileOpenW(rw->FileNameW, false);
186    }
187    Unlock(rw->lock);
188
189    return ret;
190}
191
192// 設定ファイル R/W の作成
193CFG_RW *NewCfgRw(FOLDER **root, char *cfg_name)
194{
195    return NewCfgRwEx(root, cfg_name, false);
196}
197CFG_RW *NewCfgRwW(FOLDER **root, wchar_t *cfg_name)
198{
199    return NewCfgRwExW(root, cfg_name, false);
200}
201CFG_RW *NewCfgRwEx(FOLDER **root, char *cfg_name, bool dont_backup)
202{
203    wchar_t *cfg_name_w = CopyStrToUni(cfg_name);
204    CFG_RW *ret = NewCfgRwExW(root, cfg_name_w, dont_backup);
205
206    Free(cfg_name_w);
207
208    return ret;
209}
210CFG_RW *NewCfgRwExW(FOLDER **root, wchar_t *cfg_name, bool dont_backup)
211{
212    CFG_RW *rw;
213    FOLDER *f;
214    // 引数チェック
215    if (cfg_name == NULL || root == NULL)
216    {
217        return NULL;
218    }
219
220    f = CfgReadW(cfg_name);
221    if (f == NULL)
222    {
223        rw = ZeroMalloc(sizeof(CFG_RW));
224        rw->lock = NewLock();
225        rw->FileNameW = CopyUniStr(cfg_name);
226        rw->FileName = CopyUniToStr(cfg_name);
227        rw->Io = FileCreateW(cfg_name);
228        *root = NULL;
229        rw->DontBackup = dont_backup;
230
231        return rw;
232    }
233
234    rw = ZeroMalloc(sizeof(CFG_RW));
235    rw->FileNameW = CopyUniStr(cfg_name);
236    rw->FileName = CopyUniToStr(cfg_name);
237    rw->Io = FileOpenW(cfg_name, false);
238    rw->lock = NewLock();
239
240    *root = f;
241
242    rw->DontBackup = dont_backup;
243
244    return rw;
245}
246
247// ファイルをコピーする
248bool FileCopy(char *src, char *dst)
249{
250    BUF *b;
251    bool ret = false;
252    // 引数チェック
253    if (src == NULL || dst == NULL)
254    {
255        return false;
256    }
257
258    b = ReadDump(src);
259    if (b == NULL)
260    {
261        return false;
262    }
263
264    SeekBuf(b, 0, 0);
265
266    ret = DumpBuf(b, dst);
267
268    FreeBuf(b);
269
270    return ret;
271}
272bool FileCopyW(wchar_t *src, wchar_t *dst)
273{
274    BUF *b;
275    bool ret = false;
276    // 引数チェック
277    if (src == NULL || dst == NULL)
278    {
279        return false;
280    }
281
282    b = ReadDumpW(src);
283    if (b == NULL)
284    {
285        return false;
286    }
287
288    SeekBuf(b, 0, 0);
289
290    ret = DumpBufW(b, dst);
291
292    FreeBuf(b);
293
294    return ret;
295}
296
297// ファイルへ設定を保存する
298void CfgSave(FOLDER *f, char *name)
299{
300    CfgSaveEx(NULL, f, name);
301}
302void CfgSaveW(FOLDER *f, wchar_t *name)
303{
304    CfgSaveExW(NULL, f, name);
305}
306bool CfgSaveEx(CFG_RW *rw, FOLDER *f, char *name)
307{
308    wchar_t *name_w = CopyStrToUni(name);
309    bool ret = CfgSaveExW(rw, f, name_w);
310
311    Free(name_w);
312
313    return ret;
314}
315bool CfgSaveExW(CFG_RW *rw, FOLDER *f, wchar_t *name)
316{
317    return CfgSaveExW2(rw, f, name, NULL);
318}
319bool CfgSaveExW2(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size)
320{
321    wchar_t tmp[MAX_SIZE];
322    bool text = true;
323    UCHAR hash[SHA1_SIZE];
324    BUF *b;
325    IO *o;
326    bool ret = true;
327    UINT dummy_int = 0;
328    // 引数チェック
329    if (name == NULL || f == NULL)
330    {
331        return false;
332    }
333    if (written_size == NULL)
334    {
335        written_size = &dummy_int;
336    }
337
338    // 同じディレクトリにある SAVE_BINARY_FILE_NAME_SWITCH ファイルがあるかどうか確認
339    if (IsFileExistsW(SAVE_BINARY_FILE_NAME_SWITCH))
340    {
341        text = false;
342    }
343
344    // バッファに変換
345    b = CfgFolderToBuf(f, text);
346    if (b == NULL)
347    {
348        return false;
349    }
350    // 内容をハッシュする
351    Hash(hash, b->Buf, b->Size, true);
352
353    // 最後に書き込んだ内容と書き込む内容を比較する
354    if (rw != NULL)
355    {
356        if (Cmp(hash, rw->LashHash, SHA1_SIZE) == 0)
357        {
358            // 内容が変更されていない
359            ret = false;
360        }
361        else
362        {
363            Copy(rw->LashHash, hash, SHA1_SIZE);
364        }
365    }
366
367    if (ret || OS_IS_UNIX(GetOsInfo()->OsType))
368    {
369        // 一時的なファイル名の生成
370        UniFormat(tmp, sizeof(tmp), L"%s.log", name);
371        // 現在存在するファイルを一時ファイルにコピー
372        FileCopyW(name, tmp);
373
374        // 新しいファイルを保存
375        o = FileCreateW(name);
376        if (o != NULL)
377        {
378            if (FileWrite(o, b->Buf, b->Size) == false)
379            {
380                // ファイル保存失敗
381                FileClose(o);
382                FileDeleteW(name);
383                FileRenameW(tmp, name);
384
385                if (rw != NULL)
386                {
387                    Zero(rw->LashHash, sizeof(rw->LashHash));
388                }
389            }
390            else
391            {
392                // ファイル保存成功
393                FileClose(o);
394                // 一時ファイルの削除
395                FileDeleteW(tmp);
396            }
397        }
398        else
399        {
400            // ファイル保存失敗
401            FileRenameW(tmp, name);
402
403            if (rw != NULL)
404            {
405                Zero(rw->LashHash, sizeof(rw->LashHash));
406            }
407        }
408    }
409
410    *written_size = b->Size;
411
412    // メモリ解放
413    FreeBuf(b);
414
415    return ret;
416}
417
418// ファイルから設定を読み込む
419FOLDER *CfgRead(char *name)
420{
421    wchar_t *name_w = CopyStrToUni(name);
422    FOLDER *ret = CfgReadW(name_w);
423
424    Free(name_w);
425
426    return ret;
427}
428FOLDER *CfgReadW(wchar_t *name)
429{
430    wchar_t tmp[MAX_SIZE];
431    wchar_t newfile[MAX_SIZE];
432    BUF *b;
433    IO *o;
434    UINT size;
435    void *buf;
436    FOLDER *f;
437    bool delete_new = false;
438    bool binary_file = false;
439    bool invalid_file = false;
440    UCHAR header[8];
441    // 引数チェック
442    if (name == NULL)
443    {
444        return NULL;
445    }
446
447    // 新しいファイル名の生成
448    UniFormat(newfile, sizeof(newfile), L"%s.new", name);
449    // 一時的なファイル名の生成
450    UniFormat(tmp, sizeof(tmp), L"%s.log", name);
451
452    // 新しいファイルが存在していれば読み込む
453    o = FileOpenW(newfile, false);
454    if (o == NULL)
455    {
456        // 一時的なファイルを読む
457        o = FileOpenW(tmp, false);
458    }
459    else
460    {
461        delete_new = true;
462    }
463    if (o == NULL)
464    {
465        // 一時的なファイルが無い場合は本来のファイルを読む
466        o = FileOpenW(name, false);
467    }
468    else
469    {
470        // 一時的なファイルのサイズが 0 の場合も本来のファイルを読み込む
471        if (FileSize(o) == 0)
472        {
473            invalid_file = true;
474        }
475
476        if (invalid_file)
477        {
478            FileClose(o);
479            o = FileOpenW(name, false);
480        }
481    }
482    if (o == NULL)
483    {
484        // 読み込みに失敗した
485        return NULL;
486    }
487
488    // バッファに読み込む
489    size = FileSize(o);
490    buf = Malloc(size);
491    FileRead(o, buf, size);
492    b = NewBuf();
493    WriteBuf(b, buf, size);
494    SeekBuf(b, 0, 0);
495
496    // ファイルを閉じる
497    FileClose(o);
498
499    if (delete_new)
500    {
501        // 新しいファイルを削除する
502        FileDeleteW(newfile);
503    }
504
505    // バッファの先頭 8 文字が "SEVPN_DB" の場合はバイナリファイル
506    ReadBuf(b, header, sizeof(header));
507    if (Cmp(header, TAG_BINARY, 8) == 0)
508    {
509        UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
510        binary_file = true;
511
512        // ハッシュチェック
513        ReadBuf(b, hash1, sizeof(hash1));
514
515        Hash(hash2, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
516
517        if (Cmp(hash1, hash2, SHA1_SIZE) != 0)
518        {
519            // 破損ファイル
520            invalid_file = true;
521            FreeBuf(b);
522            return NULL;
523        }
524    }
525
526    SeekBuf(b, 0, 0);
527
528    if (binary_file)
529    {
530        SeekBuf(b, 8 + SHA1_SIZE, 0);
531    }
532
533    // バッファからフォルダに変換
534    if (binary_file == false)
535    {
536        // テキストモード
537        f = CfgBufTextToFolder(b);
538    }
539    else
540    {
541        // バイナリモード
542        f = CfgBufBinToFolder(b);
543    }
544
545    // メモリ解放
546    Free(buf);
547    FreeBuf(b);
548
549    FileDeleteW(newfile);
550
551    return f;
552}
553
554// Cfg のテスト
555void CfgTest2(FOLDER *f, UINT n)
556{
557}
558
559void CfgTest()
560{
561#if 0
562    FOLDER *root;
563    BUF *b;
564    Debug("\nCFG Test Begin\n");
565
566    root = CfgCreateFolder(NULL, TAG_ROOT);
567    CfgTest2(root, 5);
568
569    b = CfgFolderToBufText(root);
570    //Print("%s\n", b->Buf);
571    SeekBuf(b, 0, 0);
572
573    CfgDeleteFolder(root);
574
575    DumpBuf(b, "test1.config");
576
577    root = CfgBufTextToFolder(b);
578
579    FreeBuf(b);
580
581    b = CfgFolderToBufText(root);
582//  Print("%s\n", b->Buf);
583    DumpBuf(b, "test2.config");
584    FreeBuf(b);
585
586    CfgSave(root, "test.txt");
587
588    CfgDeleteFolder(root);
589
590    Debug("\nCFG Test End\n");
591#endif
592}
593
594// 1 行読み込む
595char *CfgReadNextLine(BUF *b)
596{
597    char *tmp;
598    char *buf;
599    UINT len;
600    // 引数チェック
601    if (b == NULL)
602    {
603        return NULL;
604    }
605
606    // 次の改行までの文字数を調査
607    tmp = (char *)b->Buf + b->Current;
608    if ((b->Size - b->Current) == 0)
609    {
610        // 最後まで読んだ
611        return NULL;
612    }
613    len = 0;
614    while (true)
615    {
616        if (tmp[len] == 13 || tmp[len] == 10)
617        {
618            if (tmp[len] == 13)
619            {
620                if (len < (b->Size - b->Current))
621                {
622                    len++;
623                }
624            }
625            break;
626        }
627        len++;
628        if (len >= (b->Size - b->Current))
629        {
630            break;
631        }
632    }
633
634    // len だけ読み込む
635    buf = ZeroMalloc(len + 1);
636    ReadBuf(b, buf, len);
637    SeekBuf(b, 1, 1);
638
639    if (StrLen(buf) >= 1)
640    {
641        if (buf[StrLen(buf) - 1] == 13)
642        {
643            buf[StrLen(buf) - 1] = 0;
644        }
645    }
646
647    return buf;
648}
649
650// テキストストリームを読み込む
651bool CfgReadNextTextBUF(BUF *b, FOLDER *current)
652{
653    char *buf;
654    TOKEN_LIST *token;
655    char *name;
656    char *string;
657    char *data;
658    bool ret;
659    FOLDER *f;
660
661    // 引数チェック
662    if (b == NULL || current == NULL)
663    {
664        return false;
665    }
666
667    ret = true;
668
669    // 1 行読み込む
670    buf = CfgReadNextLine(b);
671    if (buf == NULL)
672    {
673        return false;
674    }
675
676    // この行を解析
677    token = ParseToken(buf, "\t ");
678    if (token == NULL)
679    {
680        Free(buf);
681        return false;
682    }
683
684    if (token->NumTokens >= 1)
685    {
686        if (!StrCmpi(token->Token[0], TAG_DECLARE))
687        {
688            if (token->NumTokens >= 2)
689            {
690                // declare
691                name = CfgUnescape(token->Token[1]);
692
693                // フォルダの作成
694                f = CfgCreateFolder(current, name);
695
696                // 次のフォルダを読み込む
697                while (true)
698                {
699                    if (CfgReadNextTextBUF(b, f) == false)
700                    {
701                        break;
702                    }
703                }
704
705                Free(name);
706            }
707        }
708        if (!StrCmpi(token->Token[0], "}"))
709        {
710            // end
711            ret = false;
712        }
713        if (token->NumTokens >= 3)
714        {
715            name = CfgUnescape(token->Token[1]);
716            data = token->Token[2];
717
718            if (!StrCmpi(token->Token[0], TAG_STRING))
719            {
720                // string
721                wchar_t *uni;
722                UINT uni_size;
723                string = CfgUnescape(data);
724                uni_size = CalcUtf8ToUni(string, StrLen(string));
725                if (uni_size != 0)
726                {
727                    uni = Malloc(uni_size);
728                    Utf8ToUni(uni, uni_size, string, StrLen(string));
729                    CfgAddUniStr(current, name, uni);
730                    Free(uni);
731                }
732                Free(string);
733            }
734            if (!StrCmpi(token->Token[0], TAG_INT))
735            {
736                // uint
737                CfgAddInt(current, name, ToInt(data));
738            }
739            if (!StrCmpi(token->Token[0], TAG_INT64))
740            {
741                // uint64
742                CfgAddInt64(current, name, ToInt64(data));
743            }
744            if (!StrCmpi(token->Token[0], TAG_BOOL))
745            {
746                // bool
747                bool b = false;
748                if (!StrCmpi(data, TAG_TRUE))
749                {
750                    b = true;
751                }
752                else if (ToInt(data) != 0)
753                {
754                    b = true;
755                }
756                CfgAddBool(current, name, b);
757            }
758            if (!StrCmpi(token->Token[0], TAG_BYTE))
759            {
760                // byte
761                char *unescaped_b64 = CfgUnescape(data);
762                void *tmp = Malloc(StrLen(unescaped_b64) * 4 + 64);
763                int size = B64_Decode(tmp, unescaped_b64, StrLen(unescaped_b64));
764                CfgAddByte(current, name, tmp, size);
765                Free(tmp);
766                Free(unescaped_b64);
767            }
768
769            Free(name);
770        }
771    }
772
773    // トークンの解放
774    FreeToken(token);
775
776    Free(buf);
777
778    return ret;
779}
780
781// ストリームテキストをフォルダに変換
782FOLDER *CfgBufTextToFolder(BUF *b)
783{
784    FOLDER *f, *c;
785    // 引数チェック
786    if (b == NULL)
787    {
788        return NULL;
789    }
790
791    // root フォルダから再帰的に読み込む
792    c = CfgCreateFolder(NULL, "tmp");
793
794    while (true)
795    {
796        // テキストストリームを読み込む
797        if (CfgReadNextTextBUF(b, c) == false)
798        {
799            break;
800        }
801    }
802
803    // root フォルダの取得
804    f = CfgGetFolder(c, TAG_ROOT);
805    if (f == NULL)
806    {
807        // root フォルダが見つからない
808        CfgDeleteFolder(c);
809        return NULL;
810    }
811
812    // tmp フォルダから root への参照を削除
813    Delete(c->Folders, f);
814    f->Parent = NULL;
815
816    // tmp フォルダを削除
817    CfgDeleteFolder(c);
818
819    // root フォルダを返す
820    return f;
821}
822
823// 次のフォルダを読み込む
824void CfgReadNextFolderBin(BUF *b, FOLDER *parent)
825{
826    char name[MAX_SIZE];
827    FOLDER *f;
828    UINT n, i;
829    UINT size;
830    UCHAR *buf;
831    wchar_t *string;
832    // 引数チェック
833    if (b == NULL || parent == NULL)
834    {
835        return;
836    }
837
838    // フォルダ名
839    ReadBufStr(b, name, sizeof(name));
840    f = CfgCreateFolder(parent, name);
841
842    // サブフォルダ数
843    n = ReadBufInt(b);
844    for (i = 0;i < n;i++)
845    {
846        // サブフォルダ
847        CfgReadNextFolderBin(b, f);
848    }
849
850    // アイテム数
851    n = ReadBufInt(b);
852    for (i = 0;i < n;i++)
853    {
854        UINT type;
855
856        // 名前
857        ReadBufStr(b, name, sizeof(name));
858        // 種類
859        type = ReadBufInt(b);
860
861        switch (type)
862        {
863        case ITEM_TYPE_INT:
864            // int
865            CfgAddInt(f, name, ReadBufInt(b));
866            break;
867
868        case ITEM_TYPE_INT64:
869            // int64
870            CfgAddInt64(f, name, ReadBufInt64(b));
871            break;
872
873        case ITEM_TYPE_BYTE:
874            // data
875            size = ReadBufInt(b);
876            buf = ZeroMalloc(size);
877            ReadBuf(b, buf, size);
878            CfgAddByte(f, name, buf, size);
879            Free(buf);
880            break;
881
882        case ITEM_TYPE_STRING:
883            // string
884            size = ReadBufInt(b);
885            buf = ZeroMalloc(size + 1);
886            ReadBuf(b, buf, size);
887            string = ZeroMalloc(CalcUtf8ToUni(buf, StrLen(buf)) + 4);
888            Utf8ToUni(string, 0, buf, StrLen(buf));
889            CfgAddUniStr(f, name, string);
890            Free(string);
891            Free(buf);
892            break;
893
894        case ITEM_TYPE_BOOL:
895            // bool
896            CfgAddBool(f, name, ReadBufInt(b) == 0 ? false : true);
897            break;
898        }
899    }
900}
901
902// バイナリをフォルダに変換
903FOLDER *CfgBufBinToFolder(BUF *b)
904{
905    FOLDER *f, *c;
906    // 引数チェック
907    if (b == NULL)
908    {
909        return NULL;
910    }
911
912    // 一時フォルダを作成
913    c = CfgCreateFolder(NULL, "tmp");
914
915    // バイナリを読み込む
916    CfgReadNextFolderBin(b, c);
917
918    // root の取得
919    f = CfgGetFolder(c, TAG_ROOT);
920    if (f == NULL)
921    {
922        // 見つからない
923        CfgDeleteFolder(c);
924        return NULL;
925    }
926
927    Delete(c->Folders, f);
928    f->Parent = NULL;
929
930    CfgDeleteFolder(c);
931
932    return f;
933}
934
935// フォルダをバイナリに変換
936BUF *CfgFolderToBufBin(FOLDER *f)
937{
938    BUF *b;
939    UCHAR hash[SHA1_SIZE];
940    // 引数チェック
941    if (f == NULL)
942    {
943        return NULL;
944    }
945
946    b = NewBuf();
947
948    // ヘッダ
949    WriteBuf(b, TAG_BINARY, 8);
950
951    // ハッシュ領域
952    Zero(hash, sizeof(hash));
953    WriteBuf(b, hash, sizeof(hash));
954
955    // ルートフォルダを出力 (再帰)
956    CfgOutputFolderBin(b, f);
957
958    // ハッシュ
959    Hash(((UCHAR *)b->Buf) + 8, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
960
961    return b;
962}
963
964// フォルダをストリームテキストに変換
965BUF *CfgFolderToBufText(FOLDER *f)
966{
967    return CfgFolderToBufTextEx(f, false);
968}
969BUF *CfgFolderToBufTextEx(FOLDER *f, bool no_banner)
970{
971    BUF *b;
972    // 引数チェック
973    if (f == NULL)
974    {
975        return NULL;
976    }
977
978    // ストリーム作成
979    b = NewBuf();
980
981    // 著作権情報
982    if (no_banner == false)
983    {
984        WriteBuf(b, TAG_CPYRIGHT, StrLen(TAG_CPYRIGHT));
985    }
986
987    // ルートフォルダを出力 (再帰)
988    CfgOutputFolderText(b, f, 0);
989
990    return b;
991}
992
993// フォルダ内容を出力 (フォルダを列挙)
994bool CfgEnumFolderProc(FOLDER *f, void *param)
995{
996    CFG_ENUM_PARAM *p;
997    // 引数チェック
998    if (f == NULL || param == NULL)
999    {
1000        return false;
1001    }
1002
1003    p = (CFG_ENUM_PARAM *)param;
1004    // フォルダ内容を出力 (再帰)
1005    CfgOutputFolderText(p->b, f, p->depth);
1006
1007    return true;
1008}
1009
1010// アイテム内容を出力 (列挙)
1011bool CfgEnumItemProc(ITEM *t, void *param)
1012{
1013    CFG_ENUM_PARAM *p;
1014    // 引数チェック
1015    if (t == NULL || param == NULL)
1016    {
1017        return false;
1018    }
1019
1020    p = (CFG_ENUM_PARAM *)param;
1021    CfgAddItemText(p->b, t, p->depth);
1022
1023    return true;
1024}
1025
1026// フォルダ内容を出力 (再帰、バイナリ)
1027void CfgOutputFolderBin(BUF *b, FOLDER *f)
1028{
1029    UINT i;
1030    // 引数チェック
1031    if (b == NULL || f == NULL)
1032    {
1033        return;
1034    }
1035
1036    // フォルダ名
1037    WriteBufStr(b, f->Name);
1038
1039    // サブフォルダ個数
1040    WriteBufInt(b, LIST_NUM(f->Folders));
1041
1042    // サブフォルダ
1043    for (i = 0;i < LIST_NUM(f->Folders);i++)
1044    {
1045        FOLDER *sub = LIST_DATA(f->Folders, i);
1046        CfgOutputFolderBin(b, sub);
1047
1048        if ((i % 100) == 99)
1049        {
1050            YieldCpu();
1051        }
1052    }
1053
1054    // アイテム個数
1055    WriteBufInt(b, LIST_NUM(f->Items));
1056
1057    // アイテム
1058    for (i = 0;i < LIST_NUM(f->Items);i++)
1059    {
1060        char *utf8;
1061        UINT utf8_size;
1062        ITEM *t = LIST_DATA(f->Items, i);
1063
1064        // アイテム名
1065        WriteBufStr(b, t->Name);
1066
1067        // 型
1068        WriteBufInt(b, t->Type);
1069
1070        switch (t->Type)
1071        {
1072        case ITEM_TYPE_INT:
1073            // 整数
1074            WriteBufInt(b, *((UINT *)t->Buf));
1075            break;
1076
1077        case ITEM_TYPE_INT64:
1078            // 64bit 整数
1079            WriteBufInt64(b, *((UINT64 *)t->Buf));
1080            break;
1081
1082        case ITEM_TYPE_BYTE:
1083            // データサイズ
1084            WriteBufInt(b, t->size);
1085            // データ
1086            WriteBuf(b, t->Buf, t->size);
1087            break;
1088
1089        case ITEM_TYPE_STRING:
1090            // 文字列
1091            utf8_size = CalcUniToUtf8((wchar_t *)t->Buf) + 1;
1092            utf8 = ZeroMalloc(utf8_size);
1093            UniToUtf8(utf8, utf8_size, (wchar_t *)t->Buf);
1094            WriteBufInt(b, StrLen(utf8));
1095            WriteBuf(b, utf8, StrLen(utf8));
1096            Free(utf8);
1097            break;
1098
1099        case ITEM_TYPE_BOOL:
1100            // ブール型
1101            if (*((bool *)t->Buf) == false)
1102            {
1103                WriteBufInt(b, 0);
1104            }
1105            else
1106            {
1107                WriteBufInt(b, 1);
1108            }
1109            break;
1110        }
1111    }
1112}
1113
1114// フォルダ内容を出力 (再帰、テキスト)
1115void CfgOutputFolderText(BUF *b, FOLDER *f, UINT depth)
1116{
1117    CFG_ENUM_PARAM p;
1118    // 引数チェック
1119    if (b == NULL || f == NULL)
1120    {
1121        return;
1122    }
1123
1124    // フォルダの開始を出力
1125    CfgAddDeclare(b, f->Name, depth);
1126    depth++;
1127
1128    Zero(&p, sizeof(CFG_ENUM_PARAM));
1129    p.depth = depth;
1130    p.b = b;
1131    p.f = f;
1132
1133    // アイテム一覧を列挙
1134    CfgEnumItem(f, CfgEnumItemProc, &p);
1135
1136    if (LIST_NUM(f->Folders) != 0 && LIST_NUM(f->Items) != 0)
1137    {
1138        WriteBuf(b, "\r\n", 2);
1139    }
1140
1141    // フォルダ一覧を列挙
1142    CfgEnumFolder(f, CfgEnumFolderProc, &p);
1143    // フォルダの終了を出力
1144    depth--;
1145    CfgAddEnd(b, depth);
1146
1147    //WriteBuf(b, "\r\n", 2);
1148}
1149
1150// アイテム内容を出力
1151void CfgAddItemText(BUF *b, ITEM *t, UINT depth)
1152{
1153    char *data;
1154    char *sub = NULL;
1155    UINT len;
1156    UINT size;
1157    char *utf8;
1158    UINT utf8_size;
1159    wchar_t *string;
1160    // 引数チェック
1161    if (b == NULL || t == NULL)
1162    {
1163        return;
1164    }
1165
1166    // データ種類別に処理をする
1167    data = NULL;
1168    switch (t->Type)
1169    {
1170    case ITEM_TYPE_INT:
1171        data = Malloc(32);
1172        ToStr(data, *((UINT *)t->Buf));
1173        break;
1174
1175    case ITEM_TYPE_INT64:
1176        data = Malloc(64);
1177        ToStr64(data, *((UINT64 *)t->Buf));
1178        break;
1179
1180    case ITEM_TYPE_BYTE:
1181        data = ZeroMalloc(t->size * 4 + 32);
1182        len = B64_Encode(data, t->Buf, t->size);
1183        data[len] = 0;
1184        break;
1185
1186    case ITEM_TYPE_STRING:
1187        string = t->Buf;
1188        utf8_size = CalcUniToUtf8(string);
1189        utf8_size++;
1190        utf8 = ZeroMalloc(utf8_size);
1191        utf8[0] = 0;
1192        UniToUtf8(utf8, utf8_size, string);
1193        size = utf8_size;
1194        data = utf8;
1195        break;
1196
1197    case ITEM_TYPE_BOOL:
1198        size = 32;
1199        data = Malloc(size);
1200        if (*((bool *)t->Buf) == false)
1201        {
1202            StrCpy(data, size, TAG_FALSE);
1203        }
1204        else
1205        {
1206            StrCpy(data, size, TAG_TRUE);
1207        }
1208        break;
1209    }
1210    if (data == NULL)
1211    {
1212        return;
1213    }
1214
1215    // データ行を出力
1216    CfgAddData(b, t->Type, t->Name, data, sub, depth);
1217
1218    // メモリ解放
1219    Free(data);
1220    if (sub != NULL)
1221    {
1222        Free(sub);
1223    }
1224}
1225
1226// データ行を出力
1227void CfgAddData(BUF *b, UINT type, char *name, char *data, char *sub, UINT depth)
1228{
1229    char *tmp;
1230    char *name2;
1231    char *data2;
1232    char *sub2 = NULL;
1233    UINT tmp_size;
1234    // 引数チェック
1235    if (b == NULL || type == 0 || name == NULL || data == NULL)
1236    {
1237        return;
1238    }
1239
1240    name2 = CfgEscape(name);
1241    data2 = CfgEscape(data);
1242    if (sub != NULL)
1243    {
1244        sub2 = CfgEscape(sub);
1245    }
1246
1247    tmp_size = StrLen(name2) + StrLen(data2) + 2 + 64 + 1;
1248    tmp = Malloc(tmp_size);
1249
1250    if (sub2 != NULL)
1251    {
1252        StrCpy(tmp, tmp_size, CfgTypeToStr(type));
1253        StrCat(tmp, tmp_size, " ");
1254        StrCat(tmp, tmp_size, name2);
1255        StrCat(tmp, tmp_size, " ");
1256        StrCat(tmp, tmp_size, data2);
1257        StrCat(tmp, tmp_size, " ");
1258        StrCat(tmp, tmp_size, sub2);
1259    }
1260    else
1261    {
1262        StrCpy(tmp, tmp_size, CfgTypeToStr(type));
1263        StrCat(tmp, tmp_size, " ");
1264        StrCat(tmp, tmp_size, name2);
1265        StrCat(tmp, tmp_size, " ");
1266        StrCat(tmp, tmp_size, data2);
1267    }
1268
1269    Free(name2);
1270    Free(data2);
1271    if (sub2 != NULL)
1272    {
1273        Free(sub2);
1274    }
1275    CfgAddLine(b, tmp, depth);
1276    Free(tmp);
1277}
1278
1279// データ種類文字列を整数値に変換
1280UINT CfgStrToType(char *str)
1281{
1282    if (!StrCmpi(str, TAG_INT)) return ITEM_TYPE_INT;
1283    if (!StrCmpi(str, TAG_INT64)) return ITEM_TYPE_INT64;
1284    if (!StrCmpi(str, TAG_BYTE)) return ITEM_TYPE_BYTE;
1285    if (!StrCmpi(str, TAG_STRING)) return ITEM_TYPE_STRING;
1286    if (!StrCmpi(str, TAG_BOOL)) return ITEM_TYPE_BOOL;
1287    return 0;
1288}
1289
1290// データの種類を文字列に変換
1291char *CfgTypeToStr(UINT type)
1292{
1293    switch (type)
1294    {
1295    case ITEM_TYPE_INT:
1296        return TAG_INT;
1297    case ITEM_TYPE_INT64:
1298        return TAG_INT64;
1299    case ITEM_TYPE_BYTE:
1300        return TAG_BYTE;
1301    case ITEM_TYPE_STRING:
1302        return TAG_STRING;
1303    case ITEM_TYPE_BOOL:
1304        return TAG_BOOL;
1305    }
1306    return NULL;
1307}
1308
1309// End 行を出力
1310void CfgAddEnd(BUF *b, UINT depth)
1311{
1312    // 引数チェック
1313    if (b == NULL)
1314    {
1315        return;
1316    }
1317
1318    CfgAddLine(b, "}", depth);
1319//  CfgAddLine(b, TAG_END, depth);
1320}
1321
1322// Declare 行を出力
1323void CfgAddDeclare(BUF *b, char *name, UINT depth)
1324{
1325    char *tmp;
1326    char *name2;
1327    UINT tmp_size;
1328    // 引数チェック
1329    if (b == NULL || name == NULL)
1330    {
1331        return;
1332    }
1333
1334    name2 = CfgEscape(name);
1335
1336    tmp_size = StrLen(name2) + 2 + StrLen(TAG_DECLARE);
1337    tmp = Malloc(tmp_size);
1338
1339    Format(tmp, 0, "%s %s", TAG_DECLARE, name2);
1340    CfgAddLine(b, tmp, depth);
1341    CfgAddLine(b, "{", depth);
1342    Free(tmp);
1343    Free(name2);
1344}
1345
1346// 1 行を出力
1347void CfgAddLine(BUF *b, char *str, UINT depth)
1348{
1349    UINT i;
1350    // 引数チェック
1351    if (b == NULL)
1352    {
1353        return;
1354    }
1355
1356    for (i = 0;i < depth;i++)
1357    {
1358        WriteBuf(b, "\t", 1);
1359    }
1360    WriteBuf(b, str, StrLen(str));
1361    WriteBuf(b, "\r\n", 2);
1362}
1363
1364// フォルダをストリームに変換
1365BUF *CfgFolderToBuf(FOLDER *f, bool textmode)
1366{
1367    return CfgFolderToBufEx(f, textmode, false);
1368}
1369BUF *CfgFolderToBufEx(FOLDER *f, bool textmode, bool no_banner)
1370{
1371    // 引数チェック
1372    if (f == NULL)
1373    {
1374        return NULL;
1375    }
1376
1377    if (textmode)
1378    {
1379        return CfgFolderToBufTextEx(f, no_banner);
1380    }
1381    else
1382    {
1383        return CfgFolderToBufBin(f);;
1384    }
1385}
1386
1387// 文字列のエスケープ復元
1388char *CfgUnescape(char *str)
1389{
1390    char *tmp;
1391    char *ret;
1392    char tmp2[16];
1393    UINT len, wp, i;
1394    UINT code;
1395    // 引数チェック
1396    if (str == NULL)
1397    {
1398        return NULL;
1399    }
1400
1401    len = StrLen(str);
1402    tmp = ZeroMalloc(len + 1);
1403    wp = 0;
1404    if (len == 1 && str[0] == '$')
1405    {
1406        // 空文字
1407        tmp[0] = 0;
1408    }
1409    else
1410    {
1411        for (i = 0;i < len;i++)
1412        {
1413            if (str[i] != '$')
1414            {
1415                tmp[wp++] = str[i];
1416            }
1417            else
1418            {
1419                tmp2[0] = '0';
1420                tmp2[1] = 'x';
1421                tmp2[2] = str[i + 1];
1422                tmp2[3] = str[i + 2];
1423                i += 2;
1424                tmp2[4] = 0;
1425                code = ToInt(tmp2);
1426                tmp[wp++] = (char)code;
1427            }
1428        }
1429    }
1430    ret = Malloc(StrLen(tmp) + 1);
1431    StrCpy(ret, StrLen(tmp) + 1, tmp);
1432    Free(tmp);
1433    return ret;
1434}
1435
1436// 文字列のエスケープ
1437char *CfgEscape(char *str)
1438{
1439    char *tmp;
1440    char *ret;
1441    char tmp2[16];
1442    UINT len;
1443    UINT wp, i;
1444    // 引数チェック
1445    if (str == NULL)
1446    {
1447        return NULL;
1448    }
1449
1450    len = StrLen(str);
1451    tmp = ZeroMalloc(len * 3 + 2);
1452    if (len == 0)
1453    {
1454        // 空文字
1455        StrCpy(tmp, (len * 3 + 2), "$");
1456    }
1457    else
1458    {
1459        // 空文字以外
1460        wp = 0;
1461        for (i = 0;i < len;i++)
1462        {
1463            if (CfgCheckCharForName(str[i]))
1464            {
1465                tmp[wp++] = str[i];
1466            }
1467            else
1468            {
1469                tmp[wp++] = '$';
1470                Format(tmp2, sizeof(tmp2), "%02X", (UINT)str[i]);
1471                tmp[wp++] = tmp2[0];
1472                tmp[wp++] = tmp2[1];
1473            }
1474        }
1475    }
1476    ret = Malloc(StrLen(tmp) + 1);
1477    StrCpy(ret, 0, tmp);
1478    Free(tmp);
1479    return ret;
1480}
1481
1482// 名前に使用することができる文字かどうかチェック
1483bool CfgCheckCharForName(char c)
1484{
1485    if (c >= 0 && c <= 31)
1486    {
1487        return false;
1488    }
1489    if (c == ' ' || c == '\t')
1490    {
1491        return false;
1492    }
1493    if (c == '$')
1494    {
1495        return false;
1496    }
1497    return true;
1498}
1499
1500// string 型の値の取得
1501bool CfgGetStr(FOLDER *f, char *name, char *str, UINT size)
1502{
1503    wchar_t *tmp;
1504    UINT tmp_size;
1505    // 引数チェック
1506    if (f == NULL || name == NULL || str == NULL)
1507    {
1508        return false;
1509    }
1510
1511    str[0] = 0;
1512
1513    // unicode 文字列を一時的に取得する
1514    tmp_size = size * 4 + 10; // 一応これくらいとっておく
1515    tmp = Malloc(tmp_size);
1516    if (CfgGetUniStr(f, name, tmp, tmp_size) == false)
1517    {
1518        // 失敗
1519        Free(tmp);
1520        return false;
1521    }
1522
1523    // ANSI 文字列にコピー
1524    UniToStr(str, size, tmp);
1525    Free(tmp);
1526
1527    return true;
1528}
1529
1530// unicode_string 型の値の取得
1531bool CfgGetUniStr(FOLDER *f, char *name, wchar_t *str, UINT size)
1532{
1533    ITEM *t;
1534    // 引数チェック
1535    if (f == NULL || name == NULL || str == NULL)
1536    {
1537        return false;
1538    }
1539
1540    str[0] = 0;
1541
1542    t = CfgFindItem(f, name);
1543    if (t == NULL)
1544    {
1545        return false;
1546    }
1547    if (t->Type != ITEM_TYPE_STRING)
1548    {
1549        return false;
1550    }
1551    UniStrCpy(str, size, t->Buf);
1552    return true;
1553}
1554
1555// フォルダの存在を確認
1556bool CfgIsFolder(FOLDER *f, char *name)
1557{
1558    // 引数チェック
1559    if (f == NULL || name == NULL)
1560    {
1561        return false;
1562    }
1563
1564    return (CfgGetFolder(f, name) == NULL) ? false : true;
1565}
1566
1567// アイテムの存在を確認
1568bool CfgIsItem(FOLDER *f, char *name)
1569{
1570    ITEM *t;
1571    // 引数チェック
1572    if (f == NULL || name == NULL)
1573    {
1574        return false;
1575    }
1576
1577    t = CfgFindItem(f, name);
1578    if (t == NULL)
1579    {
1580        return false;
1581    }
1582
1583    return true;
1584}
1585
1586// byte[] 型を BUF で取得
1587BUF *CfgGetBuf(FOLDER *f, char *name)
1588{
1589    ITEM *t;
1590    BUF *b;
1591    // 引数チェック
1592    if (f == NULL || name == NULL)
1593    {
1594        return NULL;
1595    }
1596
1597    t = CfgFindItem(f, name);
1598    if (t == NULL)
1599    {
1600        return NULL;
1601    }
1602
1603    b = NewBuf();
1604    WriteBuf(b, t->Buf, t->size);
1605    SeekBuf(b, 0, 0);
1606
1607    return b;
1608}
1609
1610// byte[] 型の値の取得
1611UINT CfgGetByte(FOLDER *f, char *name, void *buf, UINT size)
1612{
1613    ITEM *t;
1614    // 引数チェック
1615    if (f == NULL || name == NULL || buf == NULL)
1616    {
1617        return 0;
1618    }
1619
1620    t = CfgFindItem(f, name);
1621    if (t == NULL)
1622    {
1623        return 0;
1624    }
1625    if (t->Type != ITEM_TYPE_BYTE)
1626    {
1627        return 0;
1628    }
1629    if (t->size <= size)
1630    {
1631        Copy(buf, t->Buf, t->size);
1632        return t->size;
1633    }
1634    else
1635    {
1636        Copy(buf, t->Buf, size);
1637        return t->size;
1638    }
1639}
1640
1641// int64 型の値の取得
1642UINT64 CfgGetInt64(FOLDER *f, char *name)
1643{
1644    ITEM *t;
1645    UINT64 *ret;
1646    // 引数チェック
1647    if (f == NULL || name == NULL)
1648    {
1649        return 0;
1650    }
1651
1652    t = CfgFindItem(f, name);
1653    if (t == NULL)
1654    {
1655        return 0;
1656    }
1657    if (t->Type != ITEM_TYPE_INT64)
1658    {
1659        return 0;
1660    }
1661    if (t->size != sizeof(UINT64))
1662    {
1663        return 0;
1664    }
1665
1666    ret = (UINT64 *)t->Buf;
1667    return *ret;
1668}
1669
1670// bool 型の値の取得
1671bool CfgGetBool(FOLDER *f, char *name)
1672{
1673    ITEM *t;
1674    bool *ret;
1675    // 引数チェック
1676    if (f == NULL || name == NULL)
1677    {
1678        return 0;
1679    }
1680
1681    t = CfgFindItem(f, name);
1682    if (t == NULL)
1683    {
1684        return 0;
1685    }
1686    if (t->Type != ITEM_TYPE_BOOL)
1687    {
1688        return 0;
1689    }
1690    if (t->size != sizeof(bool))
1691    {
1692        return 0;
1693    }
1694
1695    ret = (bool *)t->Buf;
1696    if (*ret == false)
1697    {
1698        return false;
1699    }
1700    else
1701    {
1702        return true;
1703    }
1704}
1705
1706// int 型の値の取得
1707UINT CfgGetInt(FOLDER *f, char *name)
1708{
1709    ITEM *t;
1710    UINT *ret;
1711    // 引数チェック
1712    if (f == NULL || name == NULL)
1713    {
1714        return 0;
1715    }
1716
1717    t = CfgFindItem(f, name);
1718    if (t == NULL)
1719    {
1720        return 0;
1721    }
1722    if (t->Type != ITEM_TYPE_INT)
1723    {
1724        return 0;
1725    }
1726    if (t->size != sizeof(UINT))
1727    {
1728        return 0;
1729    }
1730
1731    ret = (UINT *)t->Buf;
1732    return *ret;
1733}
1734
1735// アイテムの検索
1736ITEM *CfgFindItem(FOLDER *parent, char *name)
1737{
1738    ITEM *t, tt;
1739    // 引数チェック
1740    if (parent == NULL || name == NULL)
1741    {
1742        return NULL;
1743    }
1744
1745    tt.Name = ZeroMalloc(StrLen(name) + 1);
1746    StrCpy(tt.Name, 0, name);
1747    t = Search(parent->Items, &tt);
1748    Free(tt.Name);
1749
1750    return t;
1751}
1752
1753// フォルダの取得
1754FOLDER *CfgGetFolder(FOLDER *parent, char *name)
1755{
1756    return CfgFindFolder(parent, name);
1757}
1758
1759// フォルダの検索
1760FOLDER *CfgFindFolder(FOLDER *parent, char *name)
1761{
1762    FOLDER *f, ff;
1763    // 引数チェック
1764    if (parent == NULL || name == NULL)
1765    {
1766        return NULL;
1767    }
1768
1769    ff.Name = ZeroMalloc(StrLen(name) + 1);
1770    StrCpy(ff.Name, 0, name);
1771    f = Search(parent->Folders, &ff);
1772    Free(ff.Name);
1773
1774    return f;
1775}
1776
1777// string 型の追加
1778ITEM *CfgAddStr(FOLDER *f, char *name, char *str)
1779{
1780    wchar_t *tmp;
1781    UINT tmp_size;
1782    ITEM *t;
1783    // 引数チェック
1784    if (f == NULL || name == NULL || str == NULL)
1785    {
1786        return NULL;
1787    }
1788
1789    // Unicode 文字列に変換
1790    tmp_size = CalcStrToUni(str);
1791    if (tmp_size == 0)
1792    {
1793        return NULL;
1794    }
1795    tmp = Malloc(tmp_size);
1796    StrToUni(tmp, tmp_size, str);
1797    t = CfgAddUniStr(f, name, tmp);
1798    Free(tmp);
1799
1800    return t;
1801}
1802
1803// unicode_string 型の追加
1804ITEM *CfgAddUniStr(FOLDER *f, char *name, wchar_t *str)
1805{
1806    // 引数チェック
1807    if (f == NULL || name == NULL || str == NULL)
1808    {
1809        return NULL;
1810    }
1811
1812    return CfgCreateItem(f, name, ITEM_TYPE_STRING, str, UniStrSize(str));
1813}
1814
1815// バイナリの追加
1816ITEM *CfgAddBuf(FOLDER *f, char *name, BUF *b)
1817{
1818    // 引数チェック
1819    if (f == NULL || name == NULL || b == NULL)
1820    {
1821        return NULL;
1822    }
1823    return CfgAddByte(f, name, b->Buf, b->Size);
1824}
1825
1826// バイト型の追加
1827ITEM *CfgAddByte(FOLDER *f, char *name, void *buf, UINT size)
1828{
1829    // 引数チェック
1830    if (f == NULL || name == NULL || buf == NULL)
1831    {
1832        return NULL;
1833    }
1834    return CfgCreateItem(f, name, ITEM_TYPE_BYTE, buf, size);
1835}
1836
1837// 64bit 整数型の追加
1838ITEM *CfgAddInt64(FOLDER *f, char *name, UINT64 i)
1839{
1840    // 引数チェック
1841    if (f == NULL || name == NULL)
1842    {
1843        return NULL;
1844    }
1845    return CfgCreateItem(f, name, ITEM_TYPE_INT64, &i, sizeof(UINT64));
1846}
1847
1848// IP アドレス型の取得
1849bool CfgGetIp(FOLDER *f, char *name, struct IP *ip)
1850{
1851    char tmp[MAX_SIZE];
1852    // 引数チェック
1853    if (f == NULL || name == NULL || ip == NULL)
1854    {
1855        return false;
1856    }
1857
1858    Zero(ip, sizeof(IP));
1859
1860    if (CfgGetStr(f, name, tmp, sizeof(tmp)) == false)
1861    {
1862        return false;
1863    }
1864
1865    if (StrToIP(ip, tmp) == false)
1866    {
1867        return false;
1868    }
1869
1870    return true;
1871}
1872UINT CfgGetIp32(FOLDER *f, char *name)
1873{
1874    IP p;
1875    // 引数チェック
1876    if (f == NULL || name == NULL)
1877    {
1878        return 0;
1879    }
1880
1881    if (CfgGetIp(f, name, &p) == false)
1882    {
1883        return 0;
1884    }
1885
1886    return IPToUINT(&p);
1887}
1888bool CfgGetIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
1889{
1890    IP ip;
1891    // 引数チェック
1892    Zero(addr, sizeof(IPV6_ADDR));
1893    if (f == NULL || name == NULL || addr == NULL)
1894    {
1895        return false;
1896    }
1897
1898    if (CfgGetIp(f, name, &ip) == false)
1899    {
1900        return false;
1901    }
1902
1903    if (IsIP6(&ip) == false)
1904    {
1905        return false;
1906    }
1907
1908    if (IPToIPv6Addr(addr, &ip) == false)
1909    {
1910        return false;
1911    }
1912
1913    return true;
1914}
1915
1916// IP アドレス型の追加
1917ITEM *CfgAddIp(FOLDER *f, char *name, struct IP *ip)
1918{
1919    char tmp[MAX_SIZE];
1920    // 引数チェック
1921    if (f == NULL || name == NULL || ip == NULL)
1922    {
1923        return NULL;
1924    }
1925
1926    IPToStr(tmp, sizeof(tmp), ip);
1927
1928    return CfgAddStr(f, name, tmp);
1929}
1930ITEM *CfgAddIp32(FOLDER *f, char *name, UINT ip)
1931{
1932    IP p;
1933    // 引数チェック
1934    if (f == NULL || name == NULL)
1935    {
1936        return NULL;
1937    }
1938
1939    UINTToIP(&p, ip);
1940
1941    return CfgAddIp(f, name, &p);
1942}
1943ITEM *CfgAddIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
1944{
1945    IP ip;
1946    // 引数チェック
1947    if (f == NULL || name == NULL || addr == NULL)
1948    {
1949        return NULL;
1950    }
1951
1952    IPv6AddrToIP(&ip, addr);
1953
1954    return CfgAddIp(f, name, &ip);
1955}
1956
1957// 整数型の追加
1958ITEM *CfgAddInt(FOLDER *f, char *name, UINT i)
1959{
1960    // 引数チェック
1961    if (f == NULL || name == NULL)
1962    {
1963        return NULL;
1964    }
1965    return CfgCreateItem(f, name, ITEM_TYPE_INT, &i, sizeof(UINT));
1966}
1967
1968// bool 型の追加
1969ITEM *CfgAddBool(FOLDER *f, char *name, bool b)
1970{
1971    bool v;
1972    // 引数チェック
1973    if (f == NULL || name == NULL)
1974    {
1975        return NULL;
1976    }
1977
1978    v = b ? 1 : 0;
1979    return CfgCreateItem(f, name, ITEM_TYPE_BOOL, &b, sizeof(bool));
1980}
1981
1982// アイテム名の比較関数
1983int CmpItemName(void *p1, void *p2)
1984{
1985    ITEM *f1, *f2;
1986    if (p1 == NULL || p2 == NULL)
1987    {
1988        return 0;
1989    }
1990    f1 = *(ITEM **)p1;
1991    f2 = *(ITEM **)p2;
1992    if (f1 == NULL || f2 == NULL)
1993    {
1994        return 0;
1995    }
1996    return StrCmpi(f1->Name, f2->Name);
1997}
1998
1999// フォルダ名の比較関数
2000int CmpFolderName(void *p1, void *p2)
2001{
2002    FOLDER *f1, *f2;
2003    if (p1 == NULL || p2 == NULL)
2004    {
2005        return 0;
2006    }
2007    f1 = *(FOLDER **)p1;
2008    f2 = *(FOLDER **)p2;
2009    if (f1 == NULL || f2 == NULL)
2010    {
2011        return 0;
2012    }
2013    return StrCmpi(f1->Name, f2->Name);
2014}
2015
2016// アイテムの列挙
2017void CfgEnumItem(FOLDER *f, ENUM_ITEM proc, void *param)
2018{
2019    UINT i;
2020    // 引数チェック
2021    if (f == NULL || proc == NULL)
2022    {
2023        return;
2024    }
2025   
2026    for (i = 0;i < LIST_NUM(f->Items);i++)
2027    {
2028        ITEM *tt = LIST_DATA(f->Items, i);
2029        if (proc(tt, param) == false)
2030        {
2031            break;
2032        }
2033    }
2034}
2035
2036// フォルダを列挙してトークンリストに格納
2037TOKEN_LIST *CfgEnumFolderToTokenList(FOLDER *f)
2038{
2039    TOKEN_LIST *t, *ret;
2040    UINT i;
2041    // 引数チェック
2042    if (f == NULL)
2043    {
2044        return NULL;
2045    }
2046
2047    t = ZeroMalloc(sizeof(TOKEN_LIST));
2048    t->NumTokens = LIST_NUM(f->Folders);
2049    t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
2050
2051    for (i = 0;i < t->NumTokens;i++)
2052    {
2053        FOLDER *ff = LIST_DATA(f->Folders, i);
2054        t->Token[i] = CopyStr(ff->Name);
2055    }
2056
2057    ret = UniqueToken(t);
2058    FreeToken(t);
2059
2060    return ret;
2061}
2062
2063// アイテムを列挙してトークンリストに格納
2064TOKEN_LIST *CfgEnumItemToTokenList(FOLDER *f)
2065{
2066    TOKEN_LIST *t, *ret;
2067    UINT i;
2068    // 引数チェック
2069    if (f == NULL)
2070    {
2071        return NULL;
2072    }
2073
2074    t = ZeroMalloc(sizeof(TOKEN_LIST));
2075    t->NumTokens = LIST_NUM(f->Items);
2076    t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
2077
2078    for (i = 0;i < t->NumTokens;i++)
2079    {
2080        FOLDER *ff = LIST_DATA(f->Items, i);
2081        t->Token[i] = CopyStr(ff->Name);
2082    }
2083
2084    ret = UniqueToken(t);
2085    FreeToken(t);
2086
2087    return ret;
2088}
2089
2090// フォルダの列挙
2091void CfgEnumFolder(FOLDER *f, ENUM_FOLDER proc, void *param)
2092{
2093    UINT i;
2094    // 引数チェック
2095    if (f == NULL || proc == NULL)
2096    {
2097        return;
2098    }
2099   
2100    for (i = 0;i < LIST_NUM(f->Folders);i++)
2101    {
2102        FOLDER *ff = LIST_DATA(f->Folders, i);
2103        if (proc(ff, param) == false)
2104        {
2105            break;
2106        }
2107
2108        if ((i % 100) == 99)
2109        {
2110            YieldCpu();
2111        }
2112    }
2113}
2114
2115// アイテムの作成
2116ITEM *CfgCreateItem(FOLDER *parent, char *name, UINT type, void *buf, UINT size)
2117{
2118    UINT name_size;
2119    ITEM *t;
2120#ifdef  CHECK_CFG_NAME_EXISTS
2121    ITEM tt;
2122#endif  // CHECK_CFG_NAME_EXISTS
2123    // 引数チェック
2124    if (parent == NULL || name == NULL || type == 0 || buf == NULL)
2125    {
2126        return NULL;
2127    }
2128
2129    name_size = StrLen(name) + 1;
2130
2131#ifdef  CHECK_CFG_NAME_EXISTS
2132
2133    // すでに同名のアイテムが無いかどうか確認
2134    tt.Name = ZeroMalloc(name_size);
2135    StrCpy(tt.Name, 0, name);
2136    t = Search(parent->Items, &tt);
2137    Free(tt.Name);
2138    if (t != NULL)
2139    {
2140        // 重複している
2141        return NULL;
2142    }
2143
2144#endif  // CHECK_CFG_NAME_EXISTS
2145
2146    t = ZeroMalloc(sizeof(ITEM));
2147    t->Buf = Malloc(size);
2148    Copy(t->Buf, buf, size);
2149    t->Name = ZeroMalloc(name_size);
2150    StrCpy(t->Name, 0, name);
2151    t->Type = type;
2152    t->size = size;
2153    t->Parent = parent;
2154   
2155    // 親のリストに追加
2156    Insert(parent->Items, t);
2157
2158    return t;
2159}
2160
2161// アイテムの削除
2162void CfgDeleteItem(ITEM *t)
2163{
2164    // 引数チェック
2165    if (t == NULL)
2166    {
2167        return;
2168    }
2169
2170    // 親のリストから削除
2171    Delete(t->Parent->Items, t);
2172
2173    // メモリ解放
2174    Free(t->Buf);
2175    Free(t->Name);
2176    Free(t);
2177}
2178
2179
2180// フォルダの削除
2181void CfgDeleteFolder(FOLDER *f)
2182{
2183    FOLDER **ff;
2184    ITEM **tt;
2185    UINT num, i;
2186    // 引数チェック
2187    if (f == NULL)
2188    {
2189        return;
2190    }
2191
2192    // サブフォルダをすべて削除
2193    num = LIST_NUM(f->Folders);
2194    ff = Malloc(sizeof(FOLDER *) * num);
2195    Copy(ff, f->Folders->p, sizeof(FOLDER *) * num);
2196    for (i = 0;i < num;i++)
2197    {
2198        CfgDeleteFolder(ff[i]);
2199    }
2200    Free(ff);
2201
2202    // アイテムをすべて削除
2203    num = LIST_NUM(f->Items);
2204    tt = Malloc(sizeof(ITEM *) * num);
2205    Copy(tt, f->Items->p, sizeof(ITEM *) * num);
2206    for (i = 0;i < num;i++)
2207    {
2208        CfgDeleteItem(tt[i]);
2209    }
2210    Free(tt);
2211
2212    // メモリ解放
2213    Free(f->Name);
2214    // 親のリストから削除
2215    if (f->Parent != NULL)
2216    {
2217        Delete(f->Parent->Folders, f);
2218    }
2219    // リストの解放
2220    ReleaseList(f->Folders);
2221    ReleaseList(f->Items);
2222
2223    // 本体のメモリの解放
2224    Free(f);
2225}
2226
2227// ルートの作成
2228FOLDER *CfgCreateRoot()
2229{
2230    return CfgCreateFolder(NULL, TAG_ROOT);
2231}
2232
2233// フォルダの作成
2234FOLDER *CfgCreateFolder(FOLDER *parent, char *name)
2235{
2236    UINT size;
2237    FOLDER *f;
2238    // 引数チェック
2239    if (name == NULL)
2240    {
2241        return NULL;
2242    }
2243
2244    size = StrLen(name) + 1;
2245
2246#ifdef  CHECK_CFG_NAME_EXISTS
2247
2248    // 親のリストの名前を検査
2249    if (parent != NULL)
2250    {
2251        FOLDER ff;
2252        ff.Name = ZeroMalloc(size);
2253        StrCpy(ff.Name, 0, name);
2254        f = Search(parent->Folders, &ff);
2255        Free(ff.Name);
2256        if (f != NULL)
2257        {
2258            // 既に同じ名前のフォルダが存在する
2259            return NULL;
2260        }
2261    }
2262
2263#endif  // CHECK_CFG_NAME_EXISTS
2264
2265    f = ZeroMalloc(sizeof(FOLDER));
2266    f->Items = NewListFast(CmpItemName);
2267    f->Folders = NewListFast(CmpFolderName);
2268    f->Name = ZeroMalloc(size);
2269    StrCpy(f->Name, 0, name);
2270    f->Parent = parent;
2271
2272    // 親のリストに追加
2273    if (f->Parent != NULL)
2274    {
2275        Insert(f->Parent->Folders, f);
2276    }
2277    return f;
2278}
2279
2280
Note: See TracBrowser for help on using the repository browser.