code:
#ifndef SCRIPTDICTIONARY_H
#define SCRIPTDICTIONARY_H

// The dictionary class relies on the script string object, thus the script
// string type must be registered with the engine before registering the
// dictionary type

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

// By default the CScriptDictionary use the std::string for the keys.
// If the application uses a custom string type, then this typedef
// can be changed accordingly.
#include <string>
typedef std::string dictKey_t;

// Forward declare CScriptDictValue so we can typedef the internal map type
BEGIN_AS_NAMESPACE
class CScriptDictValue;
END_AS_NAMESPACE

// C++11 introduced the std::unordered_map which is a hash map which is
// is generally more performatic for lookups than the std::map which is a
// binary tree.
// TODO: memory: The map allocator should use the asAllocMem and asFreeMem
#if AS_CAN_USE_CPP11
#include <unordered_map>
typedef std::unordered_map<dictKey_t, AS_NAMESPACE_QUALIFIER CScriptDictValue> dictMap_t;
#else
#include <map>
typedef std::map<dictKey_t, AS_NAMESPACE_QUALIFIER CScriptDictValue> dictMap_t;
#endif

#ifdef _MSC_VER
// Turn off annoying warnings about truncated symbol names
#pragma warning (disable:4786)
#endif

// Sometimes it may be desired to use the same method names as used by C++ STL.
// This may for example reduce time when converting code from script to C++ or
// back.
//
//  0 = off
//  1 = on

#ifndef AS_USE_STLNAMES
#define AS_USE_STLNAMES 0
#endif

BEGIN_AS_NAMESPACE

class CScriptArray;
class CScriptDictionary;

class CScriptDictValue
{
public:
	// This class must not be declared as local variable in C++, because it needs
	// to receive the script engine pointer in all operations. The engine pointer
	// is not kept as member in order to keep the size down
	CScriptDictValue();
	CScriptDictValue(asIScriptEngine *engine, void *value, int typeId);

	// Destructor must not be called without first calling FreeValue, otherwise a memory leak will occur
	~CScriptDictValue();

	// Replace the stored value
	void Set(asIScriptEngine *engine, void *value, int typeId);
	void Set(asIScriptEngine *engine, const asINT64 &value);
	void Set(asIScriptEngine *engine, const double &value);
	void Set(asIScriptEngine *engine, CScriptDictValue &value);

	// Gets the stored value. Returns false if the value isn't compatible with the informed typeId
	bool Get(asIScriptEngine *engine, void *value, int typeId) const;
	bool Get(asIScriptEngine *engine, asINT64 &value) const;
	bool Get(asIScriptEngine *engine, double &value) const;

	// Returns the address of the stored value for inspection
	const void *GetAddressOfValue() const;

	// Returns the type id of the stored value
	int  GetTypeId() const;

	// Free the stored value
	void FreeValue(asIScriptEngine *engine);

	// GC callback
	void EnumReferences(asIScriptEngine *engine);

protected:
	friend class CScriptDictionary;

	union
	{
		asINT64 m_valueInt;
		double  m_valueFlt;
		void   *m_valueObj;
	};
	int m_typeId;
};

class CScriptDictionary
{
public:
	// Factory functions
	static CScriptDictionary *Create(asIScriptEngine *engine);

	// Called from the script to instantiate a dictionary from an initialization list
	static CScriptDictionary *Create(asBYTE *buffer);

	// Reference counting
	void AddRef() const;
	void Release() const;

	// Reassign the dictionary
	CScriptDictionary &operator =(const CScriptDictionary &other);

	// Sets a key/value pair
	void Set(const dictKey_t &key, void *value, int typeId);
	void Set(const dictKey_t &key, const asINT64 &value);
	void Set(const dictKey_t &key, const double &value);

	// Gets the stored value. Returns false if the value isn't compatible with the informed typeId
	bool Get(const dictKey_t &key, void *value, int typeId) const;
	bool Get(const dictKey_t &key, asINT64 &value) const;
	bool Get(const dictKey_t &key, double &value) const;

	// Index accessors. If the dictionary is not const it inserts the value if it doesn't already exist
	// If the dictionary is const then a script exception is set if it doesn't exist and a null pointer is returned
	CScriptDictValue *operator[](const dictKey_t &key);
	const CScriptDictValue *operator[](const dictKey_t &key) const;

	// Returns the type id of the stored value, or negative if it doesn't exist
	int GetTypeId(const dictKey_t &key) const;

	// Returns true if the key is set
	bool Exists(const dictKey_t &key) const;

	// Returns true if there are no key/value pairs in the dictionary
	bool IsEmpty() const;

	// Returns the number of key/value pairs in the dictionary
	asUINT GetSize() const;

	// Deletes the key
	bool Delete(const dictKey_t &key);

	// Deletes all keys
	void DeleteAll();

	// Get an array of all keys
	CScriptArray *GetKeys() const;

	// STL style iterator
	class CIterator
	{
	public:
		void operator++();    // Pre-increment
		void operator++(int); // Post-increment

		// This is needed to support C++11 range-for
		CIterator &operator*();

		bool operator==(const CIterator &other) const;
		bool operator!=(const CIterator &other) const;

		// Accessors
		const dictKey_t &GetKey() const;
		int              GetTypeId() const;
		bool             GetValue(asINT64 &value) const;
		bool             GetValue(double &value) const;
		bool             GetValue(void *value, int typeId) const;
		const void *     GetAddressOfValue() const;

	protected:
		friend class CScriptDictionary;

		CIterator();
		CIterator(const CScriptDictionary &dict,
		          dictMap_t::const_iterator it);

		CIterator &operator=(const CIterator &) {return *this;} // Not used

		dictMap_t::const_iterator m_it;
		const CScriptDictionary &m_dict;
	};

	CIterator begin() const;
	CIterator end() const;
	CIterator find(const dictKey_t &key) const;

	// Iterator to support foreach in script
	class CScriptDictIter
	{
	public:
		// Reference counting
		void AddRef() const;
		void Release() const;

	protected:
		friend class CScriptDictionary;

		CIterator iter;
		mutable int refCount;
		asUINT iterGuard;

		CScriptDictIter(const CScriptDictionary* dict);
		~CScriptDictIter();
	};

	CScriptDictIter* opForBegin() const;
	bool opForEnd(const CScriptDictIter &iter) const;
	CScriptDictIter* opForNext(CScriptDictIter& iter) const;
	const CScriptDictValue& opForValue0(const CScriptDictIter& iter) const;
	const std::string& opForValue1(const CScriptDictIter& iter) const;

	// Garbage collections behaviours
	int GetRefCount();
	void SetGCFlag();
	bool GetGCFlag();
	void EnumReferences(asIScriptEngine *engine);
	void ReleaseAllReferences(asIScriptEngine *engine);

protected:
	// Since the dictionary uses the asAllocMem and asFreeMem functions to allocate memory
	// the constructors are made protected so that the application cannot allocate it
	// manually in a different way
	CScriptDictionary(asIScriptEngine *engine);
	CScriptDictionary(asBYTE *buffer);

	// We don't want anyone to call the destructor directly, it should be called through the Release method
	virtual ~CScriptDictionary();

	// Cache the object types needed
	void Init(asIScriptEngine *engine);

	// Our properties
	asIScriptEngine *engine;
	mutable int      refCount;
	mutable bool     gcFlag;
	dictMap_t        dict;
	asUINT           iterGuard;
};

// This function will determine the configuration of the engine
// and use one of the two functions below to register the dictionary object
void RegisterScriptDictionary(asIScriptEngine *engine);

// Call this function to register the math functions
// using native calling conventions
void RegisterScriptDictionary_Native(asIScriptEngine *engine);

// Use this one instead if native calling conventions
// are not supported on the target platform
void RegisterScriptDictionary_Generic(asIScriptEngine *engine);

END_AS_NAMESPACE

#endif


code:
#include "scriptfile.h"
#include <new>
#include <assert.h>
#include <string>
#include <string.h>
#include <stdio.h>

#ifdef _WIN32_WCE
#include <windows.h> // For GetModuleFileName
#ifdef GetObject
#undef GetObject
#endif
#endif

using namespace std;

BEGIN_AS_NAMESPACE

CScriptFile *ScriptFile_Factory()
{
	return new CScriptFile();
}

void ScriptFile_Factory_Generic(asIScriptGeneric *gen)
{
	*(CScriptFile**)gen->GetAddressOfReturnLocation()	= ScriptFile_Factory();
}

void ScriptFile_AddRef_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	file->AddRef();
}

void ScriptFile_Release_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	file->Release();
}

void ScriptFile_Open_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	std::string *f = (std::string*)gen->GetArgAddress(0);
	std::string *m = (std::string*)gen->GetArgAddress(1);
	int r = file->Open(*f, *m);
	gen->SetReturnDWord(r);
}

void ScriptFile_Close_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	int r = file->Close();
	gen->SetReturnDWord(r);
}

void ScriptFile_GetSize_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	int r = file->GetSize();
	gen->SetReturnDWord(r);
}

void ScriptFile_ReadString_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	int len = gen->GetArgDWord(0);
	string str = file->ReadString(len);
	gen->SetReturnObject(&str);
}

void ScriptFile_ReadLine_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	std::string str = file->ReadLine();
	gen->SetReturnObject(&str);
}

void ScriptFile_ReadInt_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	asUINT bytes = *(asUINT*)gen->GetAddressOfArg(0);
	*(asINT64*)gen->GetAddressOfReturnLocation() = file->ReadInt(bytes);
}

void ScriptFile_ReadUInt_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	asUINT bytes = *(asUINT*)gen->GetAddressOfArg(0);
	*(asQWORD*)gen->GetAddressOfReturnLocation() = file->ReadUInt(bytes);
}

void ScriptFile_ReadFloat_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	*(float*)gen->GetAddressOfReturnLocation() = file->ReadFloat();
}

void ScriptFile_ReadDouble_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	*(double*)gen->GetAddressOfReturnLocation() = file->ReadDouble();
}

void ScriptFile_WriteString_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	std::string *str = (std::string*)gen->GetArgAddress(0);
	gen->SetReturnDWord(file->WriteString(*str));
}

void ScriptFile_WriteInt_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	asINT64 val = *(asINT64*)gen->GetAddressOfArg(0);
	asUINT bytes = *(asUINT*)gen->GetAddressOfArg(1);
	*(int*)gen->GetAddressOfReturnLocation() = file->WriteInt(val, bytes);
}

void ScriptFile_WriteUInt_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	asQWORD val = *(asQWORD*)gen->GetAddressOfArg(0);
	asUINT bytes = *(asUINT*)gen->GetAddressOfArg(1);
	*(int*)gen->GetAddressOfReturnLocation() = file->WriteUInt(val, bytes);
}

void ScriptFile_WriteFloat_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	float val = *(float*)gen->GetAddressOfArg(0);
	*(int*)gen->GetAddressOfReturnLocation() = file->WriteFloat(val);
}

void ScriptFile_WriteDouble_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	double val = *(double*)gen->GetAddressOfArg(0);
	*(int*)gen->GetAddressOfReturnLocation() = file->WriteDouble(val);
}

void ScriptFile_IsEOF_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	bool r = file->IsEOF();
	gen->SetReturnByte(r);
}

void ScriptFile_GetPos_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	gen->SetReturnDWord(file->GetPos());
}

void ScriptFile_SetPos_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	int pos = (int)gen->GetArgDWord(0);
	gen->SetReturnDWord(file->SetPos(pos));
}

void ScriptFile_MovePos_Generic(asIScriptGeneric *gen)
{
	CScriptFile *file = (CScriptFile*)gen->GetObject();
	int delta = (int)gen->GetArgDWord(0);
	gen->SetReturnDWord(file->MovePos(delta));
}

void RegisterScriptFile_Native(asIScriptEngine *engine)
{
    int r;

    r = engine->RegisterObjectType("file", 0, asOBJ_REF); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()", asFUNCTION(ScriptFile_Factory), asCALL_CDECL); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptFile,AddRef), asCALL_THISCALL); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptFile,Release), asCALL_THISCALL); assert( r >= 0 );

    r = engine->RegisterObjectMethod("file", "int open(const string &in, const string &in)", asMETHOD(CScriptFile,Open), asCALL_THISCALL); assert( r >= 0 );
    r = engine->RegisterObjectMethod("file", "int close()", asMETHOD(CScriptFile,Close), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int getSize() const", asMETHOD(CScriptFile,GetSize), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const", asMETHOD(CScriptFile,IsEOF), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "string readString(uint)", asMETHOD(CScriptFile,ReadString), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "string readLine()", asMETHOD(CScriptFile,ReadLine), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int64 readInt(uint)", asMETHOD(CScriptFile,ReadInt), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)", asMETHOD(CScriptFile,ReadUInt), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "float readFloat()", asMETHOD(CScriptFile,ReadFloat), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "double readDouble()", asMETHOD(CScriptFile,ReadDouble), asCALL_THISCALL); assert( r >= 0 );
#if AS_WRITE_OPS == 1
	r = engine->RegisterObjectMethod("file", "int writeString(const string &in)", asMETHOD(CScriptFile,WriteString), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeInt(int64, uint)", asMETHOD(CScriptFile,WriteInt), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeUInt(uint64, uint)", asMETHOD(CScriptFile,WriteUInt), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeFloat(float)", asMETHOD(CScriptFile,WriteFloat), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeDouble(double)", asMETHOD(CScriptFile,WriteDouble), asCALL_THISCALL); assert( r >= 0 );
#endif
	r = engine->RegisterObjectMethod("file", "int getPos() const", asMETHOD(CScriptFile,GetPos), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int setPos(int)", asMETHOD(CScriptFile,SetPos), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int movePos(int)", asMETHOD(CScriptFile,MovePos), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectProperty("file", "bool mostSignificantByteFirst", asOFFSET(CScriptFile, mostSignificantByteFirst)); assert( r >= 0 );
}

void RegisterScriptFile_Generic(asIScriptEngine *engine)
{
	int r;

	r = engine->RegisterObjectType("file", 0, asOBJ_REF); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()", asFUNCTION(ScriptFile_Factory_Generic), asCALL_GENERIC); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFile_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFile_Release_Generic), asCALL_GENERIC); assert( r >= 0 );

    r = engine->RegisterObjectMethod("file", "int open(const string &in, const string &in)", asFUNCTION(ScriptFile_Open_Generic), asCALL_GENERIC); assert( r >= 0 );
    r = engine->RegisterObjectMethod("file", "int close()", asFUNCTION(ScriptFile_Close_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int getSize() const", asFUNCTION(ScriptFile_GetSize_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const", asFUNCTION(ScriptFile_IsEOF_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "string readString(uint)", asFUNCTION(ScriptFile_ReadString_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "string readLine()", asFUNCTION(ScriptFile_ReadLine_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int64 readInt(uint)", asFUNCTION(ScriptFile_ReadInt_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)", asFUNCTION(ScriptFile_ReadUInt_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "float readFloat()", asFUNCTION(ScriptFile_ReadFloat_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "double readDouble()", asFUNCTION(ScriptFile_ReadDouble_Generic), asCALL_GENERIC); assert( r >= 0 );
#if AS_WRITE_OPS == 1
	r = engine->RegisterObjectMethod("file", "int writeString(const string &in)", asFUNCTION(ScriptFile_WriteString_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeInt(int64, uint)", asFUNCTION(ScriptFile_WriteInt_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeUInt(uint64, uint)", asFUNCTION(ScriptFile_WriteUInt_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeFloat(float)", asFUNCTION(ScriptFile_WriteFloat_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int writeDouble(double)", asFUNCTION(ScriptFile_WriteDouble_Generic), asCALL_GENERIC); assert( r >= 0 );
#endif
	r = engine->RegisterObjectMethod("file", "int getPos() const", asFUNCTION(ScriptFile_GetPos_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int setPos(int)", asFUNCTION(ScriptFile_SetPos_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("file", "int movePos(int)", asFUNCTION(ScriptFile_MovePos_Generic), asCALL_GENERIC); assert( r >= 0 );

	r = engine->RegisterObjectProperty("file", "bool mostSignificantByteFirst", asOFFSET(CScriptFile, mostSignificantByteFirst)); assert( r >= 0 );
}

void RegisterScriptFile(asIScriptEngine *engine)
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
		RegisterScriptFile_Generic(engine);
	else
		RegisterScriptFile_Native(engine);
}

CScriptFile::CScriptFile()
{
	refCount = 1;
	file = 0;
	mostSignificantByteFirst = false;
}

CScriptFile::~CScriptFile()
{
	Close();
}

void CScriptFile::AddRef() const
{
	asAtomicInc(refCount);
}

void CScriptFile::Release() const
{
	if( asAtomicDec(refCount) == 0 )
		delete this;
}

int CScriptFile::Open(const std::string &filename, const std::string &mode)
{
	// Close the previously opened file handle
	if( file )
		Close();

	std::string myFilename = filename;

	// Validate the mode
	string m;
#if AS_WRITE_OPS == 1
	if( mode != "r" && mode != "w" && mode != "a" )
#else
	if( mode != "r" )
#endif
		return -1;
	else
		m = mode;

#ifdef _WIN32_WCE
	// no relative pathing on CE
	char buf[MAX_PATH];
	static TCHAR apppath[MAX_PATH] = TEXT("");
	if (!apppath[0])
	{
		GetModuleFileName(NULL, apppath, MAX_PATH);

		int appLen = _tcslen(apppath);
		while (appLen > 1)
		{
			if (apppath[appLen-1] == TEXT('\\'))
				break;
			appLen--;
		}

		// Terminate the string after the trailing backslash
		apppath[appLen] = TEXT('\0');
	}
#ifdef _UNICODE
	wcstombs(buf, apppath, wcslen(apppath)+1);
#else
	memcpy(buf, apppath, strlen(apppath));
#endif
	myFilename = buf + myFilename;
#endif

	// By default windows translates "\r\n" to "\n", but we want to read the file as-is.
	m += "b";

	// Open the file
#if _MSC_VER >= 1400 && !defined(__S3E__)
	// MSVC 8.0 / 2005 introduced new functions
	// Marmalade doesn't use these, even though it uses the MSVC compiler
	fopen_s(&file, myFilename.c_str(), m.c_str());
#else
	file = fopen(myFilename.c_str(), m.c_str());
#endif
	if( file == 0 )
		return -1;

	return 0;
}

int CScriptFile::Close()
{
	if( file == 0 )
		return -1;

	fclose(file);
	file = 0;

	return 0;
}

int CScriptFile::GetSize() const
{
	if( file == 0 )
		return -1;

	int pos = ftell(file);
	fseek(file, 0, SEEK_END);
	int size = ftell(file);
	fseek(file, pos, SEEK_SET);

	return size;
}

int CScriptFile::GetPos() const
{
	if( file == 0 )
		return -1;

	return ftell(file);
}

int CScriptFile::SetPos(int pos)
{
	if( file == 0 )
		return -1;

	int r = fseek(file, pos, SEEK_SET);

	// Return -1 on error
	return r ? -1 : 0;
}

int CScriptFile::MovePos(int delta)
{
	if( file == 0 )
		return -1;

	int r = fseek(file, delta, SEEK_CUR);

	// Return -1 on error
	return r ? -1 : 0;
}

string CScriptFile::ReadString(unsigned int length)
{
	if( file == 0 )
		return "";

	// Read the string
	string str;
	str.resize(length);
	int size = (int)fread(&str[0], 1, length, file);
	str.resize(size);

	return str;
}

string CScriptFile::ReadLine()
{
	if( file == 0 )
		return "";

	// Read until the first new-line character
	string str;
	char buf[256];

	do
	{
		// Get the current position so we can determine how many characters were read
		int start = ftell(file);

		// Set the last byte to something different that 0, so that we can check if the buffer was filled up
		buf[255] = 1;

		// Read the line (or first 255 characters, which ever comes first)
		char *r = fgets(buf, 256, file);
		if( r == 0 ) break;

		// Get the position after the read
		int end = ftell(file);

		// Add the read characters to the output buffer
		str.append(buf, end-start);
	}
	while( !feof(file) && buf[255] == 0 && buf[254] != '\n' );

	return str;
}

asINT64 CScriptFile::ReadInt(asUINT bytes)
{
	if( file == 0 )
		return 0;

	if( bytes > 8 ) bytes = 8;
	if( bytes == 0 ) return 0;

	unsigned char buf[8];
	size_t r = fread(buf, bytes, 1, file);
	if( r == 0 ) return 0;

	asINT64 val = 0;
	if( mostSignificantByteFirst )
	{
		unsigned int n = 0;
		for( ; n < bytes; n++ )
			val |= asQWORD(buf[n]) << ((bytes-n-1)*8);

		// Check the most significant byte to determine if the rest
		// of the qword must be filled to give a negative value
		if( buf[0] & 0x80 )
			for( ; n < 8; n++ )
				val |= asQWORD(0xFF) << (n*8);
	}
	else
	{
		unsigned int n = 0;
		for( ; n < bytes; n++ )
			val |= asQWORD(buf[n]) << (n*8);

		// Check the most significant byte to determine if the rest
		// of the qword must be filled to give a negative value
		if( buf[bytes-1] & 0x80 )
			for( ; n < 8; n++ )
				val |= asQWORD(0xFF) << (n*8);
	}

	return val;
}

asQWORD CScriptFile::ReadUInt(asUINT bytes)
{
	if( file == 0 )
		return 0;

	if( bytes > 8 ) bytes = 8;
	if( bytes == 0 ) return 0;

	unsigned char buf[8];
	size_t r = fread(buf, bytes, 1, file);
	if( r == 0 ) return 0;

	asQWORD val = 0;
	if( mostSignificantByteFirst )
	{
		unsigned int n = 0;
		for( ; n < bytes; n++ )
			val |= asQWORD(buf[n]) << ((bytes-n-1)*8);
	}
	else
	{
		unsigned int n = 0;
		for( ; n < bytes; n++ )
			val |= asQWORD(buf[n]) << (n*8);
	}

	return val;
}

float CScriptFile::ReadFloat()
{
	if( file == 0 )
		return 0;

	unsigned char buf[4];
	size_t r = fread(buf, 4, 1, file);
	if( r == 0 ) return 0;

	union conv
	{
		asUINT val;
		float fp;
	} value = { 0 };
	if( mostSignificantByteFirst )
	{
		unsigned int n = 0;
		for( ; n < 4; n++ )
			value.val |= asUINT(buf[n]) << ((3-n)*8);
	}
	else
	{
		unsigned int n = 0;
		for( ; n < 4; n++ )
			value.val |= asUINT(buf[n]) << (n*8);
	}

	return value.fp;
}

double CScriptFile::ReadDouble()
{
	if( file == 0 )
		return 0;

	unsigned char buf[8];
	size_t r = fread(buf, 8, 1, file);
	if( r == 0 ) return 0;

	union conv
	{
		asQWORD val;
		double fp;
	} value = { 0 };
	if( mostSignificantByteFirst )
	{
		unsigned int n = 0;
		for( ; n < 8; n++ )
			value.val |= asQWORD(buf[n]) << ((7-n)*8);
	}
	else
	{
		unsigned int n = 0;
		for( ; n < 8; n++ )
			value.val |= asQWORD(buf[n]) << (n*8);
	}

	return value.fp;
}

bool CScriptFile::IsEOF() const
{
	if( file == 0 )
		return true;

	return feof(file) ? true : false;
}

#if AS_WRITE_OPS == 1
int CScriptFile::WriteString(const std::string &str)
{
	if( file == 0 )
		return -1;

	// Write the entire string
	size_t r = fwrite(&str[0], 1, str.length(), file);

	return int(r);
}

int CScriptFile::WriteInt(asINT64 val, asUINT bytes)
{
	if( file == 0 )
		return 0;

	unsigned char buf[8];
	if( mostSignificantByteFirst )
	{
		for( unsigned int n = 0; n < bytes; n++ )
			buf[n] = (val >> ((bytes-n-1)*8)) & 0xFF;
	}
	else
	{
		for( unsigned int n = 0; n < bytes; n++ )
			buf[n] = (val >> (n*8)) & 0xFF;
	}

	size_t r = fwrite(&buf, bytes, 1, file);
	return int(r);
}

int CScriptFile::WriteUInt(asQWORD val, asUINT bytes)
{
	if( file == 0 )
		return 0;

	unsigned char buf[8];
	if( mostSignificantByteFirst )
	{
		for( unsigned int n = 0; n < bytes; n++ )
			buf[n] = (val >> ((bytes-n-1)*8)) & 0xFF;
	}
	else
	{
		for( unsigned int n = 0; n < bytes; n++ )
			buf[n] = (val >> (n*8)) & 0xFF;
	}

	size_t r = fwrite(&buf, bytes, 1, file);
	return int(r);
}

int CScriptFile::WriteFloat(float f)
{
	if( file == 0 )
		return 0;

	unsigned char buf[4];
	union conv
	{
		asUINT val;
		float fp;
	} value;
	value.fp = f;
	if( mostSignificantByteFirst )
	{
		for( unsigned int n = 0; n < 4; n++ )
			buf[n] = (value.val >> ((3-n)*4)) & 0xFF;
	}
	else
	{
		for( unsigned int n = 0; n < 4; n++ )
			buf[n] = (value.val >> (n*8)) & 0xFF;
	}

	size_t r = fwrite(&buf, 4, 1, file);
	return int(r);
}

int CScriptFile::WriteDouble(double d)
{
	if( file == 0 )
		return 0;

	unsigned char buf[8];
	union conv
	{
		asQWORD val;
		double fp;
	} value;
	value.fp = d;
	if( mostSignificantByteFirst )
	{
		for( unsigned int n = 0; n < 8; n++ )
			buf[n] = (value.val >> ((7-n)*8)) & 0xFF;
	}
	else
	{
		for( unsigned int n = 0; n < 8; n++ )
			buf[n] = (value.val >> (n*8)) & 0xFF;
	}

	size_t r = fwrite(&buf, 8, 1, file);
	return int(r);
}
#endif

END_AS_NAMESPACE

repo_name: Antidote/openrpgeditor

license: mit


code:
//
// CScriptFile
//
// This class encapsulates a FILE pointer in a reference counted class for
// use within AngelScript.
//

#ifndef SCRIPTFILE_H
#define SCRIPTFILE_H

//---------------------------
// Compilation settings
//

// Set this flag to turn on/off write support
//  0 = off
//  1 = on

#ifndef AS_WRITE_OPS
#define AS_WRITE_OPS 1
#endif

//---------------------------
// Declaration
//

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

#include <string>
#include <stdio.h>

BEGIN_AS_NAMESPACE

class CScriptFile
{
public:
	CScriptFile();

	void AddRef() const;
	void Release() const;

	// TODO: Implement the "r+", "w+" and "a+" modes
	// mode = "r" -> open the file for reading
	//        "w" -> open the file for writing (overwrites existing file)
	//        "a" -> open the file for appending
	int  Open(const std::string &filename, const std::string &mode);
	int  Close();
	int  GetSize() const;
	bool IsEOF() const;

	// Reading
	std::string ReadString(unsigned int length);
	std::string ReadLine();
	asINT64     ReadInt(asUINT bytes);
	asQWORD     ReadUInt(asUINT bytes);
	float       ReadFloat();
	double      ReadDouble();

	// Writing
	int WriteString(const std::string &str);
	int WriteInt(asINT64 v, asUINT bytes);
	int WriteUInt(asQWORD v, asUINT bytes);
	int WriteFloat(float v);
	int WriteDouble(double v);

	// Cursor
	int GetPos() const;
	int SetPos(int pos);
	int MovePos(int delta);

	// Big-endian = most significant byte first
	bool mostSignificantByteFirst;

protected:
	~CScriptFile();

	mutable int refCount;
	FILE       *file;
};

// This function will determine the configuration of the engine
// and use one of the two functions below to register the file type
void RegisterScriptFile(asIScriptEngine *engine);

// Call this function to register the file type
// using native calling conventions
void RegisterScriptFile_Native(asIScriptEngine *engine);

// Use this one instead if native calling conventions
// are not supported on the target platform
void RegisterScriptFile_Generic(asIScriptEngine *engine);

END_AS_NAMESPACE

#endif


code:
#include "scriptfilesystem.h"
#include "../autowrapper/aswrappedcall.h"
#include <string.h> // strstr()

#if defined(_WIN32)
#include <direct.h> // _getcwd
#include <Windows.h> // FindFirstFile, GetFileAttributes

#undef DeleteFile
#undef CopyFile

#else
#include <unistd.h> // getcwd
#include <dirent.h> // opendir, readdir, closedir
#include <sys/stat.h> // stat
#endif
#include <assert.h> // assert

using namespace std;

BEGIN_AS_NAMESPACE

// TODO: The file system should have a way to allow the application to define in
//       which sub directories it is allowed to make changes and/or read

CScriptFileSystem *ScriptFileSystem_Factory()
{
	return new CScriptFileSystem();
}

void RegisterScriptFileSystem_Native(asIScriptEngine *engine)
{
	int r;

	assert( engine->GetTypeInfoByName("string") );
	assert( engine->GetTypeInfoByDecl("array<string>") );
	assert( engine->GetTypeInfoByName("datetime") );

	r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", asFUNCTION(ScriptFileSystem_Factory), asCALL_CDECL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptFileSystem,AddRef), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptFileSystem,Release), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", asMETHOD(CScriptFileSystem, ChangeCurrentPath), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", asMETHOD(CScriptFileSystem, GetCurrentPath), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "array<string> @getDirs() const", asMETHOD(CScriptFileSystem, GetDirs), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "array<string> @getFiles() const", asMETHOD(CScriptFileSystem, GetFiles), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", asMETHOD(CScriptFileSystem, IsDir), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", asMETHOD(CScriptFileSystem, IsLink), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", asMETHOD(CScriptFileSystem, GetSize), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", asMETHOD(CScriptFileSystem, MakeDir), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", asMETHOD(CScriptFileSystem, RemoveDir), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", asMETHOD(CScriptFileSystem, DeleteFile), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", asMETHOD(CScriptFileSystem, CopyFile), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", asMETHOD(CScriptFileSystem, Move), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetCreateDateTime), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetModifyDateTime), asCALL_THISCALL); assert(r >= 0);
}

void RegisterScriptFileSystem_Generic(asIScriptEngine *engine)
{
	int r;

	assert( engine->GetTypeInfoByName("string") );
	assert( engine->GetTypeInfoByDecl("array<string>") );
	assert( engine->GetTypeInfoByName("datetime") );

	r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", WRAP_FN(ScriptFileSystem_Factory), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", WRAP_MFN(CScriptFileSystem,AddRef), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", WRAP_MFN(CScriptFileSystem,Release), asCALL_GENERIC); assert( r >= 0 );

	r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", WRAP_MFN(CScriptFileSystem, ChangeCurrentPath), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", WRAP_MFN(CScriptFileSystem, GetCurrentPath), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "array<string> @getDirs() const", WRAP_MFN(CScriptFileSystem, GetDirs), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "array<string> @getFiles() const", WRAP_MFN(CScriptFileSystem, GetFiles), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", WRAP_MFN(CScriptFileSystem, IsDir), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", WRAP_MFN(CScriptFileSystem, IsLink), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", WRAP_MFN(CScriptFileSystem, GetSize), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", WRAP_MFN(CScriptFileSystem, MakeDir), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", WRAP_MFN(CScriptFileSystem, RemoveDir), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", WRAP_MFN(CScriptFileSystem, DeleteFile), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, CopyFile), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, Move), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetCreateDateTime), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetModifyDateTime), asCALL_GENERIC); assert(r >= 0);
}

void RegisterScriptFileSystem(asIScriptEngine *engine)
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
		RegisterScriptFileSystem_Generic(engine);
	else
		RegisterScriptFileSystem_Native(engine);
}

CScriptFileSystem::CScriptFileSystem()
{
	refCount = 1;

	// Gets the application's current working directory as the starting point
	char buffer[1000];
	char* ret = 0;
#if defined(_WIN32)
	ret = _getcwd(buffer, 1000);
#else
	ret = getcwd(buffer, 1000);
#endif
	// TODO: check errno for proper error handling when getcwd returns null
	currentPath = ret ? ret : "";

	// Replace \ with / for consistency
	for (unsigned int n = 0; n < currentPath.size(); n++)
		if (currentPath[n] == '\\')
			currentPath[n] = '/';
}

CScriptFileSystem::~CScriptFileSystem()
{
}

void CScriptFileSystem::AddRef() const
{
	asAtomicInc(refCount);
}

void CScriptFileSystem::Release() const
{
	if( asAtomicDec(refCount) == 0 )
		delete this;
}

CScriptArray *CScriptFileSystem::GetFiles() const
{
	// Obtain a pointer to the engine
	asIScriptContext *ctx = asGetActiveContext();
	asIScriptEngine *engine = ctx->GetEngine();

	// TODO: This should only be done once
	// TODO: This assumes that CScriptArray was already registered
	asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array<string>");

	// Create the array object
	CScriptArray *array = CScriptArray::Create(arrayType);

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	string searchPattern = currentPath + "/*";
	MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000);

	WIN32_FIND_DATAW ffd;
	HANDLE hFind = FindFirstFileW(bufUTF16, &ffd);
	if( INVALID_HANDLE_VALUE == hFind )
		return array;

	do
	{
		// Skip directories
		if( (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
			continue;

		// Convert the file name back to UTF8
		char bufUTF8[10000];
		WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0);

		// Add the file to the array
		array->Resize(array->GetSize()+1);
		((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8);
	}
	while( FindNextFileW(hFind, &ffd) != 0 );

	FindClose(hFind);
#else
	dirent *ent = 0;
	DIR *dir = opendir(currentPath.c_str());
	while( (ent = readdir(dir)) != NULL )
	{
		const string filename = ent->d_name;

		// Skip . and ..
		if( filename[0] == '.' )
			continue;

		// Skip sub directories
		const string fullname = currentPath + "/" + filename;
		struct stat st;
		if( stat(fullname.c_str(), &st) == -1 )
			continue;
		if( (st.st_mode & S_IFDIR) != 0 )
			continue;

		// Add the file to the array
		array->Resize(array->GetSize()+1);
		((string*)(array->At(array->GetSize()-1)))->assign(filename);
	}
	closedir(dir);
#endif

	return array;
}

CScriptArray *CScriptFileSystem::GetDirs() const
{
	// Obtain a pointer to the engine
	asIScriptContext *ctx = asGetActiveContext();
	asIScriptEngine *engine = ctx->GetEngine();

	// TODO: This should only be done once
	// TODO: This assumes that CScriptArray was already registered
	asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array<string>");

	// Create the array object
	CScriptArray *array = CScriptArray::Create(arrayType);

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	string searchPattern = currentPath + "/*";
	MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000);

	WIN32_FIND_DATAW ffd;
	HANDLE hFind = FindFirstFileW(bufUTF16, &ffd);
	if( INVALID_HANDLE_VALUE == hFind )
		return array;

	do
	{
		// Skip files
		if( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
			continue;

		// Convert the file name back to UTF8
		char bufUTF8[10000];
		WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0);

		if( strcmp(bufUTF8, ".") == 0 || strcmp(bufUTF8, "..") == 0 )
			continue;

		// Add the dir to the array
		array->Resize(array->GetSize()+1);
		((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8);
	}
	while( FindNextFileW(hFind, &ffd) != 0 );

	FindClose(hFind);
#else
	dirent *ent = 0;
	DIR *dir = opendir(currentPath.c_str());
	while( (ent = readdir(dir)) != NULL )
	{
		const string filename = ent->d_name;

		// Skip . and ..
		if( filename[0] == '.' )
			continue;

		// Skip files
		const string fullname = currentPath + "/" + filename;
		struct stat st;
		if( stat(fullname.c_str(), &st) == -1 )
			continue;
		if( (st.st_mode & S_IFDIR) == 0 )
			continue;

		// Add the dir to the array
		array->Resize(array->GetSize()+1);
		((string*)(array->At(array->GetSize()-1)))->assign(filename);
	}
	closedir(dir);
#endif

	return array;
}

// Doesn't change anything if the new path is not valid
bool CScriptFileSystem::ChangeCurrentPath(const string &path)
{
	string newPath;
	if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 )
		newPath = path;
	else
		newPath = currentPath + "/" + path;

	// TODO: Resolve internal /./ and /../

	// Remove trailing slashes from the path
	while(newPath.length() && (newPath[newPath.length()-1] == '/' || newPath[newPath.length()-1] == '\\') )
		newPath.resize(newPath.length()-1);

	// Replace \ with / for consistency
	for (unsigned int n = 0; n < newPath.size(); n++)
		if (newPath[n] == '\\')
			newPath[n] = '/';

	if (!IsDir(newPath))
		return false;

	currentPath = newPath;
	return true;
}

bool CScriptFileSystem::IsDir(const string &path) const
{
	string search;
	if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 )
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Check if the path exists and is a directory
	DWORD attrib = GetFileAttributesW(bufUTF16);
	if( attrib == INVALID_FILE_ATTRIBUTES ||
		!(attrib & FILE_ATTRIBUTE_DIRECTORY) )
		return false;
#else
	// Check if the path exists and is a directory
	struct stat st;
	if( stat(search.c_str(), &st) == -1 )
		return false;
	if( (st.st_mode & S_IFDIR) == 0 )
		return false;
#endif

	return true;
}

bool CScriptFileSystem::IsLink(const string &path) const
{
	string search;
	if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0)
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Check if the path exists and is a link
	DWORD attrib = GetFileAttributesW(bufUTF16);
	if (attrib == INVALID_FILE_ATTRIBUTES ||
		!(attrib & FILE_ATTRIBUTE_REPARSE_POINT))
		return false;
#else
	// Check if the path exists and is a link
	struct stat st;
	if (stat(search.c_str(), &st) == -1)
		return false;
	if ((st.st_mode & S_IFLNK) == 0)
		return false;
#endif

	return true;
}

asINT64 CScriptFileSystem::GetSize(const string &path) const
{
	string search;
	if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0)
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Get the size of the file
	LARGE_INTEGER largeInt;
	HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
	BOOL success = GetFileSizeEx(file, &largeInt);
	CloseHandle(file);
	if( !success )
		return -1;
	return asINT64(largeInt.QuadPart);
#else
	// Get the size of the file
	struct stat st;
	if (stat(search.c_str(), &st) == -1)
		return -1;
	return asINT64(st.st_size);
#endif
}

// TODO: Should be able to return different codes for
//       - directory exists
//       - path not found
//       - access denied
// TODO: Should be able to define the permissions for the directory
// TODO: Should support recursively creating directories
int CScriptFileSystem::MakeDir(const string &path)
{
	string search;
	if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0)
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Create the directory
	BOOL success = CreateDirectoryW(bufUTF16, 0);
	return success ? 0 : -1;
#else
	// Create the directory
	int failure = mkdir(search.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
	return !failure ? 0 : -1;
#endif
}

// TODO: Should be able to return different codes for
//       - directory doesn't exist
//       - directory is not empty
//       - access denied
// TODO: Should have an option to remove the directory and all content recursively
int CScriptFileSystem::RemoveDir(const string &path)
{
	string search;
	if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0)
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Remove the directory
	BOOL success = RemoveDirectoryW(bufUTF16);
	return success ? 0 : -1;
#else
	// Remove the directory
	int failure = rmdir(search.c_str());
	return !failure ? 0 : -1;
#endif
}

int CScriptFileSystem::DeleteFile(const string &path)
{
	string search;
	if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0)
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Remove the file
	BOOL success = DeleteFileW(bufUTF16);
	return success ? 0 : -1;
#else
	// Remove the file
	int failure = unlink(search.c_str());
	return !failure ? 0 : -1;
#endif
}

int CScriptFileSystem::CopyFile(const string &source, const string &target)
{
	string search1;
	if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0)
		search1 = source;
	else
		search1 = currentPath + "/" + source;

	string search2;
	if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0)
		search2 = target;
	else
		search2 = currentPath + "/" + target;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16_1[10000];
	MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000);

	wchar_t bufUTF16_2[10000];
	MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000);

	// Copy the file
	BOOL success = CopyFileW(bufUTF16_1, bufUTF16_2, TRUE);
	return success ? 0 : -1;
#else
	// Copy the file manually as there is no posix function for this
	bool failure = false;
	FILE *src = 0, *tgt = 0;
	src = fopen(search1.c_str(), "r");
	if (src == 0) failure = true;
	if( !failure ) tgt = fopen(search2.c_str(), "w");
	if (tgt == 0) failure = true;
	char buf[1024];
	size_t n;
	while (!failure && (n = fread(buf, sizeof(char), sizeof(buf), src)) > 0)
	{
		if (fwrite(buf, sizeof(char), n, tgt) != n)
			failure = true;
	}
	if (src) fclose(src);
	if (tgt) fclose(tgt);
	return !failure ? 0 : -1;
#endif
}

int CScriptFileSystem::Move(const string &source, const string &target)
{
	string search1;
	if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0)
		search1 = source;
	else
		search1 = currentPath + "/" + source;

	string search2;
	if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0)
		search2 = target;
	else
		search2 = currentPath + "/" + target;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16_1[10000];
	MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000);

	wchar_t bufUTF16_2[10000];
	MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000);

	// Move the file or directory
	BOOL success = MoveFileW(bufUTF16_1, bufUTF16_2);
	return success ? 0 : -1;
#else
	// Move the file or directory
	int failure = rename(search1.c_str(), search2.c_str());
	return !failure ? 0 : -1;
#endif
}

string CScriptFileSystem::GetCurrentPath() const
{
	return currentPath;
}

CDateTime CScriptFileSystem::GetCreateDateTime(const string &path) const
{
	string search;
	if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0)
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Get the create date/time of the file
	FILETIME createTm;
	HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
	BOOL success = GetFileTime(file, &createTm, 0, 0);
	CloseHandle(file);
	if( !success )
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Failed to get file creation date/time");
		return CDateTime();
	}
	SYSTEMTIME tm;
	FileTimeToSystemTime(&createTm, &tm);
	return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond);
#else
	// Get the create date/time of the file
	struct stat st;
	if (stat(search.c_str(), &st) == -1)
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Failed to get file creation date/time");
		return CDateTime();
	}
	tm *t = localtime(&st.st_ctime);
	return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
#endif
}

CDateTime CScriptFileSystem::GetModifyDateTime(const string &path) const
{
	string search;
	if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0)
		search = path;
	else
		search = currentPath + "/" + path;

#if defined(_WIN32)
	// Windows uses UTF16 so it is necessary to convert the string
	wchar_t bufUTF16[10000];
	MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000);

	// Get the last modify date/time of the file
	FILETIME modifyTm;
	HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
	BOOL success = GetFileTime(file, 0, 0, &modifyTm);
	CloseHandle(file);
	if( !success )
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Failed to get file modify date/time");
		return CDateTime();
	}
	SYSTEMTIME tm;
	FileTimeToSystemTime(&modifyTm, &tm);
	return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond);
#else
	// Get the last modify date/time of the file
	struct stat st;
	if (stat(search.c_str(), &st) == -1)
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Failed to get file modify date/time");
		return CDateTime();
	}
	tm *t = localtime(&st.st_mtime);
	return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
#endif
}

END_AS_NAMESPACE


code:
#ifndef AS_SCRIPTFILESYSTEM_H
#define AS_SCRIPTFILESYSTEM_H

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

#include <string>
#include <stdio.h>

#include "../scriptarray/scriptarray.h"
#include "../datetime/datetime.h"

BEGIN_AS_NAMESPACE

class CScriptFileSystem
{
public:
	CScriptFileSystem();

	void AddRef() const;
	void Release() const;

	// Sets the current path that should be used in other calls when using relative paths
	// It can use relative paths too, so moving up a directory is used by passing in ".."
	bool ChangeCurrentPath(const std::string &path);
	std::string GetCurrentPath() const;

	// Returns true if the path is a directory. Input can be either a full path or a relative path.
	// This method does not return the dirs '.' and '..'
	bool IsDir(const std::string &path) const;

	// Returns true if the path is a link. Input can be either a full path or a relative path
	bool IsLink(const std::string &path) const;

	// Returns the size of file. Input can be either a full path or a relative path
	asINT64 GetSize(const std::string &path) const;

	// Returns a list of the files in the current path
	CScriptArray *GetFiles() const;

	// Returns a list of the directories in the current path
	CScriptArray *GetDirs() const;

	// Creates a new directory. Returns 0 on success
	int MakeDir(const std::string &path);

	// Removes a directory. Will only remove the directory if it is empty. Returns 0 on success
	int RemoveDir(const std::string &path);

	// Deletes a file. Returns 0 on success
	int DeleteFile(const std::string &path);

	// Copies a file. Returns 0 on success
	int CopyFile(const std::string &source, const std::string &target);

	// Moves or renames a file or directory. Returns 0 on success
	int Move(const std::string &source, const std::string &target);

	// Gets the date and time of the file/dir creation
	CDateTime GetCreateDateTime(const std::string &path) const;

	// Gets the date and time of the file/dir modification
	CDateTime GetModifyDateTime(const std::string &path) const;

protected:
	~CScriptFileSystem();

	mutable int refCount;
	std::string currentPath;
};

void RegisterScriptFileSystem(asIScriptEngine *engine);

END_AS_NAMESPACE

#endif


code:
#include <new>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h> // sprintf

#include "scriptgrid.h"

using namespace std;

BEGIN_AS_NAMESPACE

// Set the default memory routines
// Use the angelscript engine's memory routines by default
static asALLOCFUNC_t userAlloc = asAllocMem;
static asFREEFUNC_t  userFree  = asFreeMem;

// Allows the application to set which memory routines should be used by the array object
void CScriptGrid::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc)
{
	userAlloc = allocFunc;
	userFree = freeFunc;
}

static void RegisterScriptGrid_Native(asIScriptEngine *engine);

struct SGridBuffer
{
	asDWORD width;
	asDWORD height;
	asBYTE  data[1];
};

CScriptGrid *CScriptGrid::Create(asITypeInfo *ti)
{
	return CScriptGrid::Create(ti, 0, 0);
}

CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h)
{
	// Allocate the memory
	void *mem = userAlloc(sizeof(CScriptGrid));
	if( mem == 0 )
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Out of memory");

		return 0;
	}

	// Initialize the object
	CScriptGrid *a = new(mem) CScriptGrid(w, h, ti);

	return a;
}

CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, void *initList)
{
	// Allocate the memory
	void *mem = userAlloc(sizeof(CScriptGrid));
	if( mem == 0 )
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Out of memory");

		return 0;
	}

	// Initialize the object
	CScriptGrid *a = new(mem) CScriptGrid(ti, initList);

	return a;
}

CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h, void *defVal)
{
	// Allocate the memory
	void *mem = userAlloc(sizeof(CScriptGrid));
	if( mem == 0 )
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Out of memory");

		return 0;
	}

	// Initialize the object
	CScriptGrid *a = new(mem) CScriptGrid(w, h, defVal, ti);

	return a;
}

// This optional callback is called when the template type is first used by the compiler.
// It allows the application to validate if the template can be instantiated for the requested
// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect
// allow the callback to tell the engine if the template instance type shouldn't be garbage collected,
// i.e. no asOBJ_GC flag.
static bool ScriptGridTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect)
{
	// Make sure the subtype can be instantiated with a default factory/constructor,
	// otherwise we won't be able to instantiate the elements.
	int typeId = ti->GetSubTypeId();
	if( typeId == asTYPEID_VOID )
		return false;
	if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) )
	{
		asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId);
		asQWORD flags = subtype->GetFlags();
		if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) )
		{
			// Verify that there is a default constructor
			bool found = false;
			for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ )
			{
				asEBehaviours beh;
				asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh);
				if( beh != asBEHAVE_CONSTRUCT ) continue;

				if( func->GetParamCount() == 0 )
				{
					// Found the default constructor
					found = true;
					break;
				}
			}

			if( !found )
			{
				// There is no default constructor
				ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor");
				return false;
			}
		}
		else if( (flags & asOBJ_REF) )
		{
			bool found = false;

			// If value assignment for ref type has been disabled then the array
			// can be created if the type has a default factory function
			if( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) )
			{
				// Verify that there is a default factory
				for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ )
				{
					asIScriptFunction *func = subtype->GetFactoryByIndex(n);
					if( func->GetParamCount() == 0 )
					{
						// Found the default factory
						found = true;
						break;
					}
				}
			}

			if( !found )
			{
				// No default factory
				ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory");
				return false;
			}
		}

		// If the object type is not garbage collected then the array also doesn't need to be
		if( !(flags & asOBJ_GC) )
			dontGarbageCollect = true;
	}
	else if( !(typeId & asTYPEID_OBJHANDLE) )
	{
		// Arrays with primitives cannot form circular references,
		// thus there is no need to garbage collect them
		dontGarbageCollect = true;
	}
	else
	{
		assert( typeId & asTYPEID_OBJHANDLE );

		// It is not necessary to set the array as garbage collected for all handle types.
		// If it is possible to determine that the handle cannot refer to an object type
		// that can potentially form a circular reference with the array then it is not
		// necessary to make the array garbage collected.
		asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId);
		asQWORD flags = subtype->GetFlags();
		if( !(flags & asOBJ_GC) )
		{
			if( (flags & asOBJ_SCRIPT_OBJECT) )
			{
				// Even if a script class is by itself not garbage collected, it is possible
				// that classes that derive from it may be, so it is not possible to know
				// that no circular reference can occur.
				if( (flags & asOBJ_NOINHERIT) )
				{
					// A script class declared as final cannot be inherited from, thus
					// we can be certain that the object cannot be garbage collected.
					dontGarbageCollect = true;
				}
			}
			else
			{
				// For application registered classes we assume the application knows
				// what it is doing and don't mark the array as garbage collected unless
				// the type is also garbage collected.
				dontGarbageCollect = true;
			}
		}
	}

	// The type is ok
	return true;
}

// Registers the template array type
void RegisterScriptGrid(asIScriptEngine *engine)
{
	// TODO: Implement the generic calling convention
	RegisterScriptGrid_Native(engine);
}

static void RegisterScriptGrid_Native(asIScriptEngine *engine)
{
	int r;

	// Register the grid type as a template
	r = engine->RegisterObjectType("grid<class T>", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 );

	// Register a callback for validating the subtype before it is used
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptGridTemplateCallback), asCALL_CDECL); assert( r >= 0 );

	// Templates receive the object type as the first parameter. To the script writer this is hidden
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_FACTORY, "grid<T>@ f(int&in)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_FACTORY, "grid<T>@ f(int&in, uint, uint)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, asUINT, asUINT), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_FACTORY, "grid<T>@ f(int&in, uint, uint, const T &in)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, asUINT, asUINT, void *), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );

	// Register the factory that will be used for initialization lists
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_LIST_FACTORY, "grid<T>@ f(int&in type, int&in list) {repeat {repeat_same T}}", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, void*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );

	// The memory management methods
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptGrid,AddRef), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptGrid,Release), asCALL_THISCALL); assert( r >= 0 );

	// The index operator returns the template subtype
	r = engine->RegisterObjectMethod("grid<T>", "T &opIndex(uint, uint)", asMETHODPR(CScriptGrid, At, (asUINT, asUINT), void*), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("grid<T>", "const T &opIndex(uint, uint) const", asMETHODPR(CScriptGrid, At, (asUINT, asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 );

	// Other methods
	r = engine->RegisterObjectMethod("grid<T>", "void resize(uint width, uint height)", asMETHODPR(CScriptGrid, Resize, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("grid<T>", "uint width() const", asMETHOD(CScriptGrid, GetWidth), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("grid<T>", "uint height() const", asMETHOD(CScriptGrid, GetHeight), asCALL_THISCALL); assert( r >= 0 );

	// Register GC behaviours in case the array needs to be garbage collected
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptGrid, GetRefCount), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptGrid, SetFlag), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptGrid, GetFlag), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptGrid, EnumReferences), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptGrid, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 );
}

CScriptGrid::CScriptGrid(asITypeInfo *ti, void *buf)
{
	refCount = 1;
	gcFlag = false;
	objType = ti;
	objType->AddRef();
	buffer = 0;
	subTypeId = objType->GetSubTypeId();

	asIScriptEngine *engine = ti->GetEngine();

	// Determine element size
	if( subTypeId & asTYPEID_MASK_OBJECT )
		elementSize = sizeof(asPWORD);
	else
		elementSize = engine->GetSizeOfPrimitiveType(subTypeId);

	// Determine the initial size from the buffer
	asUINT height = *(asUINT*)buf;
	asUINT width = height ? *(asUINT*)((char*)(buf)+4) : 0;

	// Make sure the grid size isn't too large for us to handle
	if( !CheckMaxSize(width, height) )
	{
		// Don't continue with the initialization
		return;
	}

	// Skip the height value at the start of the buffer
	buf = (asUINT*)(buf)+1;

	// Copy the values of the grid elements from the buffer
	if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 )
	{
		CreateBuffer(&buffer, width, height);

		// Copy the values of the primitive type into the internal buffer
		for( asUINT y = 0; y < height; y++ )
		{
			// Skip the length value at the start of each row
			buf = (asUINT*)(buf)+1;

			// Copy the line
			if( width > 0 )
				memcpy(At(0,y), buf, width*elementSize);

			// Move to next line
			buf = (char*)(buf) + width*elementSize;

			// Align to 4 byte boundary
			if( asPWORD(buf) & 0x3 )
				buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
		}
	}
	else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE )
	{
		CreateBuffer(&buffer, width, height);

		// Copy the handles into the internal buffer
		for( asUINT y = 0; y < height; y++ )
		{
			// Skip the length value at the start of each row
			buf = (asUINT*)(buf)+1;

			// Copy the line
			if( width > 0 )
				memcpy(At(0,y), buf, width*elementSize);

			// With object handles it is safe to clear the memory in the received buffer
			// instead of increasing the ref count. It will save time both by avoiding the
			// call the increase ref, and also relieve the engine from having to release
			// its references too
			memset(buf, 0, width*elementSize);

			// Move to next line
			buf = (char*)(buf) + width*elementSize;

			// Align to 4 byte boundary
			if( asPWORD(buf) & 0x3 )
				buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
		}
	}
	else if( ti->GetSubType()->GetFlags() & asOBJ_REF )
	{
		// Only allocate the buffer, but not the objects
		subTypeId |= asTYPEID_OBJHANDLE;
		CreateBuffer(&buffer, width, height);
		subTypeId &= ~asTYPEID_OBJHANDLE;

		// Copy the handles into the internal buffer
		for( asUINT y = 0; y < height; y++ )
		{
			// Skip the length value at the start of each row
			buf = (asUINT*)(buf)+1;

			// Copy the line
			if( width > 0 )
				memcpy(At(0,y), buf, width*elementSize);

			// With object handles it is safe to clear the memory in the received buffer
			// instead of increasing the ref count. It will save time both by avoiding the
			// call the increase ref, and also relieve the engine from having to release
			// its references too
			memset(buf, 0, width*elementSize);

			// Move to next line
			buf = (char*)(buf) + width*elementSize;

			// Align to 4 byte boundary
			if( asPWORD(buf) & 0x3 )
				buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
		}
	}
	else
	{
		// TODO: Optimize by calling the copy constructor of the object instead of
		//       constructing with the default constructor and then assigning the value
		// TODO: With C++11 ideally we should be calling the move constructor, instead
		//       of the copy constructor as the engine will just discard the objects in the
		//       buffer afterwards.
		CreateBuffer(&buffer, width, height);

		// For value types we need to call the opAssign for each individual object
		asITypeInfo *subType = ti->GetSubType();
		asUINT subTypeSize = subType->GetSize();
		for( asUINT y = 0;y < height; y++ )
		{
			// Skip the length value at the start of each row
			buf = (asUINT*)(buf)+1;

			// Call opAssign for each of the objects on the row
			for( asUINT x = 0; x < width; x++ )
			{
				void *obj = At(x,y);
				asBYTE *srcObj = (asBYTE*)(buf) + x*subTypeSize;
				engine->AssignScriptObject(obj, srcObj, subType);
			}

			// Move to next line
			buf = (char*)(buf) + width*subTypeSize;

			// Align to 4 byte boundary
			if( asPWORD(buf) & 0x3 )
				buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
		}
	}

	// Notify the GC of the successful creation
	if( objType->GetFlags() & asOBJ_GC )
		objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
}

CScriptGrid::CScriptGrid(asUINT width, asUINT height, asITypeInfo *ti)
{
	refCount = 1;
	gcFlag = false;
	objType = ti;
	objType->AddRef();
	buffer = 0;
	subTypeId = objType->GetSubTypeId();

	// Determine element size
	if( subTypeId & asTYPEID_MASK_OBJECT )
		elementSize = sizeof(asPWORD);
	else
		elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId);

	// Make sure the array size isn't too large for us to handle
	if( !CheckMaxSize(width, height) )
	{
		// Don't continue with the initialization
		return;
	}

	CreateBuffer(&buffer, width, height);

	// Notify the GC of the successful creation
	if( objType->GetFlags() & asOBJ_GC )
		objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
}

void CScriptGrid::Resize(asUINT width, asUINT height)
{
	// Make sure the size isn't too large for us to handle
	if( !CheckMaxSize(width, height) )
		return;

	// Create a new buffer
	SGridBuffer *tmpBuffer = 0;
	CreateBuffer(&tmpBuffer, width, height);
	if( tmpBuffer == 0 )
		return;

	if( buffer )
	{
		// Copy the existing values to the new buffer
		asUINT w = width > buffer->width ? buffer->width : width;
		asUINT h = height > buffer->height ? buffer->height : height;
		for( asUINT y = 0; y < h; y++ )
			for( asUINT x = 0; x < w; x++ )
				SetValue(tmpBuffer, x, y, At(buffer, x, y));

		// Replace the internal buffer
		DeleteBuffer(buffer);
	}

	buffer = tmpBuffer;
}

CScriptGrid::CScriptGrid(asUINT width, asUINT height, void *defVal, asITypeInfo *ti)
{
	refCount = 1;
	gcFlag = false;
	objType = ti;
	objType->AddRef();
	buffer = 0;
	subTypeId = objType->GetSubTypeId();

	// Determine element size
	if( subTypeId & asTYPEID_MASK_OBJECT )
		elementSize = sizeof(asPWORD);
	else
		elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId);

	// Make sure the array size isn't too large for us to handle
	if( !CheckMaxSize(width, height) )
	{
		// Don't continue with the initialization
		return;
	}

	CreateBuffer(&buffer, width, height);

	// Notify the GC of the successful creation
	if( objType->GetFlags() & asOBJ_GC )
		objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);

	// Initialize the elements with the default value
	for( asUINT y = 0; y < GetHeight(); y++ )
		for( asUINT x = 0; x < GetWidth(); x++ )
			SetValue(x, y, defVal);
}

void CScriptGrid::SetValue(asUINT x, asUINT y, void *value)
{
	SetValue(buffer, x, y, value);
}

void CScriptGrid::SetValue(SGridBuffer *buf, asUINT x, asUINT y, void *value)
{
	// At() will take care of the out-of-bounds checking, though
	// if called from the application then nothing will be done
	void *ptr = At(buf, x, y);
	if( ptr == 0 ) return;

	if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) )
		objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType());
	else if( subTypeId & asTYPEID_OBJHANDLE )
	{
		void *tmp = *(void**)ptr;
		*(void**)ptr = *(void**)value;
		objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType());
		if( tmp )
			objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType());
	}
	else if( subTypeId == asTYPEID_BOOL ||
			 subTypeId == asTYPEID_INT8 ||
			 subTypeId == asTYPEID_UINT8 )
		*(char*)ptr = *(char*)value;
	else if( subTypeId == asTYPEID_INT16 ||
			 subTypeId == asTYPEID_UINT16 )
		*(short*)ptr = *(short*)value;
	else if( subTypeId == asTYPEID_INT32 ||
			 subTypeId == asTYPEID_UINT32 ||
			 subTypeId == asTYPEID_FLOAT ||
			 subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles
		*(int*)ptr = *(int*)value;
	else if( subTypeId == asTYPEID_INT64 ||
			 subTypeId == asTYPEID_UINT64 ||
			 subTypeId == asTYPEID_DOUBLE )
		*(double*)ptr = *(double*)value;
}

CScriptGrid::~CScriptGrid()
{
	if( buffer )
	{
		DeleteBuffer(buffer);
		buffer = 0;
	}
	if( objType ) objType->Release();
}

asUINT CScriptGrid::GetWidth() const
{
	if( buffer )
		return buffer->width;

	return 0;
}

asUINT CScriptGrid::GetHeight() const
{
	if( buffer )
		return buffer->height;

	return 0;
}

// internal
bool CScriptGrid::CheckMaxSize(asUINT width, asUINT height)
{
	// This code makes sure the size of the buffer that is allocated
	// for the array doesn't overflow and becomes smaller than requested

	asUINT maxSize = 0xFFFFFFFFul - sizeof(SGridBuffer) + 1;
	if( elementSize > 0 )
		maxSize /= elementSize;

	asINT64 numElements  = width * height;

	if( (numElements >> 32) || numElements > maxSize )
	{
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Too large grid size");

		return false;
	}

	// OK
	return true;
}

asITypeInfo *CScriptGrid::GetGridObjectType() const
{
	return objType;
}

int CScriptGrid::GetGridTypeId() const
{
	return objType->GetTypeId();
}

int CScriptGrid::GetElementTypeId() const
{
	return subTypeId;
}

void *CScriptGrid::At(asUINT x, asUINT y)
{
	return At(buffer, x, y);
}

// Return a pointer to the array element. Returns 0 if the index is out of bounds
void *CScriptGrid::At(SGridBuffer *buf, asUINT x, asUINT y)
{
	if( buf == 0 || x >= buf->width || y >= buf->height )
	{
		// If this is called from a script we raise a script exception
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Index out of bounds");
		return 0;
	}

	asUINT index = x+y*buf->width;
	if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) )
		return *(void**)(buf->data + elementSize*index);
	else
		return buf->data + elementSize*index;
}
const void *CScriptGrid::At(asUINT x, asUINT y) const
{
	return const_cast<CScriptGrid*>(this)->At(const_cast<SGridBuffer*>(buffer), x, y);
}

// internal
void CScriptGrid::CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h)
{
	asUINT numElements = w * h;

	*buf = reinterpret_cast<SGridBuffer*>(userAlloc(sizeof(SGridBuffer)-1+elementSize*numElements));

	if( *buf )
	{
		(*buf)->width  = w;
		(*buf)->height = h;
		Construct(*buf);
	}
	else
	{
		// Oops, out of memory
		asIScriptContext *ctx = asGetActiveContext();
		if( ctx )
			ctx->SetException("Out of memory");
	}
}

// internal
void CScriptGrid::DeleteBuffer(SGridBuffer *buf)
{
	assert( buf );

	Destruct(buf);

	// Free the buffer
	userFree(buf);
}

// internal
void CScriptGrid::Construct(SGridBuffer *buf)
{
	assert( buf );

	if( subTypeId & asTYPEID_OBJHANDLE )
	{
		// Set all object handles to null
		void *d = (void*)(buf->data);
		memset(d, 0, (buf->width*buf->height)*sizeof(void*));
	}
	else if( subTypeId & asTYPEID_MASK_OBJECT )
	{
		void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*));
		void **d = (void**)(buf->data);

		asIScriptEngine *engine = objType->GetEngine();
		asITypeInfo *subType = objType->GetSubType();

		for( ; d < max; d++ )
		{
			*d = (void*)engine->CreateScriptObject(subType);
			if( *d == 0 )
			{
				// Set the remaining entries to null so the destructor
				// won't attempt to destroy invalid objects later
				memset(d, 0, sizeof(void*)*(max-d));

				// There is no need to set an exception on the context,
				// as CreateScriptObject has already done that
				return;
			}
		}
	}
}

// internal
void CScriptGrid::Destruct(SGridBuffer *buf)
{
	assert( buf );

	if( subTypeId & asTYPEID_MASK_OBJECT )
	{
		asIScriptEngine *engine = objType->GetEngine();

		void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*));
		void **d   = (void**)(buf->data);

		for( ; d < max; d++ )
		{
			if( *d )
				engine->ReleaseScriptObject(*d, objType->GetSubType());
		}
	}
}

// GC behaviour
void CScriptGrid::EnumReferences(asIScriptEngine *engine)
{
	if( buffer == 0 ) return;

	// If the grid is holding handles, then we need to notify the GC of them
	if (subTypeId & asTYPEID_MASK_OBJECT)
	{
		asUINT numElements = buffer->width * buffer->height;
		void **d = (void**)buffer->data;
		asITypeInfo *subType = engine->GetTypeInfoById(subTypeId);
		if ((subType->GetFlags() & asOBJ_REF))
		{
			// For reference types we need to notify the GC of each instance
			for (asUINT n = 0; n < numElements; n++)
			{
				if (d[n])
					engine->GCEnumCallback(d[n]);
			}
		}
		else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC))
		{
			// For value types we need to forward the enum callback
			// to the object so it can decide what to do
			for (asUINT n = 0; n < numElements; n++)
			{
				if (d[n])
					engine->ForwardGCEnumReferences(d[n], subType);
			}
		}
	}
}

// GC behaviour
void CScriptGrid::ReleaseAllHandles(asIScriptEngine*)
{
	if( buffer == 0 ) return;

	DeleteBuffer(buffer);
	buffer = 0;
}

void CScriptGrid::AddRef() const
{
	// Clear the GC flag then increase the counter
	gcFlag = false;
	asAtomicInc(refCount);
}

void CScriptGrid::Release() const
{
	// Clearing the GC flag then descrease the counter
	gcFlag = false;
	if( asAtomicDec(refCount) == 0 )
	{
		// When reaching 0 no more references to this instance
		// exists and the object should be destroyed
		this->~CScriptGrid();
		userFree(const_cast<CScriptGrid*>(this));
	}
}

// GC behaviour
int CScriptGrid::GetRefCount()
{
	return refCount;
}

// GC behaviour
void CScriptGrid::SetFlag()
{
	gcFlag = true;
}

// GC behaviour
bool CScriptGrid::GetFlag()
{
	return gcFlag;
}

END_AS_NAMESPACE


code:
#ifndef SCRIPTGRID_H
#define SCRIPTGRID_H

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

BEGIN_AS_NAMESPACE

struct SGridBuffer;

class CScriptGrid
{
public:
	// Set the memory functions that should be used by all CScriptGrids
	static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc);

	// Factory functions
	static CScriptGrid *Create(asITypeInfo *ot);
	static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height);
	static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height, void *defaultValue);
	static CScriptGrid *Create(asITypeInfo *ot, void *listBuffer);

	// Memory management
	void AddRef() const;
	void Release() const;

	// Type information
	asITypeInfo *GetGridObjectType() const;
	int          GetGridTypeId() const;
	int          GetElementTypeId() const;

	// Size
	asUINT GetWidth() const;
	asUINT GetHeight() const;
	void   Resize(asUINT width, asUINT height);

	// Get a pointer to an element. Returns 0 if out of bounds
	void       *At(asUINT x, asUINT y);
	const void *At(asUINT x, asUINT y) const;

	// Set value of an element
	// Remember, if the grid holds handles the value parameter should be the
	// address of the handle. The refCount of the object will also be incremented
	void  SetValue(asUINT x, asUINT y, void *value);

	// GC methods
	int  GetRefCount();
	void SetFlag();
	bool GetFlag();
	void EnumReferences(asIScriptEngine *engine);
	void ReleaseAllHandles(asIScriptEngine *engine);

protected:
	mutable int     refCount;
	mutable bool    gcFlag;
	asITypeInfo    *objType;
	SGridBuffer    *buffer;
	int             elementSize;
	int             subTypeId;

	// Constructors
	CScriptGrid(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list
	CScriptGrid(asUINT w, asUINT h, asITypeInfo *ot);
	CScriptGrid(asUINT w, asUINT h, void *defVal, asITypeInfo *ot);
	virtual ~CScriptGrid();

	bool  CheckMaxSize(asUINT x, asUINT y);
	void  CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h);
	void  DeleteBuffer(SGridBuffer *buf);
	void  Construct(SGridBuffer *buf);
	void  Destruct(SGridBuffer *buf);
	void  SetValue(SGridBuffer *buf, asUINT x, asUINT y, void *value);
	void *At(SGridBuffer *buf, asUINT x, asUINT y);
};

void RegisterScriptGrid(asIScriptEngine *engine);

END_AS_NAMESPACE

#endif


code:
#include "scripthandle.h"
#include <new>
#include <assert.h>
#include <string.h>

BEGIN_AS_NAMESPACE

static void Construct(CScriptHandle *self) { new(self) CScriptHandle(); }
static void Construct(CScriptHandle *self, const CScriptHandle &o) { new(self) CScriptHandle(o); }
// This one is not static because it needs to be friend with the CScriptHandle class
void Construct(CScriptHandle *self, void *ref, int typeId) { new(self) CScriptHandle(ref, typeId); }
static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); }

CScriptHandle::CScriptHandle()
{
	m_ref  = 0;
	m_type = 0;
}

CScriptHandle::CScriptHandle(const CScriptHandle &other)
{
	m_ref  = other.m_ref;
	m_type = other.m_type;

	AddRefHandle();
}

CScriptHandle::CScriptHandle(void *ref, asITypeInfo *type)
{
	m_ref  = ref;
	m_type = type;

	AddRefHandle();
}

// This constructor shouldn't be called from the application
// directly as it requires an active script context
CScriptHandle::CScriptHandle(void *ref, int typeId)
{
	m_ref  = 0;
	m_type = 0;

	Assign(ref, typeId);
}

CScriptHandle::~CScriptHandle()
{
	ReleaseHandle();
}

void CScriptHandle::ReleaseHandle()
{
	if( m_ref && m_type )
	{
		asIScriptEngine *engine = m_type->GetEngine();
		engine->ReleaseScriptObject(m_ref, m_type);

		engine->Release();

		m_ref  = 0;
		m_type = 0;
	}
}

void CScriptHandle::AddRefHandle()
{
	if( m_ref && m_type )
	{
		asIScriptEngine *engine = m_type->GetEngine();
		engine->AddRefScriptObject(m_ref, m_type);

		// Hold on to the engine so it isn't destroyed while
		// a reference to a script object is still held
		engine->AddRef();
	}
}

CScriptHandle &CScriptHandle::operator =(const CScriptHandle &other)
{
	Set(other.m_ref, other.m_type);

	return *this;
}

void CScriptHandle::Set(void *ref, asITypeInfo *type)
{
	if( m_ref == ref ) return;

	ReleaseHandle();

	m_ref  = ref;
	m_type = type;

	AddRefHandle();
}

void *CScriptHandle::GetRef()
{
	return m_ref;
}

asITypeInfo *CScriptHandle::GetType() const
{
	return m_type;
}

int CScriptHandle::GetTypeId() const
{
	if( m_type == 0 ) return 0;

	return m_type->GetTypeId() | asTYPEID_OBJHANDLE;
}

// This method shouldn't be called from the application
// directly as it requires an active script context
CScriptHandle &CScriptHandle::Assign(void *ref, int typeId)
{
	// When receiving a null handle we just clear our memory
	if( typeId == 0 )
	{
		Set(0, 0);
		return *this;
	}

	// Dereference received handles to get the object
	if( typeId & asTYPEID_OBJHANDLE )
	{
		// Store the actual reference
		ref = *(void**)ref;
		typeId &= ~asTYPEID_OBJHANDLE;
	}

	// Get the object type
	asIScriptContext *ctx    = asGetActiveContext();
	asIScriptEngine  *engine = ctx->GetEngine();
	asITypeInfo      *type   = engine->GetTypeInfoById(typeId);

	// If the argument is another CScriptHandle, we should copy the content instead
	if( type && strcmp(type->GetName(), "ref") == 0 )
	{
		CScriptHandle *r = (CScriptHandle*)ref;
		ref  = r->m_ref;
		type = r->m_type;
	}

	Set(ref, type);

	return *this;
}

bool CScriptHandle::operator==(const CScriptHandle &o) const
{
	if( m_ref  == o.m_ref &&
		m_type == o.m_type )
		return true;

	// TODO: If type is not the same, we should attempt to do a dynamic cast,
	//       which may change the pointer for application registered classes

	return false;
}

bool CScriptHandle::operator!=(const CScriptHandle &o) const
{
	return !(*this == o);
}

bool CScriptHandle::Equals(void *ref, int typeId) const
{
	// Null handles are received as reference to a null handle
	if( typeId == 0 )
		ref = 0;

	// Dereference handles to get the object
	if( typeId & asTYPEID_OBJHANDLE )
	{
		// Compare the actual reference
		ref = *(void**)ref;
		typeId &= ~asTYPEID_OBJHANDLE;
	}

	// TODO: If typeId is not the same, we should attempt to do a dynamic cast,
	//       which may change the pointer for application registered classes

	if( ref == m_ref ) return true;

	return false;
}

// AngelScript: used as '@obj = cast<obj>(ref);'
void CScriptHandle::Cast(void **outRef, int typeId)
{
	// If we hold a null handle, then just return null
	if( m_type == 0 )
	{
		*outRef = 0;
		return;
	}

	// It is expected that the outRef is always a handle
	assert( typeId & asTYPEID_OBJHANDLE );

	// Compare the type id of the actual object
	typeId &= ~asTYPEID_OBJHANDLE;
	asIScriptEngine  *engine = m_type->GetEngine();
	asITypeInfo      *type   = engine->GetTypeInfoById(typeId);

	*outRef = 0;

	// RefCastObject will increment the refCount of the returned object if successful
	engine->RefCastObject(m_ref, m_type, type, outRef);
}

void CScriptHandle::EnumReferences(asIScriptEngine *inEngine)
{
	// If we're holding a reference, we'll notify the garbage collector of it
	if (m_ref)
		inEngine->GCEnumCallback(m_ref);

	// The object type itself is also garbage collected
	if( m_type)
		inEngine->GCEnumCallback(m_type);
}

void CScriptHandle::ReleaseReferences(asIScriptEngine * /*inEngine*/)
{
	// Simply clear the content to release the references
	Set(0, 0);
}

void RegisterScriptHandle_Native(asIScriptEngine *engine)
{
	int r;

#if AS_CAN_USE_CPP11
	// With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class
	r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits<CScriptHandle>()); assert( r >= 0 );
#else
	r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
#endif
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Construct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTIONPR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTIONPR(Construct, (CScriptHandle *, void *, int), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destruct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptHandle,EnumReferences), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptHandle, ReleaseReferences), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asMETHODPR(CScriptHandle, Cast, (void **, int), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asMETHOD(CScriptHandle, operator=), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 );
}

void CScriptHandle_Construct_Generic(asIScriptGeneric *gen)
{
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	new(self) CScriptHandle();
}

void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen)
{
	CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	new(self) CScriptHandle(*other);
}

void CScriptHandle_ConstructVar_Generic(asIScriptGeneric *gen)
{
	void *ref = gen->GetArgAddress(0);
	int typeId = gen->GetArgTypeId(0);
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	Construct(self, ref, typeId);
}

void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen)
{
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	self->~CScriptHandle();
}

void CScriptHandle_Cast_Generic(asIScriptGeneric *gen)
{
	void **ref = reinterpret_cast<void**>(gen->GetArgAddress(0));
	int typeId = gen->GetArgTypeId(0);
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	self->Cast(ref, typeId);
}

void CScriptHandle_Assign_Generic(asIScriptGeneric *gen)
{
	CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	*self = *other;
	gen->SetReturnAddress(self);
}

void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen)
{
	void *ref = gen->GetArgAddress(0);
	int typeId = gen->GetArgTypeId(0);
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	self->Assign(ref, typeId);
	gen->SetReturnAddress(self);
}

void CScriptHandle_Equals_Generic(asIScriptGeneric *gen)
{
	CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	gen->SetReturnByte(*self == *other);
}

void CScriptHandle_EqualsVar_Generic(asIScriptGeneric *gen)
{
	void *ref = gen->GetArgAddress(0);
	int typeId = gen->GetArgTypeId(0);
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	gen->SetReturnByte(self->Equals(ref, typeId));
}

void CScriptHandle_EnumReferences_Generic(asIScriptGeneric *gen)
{
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	self->EnumReferences(gen->GetEngine());
}

void CScriptHandle_ReleaseReferences_Generic(asIScriptGeneric *gen)
{
	CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
	self->ReleaseReferences(gen->GetEngine());
}

void RegisterScriptHandle_Generic(asIScriptEngine *engine)
{
	int r;

	r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptHandle_Construct_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTION(CScriptHandle_ConstructCopy_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTION(CScriptHandle_ConstructVar_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptHandle_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptHandle_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptHandle_ReleaseReferences_Generic), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 );
}

void RegisterScriptHandle(asIScriptEngine *engine)
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
		RegisterScriptHandle_Generic(engine);
	else
		RegisterScriptHandle_Native(engine);
}

END_AS_NAMESPACE


code:
#ifndef SCRIPTHANDLE_H
#define SCRIPTHANDLE_H

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

BEGIN_AS_NAMESPACE

class CScriptHandle
{
public:
	// Constructors
	CScriptHandle();
	CScriptHandle(const CScriptHandle &other);
	CScriptHandle(void *ref, asITypeInfo *type);
	~CScriptHandle();

	// Copy the stored value from another any object
	CScriptHandle &operator=(const CScriptHandle &other);

	// Set the reference
	void Set(void *ref, asITypeInfo *type);

	// Compare equalness
	bool operator==(const CScriptHandle &o) const;
	bool operator!=(const CScriptHandle &o) const;
	bool Equals(void *ref, int typeId) const;

	// Dynamic cast to desired handle type
	void Cast(void **outRef, int typeId);

	// Returns the type of the reference held
	asITypeInfo *GetType() const;
	int          GetTypeId() const;

	// Get the reference
	void *GetRef();

	// GC callback
	void EnumReferences(asIScriptEngine *engine);
	void ReleaseReferences(asIScriptEngine *engine);

protected:
	// These functions need to have access to protected
	// members in order to call them from the script engine
	friend void Construct(CScriptHandle *self, void *ref, int typeId);
	friend void RegisterScriptHandle_Native(asIScriptEngine *engine);
	friend void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen);

	void ReleaseHandle();
	void AddRefHandle();

	// These shouldn't be called directly by the
	// application as they requires an active context
	CScriptHandle(void *ref, int typeId);
	CScriptHandle &Assign(void *ref, int typeId);

	void        *m_ref;
	asITypeInfo *m_type;
};

void RegisterScriptHandle(asIScriptEngine *engine);

END_AS_NAMESPACE

#endif