#include "scriptfilesystem.h" #if defined(_WIN32) #include // _getcwd #include // FindFirstFile, GetFileAttributes #else #include // getcwd #include // opendir, readdir, closedir #include // stat #endif #include // assert using namespace std; BEGIN_AS_NAMESPACE CScriptFileSystem *ScriptFileSystem_Factory() { return new CScriptFileSystem(); } void RegisterScriptFileSystem_Native(asIScriptEngine *engine) { int r; 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 @getDirs()", asMETHOD(CScriptFileSystem, GetDirs), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("filesystem", "array @getFiles()", asMETHOD(CScriptFileSystem, GetFiles), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in)", asMETHOD(CScriptFileSystem, IsDir), asCALL_THISCALL); 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]; #if defined(_WIN32) currentPath = _getcwd(buffer, 1000); #else currentPath = getcwd(buffer, 1000); #endif } 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 asIObjectType *arrayType = engine->GetObjectTypeByDecl("array"); // 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 asIObjectType *arrayType = engine->GetObjectTypeByDecl("array"); // 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; } bool CScriptFileSystem::ChangeCurrentPath(const string &path) { if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 ) currentPath = path; else currentPath += "/" + path; // Remove trailing slashes from the path while( currentPath.length() && (currentPath[currentPath.length()-1] == '/' || currentPath[currentPath.length()-1] == '\\') ) currentPath.resize(currentPath.length()-1); return IsDir(currentPath); } 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; } string CScriptFileSystem::GetCurrentPath() const { return currentPath; } END_AS_NAMESPACE