void CFileSystem::GetModifiedFiles(behaviac::vector<behaviac::string>& modifiedFiles) { BEHAVIAC_UNUSED_VAR(modifiedFiles); #if BEHAVIAC_COMPILER_GCC_LINUX modifiedFiles.clear(); if (s_ModifiedFiles.empty()) { return; } behaviac::ScopedLock lock(s_mutex); std::sort(s_ModifiedFiles.begin(), s_ModifiedFiles.end()); s_ModifiedFiles.erase(std::unique(s_ModifiedFiles.begin(), s_ModifiedFiles.end()), s_ModifiedFiles.end()); s_ModifiedFiles.swap(modifiedFiles); //for (behaviac::vector<behaviac::string>::iterator it = s_ModifiedFiles.begin(); it != s_ModifiedFiles.end(); ++it) //{ // behaviac::string& s = *it; // modifiedFiles.push_back(s); //} //s_ModifiedFiles.clear(); #endif }
void ConvertTextBufferAsStringArray(const char* buffer, behaviac::vector<behaviac::string>& stringArray) { BEHAVIAC_ASSERT(buffer); const char* lineBuffer = buffer; while (*lineBuffer != '\0') { const char* currentPos = lineBuffer; while (*currentPos != '\n' && *currentPos != '\r' && *currentPos != '\0') { currentPos++; } behaviac::string line; line.assign(lineBuffer, currentPos - lineBuffer); stringArray.push_back(line); while (*currentPos == '\n' || *currentPos == '\r') { currentPos++; } lineBuffer = currentPos; } }
virtual void load(const char* instance, behaviac::vector<behaviac::string>& paramStrs) { BEHAVIAC_ASSERT(paramStrs.size() == 1); behaviac::StringUtils::StringCopySafe(kInstanceNameMax, _instance, instance); _param0 = AgentMeta::TParseProperty<IList >(paramStrs[0].c_str()); }
void CScriptSystem::EndCall(behaviac::vector<behaviac::string>& array) { if (m_nTempArg == -1) { return; } if (ExecuteFunction(m_pLS, m_nTempArg, 1)) { if (lua_istable(m_pLS, -1)) { int top = lua_gettop(m_pLS); lua_pushnil(m_pLS); // first key while (lua_next(m_pLS, top) != 0) { // `key' is at index -2 and `value' at index -1 const char* value = lua_tostring(m_pLS, -1); array.push_back(value); lua_pop(m_pLS, 1); // pop value, leave index. } } lua_pop(m_pLS, 1); } // Check for LUA stack corruption CheckStackOnEndCall(); }
//suppose params are seprated by ',' static void ParseForParams(const behaviac::string& tsrc, behaviac::vector<behaviac::string>& params) { int tsrcLen = (int)tsrc.size(); int startIndex = 0; int index = 0; int quoteDepth = 0; for (; index < tsrcLen; ++index) { if (tsrc[index] == '"') { quoteDepth++; //if (quoteDepth == 1) //{ // startIndex = index; //} if ((quoteDepth & 0x1) == 0) { //closing quote quoteDepth -= 2; BEHAVIAC_ASSERT(quoteDepth >= 0); } } else if (quoteDepth == 0 && tsrc[index] == ',') { //skip ',' inside quotes, like "count, count" int lengthTemp = index - startIndex; behaviac::string strTemp = tsrc.substr(startIndex, lengthTemp); params.push_back(strTemp); startIndex = index + 1; } }//end for // the last param int lengthTemp = index - startIndex; if (lengthTemp > 0) { behaviac::string strTemp = tsrc.substr(startIndex, lengthTemp); params.push_back(strTemp); //params.push_back(strTemp); } }
void CFileSystem::findFiles(const char* fileName, behaviac::vector<behaviac::string>& fileList, bool giveFiles, bool giveDirectories, bool recursive, int maximumSize, bool keepCase) { BEHAVIAC_ASSERT(fileName); CCounterFileSystemVisitor counterVisitor(maximumSize); Visit(counterVisitor, fileName, giveFiles, giveDirectories, recursive); fileList.reserve(counterVisitor.GetCount()); CVectorFileSystemVisitor vectorVisitor(fileList, recursive, maximumSize, keepCase); Visit(vectorVisitor, fileName, giveFiles, giveDirectories, recursive); }
void CFileSystem::StopMonitoringDirectory() { #if BEHAVIAC_CCDEFINE_GCC_LINUX if (!s_bThreadFinish) { s_bThreadFinish = true; pthread_join(s_tid, 0); s_ModifiedFiles.clear(); } #endif }
void ListFiles_android(behaviac::vector<behaviac::string>& files, const char* szDirName, bool bRecurrsive) { AAssetManager* mgr = behaviac::CFileManager::GetInstance()->GetAssetManager(); if (mgr != NULL) { const char* validDir = szDirName; //skip "assets:/" if (behaviac::StringUtils::StartsWith(validDir, "assets:/")) { validDir = validDir + 8; } AAssetDir* dir = AAssetManager_openDir(mgr, validDir); if (dir != NULL) { bool bEndsWithSlash = behaviac::StringUtils::EndsWith(szDirName, "/"); if (!bEndsWithSlash) { bEndsWithSlash = behaviac::StringUtils::EndsWith(szDirName, "\\"); } while (true) { const char* fileName = AAssetDir_getNextFileName(dir); if (fileName == NULL) { break; } if (bEndsWithSlash) { fileName = behaviac::FormatString("%s%s", szDirName, fileName); } else { fileName = behaviac::FormatString("%s/%s", szDirName, fileName); } files.push_back(fileName); } AAssetDir_close(dir); } } }
static void* ThreadFunc(void* arg) { bool isLock = false; const char* path = (char*)arg; InotifyDir inotify; InotifyDir::Event ev; inotify.init(); inotify.Watch(path); while (!s_bThreadFinish) { if (!inotify.EventPoll(ev)) { if (isLock) { isLock = false; s_mutex.Unlock(); } usleep(100); continue; } if (!isLock) { isLock = true; s_mutex.Lock(); } if (ev.type == InotifyDir::MODIFY || ev.type == InotifyDir::ADD) { ev.name.erase(0, strlen(path)); s_ModifiedFiles.push_back(ev.name.c_str()); } } if (isLock) { isLock = false; s_mutex.Unlock(); } return NULL; }
//[property] WorldState::WorldState int WorldState::time->185606213 //[property] Ship::Ship_2_3 long GameObject::age->91291 //[property] Ship::Ship_2_3 bool par_a->true void Workspace::ParseProperty(const behaviac::vector<behaviac::string>& tokens) { BEHAVIAC_UNUSED_VAR(tokens); #if !BEHAVIAC_RELEASE const behaviac::string& agentName = tokens[1]; Agent* pAgent = Agent::GetAgent(agentName.c_str()); //pAgent could be 0 if (pAgent && tokens.size() == 4) { //const behaviac::string& varTypeName = tokens[2]; const behaviac::string& varNameValue = tokens[3]; behaviac::string::size_type posb = varNameValue.find("->"); BEHAVIAC_ASSERT(posb != behaviac::string::npos); if (posb != behaviac::string::npos) { behaviac::string::size_type size = behaviac::string::npos; //varNameValue is the last one with '\n' behaviac::string::size_type pose = varNameValue.find('\n'); if (pose != behaviac::string::npos) { size = pose - posb - 1; } behaviac::string varName = varNameValue.substr(0, posb); behaviac::string varValue = varNameValue.substr(posb + 2, size); if (pAgent) { pAgent->SetVariableFromString(varName.c_str(), varValue.c_str()); }//end of if (pAgent) } } #endif }
EBTStatus Selector::SelectorUpdate(Agent* pAgent, EBTStatus childStatus, int& activeChildIndex, behaviac::vector<BehaviorTask*>& children) { EBTStatus s = childStatus; int childSize = (int)children.size(); for (;;) { BEHAVIAC_ASSERT(activeChildIndex < childSize); if (s == BT_RUNNING) { BehaviorTask* pBehavior = children[activeChildIndex]; if (this->CheckIfInterrupted(pAgent)) { return BT_FAILURE; } s = pBehavior->exec(pAgent); } // If the child fails, or keeps running, do the same. if (s != BT_FAILURE) { return s; } // Hit the end of the array, job done! ++activeChildIndex; if (activeChildIndex >= childSize) { return BT_FAILURE; } s = BT_RUNNING; } }
namespace behaviac { bool CFileSystem::GetFileInfo(const char* szFilename, CFileSystem::SFileInfo& fileInfo) { BEHAVIAC_UNUSED_VAR(szFilename); BEHAVIAC_UNUSED_VAR(fileInfo); BEHAVIAC_ASSERT(0); bool bFound = false; return bFound; } bool CFileSystem::GetFileInfo(Handle hFile, SFileInfo& fileInfo) { BEHAVIAC_UNUSED_VAR(hFile); BEHAVIAC_UNUSED_VAR(fileInfo); BEHAVIAC_ASSERT(0); return false; } CFileSystem::Handle CFileSystem::OpenCreateFile(const char* szFullPath, EOpenMode openAccess) { #if BEHAVIAC_CCDEFINE_ANDROID && (BEHAVIAC_CCDEFINE_ANDROID_VER > 8) AAssetManager* mgr = behaviac::CFileManager::GetInstance()->GetAssetManager(); Handle hFile = FILE_SYSTEM_INVALID_HANDLE; if (openAccess != EOpenMode_Read) { BEHAVIAC_LOGERROR("Only read mode is supported for asset files"); return hFile; } if (behaviac::StringUtils::StartsWith(szFullPath, "assets:/")) { //skip "assets:/" const char* fileName = szFullPath + 8; AAsset* asset = AAssetManager_open(mgr, fileName, AASSET_MODE_UNKNOWN); hFile = (Handle)asset; } #else Handle hFile = fopen(szFullPath, openMode[openAccess]); if (!hFile) { BEHAVIAC_LOGERROR("Could not open file %s", szFullPath); return hFile; } #endif return hFile; } void CFileSystem::CloseFile(Handle file) { #if BEHAVIAC_CCDEFINE_ANDROID && (BEHAVIAC_CCDEFINE_ANDROID_VER > 8) AAsset_close((AAsset*)file); #else fclose((FILE*)file); #endif } bool CFileSystem::ReadFile(Handle file, void* pBuffer, uint32_t nNumberOfBytesToRead, uint32_t* pNumberOfBytesRead) { if (!file) { BEHAVIAC_LOGERROR("File not open"); return 0; } #if BEHAVIAC_CCDEFINE_ANDROID && (BEHAVIAC_CCDEFINE_ANDROID_VER > 8) size_t ret = AAsset_read((AAsset*)file, pBuffer, nNumberOfBytesToRead); #else size_t ret = fread(pBuffer, 1, nNumberOfBytesToRead, (FILE*)file); #endif if (pNumberOfBytesRead) { *pNumberOfBytesRead = ret; } return true; } bool CFileSystem::WriteFile(Handle hFile, const void* pBuffer, uint32_t nNumberOfBytesToWrite, uint32_t* pNumberOfBytesWritten) { size_t ret = fwrite(pBuffer, 1, nNumberOfBytesToWrite, (FILE*)hFile); if (pNumberOfBytesWritten) { *pNumberOfBytesWritten = ret; } return true; } int64_t CFileSystem::SetFilePointer(Handle file, int64_t distanceToMove, ESeekMode moveMethod) { int64_t ret = 0; if (moveMethod == ESeekMode_Cur) { ret = fseek((FILE*)file, distanceToMove, SEEK_CUR); } else if (moveMethod == ESeekMode_End) { ret = fseek((FILE*)file, distanceToMove, SEEK_END); } else if (moveMethod == ESeekMode_Begin) { ret = fseek((FILE*)file, distanceToMove, SEEK_SET); } else if (moveMethod == ESeekMode_Set) { ret = fseek((FILE*)file, distanceToMove, SEEK_SET); } return ret; } void CFileSystem::FlushFile(Handle file) { fflush((FILE*)file); } bool CFileSystem::FileExist(const char* szFullPath) { struct stat st; if (stat(szFullPath, &st) || (st.st_mode & S_IFDIR)) { return false; } return true; } uint64_t CFileSystem::GetFileSize(Handle hFile) { #if BEHAVIAC_CCDEFINE_ANDROID && (BEHAVIAC_CCDEFINE_ANDROID_VER > 8) off_t fileSize = AAsset_getLength((AAsset*)hFile); return fileSize; #else struct stat buf; int fd = fileno((FILE*)hFile); fstat(fd, &buf); uint64_t size_ = buf.st_size; return size_; #endif } bool CFileSystem::Move(const char* srcFullPath, const char* destFullPath) { BEHAVIAC_UNUSED_VAR(srcFullPath); BEHAVIAC_UNUSED_VAR(destFullPath); BEHAVIAC_ASSERT(0); return false; } void CFileSystem::MakeSureDirectoryExist(const char* filename) { const int kMAX_PATH = 260; char directory[kMAX_PATH]; string_cpy(directory, filename); char* iter = directory; mode_t old = umask(0); while (*iter != 0) { if (*iter == '\\' || *iter == '/') { char c = *iter; *iter = 0; mkdir(directory, S_IWUSR); *iter = c; } iter++; } umask(old); } #if BEHAVIAC_CCDEFINE_ANDROID && (BEHAVIAC_CCDEFINE_ANDROID_VER > 8) void ListFiles_android(behaviac::vector<behaviac::string>& files, const char* szDirName, bool bRecurrsive) { AAssetManager* mgr = behaviac::CFileManager::GetInstance()->GetAssetManager(); if (mgr != NULL) { const char* validDir = szDirName; //skip "assets:/" if (behaviac::StringUtils::StartsWith(validDir, "assets:/")) { validDir = validDir + 8; } AAssetDir* dir = AAssetManager_openDir(mgr, validDir); if (dir != NULL) { bool bEndsWithSlash = behaviac::StringUtils::EndsWith(szDirName, "/"); if (!bEndsWithSlash) { bEndsWithSlash = behaviac::StringUtils::EndsWith(szDirName, "\\"); } while (true) { const char* fileName = AAssetDir_getNextFileName(dir); if (fileName == NULL) { break; } if (bEndsWithSlash) { fileName = behaviac::FormatString("%s%s", szDirName, fileName); } else { fileName = behaviac::FormatString("%s/%s", szDirName, fileName); } files.push_back(fileName); } AAssetDir_close(dir); } } } #endif void CFileSystem::ListFiles(behaviac::vector<behaviac::string>& files, const char* szDirName, bool bRecurrsive) { #if BEHAVIAC_CCDEFINE_ANDROID && (BEHAVIAC_CCDEFINE_ANDROID_VER > 8) ListFiles_android(files, szDirName, bRecurrsive); #else ListFiles_internal(files, szDirName, bRecurrsive); #endif } void CFileSystem::HandleSeekError(const char* szFilename) { BEHAVIAC_UNUSED_VAR(szFilename); #ifndef _DEBUG // uint32_t error = GetLastError(); // FatalError::DamagedDisc( szFilename ); #endif } bool CFileSystem::IsFullPath(const char* szFilename) { return strchr(szFilename, ':') != NULL || (szFilename[0] == '\\' && szFilename[1] == '\\'); } void CFileSystem::ReadError(Handle file) { BEHAVIAC_UNUSED_VAR(file); BEHAVIAC_ASSERT(0); } #if BEHAVIAC_CCDEFINE_GCC_LINUX class InotifyDir { public: enum EventType { UNKNOWN = 0, //unknow event ADD = 1, //file added MODIFY = 2, //file modified DELETE = 3, //file deleted }; struct Event { void clear() { type = UNKNOWN; name.clear(); } Event() {} Event(const std::string& s, EventType t) : name(s), type(t) {} std::string name; EventType type; }; public: InotifyDir() { m_buffIdx = 0; m_buffLen = 0; m_wfd = -1; } bool EventPoll(Event& event); void AddPathEvent(const char* path, EventType type); bool Watch(const char* path); bool init() { m_wfd = inotify_init(); int flag = fcntl(m_wfd, F_GETFL, 0); fcntl(m_wfd, F_SETFL, flag | O_NONBLOCK); if (m_wfd < 0) { return false; } return true; } private: void Unwatch(int wd) { inotify_rm_watch(m_wfd, wd); m_watchFd.erase(wd); } int m_wfd; std::map<int, std::string> m_watchFd; char m_buff[1000]; int m_buffLen; int m_buffIdx; std::deque<Event> m_pendingEv; }; bool InotifyDir::Watch(const char* path) { if (m_wfd == -1) { return false; } struct stat statbuff; stat(path, &statbuff); if (!(statbuff.st_mode & S_IFDIR)) { return false; } int wd = inotify_add_watch(m_wfd, path, IN_MODIFY | IN_MOVE | IN_CREATE | IN_DELETE | IN_MOVE_SELF); if (wd < 0) { return false; } m_watchFd[wd] = path; if (*m_watchFd[wd].rbegin() != '/') { m_watchFd[wd].push_back('/'); } struct dirent* item; DIR* dir = opendir(path); if (dir == NULL) { close(wd); return false; } while ((item = readdir(dir)) != NULL) { if (StringUtils::StringEqual(item->d_name, ".") || StringUtils::StringEqual(item->d_name, "..")) { continue; } if (item->d_type == DT_DIR) { std::string s = m_watchFd[wd] + item->d_name; Watch(s.c_str()); } } closedir(dir); return true; } void InotifyDir::AddPathEvent(const char* path, EventType type) { struct dirent* item; DIR* dir = opendir(path); if (dir == NULL) { return; } while ((item = readdir(dir)) != NULL) { if (StringUtils::StringEqual(item->d_name, ".") || StringUtils::StringEqual(item->d_name, "..")) { continue; } if (item->d_type == DT_REG) { std::string s = path; s += item->d_name; AddPathEvent(s.c_str(), type); } else { std::string s = path; s += item->d_name; Event e(s, type); m_pendingEv.push_back(e); } } closedir(dir); } bool InotifyDir::EventPoll(Event& event) { for (;;) { if (!m_pendingEv.empty()) { event = m_pendingEv.front(); m_pendingEv.pop_front(); return true; } if (m_buffIdx >= m_buffLen) { m_buffIdx = 0; m_buffLen = read(m_wfd, m_buff, sizeof(m_buff)); if (m_buffLen <= 0) { return false; } } inotify_event* ev = (inotify_event*)&m_buff[m_buffIdx]; m_buffIdx += ev->len + sizeof(inotify_event); if (ev->mask & (IN_IGNORED | IN_UNMOUNT)) { Unwatch(ev->wd); continue; } if (ev->mask & (IN_CREATE | IN_MOVED_TO)) { if (ev->mask & IN_ISDIR) { std::string s = m_watchFd[ev->wd] + ev->name; if (ev->mask & IN_MOVED_TO) { AddPathEvent(s.c_str(), ADD); } continue; } } if (ev->mask & IN_MOVED_FROM && ev->mask & IN_ISDIR) { //event can't catch continue; } if (ev->mask & IN_MOVE_SELF) { continue; } if (ev->mask & IN_DELETE) { if (ev->mask & IN_ISDIR) { continue; } } event.clear(); if (ev->mask & (IN_MOVED_TO | IN_CREATE)) { event.type = ADD; } else if (ev->mask & (IN_MOVED_FROM | IN_DELETE)) { event.type = DELETE; } else if (ev->mask & IN_MODIFY) { event.type = MODIFY; } else { event.type = UNKNOWN; } event.name = m_watchFd[ev->wd] + ev->name; return true; } } static bool s_bThreadFinish = true; static pthread_t s_tid; static behaviac::Mutex s_mutex; static behaviac::vector<behaviac::string> s_ModifiedFiles; static void* ThreadFunc(void* arg) { bool isLock = false; const char* path = (char*)arg; InotifyDir inotify; InotifyDir::Event ev; inotify.init(); inotify.Watch(path); while (!s_bThreadFinish) { if (!inotify.EventPoll(ev)) { if (isLock) { isLock = false; s_mutex.Unlock(); } usleep(100); continue; } if (!isLock) { isLock = true; s_mutex.Lock(); } if (ev.type == InotifyDir::MODIFY || ev.type == InotifyDir::ADD) { ev.name.erase(0, strlen(path)); s_ModifiedFiles.push_back(ev.name.c_str()); } } if (isLock) { isLock = false; s_mutex.Unlock(); } return NULL; } #endif bool CFileSystem::StartMonitoringDirectory(const wchar_t* dir) { BEHAVIAC_UNUSED_VAR(dir); #if BEHAVIAC_CCDEFINE_GCC_LINUX if (!s_bThreadFinish) { return true; } s_bThreadFinish = false; behaviac::wstring dirW = dir; //to use static! static behaviac::string s_buffer = ""; s_buffer = behaviac::StringUtils::Wide2Char(dirW); if (pthread_create(&s_tid, NULL, ThreadFunc, const_cast<char*>(s_buffer.c_str())) < 0) { return false; } //pthread_detach(tid); #endif return true; } void CFileSystem::StopMonitoringDirectory() { #if BEHAVIAC_CCDEFINE_GCC_LINUX if (!s_bThreadFinish) { s_bThreadFinish = true; pthread_join(s_tid, 0); s_ModifiedFiles.clear(); } #endif } void CFileSystem::GetModifiedFiles(behaviac::vector<behaviac::string>& modifiedFiles) { BEHAVIAC_UNUSED_VAR(modifiedFiles); #if BEHAVIAC_CCDEFINE_GCC_LINUX modifiedFiles.clear(); if (s_ModifiedFiles.empty()) { return; } behaviac::ScopedLock lock(s_mutex); std::sort(s_ModifiedFiles.begin(), s_ModifiedFiles.end()); s_ModifiedFiles.erase(std::unique(s_ModifiedFiles.begin(), s_ModifiedFiles.end()), s_ModifiedFiles.end()); s_ModifiedFiles.swap(modifiedFiles); //for (behaviac::vector<behaviac::string>::iterator it = s_ModifiedFiles.begin(); it != s_ModifiedFiles.end(); ++it) //{ // behaviac::string& s = *it; // modifiedFiles.push_back(s); //} //s_ModifiedFiles.clear(); #endif } }//namespace behaviac
namespace behaviac { bool CFileSystem::GetFileInfo(const char* szFilename, CFileSystem::SFileInfo& fileInfo) { BEHAVIAC_UNUSED_VAR(szFilename); BEHAVIAC_UNUSED_VAR(fileInfo); BEHAVIAC_ASSERT(0); bool bFound = false; return bFound; } bool CFileSystem::GetFileInfo(Handle hFile, SFileInfo& fileInfo) { BEHAVIAC_UNUSED_VAR(hFile); BEHAVIAC_UNUSED_VAR(fileInfo); BEHAVIAC_ASSERT(0); return false; } CFileSystem::Handle CFileSystem::OpenCreateFile(const char* szFullPath, EOpenAccess openAccess) { #if BEHAVIAC_COMPILER_ANDROID && (BEHAVIAC_COMPILER_ANDROID_VER > 8) AAssetManager* mgr = behaviac::CFileManager::GetInstance()->GetAssetManager(); Handle hFile = FILE_SYSTEM_INVALID_HANDLE; if (openAccess != EOpenAccess_Read) { BEHAVIAC_LOGERROR("Only read mode is supported for asset files"); return hFile; } if (behaviac::StringUtils::StartsWith(szFullPath, "assets:/")) { //skip "assets:/" const char* fileName = szFullPath + 8; AAsset* asset = AAssetManager_open(mgr, fileName, AASSET_MODE_UNKNOWN); hFile = (Handle)asset; } #else Handle hFile = fopen(szFullPath, openMode[openAccess]); if (!hFile) { BEHAVIAC_LOGERROR("Could not open file %s", szFullPath); return hFile; } #endif return hFile; } void CFileSystem::closeFile(Handle file) { #if BEHAVIAC_COMPILER_ANDROID && (BEHAVIAC_COMPILER_ANDROID_VER > 8) AAsset_close((AAsset*)file); #else fclose((FILE*)file); #endif } bool CFileSystem::readFile(Handle file, void* pBuffer, uint32_t nNumberOfBytesToRead, uint32_t* pNumberOfBytesRead) { if (!file) { BEHAVIAC_LOGERROR("File not open"); return 0; } #if BEHAVIAC_COMPILER_ANDROID && (BEHAVIAC_COMPILER_ANDROID_VER > 8) size_t ret = AAsset_read((AAsset*)file, pBuffer, nNumberOfBytesToRead); #else size_t ret = fread(pBuffer, 1, nNumberOfBytesToRead, (FILE*)file); #endif if (pNumberOfBytesRead) { *pNumberOfBytesRead = ret; } return true; } bool CFileSystem::writeFile(Handle hFile, const void* pBuffer, uint32_t nNumberOfBytesToWrite, uint32_t* pNumberOfBytesWritten) { size_t ret = fwrite(pBuffer, 1, nNumberOfBytesToWrite, (FILE*)hFile); if (pNumberOfBytesWritten) { *pNumberOfBytesWritten = ret; } return true; } bool CFileSystem::copyFile(const char* lpExistingFileName, const char* lpNewFileName, bool bFailIfExists) { BEHAVIAC_UNUSED_VAR(lpExistingFileName); BEHAVIAC_UNUSED_VAR(lpNewFileName); BEHAVIAC_UNUSED_VAR(bFailIfExists); BEHAVIAC_ASSERT(0); return false; } int64_t CFileSystem::SetFilePointer(Handle file, int64_t distanceToMove, ESeekMoveMode moveMethod) { int64_t ret = 0; if (moveMethod == ESeekMoveMode_Cur) { ret = fseek((FILE*)file, distanceToMove, SEEK_CUR); } else if (moveMethod == ESeekMoveMode_End) { ret = fseek((FILE*)file, distanceToMove, SEEK_END); } else if (moveMethod == ESeekMoveMode_Begin) { ret = fseek((FILE*)file, distanceToMove, SEEK_SET); } else if (moveMethod == ESeekMoveMode_Set) { ret = fseek((FILE*)file, distanceToMove, SEEK_SET); } return ret; } bool CFileSystem::SetEndOfFile(Handle file) { fseek((FILE*)file, 0, SEEK_END); return true; } void CFileSystem::FlushFile(Handle file) { fflush((FILE*)file); } bool CFileSystem::FileExist(const char* szFullPath) { struct stat st; if (stat(szFullPath, &st) || (st.st_mode & S_IFDIR)) { return false; } return true; } uint64_t CFileSystem::GetFileSize(Handle hFile) { #if BEHAVIAC_COMPILER_ANDROID && (BEHAVIAC_COMPILER_ANDROID_VER > 8) off_t fileSize = AAsset_getLength((AAsset*)hFile); return fileSize; #else struct stat buf; int fd = fileno((FILE*)hFile); fstat(fd, &buf); uint64_t size_ = buf.st_size; return size_; #endif } bool CFileSystem::Delete(const char* szPath, bool bRecursive) { BEHAVIAC_UNUSED_VAR(bRecursive); return remove(szPath) == 0; } bool CFileSystem::Move(const char* srcFullPath, const char* destFullPath) { BEHAVIAC_UNUSED_VAR(srcFullPath); BEHAVIAC_UNUSED_VAR(destFullPath); BEHAVIAC_ASSERT(0); return false; } bool CFileSystem::removeDirectory(const char* szDirectoryPath) { return remove(szDirectoryPath) == 0; } void CFileSystem::MakeSureDirectoryExist(const char* filename) { const int kMAX_PATH = 260; char directory[kMAX_PATH]; string_cpy(directory, filename); char* iter = directory; while (*iter != 0) { if (*iter == '\\' || *iter == '/') { char c = *iter; *iter = 0; mkdir(directory, S_IWUSR); *iter = c; } iter++; } } void CFileSystem::findFiles(const char* fileName, behaviac::vector<behaviac::string>& fileList, bool giveFiles, bool giveDirectories, bool recursive, int maximumSize, bool keepCase) { BEHAVIAC_ASSERT(fileName); CCounterFileSystemVisitor counterVisitor(maximumSize); Visit(counterVisitor, fileName, giveFiles, giveDirectories, recursive); fileList.reserve(counterVisitor.GetCount()); CVectorFileSystemVisitor vectorVisitor(fileList, recursive, maximumSize, keepCase); Visit(vectorVisitor, fileName, giveFiles, giveDirectories, recursive); } static bool VisitHelper ( IFileSystemVisitor& visitor, behaviac::wstring& dir, const behaviac::wstring& filter, bool visitFiles, bool visitDirectories, bool recursive, behaviac::string& tempString ) { BEHAVIAC_UNUSED_VAR(visitor); BEHAVIAC_UNUSED_VAR(dir); BEHAVIAC_UNUSED_VAR(filter); BEHAVIAC_UNUSED_VAR(visitFiles); BEHAVIAC_UNUSED_VAR(visitDirectories); BEHAVIAC_UNUSED_VAR(recursive); BEHAVIAC_UNUSED_VAR(tempString); BEHAVIAC_ASSERT(0); return false; } void CFileSystem::Visit ( IFileSystemVisitor& visitor, const char* pathWithFilter, bool visitFiles, bool visitDirectories, bool recursive ) { BEHAVIAC_ASSERT(pathWithFilter); BEHAVIAC_ASSERT(!strchr(pathWithFilter, '/')); behaviac::wstring dir; behaviac::StringUtils::Char2Wide(dir, pathWithFilter); behaviac::wstring filter; behaviac::wstring::size_type lastSeparatorPos = dir.find_last_of(L"\\:"); if (lastSeparatorPos == behaviac::wstring::npos) { dir.swap(filter); } else { filter = dir.c_str() + lastSeparatorPos + 1; dir.resize(lastSeparatorPos + 1); } behaviac::string tempString; VisitHelper(visitor, dir, filter, visitFiles, visitDirectories, recursive, tempString); } void CFileSystem::HandleDamageDisk(const char* szFilename) { BEHAVIAC_UNUSED_VAR(szFilename); #ifndef _DEBUG // uint32_t error = GetLastError(); // FatalError::DamagedDisc( szFilename ); #endif } void CFileSystem::ConvertPath(const char* szFilePathToConvert, char* szFilePathOut) { if (*szFilePathToConvert == '\\') { // If we have a network path, keep the first of the two separators at the beginning instead of skipping it. if (*(szFilePathToConvert + 1) == '\\') { *(szFilePathOut++) = *(szFilePathToConvert++); *(szFilePathOut++) = *(szFilePathToConvert++); } else { BEHAVIAC_ASSERT(0, "Absolute path that begins with \"\\\" are not supported.\n%s", szFilePathToConvert); ++szFilePathToConvert; } } // make the path lower-letters and with forward-slashes for (; *szFilePathToConvert; ++szFilePathToConvert, ++szFilePathOut) { // Skip multiple separator while ((*szFilePathToConvert == '\\' || *szFilePathToConvert == '/') && (*(szFilePathToConvert + 1) == '\\' || *(szFilePathToConvert + 1) == '/')) { szFilePathToConvert++; } if (*szFilePathToConvert == '/') { *szFilePathOut = '\\'; } else { *szFilePathOut = (char)tolower(*szFilePathToConvert); } } *szFilePathOut = '\0'; } bool CFileSystem::setFileAttributes(const char* szFilename, uint32_t fileAttributes) { BEHAVIAC_UNUSED_VAR(szFilename); BEHAVIAC_UNUSED_VAR(fileAttributes); BEHAVIAC_ASSERT(0); return false; } bool CFileSystem::getFileAttributes(const char* szFilename, uint32_t& fileAttributes) { BEHAVIAC_UNUSED_VAR(szFilename); BEHAVIAC_UNUSED_VAR(fileAttributes); BEHAVIAC_ASSERT(0); return false; } bool CFileSystem::isFullPath(const char* szFilename) { return strchr(szFilename, ':') != NULL || (szFilename[0] == '\\' && szFilename[1] == '\\'); } void CFileSystem::ReadError(Handle file) { BEHAVIAC_UNUSED_VAR(file); BEHAVIAC_ASSERT(0); } #if BEHAVIAC_COMPILER_GCC_LINUX class InotifyDir { public: enum EventType { UNKNOWN = 0, //unknow event ADD = 1, //file added MODIFY = 2, //file modified DELETE = 3, //file deleted }; struct Event { void clear() { type = UNKNOWN; name.clear(); } Event() {} Event(const std::string& s, EventType t) : name(s), type(t) {} std::string name; EventType type; }; public: InotifyDir() { m_buffIdx = 0; m_buffLen = 0; m_wfd = -1; } bool EventPoll(Event& event); void AddPathEvent(const char* path, EventType type); bool Watch(const char* path); bool init() { m_wfd = inotify_init(); int flag = fcntl(m_wfd, F_GETFL, 0); fcntl(m_wfd, F_SETFL, flag | O_NONBLOCK); if (m_wfd < 0) { return false; } return true; } private: void Unwatch(int wd) { inotify_rm_watch(m_wfd, wd); m_watchFd.erase(wd); } int m_wfd; std::map<int, std::string> m_watchFd; char m_buff[1000]; int m_buffLen; int m_buffIdx; std::deque<Event> m_pendingEv; }; bool InotifyDir::Watch(const char* path) { if (m_wfd == -1) { return false; } struct stat statbuff; stat(path, &statbuff); if (!statbuff.st_mode & S_IFDIR) { return false; } int wd = inotify_add_watch(m_wfd, path, IN_MODIFY | IN_MOVE | IN_CREATE | IN_DELETE | IN_MOVE_SELF); if (wd < 0) { return false; } m_watchFd[wd] = path; if (*m_watchFd[wd].rbegin() != '/') { m_watchFd[wd].push_back('/'); } struct dirent* item; DIR* dir = opendir(path); if (dir == NULL) { close(wd); return false; } while ((item = readdir(dir)) != NULL) { if (strcmp(item->d_name, ".") == 0 || strcmp(item->d_name, "..") == 0) { continue; } if (item->d_type == DT_DIR) { std::string s = m_watchFd[wd] + item->d_name; Watch(s.c_str()); } } closedir(dir); return true; } void InotifyDir::AddPathEvent(const char* path, EventType type) { struct dirent* item; DIR* dir = opendir(path); if (dir == NULL) { return; } while ((item = readdir(dir)) != NULL) { if (strcmp(item->d_name, ".") == 0 || strcmp(item->d_name, "..") == 0) { continue; } if (item->d_type == DT_REG) { std::string s = path; s += item->d_name; AddPathEvent(s.c_str(), type); } else { std::string s = path; s += item->d_name; Event e(s, type); m_pendingEv.push_back(e); } } closedir(dir); } bool InotifyDir::EventPoll(Event& event) { for (;;) { if (!m_pendingEv.empty()) { event = m_pendingEv.front(); m_pendingEv.pop_front(); return true; } if (m_buffIdx >= m_buffLen) { m_buffIdx = 0; m_buffLen = read(m_wfd, m_buff, sizeof(m_buff)); if (m_buffLen <= 0) { return false; } } inotify_event* ev = (inotify_event*)&m_buff[m_buffIdx]; m_buffIdx += ev->len + sizeof(inotify_event); if (ev->mask & (IN_IGNORED | IN_UNMOUNT)) { Unwatch(ev->wd); continue; } if (ev->mask & (IN_CREATE | IN_MOVED_TO)) { if (ev->mask & IN_ISDIR) { std::string s = m_watchFd[ev->wd] + ev->name; if (ev->mask & IN_MOVED_TO) { AddPathEvent(s.c_str(), ADD); } continue; } } if (ev->mask & IN_MOVED_FROM && ev->mask & IN_ISDIR) { //event can't catch continue; } if (ev->mask & IN_MOVE_SELF) { continue; } if (ev->mask & IN_DELETE) { if (ev->mask & IN_ISDIR) { continue; } } event.clear(); if (ev->mask & (IN_MOVED_TO | IN_CREATE)) { event.type = ADD; } else if (ev->mask & (IN_MOVED_FROM | IN_DELETE)) { event.type = DELETE; } else if (ev->mask & IN_MODIFY) { event.type = MODIFY; } else { event.type = UNKNOWN; } event.name = m_watchFd[ev->wd] + ev->name; return true; } } static bool s_bThreadFinish = true; static pthread_t s_tid; static behaviac::Mutex s_mutex; static behaviac::vector<behaviac::string> s_ModifiedFiles; static void* ThreadFunc(void* arg) { bool isLock = false; const char* path = (char*)arg; InotifyDir inotify; InotifyDir::Event ev; inotify.init(); inotify.Watch(path); while (!s_bThreadFinish) { if (!inotify.EventPoll(ev)) { if (isLock) { isLock = false; s_mutex.Unlock(); } usleep(100); continue; } if (!isLock) { isLock = true; s_mutex.Lock(); } if (ev.type == InotifyDir::MODIFY || ev.type == InotifyDir::ADD) { ev.name.erase(0, strlen(path)); s_ModifiedFiles.push_back(ev.name.c_str()); } } if (isLock) { isLock = false; s_mutex.Unlock(); } return NULL; } #endif bool CFileSystem::StartMonitoringDirectory(const wchar_t* dir) { BEHAVIAC_UNUSED_VAR(dir); #if BEHAVIAC_COMPILER_GCC_LINUX if (!s_bThreadFinish) { return true; } s_bThreadFinish = false; behaviac::wstring dirW = dir; //to use static! static behaviac::string s_buffer = ""; s_buffer = behaviac::StringUtils::Wide2Char(dirW); if (pthread_create(&s_tid, NULL, ThreadFunc, const_cast<char*>(s_buffer.c_str())) < 0) { return false; } //pthread_detach(tid); #endif return true; } void CFileSystem::StopMonitoringDirectory() { #if BEHAVIAC_COMPILER_GCC_LINUX if (!s_bThreadFinish) { s_bThreadFinish = true; pthread_join(s_tid, 0); s_ModifiedFiles.clear(); } #endif } void CFileSystem::GetModifiedFiles(behaviac::vector<behaviac::string>& modifiedFiles) { BEHAVIAC_UNUSED_VAR(modifiedFiles); #if BEHAVIAC_COMPILER_GCC_LINUX modifiedFiles.clear(); if (s_ModifiedFiles.empty()) { return; } behaviac::ScopedLock lock(s_mutex); std::sort(s_ModifiedFiles.begin(), s_ModifiedFiles.end()); s_ModifiedFiles.erase(std::unique(s_ModifiedFiles.begin(), s_ModifiedFiles.end()), s_ModifiedFiles.end()); s_ModifiedFiles.swap(modifiedFiles); //for (behaviac::vector<behaviac::string>::iterator it = s_ModifiedFiles.begin(); it != s_ModifiedFiles.end(); ++it) //{ // behaviac::string& s = *it; // modifiedFiles.push_back(s); //} //s_ModifiedFiles.clear(); #endif } }//namespace behaviac