source: lab.git/Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Memory.c @ 86521dd

trunk
Last change on this file since 86521dd 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: 48.6 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// Memory.c
79// メモリ管理プログラム
80
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <wchar.h>
85#include <stdarg.h>
86#include <time.h>
87#include <errno.h>
88#include <zlib/zlib.h>
89#include <Mayaqua/Mayaqua.h>
90
91#define MEMORY_SLEEP_TIME       150
92#define MEMORY_MAX_RETRY        30
93#define INIT_BUF_SIZE           10240
94
95#define FIFO_INIT_MEM_SIZE      4096
96#define FIFO_REALLOC_MEM_SIZE   (65536 * 10)    // 絶妙な値
97#define FIFO_REALLOC_MEM_SIZE_SMALL 65536
98
99#define INIT_NUM_RESERVED       32
100static UINT fifo_default_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
101
102// バイナリを検索
103UINT SearchBin(void *data, UINT data_start, UINT data_size, void *key, UINT key_size)
104{
105    UINT i;
106    // 引数チェック
107    if (data == NULL || key == NULL || key_size == 0 || data_size == 0 ||
108        (data_start >= data_size) || (data_start + key_size > data_size))
109    {
110        return INFINITE;
111    }
112
113    for (i = data_start;i < (data_size - key_size + 1);i++)
114    {
115        UCHAR *p = ((UCHAR *)data) + i;
116
117        if (Cmp(p, key, key_size) == 0)
118        {
119            return i;
120        }
121    }
122
123    return INFINITE;
124}
125
126// すぐにクラッシュする
127void CrashNow()
128{
129    // これでとりあえずどのような OS 上でもプロセスは落ちるはずである
130    while (true)
131    {
132        UINT r = Rand32();
133        UCHAR *c = (UCHAR *)r;
134
135        *c = Rand8();
136    }
137}
138
139// バッファを候補に変換
140LIST *BufToCandidate(BUF *b)
141{
142    LIST *o;
143    UINT i;
144    UINT num;
145    // 引数チェック
146    if (b == NULL)
147    {
148        return NULL;
149    }
150
151    num = ReadBufInt(b);
152    o = NewCandidateList();
153
154    for (i = 0;i < num;i++)
155    {
156        CANDIDATE *c;
157        wchar_t *s;
158        UINT64 sec64;
159        UINT len, size;
160        sec64 = ReadBufInt64(b);
161        len = ReadBufInt(b);
162        if (len >= 65536)
163        {
164            break;
165        }
166        size = (len + 1) * 2;
167        s = ZeroMalloc(size);
168        if (ReadBuf(b, s, size) != size)
169        {
170            Free(s);
171            break;
172        }
173        else
174        {
175            c = ZeroMalloc(sizeof(CANDIDATE));
176            c->LastSelectedTime = sec64;
177            c->Str = s;
178            Add(o, c);
179        }
180    }
181
182    Sort(o);
183    return o;
184}
185
186// 候補をバッファに変換
187BUF *CandidateToBuf(LIST *o)
188{
189    BUF *b;
190    UINT i;
191    // 引数チェック
192    if (o == NULL)
193    {
194        return NULL;
195    }
196
197    b = NewBuf();
198    WriteBufInt(b, LIST_NUM(o));
199    for (i = 0;i < LIST_NUM(o);i++)
200    {
201        CANDIDATE *c = LIST_DATA(o, i);
202        WriteBufInt64(b, c->LastSelectedTime);
203        WriteBufInt(b, UniStrLen(c->Str));
204        WriteBuf(b, c->Str, UniStrSize(c->Str));
205    }
206
207    SeekBuf(b, 0, 0);
208
209    return b;
210}
211
212// 候補の追加
213void AddCandidate(LIST *o, wchar_t *str, UINT num_max)
214{
215    UINT i;
216    bool exists;
217    // 引数チェック
218    if (o == NULL || str == NULL)
219    {
220        return;
221    }
222    if (num_max == 0)
223    {
224        num_max = 0x7fffffff;
225    }
226
227    // 文字列コピー
228    str = UniCopyStr(str);
229    UniTrim(str);
230
231    exists = false;
232    for (i = 0;i < LIST_NUM(o);i++)
233    {
234        CANDIDATE *c = LIST_DATA(o, i);
235        if (UniStrCmpi(c->Str, str) == 0)
236        {
237            // 既存のものを発見したので時刻を更新する
238            c->LastSelectedTime = SystemTime64();
239            exists = true;
240            break;
241        }
242    }
243
244    if (exists == false)
245    {
246        // 新しく挿入する
247        CANDIDATE *c = ZeroMalloc(sizeof(CANDIDATE));
248        c->LastSelectedTime = SystemTime64();
249        c->Str = UniCopyStr(str);
250        Insert(o, c);
251    }
252
253    // 文字列解放
254    Free(str);
255
256    // 現在の候補数を調べて、num_max より多ければ
257    // 古いものから順に削除する
258    if (LIST_NUM(o) > num_max)
259    {
260        while (LIST_NUM(o) > num_max)
261        {
262            UINT index = LIST_NUM(o) - 1;
263            CANDIDATE *c = LIST_DATA(o, index);
264            Delete(o, c);
265            Free(c->Str);
266            Free(c);
267        }
268    }
269}
270
271// 候補の比較
272int ComapreCandidate(void *p1, void *p2)
273{
274    CANDIDATE *c1, *c2;
275    if (p1 == NULL || p2 == NULL)
276    {
277        return 0;
278    }
279    c1 = *(CANDIDATE **)p1;
280    c2 = *(CANDIDATE **)p2;
281    if (c1 == NULL || c2 == NULL)
282    {
283        return 0;
284    }
285    if (c1->LastSelectedTime > c2->LastSelectedTime)
286    {
287        return -1;
288    }
289    else if (c1->LastSelectedTime < c2->LastSelectedTime)
290    {
291        return 1;
292    }
293    else
294    {
295        return UniStrCmpi(c1->Str, c2->Str);
296    }
297}
298
299// 候補リストの解放
300void FreeCandidateList(LIST *o)
301{
302    UINT i;
303    // 引数チェック
304    if (o == NULL)
305    {
306        return;
307    }
308
309    for (i = 0;i < LIST_NUM(o);i++)
310    {
311        CANDIDATE *c = LIST_DATA(o, i);
312        Free(c->Str);
313        Free(c);
314    }
315
316    ReleaseList(o);
317}
318
319// 新しい候補リストの作成
320LIST *NewCandidateList()
321{
322    return NewList(ComapreCandidate);
323}
324
325// 指定したアドレスがすべてゼロかどうか調べる
326bool IsZero(void *data, UINT size)
327{
328    UINT i;
329    UCHAR *c = (UCHAR *)data;
330    // 引数チェック
331    if (data == NULL || size == 0)
332    {
333        return true;
334    }
335
336    for (i = 0;i < size;i++)
337    {
338        if (c[i] != 0)
339        {
340            return false;
341        }
342    }
343
344    return true;
345}
346
347// データを展開する
348UINT Uncompress(void *dst, UINT dst_size, void *src, UINT src_size)
349{
350    unsigned long dst_size_long = dst_size;
351    // 引数チェック
352    if (dst == NULL || dst_size_long == 0 || src == NULL)
353    {
354        return 0;
355    }
356
357    if (uncompress(dst, &dst_size_long, src, src_size) != Z_OK)
358    {
359        return 0;
360    }
361
362    return (UINT)dst_size_long;
363}
364
365// データを圧縮する
366UINT Compress(void *dst, UINT dst_size, void *src, UINT src_size)
367{
368    return CompressEx(dst, dst_size, src, src_size, Z_DEFAULT_COMPRESSION);
369}
370
371// データをオプション付きで圧縮する
372UINT CompressEx(void *dst, UINT dst_size, void *src, UINT src_size, UINT level)
373{
374    unsigned long dst_size_long = dst_size;
375    // 引数チェック
376    if (dst == NULL || dst_size_long == 0 || src == NULL)
377    {
378        return 0;
379    }
380
381    if (compress2(dst, &dst_size_long, src, src_size, (int)level) != Z_OK)
382    {
383        return 0;
384    }
385
386    return dst_size_long;
387}
388
389// src_size データを圧縮した場合の最大サイズを取得する
390UINT CalcCompress(UINT src_size)
391{
392    // あっ これは いい加減!
393    return src_size * 2 + 100;
394}
395
396// スタックの作成
397SK *NewSk()
398{
399    return NewSkEx(false);
400}
401SK *NewSkEx(bool no_compact)
402{
403    SK *s;
404
405    s = Malloc(sizeof(SK));
406    s->lock = NewLock();
407    s->ref = NewRef();
408    s->num_item = 0;
409    s->num_reserved = INIT_NUM_RESERVED;
410    s->p = Malloc(sizeof(void *) * s->num_reserved);
411    s->no_compact = no_compact;
412
413#ifndef DONT_USE_KERNEL_STATUS
414    TrackNewObj(POINTER_TO_UINT64(s), "SK", 0);
415#endif  // DONT_USE_KERNEL_STATUS
416
417    // KS
418    KS_INC(KS_NEWSK_COUNT);
419
420    return s;
421}
422
423// スタックの解放
424void ReleaseSk(SK *s)
425{
426    // 引数チェック
427    if (s == NULL)
428    {
429        return;
430    }
431
432    if (Release(s->ref) == 0)
433    {
434        CleanupSk(s);
435    }
436}
437
438// スタックのクリーンアップ
439void CleanupSk(SK *s)
440{
441    // 引数チェック
442    if (s == NULL)
443    {
444        return;
445    }
446
447    // メモリ解放
448    Free(s->p);
449    DeleteLock(s->lock);
450    Free(s);
451
452#ifndef DONT_USE_KERNEL_STATUS
453    TrackDeleteObj(POINTER_TO_UINT64(s));
454#endif  // DONT_USE_KERNEL_STATUS
455
456    // KS
457    KS_INC(KS_FREESK_COUNT);
458}
459
460// スタックのロック
461void LockSk(SK *s)
462{
463    // 引数チェック
464    if (s == NULL)
465    {
466        return;
467    }
468
469    Lock(s->lock);
470}
471
472// スタックのロック解除
473void UnlockSk(SK *s)
474{
475    // 引数チェック
476    if (s == NULL)
477    {
478        return;
479    }
480
481    Unlock(s->lock);
482}
483
484// スタックの Push
485void Push(SK *s, void *p)
486{
487    UINT i;
488    // 引数チェック
489    if (s == NULL || p == NULL)
490    {
491        return;
492    }
493
494    i = s->num_item;
495    s->num_item++;
496
497    // サイズ拡大
498    if (s->num_item > s->num_reserved)
499    {
500        s->num_reserved = s->num_reserved * 2;
501        s->p = ReAlloc(s->p, sizeof(void *) * s->num_reserved);
502    }
503    s->p[i] = p;
504
505    // KS
506    KS_INC(KS_PUSH_COUNT);
507}
508
509// スタックの Pop
510void *Pop(SK *s)
511{
512    void *ret;
513    // 引数チェック
514    if (s == NULL)
515    {
516        return NULL;
517    }
518    if (s->num_item == 0)
519    {
520        return NULL;
521    }
522    ret = s->p[s->num_item - 1];
523    s->num_item--;
524
525    // サイズ縮小
526    if (s->no_compact == false)
527    {
528        // no_compact が true の場合は縮小しない
529        if ((s->num_item * 2) <= s->num_reserved)
530        {
531            if (s->num_reserved >= (INIT_NUM_RESERVED * 2))
532            {
533                s->num_reserved = s->num_reserved / 2;
534                s->p = ReAlloc(s->p, sizeof(void *) * s->num_reserved);
535            }
536        }
537    }
538
539    // KS
540    KS_INC(KS_POP_COUNT);
541
542    return ret;
543}
544
545// 1 つ取得
546void *GetNext(QUEUE *q)
547{
548    void *p = NULL;
549    // 引数チェック
550    if (q == NULL)
551    {
552        return NULL;
553    }
554
555    if (q->num_item == 0)
556    {
557        // アイテム無し
558        return NULL;
559    }
560
561    // FIFO から読み込む
562    ReadFifo(q->fifo, &p, sizeof(void *));
563    q->num_item--;
564
565    // KS
566    KS_INC(KS_GETNEXT_COUNT);
567
568    return p;
569}
570
571// キューに Int 型を挿入
572void InsertQueueInt(QUEUE *q, UINT value)
573{
574    UINT *p;
575    // 引数チェック
576    if (q == NULL)
577    {
578        return;
579    }
580
581    p = Clone(&value, sizeof(UINT));
582
583    InsertQueue(q, p);
584}
585
586// キューに挿入
587void InsertQueue(QUEUE *q, void *p)
588{
589    // 引数チェック
590    if (q == NULL || p == NULL)
591    {
592        return;
593    }
594
595    // FIFO に書き込む
596    WriteFifo(q->fifo, &p, sizeof(void *));
597
598    q->num_item++;
599
600    // KS
601    KS_INC(KS_INSERT_QUEUE_COUNT);
602}
603
604// キューのロック
605void LockQueue(QUEUE *q)
606{
607    // 引数チェック
608    if (q == NULL)
609    {
610        return;
611    }
612
613    Lock(q->lock);
614}
615
616// キューのロック解除
617void UnlockQueue(QUEUE *q)
618{
619    // 引数チェック
620    if (q == NULL)
621    {
622        return;
623    }
624
625    Unlock(q->lock);
626}
627
628// キューの解放
629void ReleaseQueue(QUEUE *q)
630{
631    // 引数チェック
632    if (q == NULL)
633    {
634        return;
635    }
636
637    if (q->ref == NULL || Release(q->ref) == 0)
638    {
639        CleanupQueue(q);
640    }
641}
642
643// キューのクリーンアップ
644void CleanupQueue(QUEUE *q)
645{
646    // 引数チェック
647    if (q == NULL)
648    {
649        return;
650    }
651
652    // メモリ解放
653    ReleaseFifo(q->fifo);
654    DeleteLock(q->lock);
655    Free(q);
656
657#ifndef DONT_USE_KERNEL_STATUS
658    TrackDeleteObj(POINTER_TO_UINT64(q));
659#endif  // DONT_USE_KERNEL_STATUS
660
661    // KS
662    KS_INC(KS_FREEQUEUE_COUNT);
663}
664
665// キューの作成
666QUEUE *NewQueue()
667{
668    QUEUE *q;
669
670    q = ZeroMalloc(sizeof(QUEUE));
671    q->lock = NewLock();
672    q->ref = NewRef();
673    q->num_item = 0;
674    q->fifo = NewFifo();
675
676#ifndef DONT_USE_KERNEL_STATUS
677    TrackNewObj(POINTER_TO_UINT64(q), "QUEUE", 0);
678#endif  // DONT_USE_KERNEL_STATUS
679
680    // KS
681    KS_INC(KS_NEWQUEUE_COUNT);
682
683    return q;
684}
685QUEUE *NewQueueFast()
686{
687    QUEUE *q;
688
689    q = ZeroMalloc(sizeof(QUEUE));
690    q->lock = NULL;
691    q->ref = NULL;
692    q->num_item = 0;
693    q->fifo = NewFifoFast();
694
695#ifndef DONT_USE_KERNEL_STATUS
696    TrackNewObj(POINTER_TO_UINT64(q), "QUEUE", 0);
697#endif  // DONT_USE_KERNEL_STATUS
698
699    // KS
700    KS_INC(KS_NEWQUEUE_COUNT);
701
702    return q;
703}
704
705// リストに比較関数をセットする
706void SetCmp(LIST *o, COMPARE *cmp)
707{
708    // 引数チェック
709    if (o == NULL || cmp == NULL)
710    {
711        return;
712    }
713
714    if (o->cmp != cmp)
715    {
716        o->cmp = cmp;
717        o->sorted = false;
718    }
719}
720
721// リストのクローン
722LIST *CloneList(LIST *o)
723{
724    LIST *n = NewList(o->cmp);
725
726    // メモリ再確保
727    Free(n->p);
728    n->p = ToArray(o);
729    n->num_item = n->num_reserved = LIST_NUM(o);
730    n->sorted = o->sorted;
731
732    return n;
733}
734
735// リストを配列にコピー
736void CopyToArray(LIST *o, void *p)
737{
738    // 引数チェック
739    if (o == NULL || p == NULL)
740    {
741        return;
742    }
743
744    // KS
745    KS_INC(KS_TOARRAY_COUNT);
746
747    Copy(p, o->p, sizeof(void *) * o->num_item);
748}
749
750// リストを配列化する
751void *ToArray(LIST *o)
752{
753    return ToArrayEx(o, false);
754}
755void *ToArrayEx(LIST *o, bool fast)
756{
757    void *p;
758    // 引数チェック
759    if (o == NULL)
760    {
761        return NULL;
762    }
763
764    // メモリ確保
765    if (fast == false)
766    {
767        p = Malloc(sizeof(void *) * LIST_NUM(o));
768    }
769    else
770    {
771        p = MallocFast(sizeof(void *) * LIST_NUM(o));
772    }
773    // コピー
774    CopyToArray(o, p);
775
776    return p;
777}
778
779// リストのサーチ
780void *Search(LIST *o, void *target)
781{
782    void **ret;
783    // 引数チェック
784    if (o == NULL || target == NULL)
785    {
786        return NULL;
787    }
788    if (o->cmp == NULL)
789    {
790        return NULL;
791    }
792
793    // ソートのチェック
794    if (o->sorted == false)
795    {
796        // 未ソートなのでソートを行う
797        Sort(o);
798    }
799
800    // なんだ C ライブラリのバイナリサーチ関数を呼んでいるだけか
801    ret = (void **)bsearch(&target, o->p, o->num_item, sizeof(void *),
802        (int(*)(const void *, const void *))o->cmp);
803
804    // KS
805    KS_INC(KS_SEARCH_COUNT);
806
807    if (ret != NULL)
808    {
809        return *ret;
810    }
811    else
812    {
813        return NULL;
814    }
815}
816
817// リストに項目を挿入
818// 本当はもうちょっとましなデータ構造 & アルゴリズムにするべき
819void Insert(LIST *o, void *p)
820{
821    int low, high, middle;
822    UINT pos;
823    int i;
824    // 引数チェック
825    if (o == NULL || p == NULL)
826    {
827        return;
828    }
829
830    if (o->cmp == NULL)
831    {
832        // ソート関数が無い場合は単純に追加する
833        Add(o, p);
834        return;
835    }
836
837    // ソートされていない場合は直ちにソートする
838    if (o->sorted == false)
839    {
840        Sort(o);
841    }
842
843    low = 0;
844    high = LIST_NUM(o) - 1;
845
846    pos = INFINITE;
847
848    while (low <= high)
849    {
850        int ret;
851
852        middle = (low + high) / 2;
853        ret = o->cmp(&(o->p[middle]), &p);
854
855        if (ret == 0)
856        {
857            pos = middle;
858            break;
859        }
860        else if (ret > 0)
861        {
862            high = middle - 1;
863        }
864        else
865        {
866            low = middle + 1;
867        }
868    }
869
870    if (pos == INFINITE)
871    {
872        pos = low;
873    }
874
875    o->num_item++;
876    if (o->num_item > o->num_reserved)
877    {
878        o->num_reserved *= 2;
879        o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
880    }
881
882    if (LIST_NUM(o) >= 2)
883    {
884        for (i = (LIST_NUM(o) - 2);i >= (int)pos;i--)
885        {
886            o->p[i + 1] = o->p[i];
887        }
888    }
889
890    o->p[pos] = p;
891
892    // KS
893    KS_INC(KS_INSERT_COUNT);
894}
895
896// ソートフラグの設定
897void SetSortFlag(LIST *o, bool sorted)
898{
899    // 引数チェック
900    if (o == NULL)
901    {
902        return;
903    }
904
905    o->sorted = sorted;
906}
907
908// リストのソート
909void Sort(LIST *o)
910{
911    // 引数チェック
912    if (o == NULL || o->cmp == NULL)
913    {
914        return;
915    }
916
917    qsort(o->p, o->num_item, sizeof(void *), (int(*)(const void *, const void *))o->cmp);
918    o->sorted = true;
919
920    // KS
921    KS_INC(KS_SORT_COUNT);
922}
923
924// ある文字列項目がリスト内に存在しているかどうか調べる (Unicode 版)
925bool IsInListUniStr(LIST *o, wchar_t *str)
926{
927    UINT i;
928    // 引数チェック
929    if (o == NULL || str == NULL)
930    {
931        return false;
932    }
933
934    for (i = 0;i < LIST_NUM(o);i++)
935    {
936        wchar_t *s = LIST_DATA(o, i);
937
938        if (UniStrCmpi(s, str) == 0)
939        {
940            return true;
941        }
942    }
943
944    return false;
945}
946
947// リスト内のポインタを置換する
948bool ReplaceListPointer(LIST *o, void *oldptr, void *newptr)
949{
950    UINT i;
951    // 引数チェック
952    if (o == NULL || oldptr == NULL || newptr == NULL)
953    {
954        return false;
955    }
956
957    for (i = 0;i < LIST_NUM(o);i++)
958    {
959        void *p = LIST_DATA(o, i);
960
961        if (p == oldptr)
962        {
963            o->p[i] = newptr;
964            return true;
965        }
966    }
967
968    return false;
969}
970
971// ある文字列項目がリスト内に存在しているかどうか調べる
972bool IsInListStr(LIST *o, char *str)
973{
974    UINT i;
975    // 引数チェック
976    if (o == NULL || str == NULL)
977    {
978        return false;
979    }
980
981    for (i = 0;i < LIST_NUM(o);i++)
982    {
983        char *s = LIST_DATA(o, i);
984
985        if (StrCmpi(s, str) == 0)
986        {
987            return true;
988        }
989    }
990
991    return false;
992}
993
994// リスト内を UINT 形式のポインタで走査してポインタを取得する
995void *ListKeyToPointer(LIST *o, UINT key)
996{
997    UINT i;
998    // 引数チェック
999    if (o == NULL || key == 0)
1000    {
1001        return NULL;
1002    }
1003
1004    for (i = 0;i < LIST_NUM(o);i++)
1005    {
1006        void *p = LIST_DATA(o, i);
1007
1008        if (POINTER_TO_KEY(p) == key)
1009        {
1010            return p;
1011        }
1012    }
1013
1014    return NULL;
1015}
1016
1017// あるキーがリスト内に存在するかどうか調べる
1018bool IsInListKey(LIST *o, UINT key)
1019{
1020    void *p;
1021    // 引数チェック
1022    if (o == NULL || key == 0)
1023    {
1024        return false;
1025    }
1026
1027    p = ListKeyToPointer(o, key);
1028    if (p == NULL)
1029    {
1030        return false;
1031    }
1032
1033    return true;
1034}
1035
1036// ある項目がリスト内に存在するかどうか調べる
1037bool IsInList(LIST *o, void *p)
1038{
1039    UINT i;
1040    // 引数チェック
1041    if (o == NULL || p == NULL)
1042    {
1043        return false;
1044    }
1045
1046    for (i = 0;i < LIST_NUM(o);i++)
1047    {
1048        void *q = LIST_DATA(o, i);
1049        if (p == q)
1050        {
1051            return true;
1052        }
1053    }
1054
1055    return false;
1056}
1057
1058// リストへの要素の追加
1059void Add(LIST *o, void *p)
1060{
1061    UINT i;
1062    // 引数チェック
1063    if (o == NULL || p == NULL)
1064    {
1065        return;
1066    }
1067
1068    i = o->num_item;
1069    o->num_item++;
1070
1071    if (o->num_item > o->num_reserved)
1072    {
1073        o->num_reserved = o->num_reserved * 2;
1074        o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
1075    }
1076
1077    o->p[i] = p;
1078    o->sorted = false;
1079
1080    // KS
1081    KS_INC(KS_INSERT_COUNT);
1082}
1083
1084// リストからキーで指定した要素の削除
1085bool DeleteKey(LIST *o, UINT key)
1086{
1087    void *p;
1088    // 引数チェック
1089    if (o == NULL || key == 0)
1090    {
1091        return false;
1092    }
1093
1094    p = ListKeyToPointer(o, key);
1095    if (p == NULL)
1096    {
1097        return false;
1098    }
1099
1100    return Delete(o, p);
1101}
1102
1103// リストから要素の削除
1104bool Delete(LIST *o, void *p)
1105{
1106    UINT i, n;
1107    // 引数チェック
1108    if (o == NULL || p == NULL)
1109    {
1110        return false;
1111    }
1112
1113    for (i = 0;i < o->num_item;i++)
1114    {
1115        if (o->p[i] == p)
1116        {
1117            break;
1118        }
1119    }
1120    if (i == o->num_item)
1121    {
1122        return false;
1123    }
1124
1125    n = i;
1126    for (i = n;i < (o->num_item - 1);i++)
1127    {
1128        o->p[i] = o->p[i + 1];
1129    }
1130    o->num_item--;
1131    if ((o->num_item * 2) <= o->num_reserved)
1132    {
1133        if (o->num_reserved > (INIT_NUM_RESERVED * 2))
1134        {
1135            o->num_reserved = o->num_reserved / 2;
1136            o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
1137        }
1138    }
1139
1140    // KS
1141    KS_INC(KS_DELETE_COUNT);
1142
1143    return true;
1144}
1145
1146// リストからすべての要素の削除
1147void DeleteAll(LIST *o)
1148{
1149    // 引数チェック
1150    if (o == NULL)
1151    {
1152        return;
1153    }
1154
1155    o->num_item = 0;
1156    o->num_reserved = INIT_NUM_RESERVED;
1157    o->p = ReAlloc(o->p, sizeof(void *) * INIT_NUM_RESERVED);
1158}
1159
1160// リストのロック
1161void LockList(LIST *o)
1162{
1163    // 引数チェック
1164    if (o == NULL)
1165    {
1166        return;
1167    }
1168
1169    Lock(o->lock);
1170}
1171
1172// リストのロック解除
1173void UnlockList(LIST *o)
1174{
1175    // 引数チェック
1176    if (o == NULL)
1177    {
1178        return;
1179    }
1180
1181    Unlock(o->lock);
1182}
1183
1184// リストの解放
1185void ReleaseList(LIST *o)
1186{
1187    // 引数チェック
1188    if (o == NULL)
1189    {
1190        return;
1191    }
1192
1193    if (o->ref == NULL || Release(o->ref) == 0)
1194    {
1195        CleanupList(o);
1196    }
1197}
1198
1199// リストのクリーンアップ
1200void CleanupList(LIST *o)
1201{
1202    // 引数チェック
1203    if (o == NULL)
1204    {
1205        return;
1206    }
1207
1208    Free(o->p);
1209    if (o->lock != NULL)
1210    {
1211        DeleteLock(o->lock);
1212    }
1213    Free(o);
1214
1215    // KS
1216    KS_INC(KS_FREELIST_COUNT);
1217
1218#ifndef DONT_USE_KERNEL_STATUS
1219    TrackDeleteObj(POINTER_TO_UINT64(o));
1220#endif  // DONT_USE_KERNEL_STATUS
1221}
1222
1223// 文字列比較関数 (Unicode)
1224int CompareUniStr(void *p1, void *p2)
1225{
1226    wchar_t *s1, *s2;
1227    if (p1 == NULL || p2 == NULL)
1228    {
1229        return 0;
1230    }
1231    s1 = *(wchar_t **)p1;
1232    s2 = *(wchar_t **)p2;
1233
1234    return UniStrCmp(s1, s2);
1235}
1236
1237// 文字列をリストに挿入する
1238bool InsertStr(LIST *o, char *str)
1239{
1240    // 引数チェック
1241    if (o == NULL || str == NULL)
1242    {
1243        return false;
1244    }
1245
1246    if (Search(o, str) == NULL)
1247    {
1248        Insert(o, str);
1249
1250        return true;
1251    }
1252
1253    return false;
1254}
1255
1256// 文字列比較関数
1257int CompareStr(void *p1, void *p2)
1258{
1259    char *s1, *s2;
1260    if (p1 == NULL || p2 == NULL)
1261    {
1262        return 0;
1263    }
1264    s1 = *(char **)p1;
1265    s2 = *(char **)p2;
1266
1267    return StrCmpi(s1, s2);
1268}
1269
1270// 高速リスト (ロック無し) の作成
1271LIST *NewListFast(COMPARE *cmp)
1272{
1273    return NewListEx(cmp, true);
1274}
1275
1276// リストの作成
1277LIST *NewList(COMPARE *cmp)
1278{
1279    return NewListEx(cmp, false);
1280}
1281LIST *NewListEx(COMPARE *cmp, bool fast)
1282{
1283    return NewListEx2(cmp, fast, false);
1284}
1285LIST *NewListEx2(COMPARE *cmp, bool fast, bool fast_malloc)
1286{
1287    LIST *o;
1288
1289    if (fast_malloc == false)
1290    {
1291        o = Malloc(sizeof(LIST));
1292    }
1293    else
1294    {
1295        o = MallocFast(sizeof(LIST));
1296    }
1297
1298    if (fast == false)
1299    {
1300        o->lock = NewLock();
1301        o->ref = NewRef();
1302    }
1303    else
1304    {
1305        o->lock = NULL;
1306        o->ref = NULL;
1307    }
1308    o->num_item = 0;
1309    o->num_reserved = INIT_NUM_RESERVED;
1310
1311    if (fast_malloc == false)
1312    {
1313        o->p = Malloc(sizeof(void *) * o->num_reserved);
1314    }
1315    else
1316    {
1317        o->p = MallocFast(sizeof(void *) * o->num_reserved);
1318    }
1319
1320    o->cmp = cmp;
1321    o->sorted = true;
1322
1323#ifndef DONT_USE_KERNEL_STATUS
1324    TrackNewObj(POINTER_TO_UINT64(o), "LIST", 0);
1325#endif  //DONT_USE_KERNEL_STATUS
1326
1327    // KS
1328    KS_INC(KS_NEWLIST_COUNT);
1329
1330    return o;
1331}
1332
1333// FIFO から peek する
1334UINT PeekFifo(FIFO *f, void *p, UINT size)
1335{
1336    UINT read_size;
1337    if (f == NULL || size == 0)
1338    {
1339        return 0;
1340    }
1341
1342    // KS
1343    KS_INC(KS_PEEK_FIFO_COUNT);
1344
1345    read_size = MIN(size, f->size);
1346    if (read_size == 0)
1347    {
1348        return 0;
1349    }
1350
1351    if (p != NULL)
1352    {
1353        Copy(p, (UCHAR *)f->p + f->pos, read_size);
1354    }
1355
1356    return read_size;
1357}
1358
1359// FIFO から読み取る
1360UINT ReadFifo(FIFO *f, void *p, UINT size)
1361{
1362    UINT read_size;
1363    // 引数チェック
1364    if (f == NULL || size == 0)
1365    {
1366        return 0;
1367    }
1368
1369    read_size = MIN(size, f->size);
1370    if (read_size == 0)
1371    {
1372        return 0;
1373    }
1374    if (p != NULL)
1375    {
1376        Copy(p, (UCHAR *)f->p + f->pos, read_size);
1377    }
1378    f->pos += read_size;
1379    f->size -= read_size;
1380
1381    if (f->size == 0)
1382    {
1383        f->pos = 0;
1384    }
1385
1386    // メモリの詰め直し
1387    if (f->pos >= FIFO_INIT_MEM_SIZE &&
1388        f->memsize >= f->realloc_mem_size &&
1389        (f->memsize / 2) > f->size)
1390    {
1391        void *new_p;
1392        UINT new_size;
1393
1394        new_size = MAX(f->memsize / 2, FIFO_INIT_MEM_SIZE);
1395        new_p = Malloc(new_size);
1396        Copy(new_p, (UCHAR *)f->p + f->pos, f->size);
1397
1398        Free(f->p);
1399
1400        f->memsize = new_size;
1401        f->p = new_p;
1402        f->pos = 0;
1403    }
1404
1405    // KS
1406    KS_INC(KS_READ_FIFO_COUNT);
1407
1408    return read_size;
1409}
1410
1411// FIFO に書き込む
1412void WriteFifo(FIFO *f, void *p, UINT size)
1413{
1414    UINT i, need_size;
1415    bool realloc_flag;
1416    // 引数チェック
1417    if (f == NULL || size == 0)
1418    {
1419        return;
1420    }
1421
1422    i = f->size;
1423    f->size += size;
1424    need_size = f->pos + f->size;
1425    realloc_flag = false;
1426
1427    // メモリ拡張
1428    while (need_size > f->memsize)
1429    {
1430        f->memsize = MAX(f->memsize, FIFO_INIT_MEM_SIZE) * 3;
1431        realloc_flag = true;
1432    }
1433
1434    if (realloc_flag)
1435    {
1436        f->p = ReAlloc(f->p, f->memsize);
1437    }
1438
1439    // データ書き込み
1440    if (p != NULL)
1441    {
1442        Copy((UCHAR *)f->p + f->pos + i, p, size);
1443    }
1444
1445    // KS
1446    KS_INC(KS_WRITE_FIFO_COUNT);
1447}
1448
1449// FIFO のクリア
1450void ClearFifo(FIFO *f)
1451{
1452    // 引数チェック
1453    if (f == NULL)
1454    {
1455        return;
1456    }
1457
1458    f->size = f->pos = 0;
1459    f->memsize = FIFO_INIT_MEM_SIZE;
1460    f->p = ReAlloc(f->p, f->memsize);
1461}
1462
1463// FIFO のサイズ取得
1464UINT FifoSize(FIFO *f)
1465{
1466    // 引数チェック
1467    if (f == NULL)
1468    {
1469        return 0;
1470    }
1471
1472    return f->size;
1473}
1474
1475// FIFO のロック
1476void LockFifo(FIFO *f)
1477{
1478    // 引数チェック
1479    if (f == NULL)
1480    {
1481        return;
1482    }
1483
1484    Lock(f->lock);
1485}
1486
1487// FIFO のロック解除
1488void UnlockFifo(FIFO *f)
1489{
1490    // 引数チェック
1491    if (f == NULL)
1492    {
1493        return;
1494    }
1495
1496    Unlock(f->lock);
1497}
1498
1499// FIFO の解放
1500void ReleaseFifo(FIFO *f)
1501{
1502    // 引数チェック
1503    if (f == NULL)
1504    {
1505        return;
1506    }
1507
1508    if (f->ref == NULL || Release(f->ref) == 0)
1509    {
1510        CleanupFifo(f);
1511    }
1512}
1513
1514// FIFO のクリーンアップ
1515void CleanupFifo(FIFO *f)
1516{
1517    // 引数チェック
1518    if (f == NULL)
1519    {
1520        return;
1521    }
1522
1523    DeleteLock(f->lock);
1524    Free(f->p);
1525    Free(f);
1526
1527#ifndef DONT_USE_KERNEL_STATUS
1528    TrackDeleteObj(POINTER_TO_UINT64(f));
1529#endif  //DONT_USE_KERNEL_STATUS
1530
1531    // KS
1532    KS_INC(KS_FREEFIFO_COUNT);
1533}
1534
1535// FIFO システムの初期化
1536void InitFifo()
1537{
1538    fifo_default_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
1539}
1540
1541// FIFO の作成
1542FIFO *NewFifo()
1543{
1544    return NewFifoEx(0, false);
1545}
1546FIFO *NewFifoFast()
1547{
1548    return NewFifoEx(0, true);
1549}
1550FIFO *NewFifoEx(UINT realloc_mem_size, bool fast)
1551{
1552    FIFO *f;
1553
1554    // メモリ確保
1555    f = Malloc(sizeof(FIFO));
1556
1557    if (fast == false)
1558    {
1559        f->lock = NewLock();
1560        f->ref = NewRef();
1561    }
1562    else
1563    {
1564        f->lock = NULL;
1565        f->ref = NULL;
1566    }
1567
1568    f->size = f->pos = 0;
1569    f->memsize = FIFO_INIT_MEM_SIZE;
1570    f->p = Malloc(FIFO_INIT_MEM_SIZE);
1571
1572    if (realloc_mem_size == 0)
1573    {
1574        realloc_mem_size = fifo_default_realloc_mem_size;
1575    }
1576
1577    f->realloc_mem_size = realloc_mem_size;
1578
1579#ifndef DONT_USE_KERNEL_STATUS
1580    TrackNewObj(POINTER_TO_UINT64(f), "FIFO", 0);
1581#endif  // DONT_USE_KERNEL_STATUS
1582
1583    // KS
1584    KS_INC(KS_NEWFIFO_COUNT);
1585
1586    return f;
1587}
1588
1589// FIFO のデフォルトのメモリ再確保サイズを取得する
1590UINT GetFifoDefaultReallocMemSize()
1591{
1592    return fifo_default_realloc_mem_size;
1593}
1594
1595// FIFO のデフォルトのメモリ再確保サイズを設定する
1596void SetFifoDefaultReallocMemSize(UINT size)
1597{
1598    if (size == 0)
1599    {
1600        size = FIFO_REALLOC_MEM_SIZE;
1601    }
1602
1603    fifo_default_realloc_mem_size = size;
1604}
1605
1606// バッファをファイルから読み込む
1607BUF *FileToBuf(IO *o)
1608{
1609    UCHAR hash1[MD5_SIZE], hash2[MD5_SIZE];
1610    UINT size;
1611    void *buf;
1612    BUF *b;
1613
1614    // 引数チェック
1615    if (o == NULL)
1616    {
1617        return NULL;
1618    }
1619
1620    // サイズを読み込む
1621    if (FileRead(o, &size, sizeof(size)) == false)
1622    {
1623        return NULL;
1624    }
1625    size = Endian32(size);
1626
1627    if (size > FileSize(o))
1628    {
1629        return NULL;
1630    }
1631
1632    // ハッシュを読み込む
1633    if (FileRead(o, hash1, sizeof(hash1)) == false)
1634    {
1635        return NULL;
1636    }
1637
1638    // バッファを読み込む
1639    buf = Malloc(size);
1640    if (FileRead(o, buf, size) == false)
1641    {
1642        Free(buf);
1643        return NULL;
1644    }
1645
1646    // ハッシュをとる
1647    Hash(hash2, buf, size, false);
1648
1649    // ハッシュを比較する
1650    if (Cmp(hash1, hash2, sizeof(hash1)) != 0)
1651    {
1652        // ハッシュが異なる
1653        Free(buf);
1654        return NULL;
1655    }
1656
1657    // バッファを作成する
1658    b = NewBuf();
1659    WriteBuf(b, buf, size);
1660    Free(buf);
1661    b->Current = 0;
1662
1663    return b;
1664}
1665
1666// ダンプファイルをバッファに読み込む
1667BUF *ReadDump(char *filename)
1668{
1669    IO *o;
1670    BUF *b;
1671    UINT size;
1672    void *data;
1673    // 引数チェック
1674    if (filename == NULL)
1675    {
1676        return NULL;
1677    }
1678
1679    o = FileOpen(filename, false);
1680    if (o == NULL)
1681    {
1682        return NULL;
1683    }
1684
1685    size = FileSize(o);
1686    data = Malloc(size);
1687    FileRead(o, data, size);
1688    FileClose(o);
1689
1690    b = NewBuf();
1691    WriteBuf(b, data, size);
1692    b->Current = 0;
1693    Free(data);
1694
1695    return b;
1696}
1697BUF *ReadDumpW(wchar_t *filename)
1698{
1699    IO *o;
1700    BUF *b;
1701    UINT size;
1702    void *data;
1703    // 引数チェック
1704    if (filename == NULL)
1705    {
1706        return NULL;
1707    }
1708
1709    o = FileOpenW(filename, false);
1710    if (o == NULL)
1711    {
1712        return NULL;
1713    }
1714
1715    size = FileSize(o);
1716    data = Malloc(size);
1717    FileRead(o, data, size);
1718    FileClose(o);
1719
1720    b = NewBuf();
1721    WriteBuf(b, data, size);
1722    b->Current = 0;
1723    Free(data);
1724
1725    return b;
1726}
1727
1728// バッファ内容をファイルにダンプする
1729bool DumpBuf(BUF *b, char *filename)
1730{
1731    IO *o;
1732    // 引数チェック
1733    if (b == NULL || filename == NULL)
1734    {
1735        return false;
1736    }
1737
1738    o = FileCreate(filename);
1739    if (o == NULL)
1740    {
1741        return false;
1742    }
1743    FileWrite(o, b->Buf, b->Size);
1744    FileClose(o);
1745
1746    return true;
1747}
1748bool DumpBufW(BUF *b, wchar_t *filename)
1749{
1750    IO *o;
1751    // 引数チェック
1752    if (b == NULL || filename == NULL)
1753    {
1754        return false;
1755    }
1756
1757    o = FileCreateW(filename);
1758    if (o == NULL)
1759    {
1760        return false;
1761    }
1762    FileWrite(o, b->Buf, b->Size);
1763    FileClose(o);
1764
1765    return true;
1766}
1767
1768// バッファをファイルに書き込む
1769bool BufToFile(IO *o, BUF *b)
1770{
1771    UCHAR hash[MD5_SIZE];
1772    UINT size;
1773
1774    // 引数チェック
1775    if (o == NULL || b == NULL)
1776    {
1777        return false;
1778    }
1779
1780    // データをハッシュする
1781    Hash(hash, b->Buf, b->Size, false);
1782
1783    size = Endian32(b->Size);
1784
1785    // サイズを書き込む
1786    if (FileWrite(o, &size, sizeof(size)) == false)
1787    {
1788        return false;
1789    }
1790
1791    // ハッシュを書き込む
1792    if (FileWrite(o, hash, sizeof(hash)) == false)
1793    {
1794        return false;
1795    }
1796
1797    // データを書き込む
1798    if (FileWrite(o, b->Buf, b->Size) == false)
1799    {
1800        return false;
1801    }
1802
1803    return true;
1804}
1805
1806// バッファの作成
1807BUF *NewBuf()
1808{
1809    BUF *b;
1810
1811    // メモリ確保
1812    b = Malloc(sizeof(BUF));
1813    b->Buf = Malloc(INIT_BUF_SIZE);
1814    b->Size = 0;
1815    b->Current = 0;
1816    b->SizeReserved = INIT_BUF_SIZE;
1817
1818#ifndef DONT_USE_KERNEL_STATUS
1819    TrackNewObj(POINTER_TO_UINT64(b), "BUF", 0);
1820#endif  // DONT_USE_KERNEL_STATUS
1821
1822    // KS
1823    KS_INC(KS_NEWBUF_COUNT);
1824    KS_INC(KS_CURRENT_BUF_COUNT);
1825
1826    return b;
1827}
1828
1829// バッファのクリア
1830void ClearBuf(BUF *b)
1831{
1832    // 引数チェック
1833    if (b == NULL)
1834    {
1835        return;
1836    }
1837
1838    b->Size = 0;
1839    b->Current = 0;
1840}
1841
1842// バッファへ書き込み
1843void WriteBuf(BUF *b, void *buf, UINT size)
1844{
1845    UINT new_size;
1846    // 引数チェック
1847    if (b == NULL || buf == NULL || size == 0)
1848    {
1849        return;
1850    }
1851
1852    new_size = b->Current + size;
1853    if (new_size > b->Size)
1854    {
1855        // サイズを調整する
1856        AdjustBufSize(b, new_size);
1857    }
1858    if (b->Buf != NULL)
1859    {
1860        Copy((UCHAR *)b->Buf + b->Current, buf, size);
1861    }
1862    b->Current += size;
1863    b->Size = new_size;
1864
1865    // KS
1866    KS_INC(KS_WRITE_BUF_COUNT);
1867}
1868
1869// バッファに文字列を追記
1870void AddBufStr(BUF *b, char *str)
1871{
1872    // 引数チェック
1873    if (b == NULL || str == NULL)
1874    {
1875        return;
1876    }
1877
1878    WriteBuf(b, str, StrLen(str));
1879}
1880
1881// バッファに 1 行書き込む
1882void WriteBufLine(BUF *b, char *str)
1883{
1884    char *crlf = "\r\n";
1885    // 引数チェック
1886    if (b == NULL || str == NULL)
1887    {
1888        return;
1889    }
1890
1891    WriteBuf(b, str, StrLen(str));
1892    WriteBuf(b, crlf, StrLen(crlf));
1893}
1894
1895// バッファに文字列を書き込む
1896bool WriteBufStr(BUF *b, char *str)
1897{
1898    UINT len;
1899    // 引数チェック
1900    if (b == NULL || str == NULL)
1901    {
1902        return false;
1903    }
1904
1905    // 文字列長
1906    len = StrLen(str);
1907    if (WriteBufInt(b, len + 1) == false)
1908    {
1909        return false;
1910    }
1911
1912    // 文字列本体
1913    WriteBuf(b, str, len);
1914
1915    return true;
1916}
1917
1918// バッファから文字列を読み込む
1919bool ReadBufStr(BUF *b, char *str, UINT size)
1920{
1921    UINT len;
1922    UINT read_size;
1923    // 引数チェック
1924    if (b == NULL || str == NULL || size == 0)
1925    {
1926        return false;
1927    }
1928
1929    // 文字列長を読み込む
1930    len = ReadBufInt(b);
1931    if (len == 0)
1932    {
1933        return false;
1934    }
1935    len--;
1936    if (len <= (size - 1))
1937    {
1938        size = len + 1;
1939    }
1940
1941    read_size = MIN(len, (size - 1));
1942
1943    // 文字列本体を読み込む
1944    if (ReadBuf(b, str, read_size) != read_size)
1945    {
1946        return false;
1947    }
1948    if (read_size < len)
1949    {
1950        ReadBuf(b, NULL, len - read_size);
1951    }
1952    str[read_size] = 0;
1953
1954    return true;
1955}
1956
1957// バッファに 64 bit 整数を書き込む
1958bool WriteBufInt64(BUF *b, UINT64 value)
1959{
1960    // 引数チェック
1961    if (b == NULL)
1962    {
1963        return false;
1964    }
1965
1966    value = Endian64(value);
1967
1968    WriteBuf(b, &value, sizeof(UINT64));
1969    return true;
1970}
1971
1972// バッファに整数を書き込む
1973bool WriteBufInt(BUF *b, UINT value)
1974{
1975    // 引数チェック
1976    if (b == NULL)
1977    {
1978        return false;
1979    }
1980
1981    value = Endian32(value);
1982
1983    WriteBuf(b, &value, sizeof(UINT));
1984    return true;
1985}
1986
1987// バッファから 64bit 整数を読み込む
1988UINT64 ReadBufInt64(BUF *b)
1989{
1990    UINT64 value;
1991    // 引数チェック
1992    if (b == NULL)
1993    {
1994        return 0;
1995    }
1996
1997    if (ReadBuf(b, &value, sizeof(UINT64)) != sizeof(UINT64))
1998    {
1999        return 0;
2000    }
2001    return Endian64(value);
2002}
2003
2004// バッファから整数を読み込む
2005UINT ReadBufInt(BUF *b)
2006{
2007    UINT value;
2008    // 引数チェック
2009    if (b == NULL)
2010    {
2011        return 0;
2012    }
2013
2014    if (ReadBuf(b, &value, sizeof(UINT)) != sizeof(UINT))
2015    {
2016        return 0;
2017    }
2018    return Endian32(value);
2019}
2020
2021// バッファにバッファを書き込み
2022void WriteBufBuf(BUF *b, BUF *bb)
2023{
2024    // 引数チェック
2025    if (b == NULL || bb == NULL)
2026    {
2027        return;
2028    }
2029
2030    WriteBuf(b, bb->Buf, bb->Size);
2031}
2032
2033// バッファからバッファを読み込み
2034BUF *ReadBufFromBuf(BUF *b, UINT size)
2035{
2036    BUF *ret;
2037    UCHAR *data;
2038    // 引数チェック
2039    if (b == NULL)
2040    {
2041        return NULL;
2042    }
2043
2044    data = Malloc(size);
2045    if (ReadBuf(b, data, size) != size)
2046    {
2047        Free(data);
2048        return NULL;
2049    }
2050
2051    ret = NewBuf();
2052    WriteBuf(ret, data, size);
2053    SeekBuf(ret, 0, 0);
2054
2055    Free(data);
2056
2057    return ret;
2058}
2059
2060// バッファから読み込み
2061UINT ReadBuf(BUF *b, void *buf, UINT size)
2062{
2063    UINT size_read;
2064    // 引数チェック
2065    if (b == NULL || size == 0)
2066    {
2067        return 0;
2068    }
2069
2070    if (b->Buf == NULL)
2071    {
2072        Zero(buf, size);
2073        return 0;
2074    }
2075    size_read = size;
2076    if ((b->Current + size) >= b->Size)
2077    {
2078        size_read = b->Size - b->Current;
2079        if (buf != NULL)
2080        {
2081            Zero((UCHAR *)buf + size_read, size - size_read);
2082        }
2083    }
2084
2085    if (buf != NULL)
2086    {
2087        Copy(buf, (UCHAR *)b->Buf + b->Current, size_read);
2088    }
2089
2090    b->Current += size_read;
2091
2092    // KS
2093    KS_INC(KS_READ_BUF_COUNT);
2094
2095    return size_read;
2096}
2097
2098// バッファサイズの調整
2099void AdjustBufSize(BUF *b, UINT new_size)
2100{
2101    // 引数チェック
2102    if (b == NULL)
2103    {
2104        return;
2105    }
2106
2107    if (b->SizeReserved >= new_size)
2108    {
2109        return;
2110    }
2111
2112    while (b->SizeReserved < new_size)
2113    {
2114        b->SizeReserved = b->SizeReserved * 2;
2115    }
2116    b->Buf = ReAlloc(b->Buf, b->SizeReserved);
2117
2118    // KS
2119    KS_INC(KS_ADJUST_BUFSIZE_COUNT);
2120}
2121
2122// バッファのシーク
2123void SeekBuf(BUF *b, UINT offset, int mode)
2124{
2125    UINT new_pos;
2126    // 引数チェック
2127    if (b == NULL)
2128    {
2129        return;
2130    }
2131
2132    if (mode == 0)
2133    {
2134        // 絶対位置
2135        new_pos = offset;
2136    }
2137    else
2138    {
2139        if (mode > 0)
2140        {
2141            // 右へ移動
2142            new_pos = b->Current + offset;
2143        }
2144        else
2145        {
2146            // 左へ移動
2147            if (b->Current >= offset)
2148            {
2149                new_pos = b->Current - offset;
2150            }
2151            else
2152            {
2153                new_pos = 0;
2154            }
2155        }
2156    }
2157    b->Current = MAKESURE(new_pos, 0, b->Size);
2158
2159    KS_INC(KS_SEEK_BUF_COUNT);
2160}
2161
2162// バッファの解放
2163void FreeBuf(BUF *b)
2164{
2165    // 引数チェック
2166    if (b == NULL)
2167    {
2168        return;
2169    }
2170
2171    // メモリ解放
2172    Free(b->Buf);
2173    Free(b);
2174
2175    // KS
2176    KS_INC(KS_FREEBUF_COUNT);
2177    KS_DEC(KS_CURRENT_BUF_COUNT);
2178
2179#ifndef DONT_USE_KERNEL_STATUS
2180    TrackDeleteObj(POINTER_TO_UINT64(b));
2181#endif  // DONT_USE_KERNEL_STATUS
2182}
2183
2184// Unicode 文字列のエンディアン変換
2185void EndianUnicode(wchar_t *str)
2186{
2187    UINT i, len;
2188    // 引数チェック
2189    if (str == NULL)
2190    {
2191        return;
2192    }
2193    len = UniStrLen(str);
2194
2195    for (i = 0;i < len;i++)
2196    {
2197        str[i] = Endian16(str[i]);
2198    }
2199}
2200
2201// エンディアン変換 16bit
2202USHORT Endian16(USHORT src)
2203{
2204    int x = 1;
2205    if (*((char *)&x))
2206    {
2207        return Swap16(src);
2208    }
2209    else
2210    {
2211        return src;
2212    }
2213}
2214
2215// エンディアン変換 32bit
2216UINT Endian32(UINT src)
2217{
2218    int x = 1;
2219    if (*((char *)&x))
2220    {
2221        return Swap32(src);
2222    }
2223    else
2224    {
2225        return src;
2226    }
2227}
2228
2229// エンディアン変換 64bit
2230UINT64 Endian64(UINT64 src)
2231{
2232    int x = 1;
2233    if (*((char *)&x))
2234    {
2235        return Swap64(src);
2236    }
2237    else
2238    {
2239        return src;
2240    }
2241}
2242
2243// 任意のデータのスワップ
2244void Swap(void *buf, UINT size)
2245{
2246    UCHAR *tmp, *src;
2247    UINT i;
2248    // 引数チェック
2249    if (buf == NULL || size == 0)
2250    {
2251        return;
2252    }
2253
2254    src = (UCHAR *)buf;
2255    tmp = Malloc(size);
2256    for (i = 0;i < size;i++)
2257    {
2258        tmp[size - i - 1] = src[i];
2259    }
2260
2261    Copy(buf, tmp, size);
2262    Free(buf);
2263}
2264
2265// 16bit スワップ
2266USHORT Swap16(USHORT value)
2267{
2268    USHORT r;
2269    // 汚いコード
2270    ((BYTE *)&r)[0] = ((BYTE *)&value)[1];
2271    ((BYTE *)&r)[1] = ((BYTE *)&value)[0];
2272    return r;
2273}
2274
2275// 32bit スワップ
2276UINT Swap32(UINT value)
2277{
2278    UINT r;
2279    // 汚いコード
2280    ((BYTE *)&r)[0] = ((BYTE *)&value)[3];
2281    ((BYTE *)&r)[1] = ((BYTE *)&value)[2];
2282    ((BYTE *)&r)[2] = ((BYTE *)&value)[1];
2283    ((BYTE *)&r)[3] = ((BYTE *)&value)[0];
2284    return r;
2285}
2286
2287// 64bit スワップ
2288UINT64 Swap64(UINT64 value)
2289{
2290    UINT64 r;
2291    // 汚いコード
2292    ((BYTE *)&r)[0] = ((BYTE *)&value)[7];
2293    ((BYTE *)&r)[1] = ((BYTE *)&value)[6];
2294    ((BYTE *)&r)[2] = ((BYTE *)&value)[5];
2295    ((BYTE *)&r)[3] = ((BYTE *)&value)[4];
2296    ((BYTE *)&r)[4] = ((BYTE *)&value)[3];
2297    ((BYTE *)&r)[5] = ((BYTE *)&value)[2];
2298    ((BYTE *)&r)[6] = ((BYTE *)&value)[1];
2299    ((BYTE *)&r)[7] = ((BYTE *)&value)[0];
2300    return r;
2301}
2302
2303// Base64 エンコード
2304UINT Encode64(char *dst, char *src)
2305{
2306    // 引数チェック
2307    if (dst == NULL || src == NULL)
2308    {
2309        return 0;
2310    }
2311
2312    return B64_Encode(dst, src, StrLen(src));
2313}
2314
2315// Base64 デコード
2316UINT Decode64(char *dst, char *src)
2317{
2318    // 引数チェック
2319    if (dst == NULL || src == NULL)
2320    {
2321        return 0;
2322    }
2323
2324    return B64_Decode(dst, src, StrLen(src));
2325}
2326
2327// Base64 エンコード
2328int B64_Encode(char *set, char *source, int len)
2329{
2330    BYTE *src;
2331    int i,j;
2332    src = (BYTE *)source;
2333    j = 0;
2334    i = 0;
2335    if (!len)
2336    {
2337        return 0;
2338    }
2339    while (TRUE)
2340    {
2341        if (i >= len)
2342        {
2343            return j;
2344        }
2345        if (set)
2346        {
2347            set[j] = B64_CodeToChar((src[i]) >> 2);
2348        }
2349        if (i + 1 >= len)
2350        {
2351            if (set)
2352            {
2353                set[j + 1] = B64_CodeToChar((src[i] & 0x03) << 4);
2354                set[j + 2] = '=';
2355                set[j + 3] = '=';
2356            }
2357            return j + 4;
2358        }
2359        if (set)
2360        {
2361            set[j + 1] = B64_CodeToChar(((src[i] & 0x03) << 4) + ((src[i + 1] >> 4)));
2362        }
2363        if (i + 2 >= len)
2364        {
2365            if (set)
2366            {
2367                set[j + 2] = B64_CodeToChar((src[i + 1] & 0x0f) << 2);
2368                set[j + 3] = '=';
2369            }
2370            return j + 4;
2371        }
2372        if (set)
2373        {
2374            set[j + 2] = B64_CodeToChar(((src[i + 1] & 0x0f) << 2) + ((src[i + 2] >> 6)));
2375            set[j + 3] = B64_CodeToChar(src[i + 2] & 0x3f);
2376        }
2377        i += 3;
2378        j += 4;
2379    }
2380}
2381
2382// Base64 デコード
2383int B64_Decode(char *set, char *source, int len)
2384{
2385    int i,j;
2386    char a1,a2,a3,a4;
2387    char *src;
2388    int f1,f2,f3,f4;
2389    src = source;
2390    i = 0;
2391    j = 0;
2392    while (TRUE)
2393    {
2394        f1 = f2 = f3 = f4 = 0;
2395        if (i >= len)
2396        {
2397            break;
2398        }
2399        f1 = 1;
2400        a1 = B64_CharToCode(src[i]);
2401        if (a1 == -1)
2402        {
2403            f1 = 0;
2404        }
2405        if (i >= len + 1)
2406        {
2407            a2 = 0;
2408        }
2409        else
2410        {
2411            a2 = B64_CharToCode(src[i + 1]);
2412            f2 = 1;
2413            if (a2 == -1)
2414            {
2415                f2 = 0;
2416            }
2417        }
2418        if (i >= len + 2)
2419        {
2420            a3 = 0;
2421        }
2422        else
2423        {
2424            a3 = B64_CharToCode(src[i + 2]);
2425            f3 = 1;
2426            if (a3 == -1)
2427            {
2428                f3 = 0;
2429            }
2430        }
2431        if (i >= len + 3)
2432        {
2433            a4 = 0;
2434        }
2435        else
2436        {
2437            a4 = B64_CharToCode(src[i + 3]);
2438            f4 = 1;
2439            if (a4 == -1)
2440            {
2441                f4 = 0;
2442            }
2443        }
2444        if (f1 && f2)
2445        {
2446            if (set)
2447            {
2448                set[j] = (a1 << 2) + (a2 >> 4);
2449            }
2450            j++;
2451        }
2452        if (f2 && f3)
2453        {
2454            if (set)
2455            {
2456                set[j] = (a2 << 4) + (a3 >> 2);
2457            }
2458            j++;
2459        }
2460        if (f3 && f4)
2461        {
2462            if (set)
2463            {
2464                set[j] = (a3 << 6) + a4;
2465            }
2466            j++;
2467        }
2468        i += 4;
2469    }
2470    return j;
2471}
2472
2473// Base64 - コードを文字に変換
2474char B64_CodeToChar(BYTE c)
2475{
2476    BYTE r;
2477    r = '=';
2478    if (c <= 0x19)
2479    {
2480        r = c + 'A';
2481    }
2482    if (c >= 0x1a && c <= 0x33)
2483    {
2484        r = c - 0x1a + 'a';
2485    }
2486    if (c >= 0x34 && c <= 0x3d)
2487    {
2488        r = c - 0x34 + '0';
2489    }
2490    if (c == 0x3e)
2491    {
2492        r = '+';
2493    }
2494    if (c == 0x3f)
2495    {
2496        r = '/';
2497    }
2498    return r;
2499}
2500
2501// Base64 - 文字をコードに変換
2502char B64_CharToCode(char c)
2503{
2504    if (c >= 'A' && c <= 'Z')
2505    {
2506        return c - 'A';
2507    }
2508    if (c >= 'a' && c <= 'z')
2509    {
2510        return c - 'a' + 0x1a;
2511    }
2512    if (c >= '0' && c <= '9')
2513    {
2514        return c - '0' + 0x34;
2515    }
2516    if (c == '+')
2517    {
2518        return 0x3e;
2519    }
2520    if (c == '/')
2521    {
2522        return 0x3f;
2523    }
2524    if (c == '=')
2525    {
2526        return -1;
2527    }
2528    return 0;
2529}
2530
2531// 高速な Malloc (現在未実装)
2532// 実は小さなバッファをたくさんまとめておいてそれを動的に割り当てるコードを昔
2533// 書いたのだが、Windows, Linux, Solaris で試しても普通の malloc() と比べて
2534// ほとんど速度に影響がなかったので、やめにした。
2535void *MallocFast(UINT size)
2536{
2537    return Malloc(size);
2538}
2539
2540// Malloc
2541void *Malloc(UINT size)
2542{
2543    return MallocEx(size, false);
2544}
2545void *MallocEx(UINT size, bool zero_clear_when_free)
2546{
2547    MEMTAG *tag;
2548    UINT real_size;
2549
2550    real_size = CALC_MALLOCSIZE(size);
2551
2552    tag = InternalMalloc(real_size);
2553
2554    Zero(tag, sizeof(MEMTAG));
2555    tag->Magic = MEMTAG_MAGIC;
2556    tag->Size = size;
2557    tag->ZeroFree = zero_clear_when_free;
2558
2559    return MEMTAG_TO_POINTER(tag);
2560}
2561
2562// ReAlloc
2563void *ReAlloc(void *addr, UINT size)
2564{
2565    MEMTAG *tag;
2566    bool zerofree;
2567    // 引数チェック
2568    if (IS_NULL_POINTER(addr))
2569    {
2570        return NULL;
2571    }
2572
2573    tag = POINTER_TO_MEMTAG(addr);
2574    CheckMemTag(tag);
2575
2576    zerofree = tag->ZeroFree;
2577
2578    if (tag->Size == size)
2579    {
2580        // サイズ変更無し
2581        return addr;
2582    }
2583    else
2584    {
2585        if (zerofree)
2586        {
2587            // サイズ変更有り (ゼロクリア必須)
2588            void *new_p = MallocEx(size, true);
2589
2590            if (tag->Size <= size)
2591            {
2592                // サイズ拡大
2593                Copy(new_p, addr, tag->Size);
2594            }
2595            else
2596            {
2597                // サイズ縮小
2598                Copy(new_p, addr, size);
2599            }
2600
2601            // 古いブロックの解放
2602            Free(addr);
2603
2604            return new_p;
2605        }
2606        else
2607        {
2608            // サイズ変更有り
2609            MEMTAG *tag2 = InternalReAlloc(tag, CALC_MALLOCSIZE(size));
2610
2611            Zero(tag2, sizeof(MEMTAG));
2612            tag2->Magic = MEMTAG_MAGIC;
2613            tag2->Size = size;
2614
2615            return MEMTAG_TO_POINTER(tag2);
2616        }
2617    }
2618}
2619
2620// Free
2621void Free(void *addr)
2622{
2623    MEMTAG *tag;
2624    // 引数チェック
2625    if (IS_NULL_POINTER(addr))
2626    {
2627        return;
2628    }
2629
2630    tag = POINTER_TO_MEMTAG(addr);
2631    CheckMemTag(tag);
2632
2633    if (tag->ZeroFree)
2634    {
2635        // ゼロクリア
2636        Zero(addr, tag->Size);
2637    }
2638
2639    // メモリ解放
2640    tag->Magic = 0;
2641    InternalFree(tag);
2642}
2643
2644// memtag をチェック
2645void CheckMemTag(MEMTAG *tag)
2646{
2647#ifndef DONT_CHECK_HEAP
2648    // 引数チェック
2649    if (tag == NULL)
2650    {
2651        AbortExitEx("CheckMemTag: tag == NULL");
2652        return;
2653    }
2654
2655    if (tag->Magic != MEMTAG_MAGIC)
2656    {
2657        AbortExitEx("CheckMemTag: tag->Magic != MEMTAG_MAGIC");
2658        return;
2659    }
2660#endif  // DONT_CHECK_HEAP
2661}
2662
2663// ZeroMalloc
2664void *ZeroMalloc(UINT size)
2665{
2666    return ZeroMallocEx(size, false);
2667}
2668void *ZeroMallocEx(UINT size, bool zero_clear_when_free)
2669{
2670    void *p = MallocEx(size, zero_clear_when_free);
2671    Zero(p, size);
2672    return p;
2673}
2674void *ZeroMallocFast(UINT size)
2675{
2676    void *p = MallocFast(size);
2677    Zero(p, size);
2678    return p;
2679}
2680
2681// メモリ確保
2682void *InternalMalloc(UINT size)
2683{
2684    void *addr;
2685    UINT retry = 0;
2686    size = MORE(size, 1);
2687
2688    // KS
2689    KS_INC(KS_MALLOC_COUNT);
2690    KS_INC(KS_TOTAL_MEM_COUNT);
2691    KS_ADD(KS_TOTAL_MEM_SIZE, size);
2692    KS_INC(KS_CURRENT_MEM_COUNT);
2693
2694    // メモリが確保されるまで試行する
2695    while (true)
2696    {
2697        if ((retry++) > MEMORY_MAX_RETRY)
2698        {
2699            AbortExitEx("InternalMalloc: error: malloc() failed.\n\n");
2700        }
2701        addr = OSMemoryAlloc(size);
2702        if (addr != NULL)
2703        {
2704            break;
2705        }
2706
2707        OSSleep(MEMORY_SLEEP_TIME);
2708    }
2709
2710#ifndef DONT_USE_KERNEL_STATUS
2711    TrackNewObj(POINTER_TO_UINT64(addr), "MEM", size);
2712#endif  //DONT_USE_KERNEL_STATUS
2713
2714    return addr;
2715}
2716
2717// メモリ解放
2718void InternalFree(void *addr)
2719{
2720    // 引数チェック
2721    if (addr == NULL)
2722    {
2723        return;
2724    }
2725
2726    // KS
2727    KS_DEC(KS_CURRENT_MEM_COUNT);
2728    KS_INC(KS_FREE_COUNT);
2729
2730#ifndef DONT_USE_KERNEL_STATUS
2731    TrackDeleteObj(POINTER_TO_UINT64(addr));
2732#endif  // DONT_USE_KERNEL_STATUS
2733
2734    // メモリ解放
2735    OSMemoryFree(addr);
2736}
2737
2738// メモリ再確保
2739void *InternalReAlloc(void *addr, UINT size)
2740{
2741    void *new_addr;
2742    UINT retry = 0;
2743    size = MORE(size, 1);
2744
2745    // KS
2746    KS_INC(KS_REALLOC_COUNT);
2747    KS_ADD(KS_TOTAL_MEM_SIZE, size);
2748
2749    // メモリが確保されるまで試行する
2750    while (true)
2751    {
2752        if ((retry++) > MEMORY_MAX_RETRY)
2753        {
2754            AbortExitEx("InternalReAlloc: error: realloc() failed.\n\n");
2755        }
2756        new_addr = OSMemoryReAlloc(addr, size);
2757        if (new_addr != NULL)
2758        {
2759            break;
2760        }
2761
2762        OSSleep(MEMORY_SLEEP_TIME);
2763    }
2764
2765#ifndef DONT_USE_KERNEL_STATUS
2766    TrackChangeObjSize((DWORD)addr, size, (DWORD)new_addr);
2767#endif  // DONT_USE_KERNEL_STATUS
2768
2769    return new_addr;
2770}
2771
2772// メモリ領域のクローン
2773void *Clone(void *addr, UINT size)
2774{
2775    void *ret;
2776    // 引数チェック
2777    if (addr == NULL)
2778    {
2779        return NULL;
2780    }
2781
2782    ret = Malloc(size);
2783    Copy(ret, addr, size);
2784
2785    return ret;
2786}
2787
2788// メモリコピー
2789void Copy(void *dst, void *src, UINT size)
2790{
2791    // 引数チェック
2792    if (dst == NULL || src == NULL || size == 0 || dst == src)
2793    {
2794        return;
2795    }
2796
2797    // KS
2798    KS_INC(KS_COPY_COUNT);
2799
2800    memcpy(dst, src, size);
2801}
2802
2803// メモリ比較
2804int Cmp(void *p1, void *p2, UINT size)
2805{
2806    // 引数チェック
2807    if (p1 == NULL || p2 == NULL || size == 0)
2808    {
2809        return 0;
2810    }
2811
2812    return memcmp(p1, p2, (size_t)size);
2813}
2814
2815// メモリのゼロクリア
2816void Zero(void *addr, UINT size)
2817{
2818    ZeroMem(addr, size);
2819}
2820void ZeroMem(void *addr, UINT size)
2821{
2822    // 引数チェック
2823    if (addr == NULL || size == 0)
2824    {
2825        return;
2826    }
2827
2828    // KS
2829    KS_INC(KS_ZERO_COUNT);
2830
2831    memset(addr, 0, size);
2832}
2833
2834// 文字列マップエントリの比較
2835int StrMapCmp(void *p1, void *p2)
2836{
2837    STRMAP_ENTRY *s1, *s2;
2838    if (p1 == NULL || p2 == NULL)
2839    {
2840        return 0;
2841    }
2842    s1 = *(STRMAP_ENTRY **)p1;
2843    s2 = *(STRMAP_ENTRY **)p2;
2844    if (s1 == NULL || s2 == NULL)
2845    {
2846        return 0;
2847    }
2848    return StrCmpi(s1->Name, s2->Name);
2849}
2850
2851// 文字列マップ(文字列で検索できるデータ)の作成
2852LIST *NewStrMap()
2853{
2854    return NewList(StrMapCmp);
2855}
2856
2857// 文字列マップの検索
2858void *StrMapSearch(LIST *map, char *key)
2859{
2860    STRMAP_ENTRY tmp, *result;
2861    tmp.Name = key;
2862    result = (STRMAP_ENTRY*)Search(map, &tmp);
2863    if(result != NULL)
2864    {
2865        return result->Value;
2866    }
2867    return NULL;
2868}
Note: See TracBrowser for help on using the repository browser.