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