1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-10-06 02:20:40 +03:00
SoftEtherVPN/src/Mayaqua/Memory.c
Daiyuu Nobori 2dec52b875 Heap area protection of memory has been enhanced.
When memory is released and reallocated, a random security value called a canary is written to the before/after area of memory, and if the value has been modified, the process is terminated (restarted) for safety, assuming it is a buffer overflow of the memory area. This feature may effectively prevent confidentiality or integrity violations in the event that some heap area overflow vulnerability is discovered in this system in the future.
2023-10-07 04:42:34 +02:00

4113 lines
62 KiB
C

// SoftEther VPN Source Code - Developer Edition Master Branch
// Mayaqua Kernel
// Memory.c
// Memory management program
#include "Memory.h"
#include "Encoding.h"
#include "Encrypt.h"
#include "FileIO.h"
#include "Internat.h"
#include "Kernel.h"
#include "Mayaqua.h"
#include "Object.h"
#include "OS.h"
#include "Str.h"
#include "Tick64.h"
#include "Tracking.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef OS_UNIX
#include <sys/time.h>
#endif
#include <zlib.h>
#define MEMORY_SLEEP_TIME 150
#define MEMORY_MAX_RETRY 30
#define INIT_BUF_SIZE 10240
#define FIFO_INIT_MEM_SIZE 4096
#define FIFO_REALLOC_MEM_SIZE (65536 * 10) // Exquisite value
#define INIT_NUM_RESERVED 32
static UINT fifo_current_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
static bool canary_inited = false;
typedef struct CANARY_RAND_DATA
{
UCHAR Data[CANARY_RAND_SIZE + 4];
} CANARY_RAND_DATA;
static CANARY_RAND_DATA canary_rand_data[NUM_CANARY_RAND] = { 0 };
static UINT64 canary_memtag_magic1 = 0;
static UINT64 canary_memtag_magic2 = 0;
UCHAR *GetCanaryRand(UINT id)
{
if (id >= NUM_CANARY_RAND)
{
id = NUM_CANARY_RAND - 1;
}
return &((canary_rand_data[id].Data)[0]);
}
void InitCanaryRand()
{
SYSTEMTIME st = { 0 };
char random_seed[1024] = { 0 };
UINT64 t1 = 0, t2 = 0;
if (canary_inited)
{
return;
}
#ifdef OS_WIN32
Win32GetSystemTime(&st);
memcpy(&t1, ((UCHAR *)&st) + 0, 8);
memcpy(&t2, ((UCHAR *)&st) + 8, 8);
#else // OS_WIN32
struct timeval tv = { 0 };
struct timezone tz = { 0 };
gettimeofday(&tv, &tz);
t1 = (UINT64)tv.tv_sec;
t2 = (UINT64)tv.tv_usec;
#endif // OS_WIN32
{
UINT64 dos_rand = (UINT64)rand();
UINT64 tick1 = TickHighresNano64(true);
UINT64 tick2 = TickHighresNano64(true);
UINT i;
void *p1 = malloc(1);
void *p2 = malloc(1);
for (i = 0;i < NUM_CANARY_RAND;i++)
{
// using sprintf() here is safe.
sprintf(random_seed,
"%u "
"%llu "
"%llu "
"%llu "
"%llu "
"%llu "
"%llu "
"%llu "
"%llu "
"%llu "
"%llu "
"%llu "
"%u "
,
i,
(UINT64)InitCanaryRand,
(UINT64)&canary_inited,
(UINT64) & ((canary_rand_data[0].Data)[0]),
(UINT64)&random_seed[0],
tick1,
tick2,
dos_rand,
(UINT64)p1,
(UINT64)p2,
t1,
t2,
~i
);
Sha0(canary_rand_data[i].Data, random_seed, (UINT)strlen(random_seed));
}
free(p1);
free(p2);
canary_memtag_magic1 = *((UINT64 *)(GetCanaryRand(CANARY_RAND_ID_MEMTAG_MAGIC) + 0));
canary_memtag_magic2 = *((UINT64 *)(GetCanaryRand(CANARY_RAND_ID_MEMTAG_MAGIC) + 8));
canary_inited = true;
}
}
// New PRand
PRAND *NewPRand(void *key, UINT key_size)
{
PRAND *r;
UCHAR dummy[256];
if (key == NULL || key_size == 0)
{
key = "DUMMY";
key_size = 5;
}
r = ZeroMalloc(sizeof(PRAND));
Sha1(r->Key, key, key_size);
r->Rc4 = NewCrypt(key, key_size);
Zero(dummy, sizeof(dummy));
Encrypt(r->Rc4, dummy, dummy, 256);
return r;
}
// Free PRand
void FreePRand(PRAND *r)
{
if (r == NULL)
{
return;
}
FreeCrypt(r->Rc4);
Free(r);
}
// Generate PRand
void PRand(PRAND *p, void *data, UINT size)
{
if (p == NULL)
{
return;
}
Zero(data, size);
Encrypt(p->Rc4, data, data, size);
}
// Generate UINT PRand
UINT PRandInt(PRAND *p)
{
UINT r;
if (p == NULL)
{
return 0;
}
PRand(p, &r, sizeof(UINT));
return r;
}
// Check whether the specified key item is in the hash list
bool IsInHashListKey(HASH_LIST *h, UINT key)
{
// Validate arguments
if (h == NULL || key == 0)
{
return false;
}
if (HashListKeyToPointer(h, key) == NULL)
{
return false;
}
return true;
}
// Search the item in the hash list with the key
void *HashListKeyToPointer(HASH_LIST *h, UINT key)
{
UINT num, i;
void **pp;
void *ret = NULL;
// Validate arguments
if (h == NULL || key == 0)
{
return NULL;
}
pp = HashListToArray(h, &num);
if (pp == NULL)
{
return NULL;
}
for (i = 0;i < num;i++)
{
void *p = pp[i];
if (POINTER_TO_KEY(p) == key)
{
ret = p;
}
}
Free(pp);
return ret;
}
// Lock the hash list
void LockHashList(HASH_LIST *h)
{
// Validate arguments
if (h == NULL)
{
return;
}
Lock(h->Lock);
}
// Unlock the hash list
void UnlockHashList(HASH_LIST *h)
{
// Validate arguments
if (h == NULL)
{
return;
}
Unlock(h->Lock);
}
// Write the contents of the hash list to array
void **HashListToArray(HASH_LIST *h, UINT *num)
{
void **ret = NULL;
UINT i;
UINT n = 0;
// Validate arguments
if (h == NULL || num == NULL)
{
if (num != NULL)
{
*num = 0;
}
return NULL;
}
if (h->AllList != NULL)
{
*num = LIST_NUM(h->AllList);
return ToArray(h->AllList);
}
ret = ZeroMalloc(sizeof(void *) * h->NumItems);
for (i = 0;i < h->Size;i++)
{
LIST *o = h->Entries[i];
if (o != NULL)
{
UINT j;
for (j = 0;j < LIST_NUM(o);j++)
{
void *p = LIST_DATA(o, j);
ret[n] = p;
n++;
}
}
}
*num = n;
return ret;
}
// Search an item in the hash list
void *SearchHash(HASH_LIST *h, void *t)
{
UINT r;
void *ret = NULL;
// Validate arguments
if (h == NULL || t == NULL)
{
return NULL;
}
r = CalcHashForHashList(h, t);
if (h->Entries[r] != NULL)
{
LIST *o = h->Entries[r];
void *r = Search(o, t);
if (r != NULL)
{
ret = r;
}
}
return ret;
}
// Remove an item from the hash list
bool DeleteHash(HASH_LIST *h, void *p)
{
UINT r;
bool ret = false;
// Validate arguments
if (h == NULL || p == NULL)
{
return false;
}
r = CalcHashForHashList(h, p);
if (h->Entries[r] != NULL)
{
if (Delete(h->Entries[r], p))
{
ret = true;
h->NumItems--;
}
if (LIST_NUM(h->Entries[r]) == 0)
{
ReleaseList(h->Entries[r]);
h->Entries[r] = NULL;
}
}
if (ret)
{
if (h->AllList != NULL)
{
Delete(h->AllList, p);
}
}
return ret;
}
// Add an item to the hash list
void AddHash(HASH_LIST *h, void *p)
{
UINT r;
// Validate arguments
if (h == NULL || p == NULL)
{
return;
}
r = CalcHashForHashList(h, p);
if (h->Entries[r] == NULL)
{
h->Entries[r] = NewListFast(h->CompareProc);
}
Insert(h->Entries[r], p);
if (h->AllList != NULL)
{
Add(h->AllList, p);
}
h->NumItems++;
}
// Calculation of the hash value of the object
UINT CalcHashForHashList(HASH_LIST *h, void *p)
{
UINT r;
// Validate arguments
if (h == NULL || p == NULL)
{
return 0;
}
r = h->GetHashProc(p);
return (r % h->Size);
}
// Creating a hash list
HASH_LIST *NewHashList(GET_HASH *get_hash_proc, COMPARE *compare_proc, UINT bits, bool make_list)
{
HASH_LIST *h;
// Validate arguments
if (get_hash_proc == NULL || compare_proc == NULL)
{
return NULL;
}
if (bits == 0)
{
bits = 16;
}
bits = MIN(bits, 31);
h = ZeroMalloc(sizeof(HASH_LIST));
h->Bits = bits;
h->Size = Power(2, bits);
h->Lock = NewLock();
h->Ref = NewRef();
h->Entries = ZeroMalloc(sizeof(LIST *) * h->Size);
h->GetHashProc = get_hash_proc;
h->CompareProc = compare_proc;
if (make_list)
{
h->AllList = NewListFast(NULL);
}
return h;
}
// Release the hash list
void ReleaseHashList(HASH_LIST *h)
{
// Validate arguments
if (h == NULL)
{
return;
}
if (Release(h->Ref) == 0)
{
CleanupHashList(h);
}
}
void CleanupHashList(HASH_LIST *h)
{
UINT i;
// Validate arguments
if (h == NULL)
{
return;
}
for (i = 0;i < h->Size;i++)
{
LIST *o = h->Entries[i];
if (o != NULL)
{
ReleaseList(o);
}
}
Free(h->Entries);
DeleteLock(h->Lock);
if (h->AllList != NULL)
{
ReleaseList(h->AllList);
}
Free(h);
}
// Append a string to the buffer
void AppendBufStr(BUF *b, char *str)
{
// Validate arguments
if (b == NULL || str == NULL)
{
return;
}
WriteBuf(b, str, StrLen(str));
}
// Add a UTF-8 string to the buffer
void AppendBufUtf8(BUF *b, wchar_t *str)
{
UINT size;
UCHAR *data;
// Validate arguments
if (b == NULL || str == NULL)
{
return;
}
size = CalcUniToUtf8(str) + 1;
data = ZeroMalloc(size);
UniToUtf8(data, size, str);
WriteBuf(b, data, size - 1);
Free(data);
}
// Creating a shared buffer
SHARED_BUFFER *NewSharedBuffer(void *data, UINT size)
{
SHARED_BUFFER *b = ZeroMalloc(sizeof(SHARED_BUFFER));
b->Ref = NewRef();
b->Data = ZeroMalloc(size);
b->Size = size;
if (data != NULL)
{
Copy(b->Data, data, size);
}
return b;
}
// Release of the shared buffer
void ReleaseSharedBuffer(SHARED_BUFFER *b)
{
// Validate arguments
if (b == NULL)
{
return;
}
if (Release(b->Ref) == 0)
{
CleanupSharedBuffer(b);
}
}
void CleanupSharedBuffer(SHARED_BUFFER *b)
{
// Validate arguments
if (b == NULL)
{
return;
}
Free(b->Data);
Free(b);
}
// Calculation of a ^ b (a to the b-th power)
UINT Power(UINT a, UINT b)
{
UINT ret, i;
if (a == 0)
{
return 0;
}
if (b == 0)
{
return 1;
}
ret = 1;
for (i = 0;i < b;i++)
{
ret *= a;
}
return ret;
}
// Search in the binary
UINT SearchBin(void *data, UINT data_start, UINT data_size, void *key, UINT key_size)
{
UINT i;
// Validate arguments
if (data == NULL || key == NULL || key_size == 0 || data_size == 0 ||
(data_start >= data_size) || (data_start + key_size > data_size))
{
return INFINITE;
}
for (i = data_start;i < (data_size - key_size + 1);i++)
{
UCHAR *p = ((UCHAR *)data) + i;
if (Cmp(p, key, key_size) == 0)
{
return i;
}
}
return INFINITE;
}
// Crash immediately
void CrashNow()
{
while (true)
{
UINT r = Rand32();
UCHAR *c = (UCHAR *)r;
*c = Rand8();
}
}
// Convert the buffer to candidate
LIST *BufToCandidate(BUF *b)
{
LIST *o;
UINT i;
UINT num;
// Validate arguments
if (b == NULL)
{
return NULL;
}
num = ReadBufInt(b);
o = NewCandidateList();
for (i = 0;i < num;i++)
{
CANDIDATE *c;
wchar_t *s;
UINT64 sec64;
UINT len, size;
sec64 = ReadBufInt64(b);
len = ReadBufInt(b);
if (len >= 65536)
{
break;
}
size = (len + 1) * 2;
s = ZeroMalloc(size);
if (ReadBuf(b, s, size) != size)
{
Free(s);
break;
}
else
{
c = ZeroMalloc(sizeof(CANDIDATE));
c->LastSelectedTime = sec64;
c->Str = s;
Add(o, c);
}
}
Sort(o);
return o;
}
// Convert the candidate to buffer
BUF *CandidateToBuf(LIST *o)
{
BUF *b;
UINT i;
// Validate arguments
if (o == NULL)
{
return NULL;
}
b = NewBuf();
WriteBufInt(b, LIST_NUM(o));
for (i = 0;i < LIST_NUM(o);i++)
{
CANDIDATE *c = LIST_DATA(o, i);
WriteBufInt64(b, c->LastSelectedTime);
WriteBufInt(b, UniStrLen(c->Str));
WriteBuf(b, c->Str, UniStrSize(c->Str));
}
SeekBuf(b, 0, 0);
return b;
}
// Adding a candidate
void AddCandidate(LIST *o, wchar_t *str, UINT num_max)
{
UINT i;
bool exists;
// Validate arguments
if (o == NULL || str == NULL)
{
return;
}
if (num_max == 0)
{
num_max = 0x7fffffff;
}
// String copy
str = UniCopyStr(str);
UniTrim(str);
exists = false;
for (i = 0;i < LIST_NUM(o);i++)
{
CANDIDATE *c = LIST_DATA(o, i);
if (UniStrCmpi(c->Str, str) == 0)
{
// Update the time that an existing entry have been found
c->LastSelectedTime = SystemTime64();
exists = true;
break;
}
}
if (exists == false)
{
// Insert new
CANDIDATE *c = ZeroMalloc(sizeof(CANDIDATE));
c->LastSelectedTime = SystemTime64();
c->Str = UniCopyStr(str);
Insert(o, c);
}
// Release the string
Free(str);
// Check the current number of candidates.
// If it is more than num_max, remove from an oldest candidate sequentially.
if (LIST_NUM(o) > num_max)
{
while (LIST_NUM(o) > num_max)
{
UINT index = LIST_NUM(o) - 1;
CANDIDATE *c = LIST_DATA(o, index);
Delete(o, c);
Free(c->Str);
Free(c);
}
}
}
// Comparison of candidates
int CompareCandidate(void *p1, void *p2)
{
CANDIDATE *c1, *c2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
c1 = *(CANDIDATE **)p1;
c2 = *(CANDIDATE **)p2;
if (c1 == NULL || c2 == NULL)
{
return 0;
}
if (c1->LastSelectedTime > c2->LastSelectedTime)
{
return -1;
}
else if (c1->LastSelectedTime < c2->LastSelectedTime)
{
return 1;
}
else
{
return UniStrCmpi(c1->Str, c2->Str);
}
}
// Release of the candidate list
void FreeCandidateList(LIST *o)
{
UINT i;
// Validate arguments
if (o == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(o);i++)
{
CANDIDATE *c = LIST_DATA(o, i);
Free(c->Str);
Free(c);
}
ReleaseList(o);
}
// Creating a new candidate list
LIST *NewCandidateList()
{
return NewList(CompareCandidate);
}
// Examine whether the specified address points all-zero area
bool IsZero(void *data, UINT size)
{
UINT i;
UCHAR *c = (UCHAR *)data;
// Validate arguments
if (data == NULL || size == 0)
{
return true;
}
for (i = 0;i < size;i++)
{
if (c[i] != 0)
{
return false;
}
}
return true;
}
// Expand the data
UINT Uncompress(void *dst, UINT dst_size, void *src, UINT src_size)
{
unsigned long dst_size_long = dst_size;
// Validate arguments
if (dst == NULL || dst_size_long == 0 || src == NULL)
{
return 0;
}
if (uncompress(dst, &dst_size_long, src, src_size) != Z_OK)
{
return 0;
}
return (UINT)dst_size_long;
}
BUF *UncompressBuf(BUF *src_buf)
{
UINT dst_size, dst_size2;
UCHAR *dst;
BUF *b;
// Validate arguments
if (src_buf == NULL)
{
return NULL;
}
SeekBuf(src_buf, 0, 0);
dst_size = ReadBufInt(src_buf);
dst = Malloc(dst_size);
dst_size2 = Uncompress(dst, dst_size, ((UCHAR *)src_buf->Buf) + sizeof(UINT), src_buf->Size - sizeof(UINT));
b = NewBuf();
WriteBuf(b, dst, dst_size2);
Free(dst);
return b;
}
// Compress the data
UINT Compress(void *dst, UINT dst_size, void *src, UINT src_size)
{
return CompressEx(dst, dst_size, src, src_size, Z_DEFAULT_COMPRESSION);
}
BUF *CompressBuf(BUF *src_buf)
{
UINT dst_size;
UCHAR *dst_buf;
BUF *b;
// Validate arguments
if (src_buf == NULL)
{
return NULL;
}
dst_size = CalcCompress(src_buf->Size);
dst_buf = Malloc(dst_size);
dst_size = Compress(dst_buf, dst_size, src_buf->Buf, src_buf->Size);
if (dst_size == 0)
{
Free(dst_buf);
return NULL;
}
b = NewBuf();
WriteBufInt(b, src_buf->Size);
WriteBuf(b, dst_buf, dst_size);
Free(dst_buf);
return b;
}
// Compress the data with options
UINT CompressEx(void *dst, UINT dst_size, void *src, UINT src_size, UINT level)
{
unsigned long dst_size_long = dst_size;
// Validate arguments
if (dst == NULL || dst_size_long == 0 || src == NULL)
{
return 0;
}
if (compress2(dst, &dst_size_long, src, src_size, (int)level) != Z_OK)
{
return 0;
}
return dst_size_long;
}
// Get the maximum size of compressed data from data of src_size
UINT CalcCompress(UINT src_size)
{
return src_size * 2 + 256;
}
// Creating a Stack
SK *NewSk()
{
return NewSkEx(false);
}
SK *NewSkEx(bool no_compact)
{
SK *s;
s = Malloc(sizeof(SK));
s->lock = NewLock();
s->ref = NewRef();
s->num_item = 0;
s->num_reserved = INIT_NUM_RESERVED;
s->p = Malloc(sizeof(void *) * s->num_reserved);
s->no_compact = no_compact;
// KS
KS_INC(KS_NEWSK_COUNT);
return s;
}
// Release of the stack
void ReleaseSk(SK *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
if (Release(s->ref) == 0)
{
CleanupSk(s);
}
}
// Clean up the stack
void CleanupSk(SK *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
// Memory release
Free(s->p);
DeleteLock(s->lock);
Free(s);
// KS
KS_INC(KS_FREESK_COUNT);
}
// Lock of the stack
void LockSk(SK *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
Lock(s->lock);
}
// Unlock the stack
void UnlockSk(SK *s)
{
// Validate arguments
if (s == NULL)
{
return;
}
Unlock(s->lock);
}
// Push to the stack
void Push(SK *s, void *p)
{
UINT i;
// Validate arguments
if (s == NULL || p == NULL)
{
return;
}
i = s->num_item;
s->num_item++;
// Size expansion
if (s->num_item > s->num_reserved)
{
s->num_reserved = s->num_reserved * 2;
s->p = ReAlloc(s->p, sizeof(void *) * s->num_reserved);
}
s->p[i] = p;
// KS
KS_INC(KS_PUSH_COUNT);
}
// Pop from the stack
void *Pop(SK *s)
{
void *ret;
// Validate arguments
if (s == NULL)
{
return NULL;
}
if (s->num_item == 0)
{
return NULL;
}
ret = s->p[s->num_item - 1];
s->num_item--;
// Size reduction
if (s->no_compact == false)
{
// Not to shrink when no_compact is true
if ((s->num_item * 2) <= s->num_reserved)
{
if (s->num_reserved >= (INIT_NUM_RESERVED * 2))
{
s->num_reserved = s->num_reserved / 2;
s->p = ReAlloc(s->p, sizeof(void *) * s->num_reserved);
}
}
}
// KS
KS_INC(KS_POP_COUNT);
return ret;
}
// Get the number of queued items
UINT GetQueueNum(QUEUE *q)
{
// Validate arguments
if (q == NULL)
{
return 0;
}
return q->num_item;
}
// Get one
void *GetNext(QUEUE *q)
{
void *p = NULL;
// Validate arguments
if (q == NULL)
{
return NULL;
}
if (q->num_item == 0)
{
// No items
return NULL;
}
// Read from the FIFO
ReadFifo(q->fifo, &p, sizeof(void *));
q->num_item--;
// KS
KS_INC(KS_GETNEXT_COUNT);
return p;
}
// Get one item from the queue (locking)
void *GetNextWithLock(QUEUE *q)
{
void *p;
// Validate arguments
if (q == NULL)
{
return NULL;
}
LockQueue(q);
{
p = GetNext(q);
}
UnlockQueue(q);
return p;
}
// Insert the int type in the queue
void InsertQueueInt(QUEUE *q, UINT value)
{
UINT *p;
// Validate arguments
if (q == NULL)
{
return;
}
p = Clone(&value, sizeof(UINT));
InsertQueue(q, p);
}
// Insert to the queue
void InsertQueue(QUEUE *q, void *p)
{
// Validate arguments
if (q == NULL || p == NULL)
{
return;
}
// Write to the FIFO
WriteFifo(q->fifo, &p, sizeof(void *));
q->num_item++;
/*{
static UINT max_num_item;
static UINT64 next_tick = 0;
UINT64 now = Tick64();
max_num_item = MAX(q->num_item, max_num_item);
if (next_tick == 0 || next_tick <= now)
{
next_tick = now + (UINT64)1000;
printf("max_queue = %u\n", max_num_item);
}
}*/
// KS
KS_INC(KS_INSERT_QUEUE_COUNT);
}
// Insert to the queue (locking)
void InsertQueueWithLock(QUEUE *q, void *p)
{
// Validate arguments
if (q == NULL || p == NULL)
{
return;
}
LockQueue(q);
{
InsertQueue(q, p);
}
UnlockQueue(q);
}
// Lock the queue
void LockQueue(QUEUE *q)
{
// Validate arguments
if (q == NULL)
{
return;
}
Lock(q->lock);
}
// Unlock the queue
void UnlockQueue(QUEUE *q)
{
// Validate arguments
if (q == NULL)
{
return;
}
Unlock(q->lock);
}
// Release of the queue
void ReleaseQueue(QUEUE *q)
{
// Validate arguments
if (q == NULL)
{
return;
}
if (q->ref == NULL || Release(q->ref) == 0)
{
CleanupQueue(q);
}
}
// Clean-up the queue
void CleanupQueue(QUEUE *q)
{
// Validate arguments
if (q == NULL)
{
return;
}
// Memory release
ReleaseFifo(q->fifo);
DeleteLock(q->lock);
Free(q);
// KS
KS_INC(KS_FREEQUEUE_COUNT);
}
// Creating a Queue
QUEUE *NewQueue()
{
QUEUE *q;
q = ZeroMalloc(sizeof(QUEUE));
q->lock = NewLock();
q->ref = NewRef();
q->num_item = 0;
q->fifo = NewFifo();
// KS
KS_INC(KS_NEWQUEUE_COUNT);
return q;
}
QUEUE *NewQueueFast()
{
QUEUE *q;
q = ZeroMalloc(sizeof(QUEUE));
q->lock = NULL;
q->ref = NULL;
q->num_item = 0;
q->fifo = NewFifoFast();
// KS
KS_INC(KS_NEWQUEUE_COUNT);
return q;
}
// Clone the list
LIST *CloneList(LIST *o)
{
LIST *n = NewList(o->cmp);
// Memory reallocation
Free(n->p);
n->p = ToArray(o);
n->num_item = n->num_reserved = LIST_NUM(o);
n->sorted = o->sorted;
return n;
}
// Copy the list to an array
void CopyToArray(LIST *o, void *p)
{
// Validate arguments
if (o == NULL || p == NULL)
{
return;
}
// KS
KS_INC(KS_TOARRAY_COUNT);
Copy(p, o->p, sizeof(void *) * o->num_item);
}
// Arrange the list to an array
void *ToArray(LIST *o)
{
return ToArrayEx(o, false);
}
void *ToArrayEx(LIST *o, bool fast)
{
void *p;
// Validate arguments
if (o == NULL)
{
return NULL;
}
// Memory allocation
if (fast == false)
{
p = Malloc(sizeof(void *) * LIST_NUM(o));
}
else
{
p = MallocFast(sizeof(void *) * LIST_NUM(o));
}
// Copy
CopyToArray(o, p);
return p;
}
// Search in the list
void *Search(LIST *o, void *target)
{
void **ret;
// Validate arguments
if (o == NULL || target == NULL)
{
return NULL;
}
if (o->cmp == NULL)
{
return NULL;
}
// Check the sort
if (o->sorted == false)
{
// Sort because it is not sorted
Sort(o);
}
ret = (void **)bsearch(&target, o->p, o->num_item, sizeof(void *),
(int(*)(const void *, const void *))o->cmp);
// KS
KS_INC(KS_SEARCH_COUNT);
if (ret != NULL)
{
return *ret;
}
else
{
return NULL;
}
}
// Insert an item to the list
void Insert(LIST *o, void *p)
{
int low, high, middle;
UINT pos;
int i;
// Validate arguments
if (o == NULL || p == NULL)
{
return;
}
if (o->cmp == NULL)
{
// adding simply if there is no sort function
Add(o, p);
return;
}
// Sort immediately if it is not sorted
if (o->sorted == false)
{
Sort(o);
}
low = 0;
high = LIST_NUM(o) - 1;
pos = INFINITE;
while (low <= high)
{
int ret;
middle = (low + high) / 2;
ret = o->cmp(&(o->p[middle]), &p);
if (ret == 0)
{
pos = middle;
break;
}
else if (ret > 0)
{
high = middle - 1;
}
else
{
low = middle + 1;
}
}
if (pos == INFINITE)
{
pos = low;
}
o->num_item++;
if (o->num_item > o->num_reserved)
{
o->num_reserved *= 2;
o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
}
if (LIST_NUM(o) >= 2)
{
for (i = (LIST_NUM(o) - 2);i >= (int)pos;i--)
{
o->p[i + 1] = o->p[i];
}
}
o->p[pos] = p;
// KS
KS_INC(KS_INSERT_COUNT);
}
// Sort the list
void Sort(LIST *o)
{
// Validate arguments
if (o == NULL || o->cmp == NULL)
{
return;
}
qsort(o->p, o->num_item, sizeof(void *), (int(*)(const void *, const void *))o->cmp);
o->sorted = true;
// KS
KS_INC(KS_SORT_COUNT);
}
// Replace the pointer in the list
bool ReplaceListPointer(LIST *o, void *oldptr, void *newptr)
{
UINT i;
// Validate arguments
if (o == NULL || oldptr == NULL || newptr == NULL)
{
return false;
}
for (i = 0;i < LIST_NUM(o);i++)
{
void *p = LIST_DATA(o, i);
if (p == oldptr)
{
o->p[i] = newptr;
return true;
}
}
return false;
}
// New string list
LIST *NewStrList()
{
return NewListFast(CompareStr);
}
// Release string list
void ReleaseStrList(LIST *o)
{
UINT i;
if (o == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(o);i++)
{
char *s = LIST_DATA(o, i);
Free(s);
}
ReleaseList(o);
}
// Add a string distinct to the string list
bool AddStrToStrListDistinct(LIST *o, char *str)
{
if (o == NULL || str == NULL)
{
return false;
}
if (IsInListStr(o, str) == false)
{
Add(o, CopyStr(str));
return true;
}
return false;
}
// Examine whether a string items are present in the list
bool IsInListStr(LIST *o, char *str)
{
UINT i;
// Validate arguments
if (o == NULL || str == NULL)
{
return false;
}
for (i = 0;i < LIST_NUM(o);i++)
{
char *s = LIST_DATA(o, i);
if (StrCmpi(s, str) == 0)
{
return true;
}
}
return false;
}
bool IsInListUniStr(LIST *o, wchar_t *str)
{
UINT i;
// Validate arguments
if (o == NULL || str == NULL)
{
return false;
}
for (i = 0; i < LIST_NUM(o); i++)
{
wchar_t *s = LIST_DATA(o, i);
if (UniStrCmpi(s, str) == 0)
{
return true;
}
}
return false;
}
// Get the pointer by scanning by UINT pointer in the list
void *ListKeyToPointer(LIST *o, UINT key)
{
UINT i;
// Validate arguments
if (o == NULL || key == 0)
{
return NULL;
}
for (i = 0;i < LIST_NUM(o);i++)
{
void *p = LIST_DATA(o, i);
if (POINTER_TO_KEY(p) == key)
{
return p;
}
}
return NULL;
}
// Examine whether the key is present in the list
bool IsInListKey(LIST *o, UINT key)
{
void *p;
// Validate arguments
if (o == NULL || key == 0)
{
return false;
}
p = ListKeyToPointer(o, key);
if (p == NULL)
{
return false;
}
return true;
}
// Examine whether the item exists in the list
bool IsInList(LIST *o, void *p)
{
UINT i;
// Validate arguments
if (o == NULL || p == NULL)
{
return false;
}
for (i = 0;i < LIST_NUM(o);i++)
{
void *q = LIST_DATA(o, i);
if (p == q)
{
return true;
}
}
return false;
}
// Add an element to the list (Don't add if it already exists)
void AddDistinct(LIST *o, void *p)
{
// Validate arguments
if (o == NULL || p == NULL)
{
return;
}
if (IsInList(o, p))
{
return;
}
Add(o, p);
}
// Add an element to the list
void Add(LIST *o, void *p)
{
UINT i;
// Validate arguments
if (o == NULL || p == NULL)
{
return;
}
i = o->num_item;
o->num_item++;
if (o->num_item > o->num_reserved)
{
o->num_reserved = o->num_reserved * 2;
o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
}
o->p[i] = p;
o->sorted = false;
// KS
KS_INC(KS_INSERT_COUNT);
}
// Delete the element from the list
bool Delete(LIST *o, void *p)
{
UINT i, n;
// Validate arguments
if (o == NULL || p == NULL)
{
return false;
}
for (i = 0;i < o->num_item;i++)
{
if (o->p[i] == p)
{
break;
}
}
if (i == o->num_item)
{
return false;
}
n = i;
for (i = n;i < (o->num_item - 1);i++)
{
o->p[i] = o->p[i + 1];
}
o->num_item--;
if ((o->num_item * 2) <= o->num_reserved)
{
if (o->num_reserved > (INIT_NUM_RESERVED * 2))
{
o->num_reserved = o->num_reserved / 2;
o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
}
}
// KS
KS_INC(KS_DELETE_COUNT);
return true;
}
// Delete all elements from the list
void DeleteAll(LIST *o)
{
// Validate arguments
if (o == NULL)
{
return;
}
o->num_item = 0;
o->num_reserved = INIT_NUM_RESERVED;
o->p = ReAlloc(o->p, sizeof(void *) * INIT_NUM_RESERVED);
}
// Lock the list
void LockList(LIST *o)
{
// Validate arguments
if (o == NULL)
{
return;
}
Lock(o->lock);
}
// Unlock the list
void UnlockList(LIST *o)
{
// Validate arguments
if (o == NULL)
{
return;
}
Unlock(o->lock);
}
// Release the list
void ReleaseList(LIST *o)
{
// Validate arguments
if (o == NULL)
{
return;
}
if (o->ref == NULL || Release(o->ref) == 0)
{
CleanupList(o);
}
}
// Clean up the list
void CleanupList(LIST *o)
{
// Validate arguments
if (o == NULL)
{
return;
}
Free(o->p);
if (o->lock != NULL)
{
DeleteLock(o->lock);
}
Free(o);
// KS
KS_INC(KS_FREELIST_COUNT);
}
// Check whether the specified number is already in the list
bool IsIntInList(LIST *o, UINT i)
{
UINT j;
// Validate arguments
if (o == NULL)
{
return false;
}
for (j = 0;j < LIST_NUM(o);j++)
{
UINT *p = LIST_DATA(o, j);
if (*p == i)
{
return true;
}
}
return false;
}
bool IsInt64InList(LIST *o, UINT64 i)
{
UINT j;
// Validate arguments
if (o == NULL)
{
return false;
}
for (j = 0;j < LIST_NUM(o);j++)
{
UINT64 *p = LIST_DATA(o, j);
if (*p == i)
{
return true;
}
}
return false;
}
// Release the integer list
void ReleaseIntList(LIST *o)
{
UINT i;
// Validate arguments
if (o == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(o);i++)
{
UINT *p = LIST_DATA(o, i);
Free(p);
}
ReleaseList(o);
}
void ReleaseInt64List(LIST *o)
{
UINT i;
// Validate arguments
if (o == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(o);i++)
{
UINT64 *p = LIST_DATA(o, i);
Free(p);
}
ReleaseList(o);
}
// Delete an integer from list
void DelInt(LIST *o, UINT i)
{
LIST *o2 = NULL;
UINT j;
// Validate arguments
if (o == NULL)
{
return;
}
for (j = 0;j < LIST_NUM(o);j++)
{
UINT *p = LIST_DATA(o, j);
if (*p == i)
{
if (o2 == NULL)
{
o2 = NewListFast(NULL);
}
Add(o2, p);
}
}
for (j = 0;j < LIST_NUM(o2);j++)
{
UINT *p = LIST_DATA(o2, j);
Delete(o, p);
Free(p);
}
if (o2 != NULL)
{
ReleaseList(o2);
}
}
// Create a new list of integers
LIST *NewIntList(bool sorted)
{
LIST *o = NewList(sorted ? CompareInt : NULL);
return o;
}
LIST *NewInt64List(bool sorted)
{
LIST *o = NewList(sorted ? CompareInt64 : NULL);
return o;
}
// Comparison of items in the list of integers
int CompareInt(void *p1, void *p2)
{
UINT *v1, *v2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
v1 = *((UINT **)p1);
v2 = *((UINT **)p2);
if (v1 == NULL || v2 == NULL)
{
return 0;
}
return COMPARE_RET(*v1, *v2);
}
int CompareInt64(void *p1, void *p2)
{
UINT64 *v1, *v2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
v1 = *((UINT64 **)p1);
v2 = *((UINT64 **)p2);
if (v1 == NULL || v2 == NULL)
{
return 0;
}
return COMPARE_RET(*v1, *v2);
}
// Add an integer to the list
void AddInt(LIST *o, UINT i)
{
// Validate arguments
if (o == NULL)
{
return;
}
Add(o, Clone(&i, sizeof(UINT)));
}
void AddInt64(LIST *o, UINT64 i)
{
// Validate arguments
if (o == NULL)
{
return;
}
Add(o, Clone(&i, sizeof(UINT64)));
}
void InsertInt(LIST *o, UINT i)
{
// Validate arguments
if (o == NULL)
{
return;
}
Insert(o, Clone(&i, sizeof(UINT)));
}
// Add an integer to the list (no duplicates)
void AddIntDistinct(LIST *o, UINT i)
{
// Validate arguments
if (o == NULL)
{
return;
}
if (IsIntInList(o, i) == false)
{
AddInt(o, i);
}
}
void AddInt64Distinct(LIST *o, UINT64 i)
{
// Validate arguments
if (o == NULL)
{
return;
}
if (IsInt64InList(o, i) == false)
{
AddInt64(o, i);
}
}
void InsertIntDistinct(LIST *o, UINT i)
{
// Validate arguments
if (o == NULL)
{
return;
}
if (IsIntInList(o, i) == false)
{
InsertInt(o, i);
}
}
// String comparison function (Unicode)
int CompareUniStr(void *p1, void *p2)
{
wchar_t *s1, *s2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
s1 = *(wchar_t **)p1;
s2 = *(wchar_t **)p2;
return UniStrCmp(s1, s2);
}
// Insert the string to the list
bool InsertStr(LIST *o, char *str)
{
// Validate arguments
if (o == NULL || str == NULL)
{
return false;
}
if (Search(o, str) == NULL)
{
Insert(o, str);
return true;
}
return false;
}
// String comparison function
int CompareStr(void *p1, void *p2)
{
char *s1, *s2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
s1 = *(char **)p1;
s2 = *(char **)p2;
return StrCmpi(s1, s2);
}
// Create a list with an item
LIST *NewListSingle(void *p)
{
LIST *o = NewListFast(NULL);
Add(o, p);
return o;
}
// Creating a high-speed list (without lock)
LIST *NewListFast(COMPARE *cmp)
{
return NewListEx(cmp, true);
}
// Creating a list
LIST *NewList(COMPARE *cmp)
{
return NewListEx(cmp, false);
}
LIST *NewListEx(COMPARE *cmp, bool fast)
{
return NewListEx2(cmp, fast, false);
}
LIST *NewListEx2(COMPARE *cmp, bool fast, bool fast_malloc)
{
LIST *o;
if (fast_malloc == false)
{
o = Malloc(sizeof(LIST));
}
else
{
o = MallocFast(sizeof(LIST));
}
if (fast == false)
{
o->lock = NewLock();
o->ref = NewRef();
}
else
{
o->lock = NULL;
o->ref = NULL;
}
o->num_item = 0;
o->num_reserved = INIT_NUM_RESERVED;
o->Param1 = 0;
if (fast_malloc == false)
{
o->p = Malloc(sizeof(void *) * o->num_reserved);
}
else
{
o->p = MallocFast(sizeof(void *) * o->num_reserved);
}
o->cmp = cmp;
o->sorted = true;
// KS
KS_INC(KS_NEWLIST_COUNT);
return o;
}
// Parses a string by identifying its parts using the specified separators
LIST *NewEntryList(char *src, char *key_separator, char *value_separator)
{
LIST *o = NewListFast(NULL);
TOKEN_LIST *t;
t = ParseTokenWithoutNullStr(src, key_separator);
if (t != NULL)
{
UINT i;
for (i = 0; i < t->NumTokens; i++)
{
char key[MAX_SIZE];
char value[MAX_SIZE];
char *line = t->Token[i];
Trim(line);
if (GetKeyAndValue(line, key, sizeof(key), value, sizeof(value), value_separator))
{
INI_ENTRY *e = ZeroMalloc(sizeof(INI_ENTRY));
e->Key = CopyStr(key);
e->Value = CopyStr(value);
Add(o, e);
}
}
FreeToken(t);
}
return o;
}
// Checks whether the list contains the specified entry
bool EntryListHasKey(LIST *o, char *key)
{
// Validate arguments
if (o == NULL || key == NULL)
{
return false;
}
if (GetIniEntry(o, key) != NULL)
{
return true;
}
return false;
}
// Gets the value of the specified key from the entry list
char *EntryListStrValue(LIST *o, char *key)
{
return IniStrValue(o, key);
}
UINT EntryListIntValue(LIST *o, char *key)
{
return IniIntValue(o, key);
}
// Release the entry list
void FreeEntryList(LIST *o)
{
// Validate arguments
if (o == NULL)
{
return;
}
FreeIni(o);
}
// Read all data from FIFO
BUF *ReadFifoAll(FIFO *f)
{
BUF *buf;
UCHAR *tmp;
UINT size;
if (f == NULL)
{
return NewBuf();
}
size = FifoSize(f);
tmp = Malloc(size);
ReadFifo(f, tmp, size);
buf = MemToBuf(tmp, size);
Free(tmp);
return buf;
}
// Read from the FIFO
UINT ReadFifo(FIFO *f, void *p, UINT size)
{
UINT read_size;
// Validate arguments
if (f == NULL || size == 0)
{
return 0;
}
read_size = MIN(size, f->size);
if (read_size == 0)
{
return 0;
}
if (p != NULL)
{
Copy(p, (UCHAR *)f->p + f->pos, read_size);
}
f->pos += read_size;
f->size -= read_size;
f->total_read_size += (UINT64)read_size;
if (f->fixed == false)
{
if (f->size == 0)
{
f->pos = 0;
}
}
ShrinkFifoMemory(f);
// KS
KS_INC(KS_READ_FIFO_COUNT);
return read_size;
}
// Rearrange the memory
void ShrinkFifoMemory(FIFO *f)
{
// Validate arguments
if (f == NULL)
{
return;
}
if (f->fixed)
{
return;
}
// Rearrange the memory
if (f->pos >= FIFO_INIT_MEM_SIZE &&
f->memsize >= fifo_current_realloc_mem_size &&
(f->memsize / 2) > f->size)
{
void *new_p;
UINT new_size;
new_size = MAX(f->memsize / 2, FIFO_INIT_MEM_SIZE);
new_p = Malloc(new_size);
Copy(new_p, (UCHAR *)f->p + f->pos, f->size);
Free(f->p);
f->memsize = new_size;
f->p = new_p;
f->pos = 0;
}
}
// Write to the FIFO
void WriteFifo(FIFO *f, void *p, UINT size)
{
UINT i, need_size;
bool realloc_flag;
// Validate arguments
if (f == NULL || size == 0)
{
return;
}
i = f->size;
f->size += size;
need_size = f->pos + f->size;
realloc_flag = false;
// Memory expansion
while (need_size > f->memsize)
{
f->memsize = MAX(f->memsize, FIFO_INIT_MEM_SIZE) * 3;
realloc_flag = true;
}
if (realloc_flag)
{
f->p = ReAlloc(f->p, f->memsize);
}
// Write the data
if (p != NULL)
{
Copy((UCHAR *)f->p + f->pos + i, p, size);
}
f->total_write_size += (UINT64)size;
// KS
KS_INC(KS_WRITE_FIFO_COUNT);
}
// Get the current pointer of the FIFO
UCHAR *GetFifoPointer(FIFO *f)
{
// Validate arguments
if (f == NULL)
{
return NULL;
}
return ((UCHAR *)f->p) + f->pos;
}
UCHAR *FifoPtr(FIFO *f)
{
return GetFifoPointer(f);
}
// Get the size of the FIFO
UINT FifoSize(FIFO *f)
{
// Validate arguments
if (f == NULL)
{
return 0;
}
return f->size;
}
// Release the FIFO
void ReleaseFifo(FIFO *f)
{
// Validate arguments
if (f == NULL)
{
return;
}
if (f->ref == NULL || Release(f->ref) == 0)
{
CleanupFifo(f);
}
}
// Clean-up the FIFO
void CleanupFifo(FIFO *f)
{
// Validate arguments
if (f == NULL)
{
return;
}
DeleteLock(f->lock);
Free(f->p);
Free(f);
// KS
KS_INC(KS_FREEFIFO_COUNT);
}
// Initialize the FIFO system
void InitFifo()
{
fifo_current_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
}
// Create a FIFO
FIFO *NewFifo()
{
return NewFifoEx(false);
}
FIFO *NewFifoFast()
{
return NewFifoEx(true);
}
FIFO *NewFifoEx(bool fast)
{
return NewFifoEx2(fast, false);
}
FIFO *NewFifoEx2(bool fast, bool fixed)
{
FIFO *f;
// Memory allocation
f = ZeroMalloc(sizeof(FIFO));
if (fast == false)
{
f->lock = NewLock();
f->ref = NewRef();
}
else
{
f->lock = NULL;
f->ref = NULL;
}
f->size = f->pos = 0;
f->memsize = FIFO_INIT_MEM_SIZE;
f->p = Malloc(FIFO_INIT_MEM_SIZE);
f->fixed = false;
// KS
KS_INC(KS_NEWFIFO_COUNT);
return f;
}
// Set the default memory reclaiming size of the FIFO
void SetFifoCurrentReallocMemSize(UINT size)
{
if (size == 0)
{
size = FIFO_REALLOC_MEM_SIZE;
}
fifo_current_realloc_mem_size = size;
}
// Read a buffer from a file
BUF *FileToBuf(IO *o)
{
UCHAR hash1[MD5_SIZE], hash2[MD5_SIZE];
UINT size;
void *buf;
BUF *b;
// Validate arguments
if (o == NULL)
{
return NULL;
}
// Read the size
if (FileRead(o, &size, sizeof(size)) == false)
{
return NULL;
}
size = Endian32(size);
if (size > FileSize(o))
{
return NULL;
}
// Read a hash
if (FileRead(o, hash1, sizeof(hash1)) == false)
{
return NULL;
}
// Read from the buffer
buf = Malloc(size);
if (FileRead(o, buf, size) == false)
{
Free(buf);
return NULL;
}
// Take a hash
Md5(hash2, buf, size);
// Compare the hashes
if (Cmp(hash1, hash2, sizeof(hash1)) != 0)
{
// Hashes are different
Free(buf);
return NULL;
}
// Create a buffer
b = NewBuf();
WriteBuf(b, buf, size);
Free(buf);
b->Current = 0;
return b;
}
// Read a dump file into a buffer
BUF *ReadDump(char *filename)
{
return ReadDumpWithMaxSize(filename, 0);
}
BUF *ReadDumpWithMaxSize(char *filename, UINT max_size)
{
IO *o;
BUF *b;
UINT size;
void *data;
// Validate arguments
if (filename == NULL)
{
return NULL;
}
o = FileOpen(filename, false);
if (o == NULL)
{
return NULL;
}
size = FileSize(o);
if (max_size != 0)
{
if (size > max_size)
{
size = max_size;
}
}
data = Malloc(size);
FileRead(o, data, size);
FileClose(o);
b = NewBuf();
WriteBuf(b, data, size);
b->Current = 0;
Free(data);
return b;
}
BUF *ReadDumpW(wchar_t *filename)
{
return ReadDumpExW(filename, true);
}
BUF *ReadDumpExW(wchar_t *filename, bool read_lock)
{
IO *o;
BUF *b;
UINT size;
void *data;
// Validate arguments
if (filename == NULL)
{
return NULL;
}
o = FileOpenExW(filename, false, read_lock);
if (o == NULL)
{
return NULL;
}
size = FileSize(o);
data = Malloc(size);
FileRead(o, data, size);
FileClose(o);
b = NewBuf();
WriteBuf(b, data, size);
b->Current = 0;
Free(data);
return b;
}
// Write down the data
bool DumpDataW(void *data, UINT size, wchar_t *filename)
{
IO *o;
// Validate arguments
if (filename == NULL || (size != 0 && data == NULL))
{
return false;
}
o = FileCreateW(filename);
if (o == NULL)
{
return false;
}
FileWrite(o, data, size);
FileClose(o);
return true;
}
// Dump the contents of the buffer to the file
bool DumpBuf(BUF *b, char *filename)
{
IO *o;
// Validate arguments
if (b == NULL || filename == NULL)
{
return false;
}
o = FileCreate(filename);
if (o == NULL)
{
return false;
}
FileWrite(o, b->Buf, b->Size);
FileClose(o);
return true;
}
bool DumpBufW(BUF *b, wchar_t *filename)
{
IO *o;
// Validate arguments
if (b == NULL || filename == NULL)
{
return false;
}
o = FileCreateW(filename);
if (o == NULL)
{
return false;
}
FileWrite(o, b->Buf, b->Size);
FileClose(o);
return true;
}
// Write to the file only if the contents of the file is different
bool DumpBufWIfNecessary(BUF *b, wchar_t *filename)
{
BUF *now;
bool need = true;
// Validate arguments
if (b == NULL || filename == NULL)
{
return false;
}
now = ReadDumpW(filename);
if (now != NULL)
{
if (CompareBuf(now, b))
{
need = false;
}
FreeBuf(now);
}
if (need == false)
{
return true;
}
else
{
return DumpBufW(b, filename);
}
}
// Write the buffer to a file
bool BufToFile(IO *o, BUF *b)
{
UCHAR hash[MD5_SIZE];
UINT size;
// Validate arguments
if (o == NULL || b == NULL)
{
return false;
}
// Hash the data
Md5(hash, b->Buf, b->Size);
size = Endian32(b->Size);
// Write the size
if (FileWrite(o, &size, sizeof(size)) == false)
{
return false;
}
// Write a hash
if (FileWrite(o, hash, sizeof(hash)) == false)
{
return false;
}
// Write the data
if (FileWrite(o, b->Buf, b->Size) == false)
{
return false;
}
return true;
}
// Create a buffer from memory
BUF *NewBufFromMemory(void *buf, UINT size)
{
BUF *b;
// Validate arguments
if (buf == NULL && size != 0)
{
return NULL;
}
b = NewBuf();
WriteBuf(b, buf, size);
SeekBufToBegin(b);
return b;
}
// Creating a buffer
BUF *NewBuf()
{
BUF *b;
// Memory allocation
b = Malloc(sizeof(BUF));
b->Buf = Malloc(INIT_BUF_SIZE);
b->Size = 0;
b->Current = 0;
b->SizeReserved = INIT_BUF_SIZE;
// KS
KS_INC(KS_NEWBUF_COUNT);
KS_INC(KS_CURRENT_BUF_COUNT);
return b;
}
// Clearing the buffer
void ClearBuf(BUF *b)
{
// Validate arguments
if (b == NULL)
{
return;
}
b->Size = 0;
b->Current = 0;
}
// Write to the buffer
void WriteBuf(BUF *b, void *buf, UINT size)
{
UINT new_size;
// Validate arguments
if (b == NULL || buf == NULL || size == 0)
{
return;
}
new_size = b->Current + size;
if (new_size > b->Size)
{
// Adjust the size
AdjustBufSize(b, new_size);
}
if (b->Buf != NULL)
{
Copy((UCHAR *)b->Buf + b->Current, buf, size);
}
b->Current += size;
b->Size = new_size;
// KS
KS_INC(KS_WRITE_BUF_COUNT);
}
// Append a string to the buffer
void AddBufStr(BUF *b, char *str)
{
// Validate arguments
if (b == NULL || str == NULL)
{
return;
}
WriteBuf(b, str, StrLen(str));
}
// Write a line to the buffer
void WriteBufLine(BUF *b, char *str)
{
char *crlf = "\r\n";
// Validate arguments
if (b == NULL || str == NULL)
{
return;
}
WriteBuf(b, str, StrLen(str));
WriteBuf(b, crlf, StrLen(crlf));
}
// Write a string to a buffer
bool WriteBufStr(BUF *b, char *str)
{
UINT len;
// Validate arguments
if (b == NULL || str == NULL)
{
return false;
}
// String length
len = StrLen(str);
if (WriteBufInt(b, len + 1) == false)
{
return false;
}
// String body
WriteBuf(b, str, len);
return true;
}
// Read a string from the buffer
bool ReadBufStr(BUF *b, char *str, UINT size)
{
UINT len;
UINT read_size;
// Validate arguments
if (b == NULL || str == NULL || size == 0)
{
return false;
}
// Read the length of the string
len = ReadBufInt(b);
if (len == 0)
{
return false;
}
len--;
if (len <= (size - 1))
{
size = len + 1;
}
read_size = MIN(len, (size - 1));
// Read the string body
if (ReadBuf(b, str, read_size) != read_size)
{
return false;
}
if (read_size < len)
{
ReadBuf(b, NULL, len - read_size);
}
str[read_size] = 0;
return true;
}
// Write a 64 bit integer to the buffer
bool WriteBufInt64(BUF *b, UINT64 value)
{
// Validate arguments
if (b == NULL)
{
return false;
}
value = Endian64(value);
WriteBuf(b, &value, sizeof(UINT64));
return true;
}
// Write an integer in the the buffer
bool WriteBufInt(BUF *b, UINT value)
{
// Validate arguments
if (b == NULL)
{
return false;
}
value = Endian32(value);
WriteBuf(b, &value, sizeof(UINT));
return true;
}
// Write a short integer in the the buffer
bool WriteBufShort(BUF *b, USHORT value)
{
// Validate arguments
if (b == NULL)
{
return false;
}
value = Endian16(value);
WriteBuf(b, &value, sizeof(USHORT));
return true;
}
// Write a UCHAR to the buffer
bool WriteBufChar(BUF *b, UCHAR uc)
{
// Validate arguments
if (b == NULL)
{
return false;
}
WriteBuf(b, &uc, 1);
return true;
}
// Read a UCHAR from the buffer
UCHAR ReadBufChar(BUF *b)
{
UCHAR uc;
// Validate arguments
if (b == NULL)
{
return 0;
}
if (ReadBuf(b, &uc, 1) != 1)
{
return 0;
}
return uc;
}
// Read a 64bit integer from the buffer
UINT64 ReadBufInt64(BUF *b)
{
UINT64 value;
// Validate arguments
if (b == NULL)
{
return 0;
}
if (ReadBuf(b, &value, sizeof(UINT64)) != sizeof(UINT64))
{
return 0;
}
return Endian64(value);
}
// Read an integer from the buffer
UINT ReadBufInt(BUF *b)
{
UINT value;
// Validate arguments
if (b == NULL)
{
return 0;
}
if (ReadBuf(b, &value, sizeof(UINT)) != sizeof(UINT))
{
return 0;
}
return Endian32(value);
}
// Read a short integer from the buffer
USHORT ReadBufShort(BUF *b)
{
USHORT value;
// Validate arguments
if (b == NULL)
{
return 0;
}
if (ReadBuf(b, &value, sizeof(USHORT)) != sizeof(USHORT))
{
return 0;
}
return Endian16(value);
}
// Write the buffer to a buffer
void WriteBufBuf(BUF *b, BUF *bb)
{
// Validate arguments
if (b == NULL || bb == NULL)
{
return;
}
WriteBuf(b, bb->Buf, bb->Size);
}
// Write the buffer (from the offset) to a buffer
void WriteBufBufWithOffset(BUF *b, BUF *bb)
{
// Validate arguments
if (b == NULL || bb == NULL)
{
return;
}
WriteBuf(b, ((UCHAR *)bb->Buf) + bb->Current, bb->Size - bb->Current);
}
// Skip UTF-8 BOM
bool BufSkipUtf8Bom(BUF *b)
{
if (b == NULL)
{
return false;
}
SeekBufToBegin(b);
if (b->Size >= 3)
{
UCHAR *data = b->Buf;
if (data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF)
{
SeekBuf(b, 3, 1);
return true;
}
}
return false;
}
// Read into a buffer from the buffer
BUF *ReadBufFromBuf(BUF *b, UINT size)
{
BUF *ret;
UCHAR *data;
// Validate arguments
if (b == NULL)
{
return NULL;
}
data = Malloc(size);
if (ReadBuf(b, data, size) != size)
{
Free(data);
return NULL;
}
ret = NewBuf();
WriteBuf(ret, data, size);
SeekBuf(ret, 0, 0);
Free(data);
return ret;
}
// Read from the buffer
UINT ReadBuf(BUF *b, void *buf, UINT size)
{
UINT size_read;
// Validate arguments
if (b == NULL || size == 0)
{
return 0;
}
if (b->Buf == NULL)
{
Zero(buf, size);
return 0;
}
size_read = size;
if ((b->Current + size) >= b->Size)
{
size_read = b->Size - b->Current;
if (buf != NULL)
{
Zero((UCHAR *)buf + size_read, size - size_read);
}
}
if (buf != NULL)
{
Copy(buf, (UCHAR *)b->Buf + b->Current, size_read);
}
b->Current += size_read;
// KS
KS_INC(KS_READ_BUF_COUNT);
return size_read;
}
// Adjusting the buffer size
void AdjustBufSize(BUF *b, UINT new_size)
{
// Validate arguments
if (b == NULL)
{
return;
}
if (b->SizeReserved >= new_size)
{
return;
}
while (b->SizeReserved < new_size)
{
if (b->SizeReserved > 0x7FFFFFFF)
{
AbortExitEx("AdjustBufSize(): too large buffer size");
}
b->SizeReserved = b->SizeReserved * 2;
}
b->Buf = ReAlloc(b->Buf, b->SizeReserved);
// KS
KS_INC(KS_ADJUST_BUFSIZE_COUNT);
}
// Seek to the beginning of the buffer
void SeekBufToBegin(BUF *b)
{
// Validate arguments
if (b == NULL)
{
return;
}
SeekBuf(b, 0, 0);
}
// Seek to end of the buffer
void SeekBufToEnd(BUF *b)
{
// Validate arguments
if (b == NULL)
{
return;
}
SeekBuf(b, b->Size, 0);
}
// Seek of the buffer
void SeekBuf(BUF *b, UINT offset, int mode)
{
UINT new_pos;
// Validate arguments
if (b == NULL)
{
return;
}
if (mode == 0)
{
// Absolute position
new_pos = offset;
}
else
{
if (mode > 0)
{
// Move Right
new_pos = b->Current + offset;
}
else
{
// Move Left
if (b->Current >= offset)
{
new_pos = b->Current - offset;
}
else
{
new_pos = 0;
}
}
}
b->Current = MAKESURE(new_pos, 0, b->Size);
KS_INC(KS_SEEK_BUF_COUNT);
}
// Free the buffer
void FreeBuf(BUF *b)
{
// Validate arguments
if (b == NULL)
{
return;
}
// Memory release
Free(b->Buf);
Free(b);
// KS
KS_INC(KS_FREEBUF_COUNT);
KS_DEC(KS_CURRENT_BUF_COUNT);
}
// Compare BUFs whether two are identical
bool CompareBuf(BUF *b1, BUF *b2)
{
// Validate arguments
if (b1 == NULL && b2 == NULL)
{
return true;
}
if (b1 == NULL || b2 == NULL)
{
return false;
}
if (b1->Size != b2->Size)
{
return false;
}
if (Cmp(b1->Buf, b2->Buf, b1->Size) != 0)
{
return false;
}
return true;
}
// Create a buffer from the memory area
BUF *MemToBuf(void *data, UINT size)
{
BUF *b;
// Validate arguments
if (data == NULL && size != 0)
{
return NULL;
}
b = NewBuf();
WriteBuf(b, data, size);
SeekBuf(b, 0, 0);
return b;
}
// Creating a random number buffer
BUF *RandBuf(UINT size)
{
void *data = Malloc(size);
BUF *ret;
Rand(data, size);
ret = MemToBuf(data, size);
Free(data);
return ret;
}
// Read the rest part of the buffer
BUF *ReadRemainBuf(BUF *b)
{
UINT size;
// Validate arguments
if (b == NULL)
{
return NULL;
}
if (b->Size < b->Current)
{
return NULL;
}
size = b->Size - b->Current;
return ReadBufFromBuf(b, size);
}
// Get the length of the rest
UINT ReadBufRemainSize(BUF *b)
{
// Validate arguments
if (b == NULL)
{
return 0;
}
if (b->Size < b->Current)
{
return 0;
}
return b->Size - b->Current;
}
// Clone the buffer
BUF *CloneBuf(BUF *b)
{
BUF *bb;
// Validate arguments
if (b == NULL)
{
return NULL;
}
bb = MemToBuf(b->Buf, b->Size);
return bb;
}
// Endian conversion of Unicode string
void EndianUnicode(wchar_t *str)
{
UINT i, len;
// Validate arguments
if (str == NULL)
{
return;
}
len = UniStrLen(str);
for (i = 0;i < len;i++)
{
str[i] = Endian16(str[i]);
}
}
// Endian conversion 16bit
USHORT Endian16(USHORT src)
{
int x = 1;
if (*((char *)&x))
{
return Swap16(src);
}
else
{
return src;
}
}
// Endian conversion 32bit
UINT Endian32(UINT src)
{
int x = 1;
if (*((char *)&x))
{
return Swap32(src);
}
else
{
return src;
}
}
// Endian conversion 64bit
UINT64 Endian64(UINT64 src)
{
int x = 1;
if (*((char *)&x))
{
return Swap64(src);
}
else
{
return src;
}
}
// Endian conversion 16bit
USHORT LittleEndian16(USHORT src)
{
int x = 0x01000000;
if (*((char *)&x))
{
return Swap16(src);
}
else
{
return src;
}
}
// Endian conversion 32bit
UINT LittleEndian32(UINT src)
{
int x = 0x01000000;
if (*((char *)&x))
{
return Swap32(src);
}
else
{
return src;
}
}
// Endian conversion 64bit
UINT64 LittleEndian64(UINT64 src)
{
int x = 0x01000000;
if (*((char *)&x))
{
return Swap64(src);
}
else
{
return src;
}
}
// 16bit swap
USHORT Swap16(USHORT value)
{
USHORT r;
((BYTE *)&r)[0] = ((BYTE *)&value)[1];
((BYTE *)&r)[1] = ((BYTE *)&value)[0];
return r;
}
// 32bit swap
UINT Swap32(UINT value)
{
UINT r;
((BYTE *)&r)[0] = ((BYTE *)&value)[3];
((BYTE *)&r)[1] = ((BYTE *)&value)[2];
((BYTE *)&r)[2] = ((BYTE *)&value)[1];
((BYTE *)&r)[3] = ((BYTE *)&value)[0];
return r;
}
// 64-bit swap
UINT64 Swap64(UINT64 value)
{
UINT64 r;
((BYTE *)&r)[0] = ((BYTE *)&value)[7];
((BYTE *)&r)[1] = ((BYTE *)&value)[6];
((BYTE *)&r)[2] = ((BYTE *)&value)[5];
((BYTE *)&r)[3] = ((BYTE *)&value)[4];
((BYTE *)&r)[4] = ((BYTE *)&value)[3];
((BYTE *)&r)[5] = ((BYTE *)&value)[2];
((BYTE *)&r)[6] = ((BYTE *)&value)[1];
((BYTE *)&r)[7] = ((BYTE *)&value)[0];
return r;
}
void *Base64ToBin(UINT *out_size, const void *src, const UINT size)
{
if (src == NULL || size == 0)
{
return NULL;
}
UINT bin_size = Base64Decode(NULL, src, size);
if (bin_size == 0)
{
return NULL;
}
void *bin = ZeroMalloc(bin_size + 1);
bin_size = Base64Decode(bin, src, size);
if (bin_size == 0)
{
Free(bin);
return NULL;
}
if (out_size != NULL)
{
*out_size = bin_size;
}
return bin;
}
void *Base64FromBin(UINT *out_size, const void *src, const UINT size)
{
if (src == NULL || size == 0)
{
return NULL;
}
UINT base64_size = Base64Encode(NULL, src, size);
if (base64_size == 0)
{
return NULL;
}
void *base64 = Malloc(base64_size);
base64_size = Base64Encode(base64, src, size);
if (base64_size == 0)
{
Free(base64);
return NULL;
}
if (out_size != NULL)
{
*out_size = base64_size;
}
return base64;
}
// Malloc
void *Malloc(UINT size)
{
return MallocEx(size, false);
}
void *MallocEx(UINT size, bool zero_clear_when_free)
{
MEMTAG1 *tag1;
MEMTAG2 *tag2;
UINT real_size;
if (canary_inited == false)
{
InitCanaryRand();
}
if (size > MAX_MALLOC_MEM_SIZE)
{
AbortExitEx("MallocEx() error: too large size");
}
real_size = CALC_MALLOCSIZE(size);
tag1 = InternalMalloc(real_size);
tag1->Magic = canary_memtag_magic1 ^ ((UINT64)tag1 * GOLDEN_RATION_PRIME_U64);
tag1->Size = size;
tag1->ZeroFree = zero_clear_when_free;
tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2));
tag2->Magic = canary_memtag_magic2 ^ ((UINT64)tag2 * GOLDEN_RATION_PRIME_U64);
return MEMTAG1_TO_POINTER(tag1);
}
// Get memory size
UINT GetMemSize(void *addr)
{
MEMTAG1 *tag;
if (canary_inited == false)
{
InitCanaryRand();
}
// Validate arguments
if (IS_NULL_POINTER(addr))
{
return 0;
}
tag = POINTER_TO_MEMTAG1(addr);
CheckMemTag1(tag);
return tag->Size;
}
// ReAlloc
void *ReAlloc(void *addr, UINT size)
{
MEMTAG1 *tag1;
MEMTAG2 *tag2;
bool zerofree;
if (canary_inited == false)
{
InitCanaryRand();
}
if (size > MAX_MALLOC_MEM_SIZE)
{
AbortExitEx("ReAlloc() error: too large size");
}
// Validate arguments
if (IS_NULL_POINTER(addr))
{
return NULL;
}
tag1 = POINTER_TO_MEMTAG1(addr);
CheckMemTag1(tag1);
tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2));
CheckMemTag2(tag2);
zerofree = tag1->ZeroFree;
if (tag1->Size == size)
{
// No size change
return addr;
}
else
{
if (zerofree)
{
// Size changed (zero clearing required)
void *new_p = MallocEx(size, true);
if (tag1->Size <= size)
{
// Size expansion
Copy(new_p, addr, tag1->Size);
}
else
{
// Size reduction
Copy(new_p, addr, size);
}
// Release the old block
Free(addr);
return new_p;
}
else
{
// Size changed
MEMTAG1 *tag1_new;
MEMTAG2 *tag2_new;
tag1->Magic = 0;
tag2->Magic = 0;
tag1_new = InternalReAlloc(tag1, CALC_MALLOCSIZE(size));
tag1_new->Magic = canary_memtag_magic1 ^ ((UINT64)tag1_new * GOLDEN_RATION_PRIME_U64);
tag1_new->Size = size;
tag1_new->ZeroFree = 0;
tag2_new = (MEMTAG2 *)(((UCHAR *)tag1_new) + CALC_MALLOCSIZE(size) - sizeof(MEMTAG2));
tag2_new->Magic = canary_memtag_magic2 ^ ((UINT64)tag2_new * GOLDEN_RATION_PRIME_U64);
return MEMTAG1_TO_POINTER(tag1_new);
}
}
}
// Free
void Free(void *addr)
{
MEMTAG1 *tag1;
MEMTAG2 *tag2;
// Validate arguments
if (IS_NULL_POINTER(addr))
{
return;
}
if (canary_inited == false)
{
InitCanaryRand();
}
tag1 = POINTER_TO_MEMTAG1(addr);
CheckMemTag1(tag1);
tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2));
CheckMemTag2(tag2);
if (tag1->ZeroFree)
{
// Zero clear
Zero(addr, tag1->Size);
}
// Memory release
tag1->Magic = 0;
tag2->Magic = 0;
InternalFree(tag1);
}
// Free and set pointer's value to NULL
void FreeSafe(void **addr)
{
Free(*addr);
*addr = NULL;
}
// Check the memtag1
void CheckMemTag1(MEMTAG1 *tag)
{
// Validate arguments
if (tag == NULL)
{
AbortExitEx("CheckMemTag1: tag1 == NULL");
return;
}
if (tag->Magic != (canary_memtag_magic1 ^ ((UINT64)tag * GOLDEN_RATION_PRIME_U64)))
{
AbortExitEx("CheckMemTag1: tag1->Magic != canary_memtag_magic1");
return;
}
}
// Check the memtag2
void CheckMemTag2(MEMTAG2 *tag)
{
// Validate arguments
if (tag == NULL)
{
AbortExitEx("CheckMemTag2: tag2 == NULL");
return;
}
if (tag->Magic != (canary_memtag_magic2 ^ ((UINT64)tag * GOLDEN_RATION_PRIME_U64)))
{
AbortExitEx("CheckMemTag2: tag2->Magic != canary_memtag_magic2");
return;
}
}
// ZeroMalloc
void *ZeroMalloc(UINT size)
{
return ZeroMallocEx(size, false);
}
void *ZeroMallocEx(UINT size, bool zero_clear_when_free)
{
void *p = MallocEx(size, zero_clear_when_free);
Zero(p, size);
return p;
}
// Memory allocation
void *InternalMalloc(UINT size)
{
void *addr;
UINT retry = 0;
size = MORE(size, 1);
// KS
KS_INC(KS_MALLOC_COUNT);
KS_INC(KS_TOTAL_MEM_COUNT);
KS_ADD(KS_TOTAL_MEM_SIZE, size);
KS_INC(KS_CURRENT_MEM_COUNT);
// Attempt to allocate memory until success
while (true)
{
if ((retry++) > MEMORY_MAX_RETRY)
{
AbortExitEx("InternalMalloc: error: malloc() failed.\n\n");
}
addr = OSMemoryAlloc(size);
if (addr != NULL)
{
break;
}
OSSleep(MEMORY_SLEEP_TIME);
}
TrackNewObj(POINTER_TO_UINT64(addr), "MEM", size);
return addr;
}
// Memory release
void InternalFree(void *addr)
{
// Validate arguments
if (addr == NULL)
{
return;
}
// KS
KS_DEC(KS_CURRENT_MEM_COUNT);
KS_INC(KS_FREE_COUNT);
TrackDeleteObj(POINTER_TO_UINT64(addr));
// Memory release
OSMemoryFree(addr);
}
// Memory reallocation
void *InternalReAlloc(void *addr, UINT size)
{
void *new_addr;
UINT retry = 0;
size = MORE(size, 1);
// KS
KS_INC(KS_REALLOC_COUNT);
KS_ADD(KS_TOTAL_MEM_SIZE, size);
// Attempt to allocate memory until success
while (true)
{
if ((retry++) > MEMORY_MAX_RETRY)
{
AbortExitEx("InternalReAlloc: error: realloc() failed.\n\n");
}
new_addr = OSMemoryReAlloc(addr, size);
if (new_addr != NULL)
{
break;
}
OSSleep(MEMORY_SLEEP_TIME);
}
TrackChangeObjSize(POINTER_TO_UINT64(addr), size, POINTER_TO_UINT64(new_addr));
return new_addr;
}
// Add the heading space to the memory area
void *AddHead(void *src, UINT src_size, void *head, UINT head_size)
{
void *ret;
UINT ret_size;
// Validate arguments
if ((src == NULL && src_size != 0) || (head == NULL && head_size != 0))
{
return NULL;
}
ret_size = src_size + head_size;
ret = Malloc(ret_size);
Copy(ret, head, head_size);
Copy(((UCHAR *)ret) + head_size, src, src_size);
return ret;
}
// Clone the memory area
void *Clone(void *addr, UINT size)
{
void *ret;
// Validate arguments
if (addr == NULL)
{
return NULL;
}
ret = Malloc(size);
Copy(ret, addr, size);
return ret;
}
// Memory copy
void Copy(void *dst, void *src, UINT size)
{
// Validate arguments
if (dst == NULL || src == NULL || size == 0 || dst == src)
{
return;
}
// KS
KS_INC(KS_COPY_COUNT);
memcpy(dst, src, size);
}
// Memory move
void Move(void *dst, void *src, UINT size)
{
// Validate arguments
if (dst == NULL || src == NULL || size == 0 || dst == src)
{
return;
}
// KS
KS_INC(KS_COPY_COUNT);
memmove(dst, src, size);
}
// Memory comparison
int Cmp(void *p1, void *p2, UINT size)
{
// Validate arguments
if (p1 == NULL || p2 == NULL || size == 0)
{
return 0;
}
return memcmp(p1, p2, (size_t)size);
}
// Memory comparison (case-insensitive)
int CmpCaseIgnore(void *p1, void *p2, UINT size)
{
UINT i;
// Validate arguments
if (p1 == NULL || p2 == NULL || size == 0)
{
return 0;
}
for (i = 0;i < size;i++)
{
char c1 = (char)(*(((UCHAR *)p1) + i));
char c2 = (char)(*(((UCHAR *)p2) + i));
c1 = ToUpper(c1);
c2 = ToUpper(c2);
if (c1 != c2)
{
return COMPARE_RET(c1, c2);
}
}
return 0;
}
// Zero-clear of memory
void Zero(void *addr, UINT size)
{
// Validate arguments
if (addr == NULL || size == 0)
{
return;
}
// KS
KS_INC(KS_ZERO_COUNT);
memset(addr, 0, size);
}
// Compare the string map entries
int StrMapCmp(void *p1, void *p2)
{
STRMAP_ENTRY *s1, *s2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
s1 = *(STRMAP_ENTRY **)p1;
s2 = *(STRMAP_ENTRY **)p2;
if (s1 == NULL || s2 == NULL)
{
return 0;
}
return StrCmpi(s1->Name, s2->Name);
}
// Create a string map (the data that can be searched by the string)
LIST *NewStrMap()
{
return NewList(StrMapCmp);
}
// Search in string map
void *StrMapSearch(LIST *map, char *key)
{
STRMAP_ENTRY tmp, *result;
tmp.Name = key;
result = (STRMAP_ENTRY*)Search(map, &tmp);
if(result != NULL)
{
return result->Value;
}
return NULL;
}
// XOR the data
void XorData(void *dst, void *src1, void *src2, UINT size)
{
UINT i;
UCHAR *d, *c1, *c2;
// Validate arguments
if (dst == NULL || src1 == NULL || src2 == NULL || size == 0)
{
return;
}
d = (UCHAR *)dst;
c1 = (UCHAR *)src1;
c2 = (UCHAR *)src2;
for (i = 0;i < size;i++)
{
*d = (*c1) ^ (*c2);
d++;
c1++;
c2++;
}
}