/*	Renegade Scripts.dll
	Engine classes and calls for the Shader Database editor
	Copyright 2007 Jonathan Wilson

	This file is part of the Renegade scripts.dll
	The Renegade scripts.dll is free software; you can redistribute it and/or modify it under
	the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2, or (at your option) any later
	version. See the file COPYING for more details.
	In addition, an exemption is given to allow Run Time Dynamic Linking of this code with any closed source module that does not contain code covered by this licence.
	Only the source code to the module(s) containing the licenced code has to be released.
*/
#include "scripts.h"
#include "shadereng.h"

char n = 0;
char *StringClass::m_NullChar = &n;
char **StringClass::m_EmptyString = &StringClass::m_NullChar;
bool *HasSSE;

#undef malloc
#undef free
void* AllocMemory(size_t reportedSize)
{
	return malloc(reportedSize);
}
void DeallocMemory(void *reportedAddress)
{
	free(reportedAddress);
}

class RawFileClass : public FileClass {
private:
	int Rights;
	int BiasStart;
	int BiasLength;
	void* Handle;
	char* Filename;
	unsigned short Date;
	unsigned short Time;
	bool allocated;
public:
	RawFileClass()
	{
		BiasLength = -1;
		Handle = (HANDLE)-1;
		Rights = 0;
		BiasStart = 0;
		Date = 0;
		Time = 0;
		allocated = false;
		Filename = 0;
	}
	RawFileClass(char *filename)
	{
		BiasLength = -1;
		Handle = (HANDLE)-1;
		Rights = 0;
		BiasStart = 0;
		Date = 0;
		Time = 0;
		allocated = true;
		Filename = newstr(filename);
	}
	int Transfer_Block_Size()
	{
		return -11;
	}
	void Reset()
	{
		Close();
		if ((allocated) && (Filename))
		{
			delete[] Filename;
		}
		allocated = false;
		Filename = 0;
	}
	~RawFileClass()
	{
		Reset();
	}
	char *File_Name()
	{
		return Filename;
	}
	char *Set_Name(const char* name)
	{
		Reset();
		if (name)
		{
			Bias(0,-1);
			char *c = newstr(name);
			if (!c)
			{
				Error(0x0C,(int)c,(char *)name);
			}
			Filename = c;
			allocated = true;
		}
		return 0;
	}
	bool Create()
	{
		Close();
		if (!Open(2))
		{
			return false;
		}
		if (BiasLength != -1)
		{
			Seek(0,0);
		}
		Close();
		return true;
	}
	bool Delete()
	{
		Close();
		if (!Filename)
		{
			Error(2,0,0);
		}
		if (!Is_Available(0))
		{
			return false;
		}
		if (!DeleteFile(Filename))
		{
			Error(GetLastError(),0,Filename);
			return false;
		}
		return true;
	}
	bool Is_Available(int handle)
	{
		if (!Filename)
		{
			return false;
		}
		if (!Is_Open())
		{
			if (Handle)
			{
				Open(1);
				Close();
			}
			Handle = CreateFile(Filename,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
			if (!Handle)
			{
				return false;
			}
			if (!CloseHandle(Handle))
			{
				Error(GetLastError(),0,Filename);
			}
			Handle = (HANDLE)-1;
		}
		return true;
	}
	bool Is_Open()
	{
		if (Handle != (HANDLE)-1)
		{
			return true;
		}
		return false;
	}
	int Open(const char* name, int mode)
	{
		Set_Name(name);
		return Open(mode);
	}
	int Open(int mode)
	{
		Close();
		if (!Filename)
		{
			Error(2,0,0);
		}
		Rights = mode;
		switch (Rights)
		{
		case 2:
			Handle = CreateFile(Filename,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
			break;
		case 1:
			Handle = CreateFile(Filename,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
			break;
		case 0:
			Handle = CreateFile(Filename,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
			break;
		default:
			errno = EINVAL;
		}
		if ((BiasStart) && (BiasLength != -1))
		{
			Seek(0,0);
		}
		if (Handle != (HANDLE)-1)
		{
			return true;
		}
		return false;
	}
	int Read(void* buffer, int size)
	{
		bool opened = false;
		long bytesread = 0;
		long bytesread2 = 0;
		if (!Is_Open())
		{
			if (!Open(2))
			{
				return 0;
			}
			opened = true;
		}
		if (BiasLength != -1)
		{
			int x = Seek(0,1) + BiasLength;
			if (size >= x)
			{
				size = x;
			}
		}
		while (size > 0)
		{
			if (!ReadFile(Handle,buffer,size,(LPDWORD)&bytesread,0))
			{
				Error(GetLastError(),1,Filename);
				bytesread2 += bytesread;
			}
			else
			{
				bytesread2 += bytesread;
				if (!bytesread)
				{
					break;
				}
			}
			size -= bytesread;
		}
		if (opened)
		{
			Close();
		}
		return bytesread;
	}
	int Seek(int pos, int dir)
	{
		if (BiasLength != -1)
		{
			switch (dir)
			{
			case 0:
				if (pos > BiasLength)
				{
					pos = BiasLength;
				}
				pos += BiasStart;
				break;
			case 2:
				pos += (BiasStart + BiasLength);
				dir = 0;
				break;
			}
			int seek = Raw_Seek(pos,dir) - BiasStart;
			if (seek < 0)
			{
				seek = Raw_Seek(BiasStart,0) - BiasStart;
			}
			if (seek > BiasLength)
			{
				seek = Raw_Seek(BiasStart + BiasLength,0) - BiasStart;
			}
			return seek;
		}
		else
		{
			return Raw_Seek(pos,dir);
		}
	}
	int Raw_Seek(int pos, int dir)
	{
		if (!Is_Open())
		{
			Error(9,0,Filename);
		}
		int seek = SetFilePointer(Handle,pos,0,dir);
		if (seek == -1)
		{
			Error(GetLastError(),0,Filename);
		}
		return seek;
	}
	int Size()
	{
		int size = 0;
		if (BiasLength == -1)
		{
			if (Is_Open())
			{
				size = GetFileSize(Handle,0);
				if (size == -1)
				{
					Error(GetLastError(),0,Filename);
				}
			}
			else
			{
				if (Open(1))
				{
					size = Size();
					Close();
				}
			}
			BiasLength = size - BiasStart;
			return BiasLength;
		}
		else
		{
			return BiasLength;
		}
	}
	int Write(void* buffer, int size)
	{
		bool opened = false;
		long byteswritten = 0;
		if (!Is_Open())
		{
			if (!Open(2))
			{
				return 0;
			}
			opened = true;
		}
		if (!WriteFile(Handle,buffer,size,(LPDWORD)&byteswritten,0))
		{
			Error(GetLastError(),0,Filename);
		}
		if (BiasLength != -1)
		{
			if (Raw_Seek(0,1) > BiasStart + BiasLength)
			{
				BiasLength = Raw_Seek(0,1) - BiasStart;
			}
		}
		if (opened)
		{
			Close();
		}
		return byteswritten;
	}
	void Close()
	{
		if (Is_Open())
		{
			if (!CloseHandle(Handle))
			{
				Error(GetLastError(),0,Filename);
			}
			Handle = (HANDLE)-1;
		}
	}
	unsigned long Get_Date_Time()
	{
		BY_HANDLE_FILE_INFORMATION info;
		unsigned short dostime;
		unsigned short dosdate;
		if (GetFileInformationByHandle(Handle,&info))
		{
			FileTimeToDosDateTime(&info.ftLastWriteTime,&dosdate,&dostime);
			return dosdate << 0x10 | dostime;
		}
		return 0;
	}
	bool Set_Date_Time(unsigned long datetime)
	{
		BY_HANDLE_FILE_INFORMATION info;
		FILETIME filetime;
		if (Is_Open())
		{
			if (GetFileInformationByHandle(Handle,&info))
			{
				if (DosDateTimeToFileTime((WORD)datetime,(WORD)(datetime >> 0x10),&filetime))
				{
					if (SetFileTime(Handle,&info.ftCreationTime,&filetime,&filetime))
					{
						return true;
					}
				}
			}
		}
		return false;
	}
	void Error(int a, int b, char *c)
	{
	}
	HANDLE Get_File_Handle()
	{
		return Handle;
	}
	void Bias(int start, int length)
	{
		if (!start)
		{
			BiasStart = 0;
			BiasLength = -1;
		}
		else
		{
			BiasLength = Size();
			BiasStart += start;
			if (length != -1)
			{
				if (BiasLength > length)
				{
					BiasLength = length;
				}
				int b = (BiasLength <= 0 ? 1 : 0);
				b--;
				BiasLength &= b;
			}
		}
	}
	void Attach(HANDLE handle,int rights)
	{
		Reset();
		Handle = handle;
		Rights = rights;
		BiasStart = 0;
		BiasLength = -1;
		Date = 0;
		Time = 0;
		allocated = false;
	}
	void Detach()
	{
		Rights = 0;
		Handle = (HANDLE)-1;
		BiasStart = 0;
		BiasLength = -1;
		Date = 0;
		Time = 0;
		allocated = false;
	}
};

FileClass *Get_Data_File(char *file)
{
	return new RawFileClass(file);
}

void Close_Data_File(FileClass *file)
{
	file->Close();
	delete file; //I hope you aren't using it anymore
}

ChunkLoadClass::ChunkLoadClass(FileClass *file)
{
	File = file;
	StackIndex = 0;
	memset(HeaderStack,0,sizeof(HeaderStack));
	memset(PositionStack,0,sizeof(PositionStack));
	InMicroChunk = false;
	MicroChunkPosition = 0;
	MCHeader.ChunkType = 0;
}

bool ChunkLoadClass::Open_Chunk()
{
	if ((StackIndex <= 0) || (PositionStack[StackIndex-1] != (HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF)))
	{
		if (File->Read(&HeaderStack[StackIndex],8) == 8)
		{
			PositionStack[StackIndex] = 0;
			StackIndex++;
			return true;
		}
	}
	return false;
}

bool ChunkLoadClass::Peek_Next_Chunk(unsigned int *id, unsigned int *length)
{
	ChunkHeader h;
	if ((StackIndex <= 0) || (PositionStack[StackIndex-1] != (HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF)))
	{
		if (File->Read(&h,8) == 8)
		{
			File->Seek(-8,1);
			if (length)
			{
				*length = h.ChunkSize;
			}
			if (id)
			{
				*id = h.ChunkType & 0x7FFFFFFF;
			}
			return true;
		}
	}
	return false;
}

bool ChunkLoadClass::Close_Chunk()
{
	unsigned int x = HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF;
	if (PositionStack[StackIndex-1] < (x))
	{
		File->Seek((x) - PositionStack[StackIndex-1],1);
	}
	StackIndex--;
	if (StackIndex > 0)
	{
		PositionStack[StackIndex-1] += (x);
		PositionStack[StackIndex-1] += 8;
	}
	return true;
}

unsigned long ChunkLoadClass::Cur_Chunk_ID()
{
	return HeaderStack[StackIndex-1].ChunkType;
}

unsigned long ChunkLoadClass::Cur_Chunk_Length()
{
	return HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF;
}

int ChunkLoadClass::Cur_Chunk_Depth()
{
	return StackIndex;
}

int ChunkLoadClass::Contains_Chunks()
{
	return HeaderStack[StackIndex-1].ChunkSize & 0x80000000;
}

bool ChunkLoadClass::Open_Micro_Chunk()
{
	int bytesread = Read(&MCHeader,2);
	if (bytesread == 2)
	{
		MicroChunkPosition = 0;
		InMicroChunk = true;
		return true;
	}
	return false;
}

bool ChunkLoadClass::Close_Micro_Chunk()
{
	InMicroChunk = false;
	if (MicroChunkPosition < 0)
	{
		File->Seek(MCHeader.ChunkSize - MicroChunkPosition,1);
		if (StackIndex > 0)
		{
			PositionStack[StackIndex-1] += MCHeader.ChunkSize - MicroChunkPosition;
		}
	}
	return true;
}

unsigned long ChunkLoadClass::Cur_Micro_Chunk_ID()
{
	return MCHeader.ChunkType;
}

unsigned long ChunkLoadClass::Cur_Micro_Chunk_Length()
{
	return MCHeader.ChunkSize;
}

long ChunkLoadClass::Seek(unsigned long nbytes)
{
	if ((PositionStack[StackIndex-1] + nbytes) <= (HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF))
	{
		if ((!InMicroChunk) || ((MicroChunkPosition + nbytes) <= MCHeader.ChunkSize))
		{
			int pos = File->Tell();
			int seek = File->Seek(nbytes,1);
			if ((seek - pos) == (int)nbytes)
			{
				PositionStack[StackIndex-1] += nbytes;
				if (InMicroChunk)
				{
					MicroChunkPosition += nbytes;
				}
				return nbytes;
			}
		}
	}
	return 0;
}

long ChunkLoadClass::Read(void *buf, unsigned long nbytes)
{
	if ((PositionStack[StackIndex-1] + nbytes) <= (HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF))
	{
		if ((!InMicroChunk) || ((MicroChunkPosition + nbytes) <= MCHeader.ChunkSize))
		{
			int read = File->Read(buf,nbytes);
			if (read == (int)nbytes)
			{
				PositionStack[StackIndex-1] += nbytes;
				if (InMicroChunk)
				{
					MicroChunkPosition += nbytes;
				}
				return nbytes;
			}
		}
	}
	return 0;
}

long ChunkLoadClass::Read(IOVector2Struct *v)
{
	return Read(v,4);
}

long ChunkLoadClass::Read(IOVector3Struct *v)
{
	return Read(v,4);
}

long ChunkLoadClass::Read(IOVector4Struct *v)
{
	return Read(v,4);
}

long ChunkLoadClass::Read(IOQuaternionStruct *q)
{
	return Read(q,4);
}

ChunkSaveClass::ChunkSaveClass(FileClass *file)
{
	File = file;
	StackIndex = 0;
	memset(HeaderStack,0,sizeof(HeaderStack));
	memset(PositionStack,0,sizeof(PositionStack));
	InMicroChunk = false;
	MicroChunkPosition = 0;
	MCHeader.ChunkType = 0;
}

bool ChunkSaveClass::Begin_Chunk(unsigned long id)
{
	ChunkHeader chunkh;
	chunkh.ChunkSize = 0;
	chunkh.ChunkType = 0;
	if (StackIndex > 0)
	{
		HeaderStack[StackIndex-1].ChunkSize |= 0x80000000;
	}
	chunkh.ChunkType = id;
	chunkh.ChunkSize &= 0x80000000;
	PositionStack[StackIndex] = File->Seek(0,1);
	HeaderStack[StackIndex].ChunkType = chunkh.ChunkType;
	HeaderStack[StackIndex].ChunkSize = chunkh.ChunkSize;
	StackIndex++;
	if (File->Write(&chunkh,8) == 8)
	{
		return true;
	}
	return false;
}

bool ChunkSaveClass::End_Chunk()
{
	ChunkHeader chunkh;
	int temp = File->Seek(0,1);
	StackIndex--;
	chunkh.ChunkType = HeaderStack[StackIndex].ChunkType;
	chunkh.ChunkSize = HeaderStack[StackIndex].ChunkSize;
	File->Seek(PositionStack[StackIndex],0);
	if (File->Write(&chunkh,8) == 8)
	{
		if (StackIndex && (StackIndex < 256))
		{
			int temp2 = (HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF) + (chunkh.ChunkSize & 0x7FFFFFFF) + 8;
			if (HeaderStack[StackIndex-1].ChunkSize & 0x80000000)
			{
				temp2 |= 0x80000000;
			}
			HeaderStack[StackIndex-1].ChunkSize = temp2;
		}
		File->Seek(temp,0);
		return true;
	}
	return false;
}

int ChunkSaveClass::Cur_Chunk_Depth()
{
	return StackIndex;
}

bool ChunkSaveClass::Begin_Micro_Chunk(unsigned long id)
{
	MCHeader.ChunkType = (unsigned char)id;
	MicroChunkPosition = File->Seek(0,1);
	MCHeader.ChunkSize = 0;
	if (Write(&MCHeader,2) == 2)
	{
		InMicroChunk = true;
		return true;
	}
	return false;
}

bool ChunkSaveClass::End_Micro_Chunk()
{
	int temp = File->Seek(0,1);
	File->Seek(MicroChunkPosition,0);
	if (File->Write(&MCHeader,2) == 2)
	{
		File->Seek(temp,0);
		InMicroChunk = false;
		return true;
	}
	return false;
}

unsigned long ChunkSaveClass::Write(void* buf,unsigned long nbytes)
{
	if (File->Write(buf,nbytes) == (int)nbytes)
	{
		int temp = (HeaderStack[StackIndex-1].ChunkSize & 0x7FFFFFFF) + nbytes;
		if (HeaderStack[StackIndex-1].ChunkSize & 0x80000000)
		{
			temp |= 0x80000000;
		}
		HeaderStack[StackIndex-1].ChunkSize = temp;
		if (InMicroChunk)
		{
			MCHeader.ChunkSize = MCHeader.ChunkSize + (unsigned char)nbytes;
		}
		return nbytes;
	}
	return 0;
}

unsigned long ChunkSaveClass::Write(IOVector2Struct& v)
{
	return Write(&v,4);
}

unsigned long ChunkSaveClass::Write(IOVector3Struct& v)
{
	return Write(&v,4);
}

unsigned long ChunkSaveClass::Write(IOVector4Struct& v)
{
	return Write(&v,4);
}

unsigned long ChunkSaveClass::Write(IOQuaternionStruct& q)
{
	return Write(&q,4);
}

StringClass::StringClass(StringClass& string,bool hint_temporary)
{
	m_Buffer = *m_EmptyString;
	if (hint_temporary || string.Get_Length())
	{
		Get_String(string.Get_Length()+1,hint_temporary);
	}
	*this = string;
}

StringClass::StringClass(int initial_len,bool hint_temporary)
{
	m_Buffer = *m_EmptyString;
	Get_String(initial_len,hint_temporary);
	m_Buffer[0] = *m_NullChar;
}

StringClass::~StringClass()
{
	Free_String();
}

StringClass& StringClass::operator=(const char* string)
{
	if (string)
	{
		int x = strlen(string);
		Uninitialised_Grow(x+1);
		Store_Length(x);
		memcpy(m_Buffer,string,x+1);
	}
	return *this;
}

StringClass& StringClass::operator=(StringClass& string)
{
	int x = string.Get_Length();
	Uninitialised_Grow(x+1);
	Store_Length(x);
	memcpy(m_Buffer,string.m_Buffer,x+1);
	return *this;
}

StringClass& StringClass::operator+=(const char* string)
{
	int len = Get_Length();
	int len2 = strlen(string);
	Resize(len+len2+1);
	Store_Length(len+len2);
	memcpy(Get_Buffer(len),string,len2);
	return *this;
}

StringClass& StringClass::operator+=(StringClass& string)
{
	int len = string.Get_Length();
	if (len)
	{
		int len2 = Get_Length();
		Resize(len+len2+1);
		Store_Length(len+len2);
		memcpy(Get_Buffer(len2),string,len+1);
	}
	return *this;
}

int StringClass::Get_Length()
{
	if (!Is_Empty())
	{
		if (!Get_Header()->length)
		{
			Get_Header()->length = strlen(m_Buffer);
		}
		return Get_Header()->length;
	}
	return 0;
}

int cdeclx StringClass::Format(char* format,...)
{
	va_list arg_list;
	va_start(arg_list,format);
	return Format_Args(format,arg_list);
}

#ifndef WIN32
#define _vsnprintf vsnprintf
#endif

int cdeclx StringClass::Format_Args(char* format,va_list& arg_list)
{
	char temp_buffer[512];
	int x = _vsnprintf(temp_buffer,512,format,arg_list);
	*this = (const char *)temp_buffer;
	return x;
}

void StringClass::Get_String(int length,bool is_temp)
{
	if (!is_temp && !length)
	{
		m_Buffer = *m_EmptyString;
		return;
	}
	if (is_temp)
	{
		return;
	}
	if (length > 0)
	{
		char *x = Allocate_Buffer(length);
		Free_String();
		Set_Buffer_And_Allocated_Length(x,length);
	}
	else
	{
		Free_String();
	}
}

void StringClass::Resize(int new_len)
{
	if (new_len > Get_Allocated_Length())
	{
		char *x = Allocate_Buffer(new_len);
		strcpy(x,m_Buffer);
		Free_String();
		Set_Buffer_And_Allocated_Length(x,new_len);
	}
}

void StringClass::Uninitialised_Grow(int new_len)
{
	if (new_len > Get_Allocated_Length())
	{
		char *x = Allocate_Buffer(new_len);
		Free_String();
		Set_Buffer_And_Allocated_Length(x,new_len);
	}
}

void StringClass::Free_String()
{
	if (!Is_Empty())
	{
		delete[] Get_Header();
		m_Buffer = *m_EmptyString;
	}
}

void StringClass::Store_Length(int length)
{
	if (!Is_Empty())
	{
		Get_Header()->length = length;
	}
}

void StringClass::Release_Resources()
{
	Free_String();
}

bool StringClass::Copy_Wide(const wchar_t *str)
{
	if (!str)
	{
		return false;
	}
	mbstate_t ps;
	memset(&ps,0,sizeof(ps));
	int len = wcsrtombs(0,&str,0,&ps);
	if (len > 0)
	{
		Uninitialised_Grow(len+1);
		wcsrtombs(m_Buffer,&str,len,&ps);
		m_Buffer[len] = 0;
	}
	return false;
}

unsigned long crc_table[256] = {
	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 
	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 
	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 
	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 
	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 
	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 
	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 
	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 
	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 
	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 
	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 
	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 
	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 
	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 
	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 
	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 
	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 
	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 
	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 
	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 
	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 
	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 
	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 
	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 
	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 
	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 
	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 
	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 
	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 
	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 
	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 
	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};

unsigned long CRC_Memory(const unsigned char *data,unsigned long length,unsigned long crc)
{
	if (!length)
	{
		return 0;
	}
	crc = 0xFFFFFFFF;
	do
	{
		crc = (crc >> 8) ^ crc_table[(crc & 0xff) ^ *data];
		data++;
		length--;
	} while (length);
	crc ^= ~0;
	return crc;
}

char *cpystr(const char* src,char* dst)
{
	memcpy(dst,src,strlen(src)+1);
	return dst;
};

#ifndef DEBUG
char *newstr(const char *str)
{
	unsigned long len = strlen(str)+1;
	char *s = new char[len];
	memcpy(s,str,len);
	return s;	
};
#endif
