2448 lines
69 KiB
C++
2448 lines
69 KiB
C++
/** @file
|
|
* @author Edouard DUPIN
|
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
* @license MPL v2.0 (see license file)
|
|
*/
|
|
|
|
|
|
#include <etk/types.hpp>
|
|
#include <etk/os/FSNode.hpp>
|
|
#include <unistd.h>
|
|
#include <cstdlib>
|
|
#include <etk/tool.hpp>
|
|
#include <etk/debug.hpp>
|
|
#include <etk/Map.hpp>
|
|
#include <mutex>
|
|
#ifdef __TARGET_OS__Windows
|
|
#include <tchar.h>
|
|
#include <iostream>
|
|
#include <windows.h>
|
|
#endif
|
|
extern "C" {
|
|
// file browsing ...
|
|
#include <dirent.h>
|
|
#include <sys/stat.h>
|
|
#include <cerrno>
|
|
}
|
|
|
|
#ifdef HAVE_ZIP_DATA
|
|
# include <etk/archive/Archive.hpp>
|
|
#endif
|
|
|
|
|
|
#ifdef __TARGET_OS__Windows
|
|
// For ctime
|
|
#include <time.h>
|
|
#endif
|
|
|
|
#define TK_DBG_MODE TK_VERBOSE
|
|
//#define TK_DBG_MODE TK_DEBUG
|
|
|
|
|
|
#ifdef __TARGET_OS__Windows
|
|
static etk::Vector<etk::String> getListDrive() {
|
|
etk::Vector<etk::String> out;
|
|
int dr_type=99;
|
|
char dr_avail[4096];
|
|
char *temp=dr_avail;
|
|
/* 1st we fill the buffer */
|
|
GetLogicalDriveStrings(4096,dr_avail);
|
|
while(*temp != 0) {
|
|
dr_type=GetDriveType(temp);
|
|
etk::String driveName = etk::replace(etk::String(temp), '\\', '/');
|
|
switch(dr_type) {
|
|
case 0: // Unknown
|
|
TK_WARNING("'" << driveName << "' : Unknown Drive type");
|
|
break;
|
|
case 1: // Invalid
|
|
TK_WARNING("'" << driveName << "' : Drive is invalid");
|
|
break;
|
|
case 2: // Removable Drive
|
|
TK_WARNING("'" << driveName << "' : Removable Drive type");
|
|
out.pushBack(driveName);
|
|
break;
|
|
case 3: // Fixed
|
|
TK_WARNING("'" << driveName << "' : Hard Disk (Fixed) Drive type");
|
|
out.pushBack(driveName);
|
|
break;
|
|
case 4: // Remote
|
|
TK_WARNING("'" << driveName << "' : Remote (Network) Drive type");
|
|
out.pushBack(driveName);
|
|
break;
|
|
case 5: // CDROM
|
|
TK_WARNING("'" << driveName << "' : CD-Rom/DVD-Rom Drive type");
|
|
out.pushBack(driveName);
|
|
break;
|
|
case 6: // RamDrive
|
|
TK_WARNING("'" << driveName << "' : Ram Drive type");
|
|
out.pushBack(driveName);
|
|
break;
|
|
}
|
|
temp += lstrlen(temp) + 1; // incriment the buffer
|
|
}
|
|
return out;
|
|
}
|
|
#else
|
|
static etk::Vector<etk::String> getListDrive() {
|
|
etk::Vector<etk::String> out;
|
|
return out;
|
|
}
|
|
#endif
|
|
|
|
etk::String etk::simplifyPath(etk::String _input) {
|
|
// step 1 : for windows change \ in /:
|
|
TK_DEBUG("Simplify(1) : '" << _input << "'");
|
|
size_t currentPos = 0;
|
|
if (_input.size() == 0) {
|
|
return _input;
|
|
}
|
|
while(currentPos < _input.size()) {
|
|
if (_input[currentPos] == '\\') {
|
|
_input[currentPos] = '/';
|
|
}
|
|
currentPos++;
|
|
continue;
|
|
}
|
|
// step 2 : remove all '//'
|
|
TK_DBG_MODE("Simplify(2) : '" << _input << "'");
|
|
currentPos = 0;
|
|
if (_input.size() <= 1) {
|
|
return _input;
|
|
}
|
|
while(currentPos < _input.size()-1) {
|
|
if ( _input[currentPos] != '/'
|
|
|| _input[currentPos+1] != '/') {
|
|
currentPos++;
|
|
continue;
|
|
}
|
|
_input.erase(currentPos, 1);
|
|
}
|
|
// step 3 : remove all '/./'
|
|
TK_DBG_MODE("Simplify(3) : '" << _input << "'");
|
|
currentPos = 0;
|
|
if (_input.size() <= 1) {
|
|
return _input;
|
|
}
|
|
while( currentPos < _input.size()-2
|
|
&& _input.size() > 2) {
|
|
if ( _input[currentPos] != '/'
|
|
|| _input[currentPos+1] != '.'
|
|
|| _input[currentPos+2] != '/') {
|
|
currentPos++;
|
|
continue;
|
|
}
|
|
_input.erase(currentPos, 2);
|
|
}
|
|
if (end_with(_input, "/.") == true) {
|
|
_input.erase(_input.size()-1, 1);
|
|
}
|
|
// step 4 remove xxx/..
|
|
TK_DBG_MODE("Simplify(4) : '" << _input << "'");
|
|
size_t lastSlashPos = etk::String::npos;
|
|
currentPos = 0;
|
|
while( currentPos < _input.size()-2
|
|
&& _input.size() > 2) {
|
|
if ( _input[currentPos] != '/'
|
|
|| _input[currentPos+1] != '.'
|
|
|| _input[currentPos+2] != '.') {
|
|
if (_input[currentPos] == '/') {
|
|
lastSlashPos = currentPos;
|
|
}
|
|
currentPos++;
|
|
continue;
|
|
}
|
|
if (lastSlashPos == etk::String::npos) {
|
|
currentPos++;
|
|
continue;
|
|
}
|
|
_input.erase(lastSlashPos, currentPos+2-lastSlashPos+1);
|
|
TK_DEBUG("update : '" << _input << "'");
|
|
lastSlashPos = etk::String::npos;
|
|
currentPos = 0;
|
|
}
|
|
TK_DBG_MODE("Simplify(5) : '" << _input << "'");
|
|
if (_input.size() == 0) {
|
|
_input = "/";
|
|
}
|
|
#ifdef __TARGET_OS__Windows
|
|
etk::String base;
|
|
base += _input[0];
|
|
base += ":";
|
|
if ( _input == base + "/../"
|
|
|| _input == base + "/.."
|
|
|| _input == base + "/./"
|
|
|| _input == base + "/."
|
|
|| _input == "/") {
|
|
_input = base + "/";
|
|
}
|
|
#else
|
|
if ( _input == "/../"
|
|
|| _input == "/.."
|
|
|| _input == "/./"
|
|
|| _input == "/.") {
|
|
_input = "/";
|
|
}
|
|
#endif
|
|
|
|
TK_DEBUG("Simplify(end) : '" << _input << "'");
|
|
return _input;
|
|
}
|
|
static int32_t FSNODE_LOCAL_mkdir(const char* _path, mode_t _mode) {
|
|
struct stat st;
|
|
int32_t status = 0;
|
|
if (stat(_path, &st) != 0) {
|
|
/* Directory does not exist. EEXIST for race condition */
|
|
#ifdef __TARGET_OS__Windows
|
|
if(0!=mkdir(_path)
|
|
#else
|
|
if(0!=mkdir(_path, _mode)
|
|
#endif
|
|
&& errno != EEXIST) {
|
|
status = -1;
|
|
}
|
|
} else if (!S_ISDIR(st.st_mode)) {
|
|
errno = ENOTDIR;
|
|
status = -1;
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
static int32_t FSNODE_LOCAL_mkPath(const char* _path, mode_t _mode) {
|
|
char *pp;
|
|
char *sp;
|
|
int status;
|
|
char *copypath = strdup(_path);
|
|
if (copypath == nullptr) {
|
|
return -1;
|
|
}
|
|
status = 0;
|
|
pp = copypath;
|
|
while (status == 0 && (sp = strchr(pp, '/')) != 0) {
|
|
if (sp != pp) {
|
|
/* Neither root nor double slash in path */
|
|
*sp = '\0';
|
|
status = FSNODE_LOCAL_mkdir(copypath, _mode);
|
|
*sp = '/';
|
|
}
|
|
pp = sp + 1;
|
|
}
|
|
if (status == 0) {
|
|
status = FSNODE_LOCAL_mkdir(_path, _mode);
|
|
}
|
|
free(copypath);
|
|
return (status);
|
|
}
|
|
|
|
static bool FSNODE_LOCAL_exist(const etk::String& _path) {
|
|
struct stat st;
|
|
int32_t status = 0;
|
|
if (stat(_path.c_str(), &st) != 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
static bool FSNODE_LOCAL_isDirectory(const etk::String& _path) {
|
|
struct stat st;
|
|
int32_t status = 0;
|
|
if (stat(_path.c_str(), &st) != 0) {
|
|
return false;
|
|
} else if (!S_ISDIR(st.st_mode)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
static bool FSNODE_LOCAL_isFile(const etk::String& _path) {
|
|
struct stat st;
|
|
int32_t status = 0;
|
|
if (stat(_path.c_str(), &st) != 0) {
|
|
return false;
|
|
} else if (!S_ISREG(st.st_mode)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
static etk::String FSNODE_LOCAL_join(const etk::String& _path1, const etk::String& _path2) {
|
|
etk::String out = etk::replace(_path1, '\\', '/');
|
|
if (out.size() == 0) {
|
|
out = etk::replace(_path2, '\\', '/');;
|
|
return out;
|
|
}
|
|
if (_path2.size() == 0) {
|
|
return out;
|
|
}
|
|
if (out[out.size()-1] != '/') {
|
|
out += "/";
|
|
}
|
|
out += etk::replace(_path2, '\\', '/');;
|
|
return out;
|
|
}
|
|
|
|
|
|
static std::mutex& getNodeMutex() {
|
|
static std::mutex g_nodeMutex;
|
|
return g_nodeMutex;
|
|
}
|
|
|
|
// zip file of the apk file for Android ==> set to zip file apk access
|
|
static etk::String s_fileAPK = "";
|
|
static etk::String baseApplName = "ewolNoName";
|
|
static etk::String baseApplPath = "ewolNoName";
|
|
static etk::String baseRunPath = "/";
|
|
static etk::String baseRunPathInHome = "/";
|
|
#if defined(__TARGET_OS__Android)
|
|
static etk::String baseFolderHome = "/sdcard/"; // home folder
|
|
static etk::String baseFolderData = "assets/"; // program Data
|
|
static etk::String baseFolderDataUser = "/sdcard/.tmp/userData/"; // Data specific user (local modification)
|
|
static etk::String baseFolderCache = "/sdcard/.tmp/cache/"; // Temporary data (can be removed the next time)
|
|
#elif defined(__TARGET_OS__Windows)
|
|
static etk::String baseFolderHome = "c:/test"; // home folder
|
|
static etk::String baseFolderData = "c:/test/share/"; // program Data
|
|
static etk::String baseFolderDataUser = "c:/test/userData/"; // Data specific user (local modification)
|
|
static etk::String baseFolderCache = "c:/Windows/Temp/ewol/"; // Temporary data (can be removed the next time)
|
|
#else
|
|
static etk::String baseFolderHome = "~"; // home folder
|
|
static etk::String baseFolderData = "share/"; // program Data
|
|
static etk::String baseFolderDataUser = "~/.tmp/userData/"; // Data specific user (local modification)
|
|
static etk::String baseFolderCache = "~/.tmp/cache/"; // Temporary data (can be removed the next time)
|
|
#endif
|
|
|
|
etk::String etk::FSNodeGetApplicationName() {
|
|
return baseApplName;
|
|
}
|
|
|
|
etk::String etk::FSNodeGetApplicationPath() {
|
|
return baseApplPath;
|
|
}
|
|
|
|
etk::String etk::FSNodeGetHomePath() {
|
|
return baseFolderHome;
|
|
}
|
|
|
|
#ifdef HAVE_ZIP_DATA
|
|
static etk::Archive* s_APKArchive = nullptr;
|
|
static void loadAPK(const etk::String& _apkPath) {
|
|
#ifdef __TARGET_OS__Android
|
|
std::unique_lock<std::mutex> lock(getNodeMutex());
|
|
TK_INFO("Loading APK '" << _apkPath << "'");
|
|
s_APKArchive = etk::Archive::load(_apkPath);
|
|
TK_ASSERT(s_APKArchive != nullptr, "Error loading APK ... '" << _apkPath << "'");
|
|
#else
|
|
TK_INFO("Loading Intarnal data '" << _apkPath << "'");
|
|
//s_APKArchive = etk::Archive::loadPackage(_apkPath);
|
|
s_APKArchive = etk::Archive::load(_apkPath);
|
|
/*
|
|
FILE* tmp = fopen(_apkPath.c_str(), "r");
|
|
if (tmp == nullptr) {
|
|
TK_ERROR("File does not exist ...");
|
|
} else {
|
|
TK_ERROR("File open OK ...");
|
|
}
|
|
*/
|
|
TK_ASSERT(s_APKArchive != nullptr, "Error loading PKG ... '" << _apkPath << "'");
|
|
#endif
|
|
#ifdef DEBUG
|
|
//Just for debug, print APK contents
|
|
s_APKArchive->display();
|
|
#endif
|
|
}
|
|
#ifdef __TARGET_OS__Windows
|
|
static void loadAPKBin(const etk::String& _apkPath) {
|
|
TK_ERROR("Loading Intarnal data '" << _apkPath << "'");
|
|
s_APKArchive = etk::Archive::loadPackage(_apkPath);
|
|
TK_ASSERT(s_APKArchive != nullptr, "Error loading PKG ... '" << _apkPath << "'");
|
|
#ifdef DEBUG
|
|
//Just for debug, print APK contents
|
|
s_APKArchive->display();
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
// for specific device contraint :
|
|
void etk::setBaseFolderData(const char* _folder, const char* _applName) {
|
|
#ifdef __TARGET_OS__Android
|
|
{
|
|
std::unique_lock<std::mutex> lock(getNodeMutex());
|
|
baseFolderData = "assets/";
|
|
if (_applName != nullptr) {
|
|
baseFolderData += _applName;
|
|
baseFolderData += "/";
|
|
}
|
|
s_fileAPK = _folder;
|
|
}
|
|
TK_INFO("baseFolderData : '" << baseFolderData << "'");
|
|
loadAPK(s_fileAPK);
|
|
#else
|
|
TK_WARNING("Not Availlable Outside Android");
|
|
#endif
|
|
}
|
|
|
|
void etk::setBaseFolderDataUser(const char* _folder) {
|
|
std::unique_lock<std::mutex> lock(getNodeMutex());
|
|
#ifdef __TARGET_OS__Android
|
|
baseFolderDataUser = _folder;
|
|
TK_INFO("baseFolderDataUser : '" << baseFolderDataUser << "'");
|
|
#else
|
|
TK_WARNING("Not Availlable Outside Android");
|
|
#endif
|
|
}
|
|
|
|
void etk::setBaseFolderCache(const char* _folder) {
|
|
std::unique_lock<std::mutex> lock(getNodeMutex());
|
|
#ifdef __TARGET_OS__Android
|
|
baseFolderCache = _folder;
|
|
TK_INFO("baseFolderCache : '" << baseFolderCache << "'");
|
|
#else
|
|
TK_WARNING("Not Availlable Outside Android");
|
|
#endif
|
|
}
|
|
|
|
etk::String l_argZero = "";
|
|
void etk::setArgZero(const etk::String& _val) {
|
|
std::unique_lock<std::mutex> lock(getNodeMutex());
|
|
l_argZero = _val;
|
|
// set defaiult application name ...
|
|
etk::Vector<etk::String> elems = etk::split(_val, '/');
|
|
etk::initDefaultFolder(elems[elems.size()-1].c_str());
|
|
}
|
|
/*
|
|
On Unixes with /proc really straight and realiable way is to:
|
|
readlink("/proc/self/exe", buf, bufsize) (Linux)
|
|
readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)
|
|
readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)
|
|
On Unixes without /proc (i.e. if above fails):
|
|
If argv[0] starts with "/" (absolute path) this is the path.
|
|
Otherwise if argv[0] contains "/" (relative path) append it to cwd (assuming it hasn't been changed yet).
|
|
Otherwise search directories in $PATH for executable argv[0].
|
|
Afterwards it may be reasonable to check whether the executable isn't actually a symlink. If it is resolve it relative to the symlink directory.
|
|
This step is not necessary in /proc method (at least for Linux). There the proc symlink points directly to executable.
|
|
Note that it is up to the calling process to set argv[0] correctly. It is right most of the times however there are occasions when the calling process cannot be trusted (ex. setuid executable).
|
|
On Windows: use GetModuleFileName(nullptr, buf, bufsize)
|
|
*/
|
|
etk::String getApplicationPath() {
|
|
etk::String binaryName = "no-name";
|
|
char binaryCompleatePath[FILENAME_MAX];
|
|
memset(binaryCompleatePath, 0, FILENAME_MAX);
|
|
#ifdef __TARGET_OS__Windows
|
|
GetModuleFileName(nullptr, binaryCompleatePath, FILENAME_MAX);
|
|
if (strlen(binaryCompleatePath) == 0) {
|
|
TK_CRITICAL("Can not get the binary position in the tree ==> this is really bad ...");
|
|
} else {
|
|
binaryName = binaryCompleatePath;
|
|
}
|
|
#else
|
|
// check it to prevent test mode in local folder ...
|
|
// Generic Linux system
|
|
readlink("/proc/self/exe", binaryCompleatePath, FILENAME_MAX);
|
|
if(strlen(binaryCompleatePath) != 0) {
|
|
binaryName = binaryCompleatePath;
|
|
return binaryName;
|
|
}
|
|
// generic FreeBSD system
|
|
memset(binaryCompleatePath, 0, FILENAME_MAX);
|
|
readlink("/proc/curproc/file", binaryCompleatePath, FILENAME_MAX);
|
|
if(strlen(binaryCompleatePath) != 0) {
|
|
binaryName = binaryCompleatePath;
|
|
return binaryName;
|
|
}
|
|
// generic Solaris system
|
|
memset(binaryCompleatePath, 0, FILENAME_MAX);
|
|
readlink("/proc/self/path/a.out", binaryCompleatePath, FILENAME_MAX);
|
|
if(strlen(binaryCompleatePath) != 0) {
|
|
binaryName = binaryCompleatePath;
|
|
return binaryName;
|
|
}
|
|
// now we are in a really bad case ...
|
|
if (l_argZero.size() == 0) {
|
|
TK_CRITICAL("Can not get the binary position in the tree ==> this is really bad ... arg 0 is as bad as other ...");
|
|
return binaryName;
|
|
}
|
|
TK_VERBOSE("Parse arg0 = '" << l_argZero << "' start with '/' ???");
|
|
if (l_argZero[0] == '/') {
|
|
binaryName = l_argZero;
|
|
return etk::simplifyPath(binaryName);
|
|
}
|
|
TK_VERBOSE("Parse arg0 = '" << l_argZero << "' try add PWD");
|
|
char * basicPathPWD = getenv("PWD");
|
|
if (nullptr != basicPathPWD) {
|
|
etk::String testCompleatePath = basicPathPWD;
|
|
testCompleatePath += "/";
|
|
testCompleatePath += l_argZero;
|
|
// check if the element existed :
|
|
TK_VERBOSE("test path: '" << testCompleatePath << "'");
|
|
memset(binaryCompleatePath, 0, FILENAME_MAX);
|
|
struct stat statProperty;
|
|
if (-1 != stat(testCompleatePath.c_str(), &statProperty)) {
|
|
//Normal case when the file does not exist ... ==> the it was in unknow mode ...
|
|
binaryName = testCompleatePath;
|
|
TK_VERBOSE("find real name = '" << binaryName << "'");
|
|
return etk::simplifyPath(binaryName);
|
|
}
|
|
}
|
|
//char * basicPathPATH = getenv("PATH");
|
|
//if (nullptr != basicPathPWD) {
|
|
// TODO : bad case ...
|
|
//}
|
|
// and now we will really in a bad mood ...
|
|
#endif
|
|
TK_INFO("Binary name : " << binaryName);
|
|
return binaryName;
|
|
}
|
|
|
|
void etk::initDefaultFolder(const char* _applName) {
|
|
baseApplName = _applName;
|
|
char cCurrentPath[FILENAME_MAX];
|
|
char * basicPath = getenv("HOME");
|
|
if (nullptr == basicPath) {
|
|
TK_WARNING("ERROR while trying to get the path of the home folder");
|
|
#if defined(__TARGET_OS__Windows)
|
|
baseFolderHome = "c:/";
|
|
#elif defined(__TARGET_OS__Android)
|
|
baseFolderHome = "/sdcard";
|
|
#else
|
|
baseFolderHome = "~";
|
|
#endif
|
|
} else {
|
|
baseFolderHome = basicPath;
|
|
}
|
|
if (!getcwd(cCurrentPath, FILENAME_MAX)) {
|
|
baseRunPath = ".";
|
|
baseRunPathInHome = ".";
|
|
} else {
|
|
cCurrentPath[FILENAME_MAX - 1] = '\0';
|
|
if (cCurrentPath[0] == '/') {
|
|
baseRunPath = cCurrentPath;
|
|
} else {
|
|
baseRunPath = etk::String("/") + cCurrentPath;
|
|
}
|
|
if (start_with(baseRunPath, baseFolderHome) == true) {
|
|
baseRunPathInHome = etk::String(baseRunPath, baseFolderHome.size());
|
|
} else {
|
|
baseRunPathInHome = baseRunPath;
|
|
}
|
|
}
|
|
TK_DBG_MODE("Find Basic running PATH : '" << baseRunPath << "'");
|
|
#if defined(__TARGET_OS__Web)
|
|
loadAPK("data.zip");
|
|
baseFolderData = "zz_generic_zz/";
|
|
#endif
|
|
#if !defined(__TARGET_OS__Android) \
|
|
&& !defined(__TARGET_OS__Web)
|
|
etk::String binaryPath = getApplicationPath();
|
|
binaryPath = etk::replace(binaryPath, '\\', '/');
|
|
size_t pos = binaryPath.rfind('/');
|
|
etk::String binaryName(binaryPath, pos);
|
|
while( binaryName.size() >= 2
|
|
&& binaryName[1] == '/') {
|
|
binaryName = etk::String(binaryName.begin()+1, binaryName.end());
|
|
}
|
|
binaryPath.erase(binaryPath.begin() + pos, binaryPath.end());
|
|
baseApplPath = binaryPath;
|
|
TK_INFO("Bianry name : '" << binaryPath << "' && '" << binaryName << "'" );
|
|
#ifdef __TARGET_OS__Windows
|
|
// check if we have a data path just near the .exe file
|
|
if ( FSNODE_LOCAL_exist(FSNODE_LOCAL_join(binaryPath,"data")) == true
|
|
&& FSNODE_LOCAL_isDirectory(FSNODE_LOCAL_join(binaryPath,"data")) == true) {
|
|
TK_INFO("Find data in external 'data' path");
|
|
baseFolderData = binaryPath;
|
|
baseFolderData += "/data/";
|
|
}
|
|
#ifdef HAVE_ZIP_DATA
|
|
// check if we have a data.zip just near the .exe file
|
|
else if ( FSNODE_LOCAL_exist(FSNODE_LOCAL_join(binaryPath,"data.zip")) == true
|
|
&& FSNODE_LOCAL_isFile(FSNODE_LOCAL_join(binaryPath,"data.zip")) == true) {
|
|
TK_INFO("Find data in external data.zip file");
|
|
loadAPK(FSNODE_LOCAL_join(binaryPath,"data.zip"));
|
|
baseFolderData = "";
|
|
}
|
|
// check if the application named .pkg.exe (this mean the data is inside the executable as a zip next the binary)
|
|
else if (etk::end_with(binaryName, ".pkg.exe") == true) {
|
|
TK_INFO("Find data in external internal exe package");
|
|
loadAPKBin(FSNODE_LOCAL_join(binaryPath,binaryName));
|
|
baseFolderData = "";
|
|
}
|
|
#endif
|
|
baseFolderData += etk::String(binaryName.begin()+1, binaryName.end()-4);
|
|
baseFolderData += "/";
|
|
|
|
baseFolderDataUser = binaryPath;
|
|
baseFolderDataUser += "/user/";
|
|
|
|
baseFolderCache = binaryPath;
|
|
baseFolderCache += "/tmp/";
|
|
#else
|
|
// if element is installed :
|
|
baseFolderData = "/usr/share";
|
|
baseFolderData += binaryName;
|
|
baseFolderData += "/";
|
|
|
|
etk::String theoricInstalledName = "/usr/bin";
|
|
theoricInstalledName += binaryName;
|
|
TK_DEBUG(" position : '" << binaryPath << "' installed position : '" << theoricInstalledName << "'");
|
|
if (binaryPath != theoricInstalledName) {
|
|
// can also be in application package:
|
|
etk::String endWith = binaryName + ".app/bin";
|
|
if (etk::end_with(binaryPath, endWith) == true) {
|
|
TK_INFO("Application istall in user standalone mode: '" << binaryPath << "'");
|
|
} else {
|
|
TK_INFO(" base path is not correct try to find it : (must only appear in test and not when installed) base name : '" << binaryPath << "'");
|
|
}
|
|
// remove bin/applName
|
|
baseFolderData = binaryPath;
|
|
#if defined(__TARGET_OS__MacOs)
|
|
baseFolderData += "/../Resources/";
|
|
#elif defined(__TARGET_OS__IOs)
|
|
baseFolderData += "/share/";
|
|
#else
|
|
baseFolderData += "/../share/";
|
|
#endif
|
|
baseFolderData += binaryName;
|
|
baseFolderData += "/";
|
|
baseFolderData = simplifyPath(baseFolderData);
|
|
#if defined(__TARGET_OS__Linux) \
|
|
|| defined(__TARGET_OS__buildroot)
|
|
{
|
|
struct stat statProperty;
|
|
if (-1 == stat(baseFolderData.c_str(), &statProperty)) {
|
|
//Normal case when the file does not exist ... ==> the it was in unknow mode ...
|
|
TK_INFO("Path does not exit : '" << baseFolderData << "' ==> try tools data folder ...");
|
|
baseFolderData += "/../../share/";
|
|
baseFolderData += binaryName;
|
|
baseFolderData += "/";
|
|
baseFolderData = simplifyPath(baseFolderData);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#if defined(__TARGET_OS__IOs)
|
|
baseFolderDataUser = binaryPath;
|
|
baseFolderDataUser += "/../Documents/";
|
|
baseFolderDataUser = simplifyPath(baseFolderDataUser);
|
|
#else
|
|
baseFolderDataUser = baseFolderHome;
|
|
baseFolderDataUser += "/.local/share/";
|
|
baseFolderDataUser += binaryName;
|
|
baseFolderDataUser += "/";
|
|
#endif
|
|
#if defined(__TARGET_OS__IOs)
|
|
baseFolderCache = binaryPath;
|
|
baseFolderCache += "/../tmp/";
|
|
baseFolderCache = simplifyPath(baseFolderCache);
|
|
#else
|
|
baseFolderCache = "/tmp/";
|
|
baseFolderCache += binaryName;
|
|
baseFolderCache += "/";
|
|
#endif
|
|
#endif
|
|
#endif
|
|
TK_INFO("baseRunPath : '" << baseRunPath << "'");
|
|
TK_INFO("baseRunPathInHome : ~|HOME: + '" << baseRunPathInHome << "'");
|
|
TK_INFO("baseFolderHome : '" << baseFolderHome << "'");
|
|
TK_INFO("baseFolderData : '" << baseFolderData << "'");
|
|
TK_INFO("baseFolderDataUser : '" << baseFolderDataUser << "'");
|
|
TK_INFO("baseFolderCache : '" << baseFolderCache << "'");
|
|
}
|
|
|
|
etk::String etk::getUserHomeFolder() {
|
|
return baseFolderHome;
|
|
}
|
|
|
|
etk::String etk::getUserRunFolder() {
|
|
return baseRunPath;
|
|
}
|
|
|
|
|
|
#ifdef HAVE_ZIP_DATA
|
|
bool etk::FSNode::loadDataZip() {
|
|
std::unique_lock<std::mutex> lock(getNodeMutex());
|
|
if (s_APKArchive == nullptr) {
|
|
return false;
|
|
}
|
|
if (m_zipContent != nullptr) {
|
|
return true;
|
|
}
|
|
if (false == s_APKArchive->exist(m_systemFileName)) {
|
|
return false;
|
|
}
|
|
m_zipContent = &s_APKArchive->getContent(m_systemFileName);
|
|
if (m_zipContent != nullptr) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
|
|
etk::FSNode::FSNode(const etk::String& _nodeName) :
|
|
m_userFileName(""),
|
|
m_type(etk::FSNType_unknow),
|
|
m_typeNode(etk::typeNode_unknow),
|
|
m_PointerFile(nullptr),
|
|
m_timeCreate(0),
|
|
m_timeModify(0),
|
|
m_timeAccess(0)
|
|
#ifdef HAVE_ZIP_DATA
|
|
, m_zipContent(nullptr),
|
|
m_zipReadingOffset(-1)
|
|
#endif
|
|
{
|
|
privateSetName(_nodeName);
|
|
}
|
|
|
|
|
|
etk::FSNode::~FSNode() {
|
|
if( nullptr != m_PointerFile
|
|
#ifdef HAVE_ZIP_DATA
|
|
|| nullptr != m_zipContent
|
|
#endif
|
|
) {
|
|
TK_ERROR("Missing to close the file : \"" << *this << "\"");
|
|
fileClose();
|
|
}
|
|
}
|
|
|
|
|
|
void etk::FSNode::sortElementList(etk::Vector<etk::FSNode *>& _list) {
|
|
etk::Vector<etk::FSNode *> tmpList = _list;
|
|
_list.clear();
|
|
for(size_t iii=0; iii<tmpList.size(); iii++) {
|
|
if (nullptr != tmpList[iii]) {
|
|
size_t findPos = 0;
|
|
for(size_t jjj=0; jjj<_list.size(); jjj++) {
|
|
//EWOL_DEBUG("compare : \""<<*tmpList[iii] << "\" and \"" << *m_listDirectory[jjj] << "\"");
|
|
if (_list[jjj]!=nullptr) {
|
|
// TODO : Do something better : this methode is a litthe hard!!!
|
|
if (etk::toupper(tmpList[iii]->getNameFile()) > etk::toupper(_list[jjj]->getNameFile())) {
|
|
findPos = jjj+1;
|
|
}
|
|
}
|
|
}
|
|
//EWOL_DEBUG("position="<<findPos);
|
|
_list.insert(_list.begin() + findPos, tmpList[iii]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void etk::FSNode::privateSetName(etk::String _newName) {
|
|
if( nullptr != m_PointerFile
|
|
#ifdef HAVE_ZIP_DATA
|
|
|| nullptr != m_zipContent
|
|
#endif
|
|
) {
|
|
TK_ERROR("Missing to close the file : '" << *this << "'");
|
|
fileClose();
|
|
}
|
|
// set right at nullptr ...
|
|
m_rights = 0;
|
|
|
|
m_libSearch = "";
|
|
if ( _newName.size() > 0
|
|
&& _newName[0] == '{') {
|
|
// special case: Reference of searching in subLib folder ==> library use-case
|
|
size_t firstPos = _newName.find('}');
|
|
if (firstPos != etk::String::npos) {
|
|
// we find a theme name : We extracted it :
|
|
m_libSearch = etk::String(_newName, 1, firstPos-1);
|
|
_newName = etk::String(_newName, firstPos+1);
|
|
} else {
|
|
TK_ERROR("start a path name with '{' without '}' : " << _newName);
|
|
// remove in case the {
|
|
_newName = etk::String(_newName, 1);
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_ZIP_DATA
|
|
m_zipContent = nullptr;
|
|
m_zipReadingOffset = 0;
|
|
#endif
|
|
// Reset ALL DATA :
|
|
m_userFileName = "";
|
|
m_type = etk::FSNType_unknow;
|
|
TK_DBG_MODE("1 : Set Name : \"" << _newName << "\"");
|
|
|
|
// generate destination name in case of the input error
|
|
etk::String destFilename;
|
|
if (_newName.size() == 0) {
|
|
// if no name ==> go to the root Folder
|
|
destFilename = "ROOT:";
|
|
} else {
|
|
destFilename = _newName;
|
|
}
|
|
|
|
bool isRootFolder = false;
|
|
#ifdef __TARGET_OS__Windows
|
|
for (char iii='a' ; iii<='z' ; iii++) {
|
|
char tmpVal[10];
|
|
char tmpValMaj[10];
|
|
sprintf(tmpVal, "%c:/", iii);
|
|
sprintf(tmpValMaj, "%c:/", iii+'A'-'a');
|
|
if( etk::start_with(destFilename, tmpVal) == true
|
|
|| etk::start_with(destFilename, tmpValMaj) == true) {
|
|
isRootFolder = true;
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
isRootFolder = destFilename[0] == '/';
|
|
#endif
|
|
if( start_with(destFilename, "ROOT:") == true
|
|
|| start_with(destFilename, "root:") == true ) {
|
|
TK_DBG_MODE(" ==> detect root 2 ");
|
|
destFilename.erase(0, 5);
|
|
m_type = etk::FSNType_direct;
|
|
if(start_with(destFilename, "~") == true) {
|
|
destFilename.erase(0, 1);
|
|
m_type = etk::FSNType_home;
|
|
}
|
|
} else if( start_with(destFilename, "DIRECT:") == true
|
|
|| start_with(destFilename, "direct:") == true ) {
|
|
TK_DBG_MODE(" ==> detect direct");
|
|
destFilename.erase(0, 7);
|
|
m_type = etk::FSNType_direct;
|
|
if(start_with(destFilename, "~") == true) {
|
|
destFilename.erase(0, 1);
|
|
m_type = etk::FSNType_home;
|
|
}
|
|
} else if( start_with(destFilename, "DATA:") == true
|
|
|| start_with(destFilename, "data:") == true ) {
|
|
TK_DBG_MODE(" ==> detect data");
|
|
destFilename.erase(0, 5);
|
|
m_type = etk::FSNType_data;
|
|
} else if( start_with(destFilename, "USERDATA:") == true
|
|
|| start_with(destFilename, "userdata:") == true ) {
|
|
TK_DBG_MODE(" ==> detect User-data");
|
|
destFilename.erase(0, 9);
|
|
m_type = etk::FSNType_userData;
|
|
} else if( start_with(destFilename, "CACHE:") == true
|
|
|| start_with(destFilename, "cache:") == true ) {
|
|
TK_DBG_MODE(" ==> detect Cache");
|
|
destFilename.erase(0, 6);
|
|
m_type = etk::FSNType_cache;
|
|
} else if( start_with(destFilename, "THEME:") == true
|
|
|| start_with(destFilename, "theme:") == true ) {
|
|
TK_DBG_MODE(" ==> detect theme");
|
|
destFilename.erase(0, 6);
|
|
m_type = etk::FSNType_theme;
|
|
} else if(start_with(destFilename, "./") == true) {
|
|
TK_DBG_MODE(" ==> detect relatif 1");
|
|
destFilename.erase(0, 2);
|
|
while (destFilename.size()>0 && destFilename[0] == '/') {
|
|
destFilename.erase(0, 1);
|
|
}
|
|
m_type = etk::FSNType_relatif;
|
|
} else if( start_with(destFilename, "REL:") == true
|
|
|| start_with(destFilename, "rel:") == true ) {
|
|
TK_DBG_MODE(" ==> detect relatif 2");
|
|
destFilename.erase(0, 4);
|
|
while (destFilename.size()>0 && destFilename[0] == '/') {
|
|
destFilename.erase(0, 1);
|
|
}
|
|
m_type = etk::FSNType_relatif;
|
|
} else if(start_with(destFilename, baseRunPath) == true) {
|
|
TK_DBG_MODE(" ==> detect relatif 3 (run path=" << baseRunPath << ")");
|
|
destFilename.erase(0, baseRunPath.size());
|
|
while (destFilename.size()>0 && destFilename[0] == '/') {
|
|
destFilename.erase(0, 1);
|
|
}
|
|
m_type = etk::FSNType_relatif;
|
|
} else if (( baseRunPath != baseRunPathInHome
|
|
&& ( start_with(destFilename, "~" + baseRunPathInHome) == true
|
|
|| start_with(destFilename, "HOME:" + baseRunPathInHome) == true
|
|
|| start_with(destFilename, "home:" + baseRunPathInHome) == true ) ) ) {
|
|
TK_DBG_MODE(" ==> detect relatif 4");
|
|
if (start_with(destFilename, "~" + baseRunPathInHome) == true) {
|
|
destFilename.erase(0, 1);
|
|
} else {
|
|
destFilename.erase(0, 5);
|
|
}
|
|
destFilename.erase(0, baseRunPathInHome.size());
|
|
while (destFilename.size()>0 && destFilename[0] == '/') {
|
|
destFilename.erase(0, 1);
|
|
}
|
|
m_type = etk::FSNType_relatif;
|
|
} else if(start_with(destFilename, "~")) {
|
|
TK_DBG_MODE(" ==> detect home 2");
|
|
destFilename.erase(0, 1);
|
|
m_type = etk::FSNType_home;
|
|
} else if( start_with(destFilename, "HOME:") == true
|
|
|| start_with(destFilename, "home:") == true ) {
|
|
TK_DBG_MODE(" ==> detect home 3");
|
|
destFilename.erase(0, 5);
|
|
m_type = etk::FSNType_home;
|
|
if(start_with(destFilename, "~") == true) {
|
|
destFilename.erase(0, 1);
|
|
}
|
|
} else if (start_with(destFilename, baseFolderHome) == true) {
|
|
TK_DBG_MODE(" ==> detect home");
|
|
destFilename.erase(0, baseFolderHome.size());
|
|
m_type = etk::FSNType_home;
|
|
} else if(isRootFolder == true) {
|
|
TK_DBG_MODE(" ==> detect root");
|
|
#ifdef __TARGET_OS__Windows
|
|
destFilename.erase(0, 3);
|
|
#else
|
|
destFilename.erase(0, 1);
|
|
#endif
|
|
m_type = etk::FSNType_direct;
|
|
} else {
|
|
TK_DBG_MODE(" ==> detect other");
|
|
// nothing to remove
|
|
//Other type is Relative :
|
|
m_type = etk::FSNType_relatif;
|
|
}
|
|
m_userFileName = destFilename;
|
|
TK_DBG_MODE("3 : parse done : [" << m_type << "]->\"" << m_userFileName << "\"");
|
|
|
|
// Now we reduce the path with all un-needed ../ and other thinks ...
|
|
// TODO : Do it whith link and the other sub thinks ...
|
|
m_userFileName = simplifyPath(m_userFileName);
|
|
TK_DBG_MODE("4 : Path simplification : [" << m_type << "]->\"" << m_userFileName << "\"");
|
|
|
|
// Now we generate the real FS path:
|
|
generateFileSystemPath();
|
|
TK_DBG_MODE("5 : file System Real name : \"" << m_systemFileName << "\"");
|
|
|
|
// now we get all the right if the file existed:
|
|
updateFileSystemProperty();
|
|
TK_DBG_MODE("6 : type : [" << m_typeNode << "] right :" << m_rights);
|
|
}
|
|
|
|
bool directCheckFile(etk::String _tmpFileNameDirect, bool _checkInAPKIfNeeded = false) {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if (true == _checkInAPKIfNeeded) {
|
|
if( nullptr != s_APKArchive
|
|
&& true == s_APKArchive->exist(_tmpFileNameDirect) ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
// tmpStat Buffer :
|
|
struct stat statProperty;
|
|
if (-1 == stat(_tmpFileNameDirect.c_str(), &statProperty)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
// Now we generate the real FS path:
|
|
void etk::FSNode::generateFileSystemPath() {
|
|
bool forceLibFolder(false);
|
|
if ( m_libSearch.size() > 0
|
|
&& m_libSearch[0] == '@') {
|
|
forceLibFolder = true;
|
|
}
|
|
switch (m_type) {
|
|
default:
|
|
case etk::FSNType_unknow:
|
|
m_systemFileName = baseFolderHome;
|
|
break;
|
|
case etk::FSNType_direct:
|
|
m_systemFileName = "/";
|
|
break;
|
|
case etk::FSNType_relatif: {
|
|
// Get the command came from the running of the program :
|
|
char cCurrentPath[FILENAME_MAX];
|
|
if (!getcwd(cCurrentPath, FILENAME_MAX)) {
|
|
TK_WARNING("Can not get the curent path");
|
|
cCurrentPath[0] = '/';
|
|
cCurrentPath[1] = '\0';
|
|
}
|
|
cCurrentPath[FILENAME_MAX - 1] = '\0';
|
|
m_systemFileName = cCurrentPath;
|
|
//m_systemFileName += "/";
|
|
break;
|
|
}
|
|
case etk::FSNType_home:
|
|
m_systemFileName = baseFolderHome;
|
|
break;
|
|
case etk::FSNType_data:
|
|
{
|
|
TK_DBG_MODE("DATA lib : '" << m_libSearch << "' => '" << m_userFileName << "' forceLib = " << forceLibFolder);
|
|
// search the correct folder:
|
|
if (forceLibFolder == false) {
|
|
// check in the application folder.
|
|
TK_DBG_MODE("DATA Search in application data:");
|
|
m_systemFileName = simplifyPath(baseFolderData + "/" + m_userFileName);
|
|
if (directCheckFile(m_systemFileName, true) == true) {
|
|
return;
|
|
}
|
|
if (m_libSearch.size() == 0) {
|
|
return;
|
|
}
|
|
}
|
|
m_systemFileName = simplifyPath(baseFolderData + "/../" + m_libSearch + "/" + m_userFileName);
|
|
return;
|
|
}
|
|
break;
|
|
case etk::FSNType_userData:
|
|
m_systemFileName = baseFolderDataUser;
|
|
break;
|
|
case etk::FSNType_cache:
|
|
m_systemFileName = baseFolderCache;
|
|
break;
|
|
case etk::FSNType_theme:
|
|
case etk::FSNType_themeData:
|
|
{
|
|
etk::String themeName("");
|
|
etk::String basicName(m_userFileName);
|
|
size_t firstPos = m_userFileName.find(':');
|
|
if (firstPos != etk::String::npos) {
|
|
// we find a theme name : We extracted it :
|
|
themeName = etk::String(m_userFileName, 0, firstPos);
|
|
basicName = etk::String(m_userFileName, firstPos+1);
|
|
}
|
|
TK_DBG_MODE(" THEME party : \"" << themeName << "\" => \"" << basicName << "\"");
|
|
themeName = etk::theme::getName(themeName);
|
|
etk::String themeNameDefault = etk::theme::getNameDefault(themeName);
|
|
TK_DBG_MODE(" ==> theme Folder \"" << themeName << "\"");
|
|
// search the correct folder :
|
|
if (themeName == "") {
|
|
TK_WARNING("no theme name detected : set it to '" << themeNameDefault << "'");
|
|
} else if (themeName != themeNameDefault) {
|
|
if (forceLibFolder == false) {
|
|
// Selected theme :
|
|
// check in the user data :
|
|
m_systemFileName = simplifyPath(baseFolderDataUser + "theme/" + themeName + "/" + basicName);
|
|
if (directCheckFile(m_systemFileName) == true) {
|
|
return;
|
|
}
|
|
// check in the Appl data :
|
|
m_systemFileName = simplifyPath(baseFolderData + "theme/" + themeName + "/" + basicName);
|
|
if (directCheckFile(m_systemFileName, true) == true) {
|
|
m_type = etk::FSNType_themeData;
|
|
return;
|
|
}
|
|
}
|
|
if (m_libSearch.size() > 0) {
|
|
// Selected theme :
|
|
// check in the user data :
|
|
m_systemFileName = simplifyPath(baseFolderDataUser + "/../" + m_libSearch + "/theme/" + themeName + "/" + basicName);
|
|
if (directCheckFile(m_systemFileName) == true) {
|
|
return;
|
|
}
|
|
// check in the Appl data :
|
|
m_systemFileName = simplifyPath(baseFolderData + "/../" + m_libSearch + "/theme/" + themeName + "/" + basicName);
|
|
if (directCheckFile(m_systemFileName, true) == true) {
|
|
m_type = etk::FSNType_themeData;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// default theme :
|
|
if (forceLibFolder == false) {
|
|
// check in the user data :
|
|
m_systemFileName = simplifyPath(baseFolderDataUser + "theme/" + themeNameDefault + "/" + basicName);
|
|
if (true==directCheckFile(m_systemFileName)) {
|
|
return;
|
|
}
|
|
// check in the Appl data : In every case we return this one ...
|
|
m_systemFileName = simplifyPath(baseFolderData + "theme/" + themeNameDefault + "/" + basicName);
|
|
if (true==directCheckFile(m_systemFileName, true)) {
|
|
m_type = etk::FSNType_themeData;
|
|
return;
|
|
}
|
|
if (m_libSearch.size() == 0) {
|
|
m_type = etk::FSNType_unknow;
|
|
return;
|
|
}
|
|
}
|
|
// check in the user data :
|
|
m_systemFileName = simplifyPath(baseFolderDataUser + "/../" + m_libSearch + "/theme/" + themeNameDefault + "/" + basicName);
|
|
if (directCheckFile(m_systemFileName) == true) {
|
|
return;
|
|
}
|
|
// check in the Appl data : In every case we return this one ...
|
|
m_systemFileName = simplifyPath(baseFolderData + "/../" + m_libSearch + "/theme/" + themeNameDefault + "/" + basicName);
|
|
if (directCheckFile(m_systemFileName, true) == true) {
|
|
m_type = etk::FSNType_themeData;
|
|
return;
|
|
}
|
|
m_type = etk::FSNType_unknow;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
if (m_userFileName != "") {
|
|
if ( m_systemFileName.size()>0
|
|
&& m_systemFileName[m_systemFileName.size()-1] != '/') {
|
|
m_systemFileName += '/';
|
|
}
|
|
m_systemFileName += m_userFileName;
|
|
}
|
|
}
|
|
|
|
|
|
// now we get all the right if the file existed:
|
|
void etk::FSNode::updateFileSystemProperty() {
|
|
// clean general properties :
|
|
m_rights.clear();
|
|
m_timeCreate = 0;
|
|
m_timeModify = 0;
|
|
m_timeAccess = 0;
|
|
m_idOwner = 0;
|
|
m_idGroup = 0;
|
|
// File type is not knowns ...
|
|
m_typeNode=typeNode_unknow;
|
|
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
// ----------------------------------------
|
|
// = Check if it was a folder : =
|
|
// ----------------------------------------
|
|
etk::String folderName = "/";
|
|
if (etk::end_with(m_systemFileName, folderName) == true) {
|
|
folderName = m_systemFileName;
|
|
} else {
|
|
folderName = m_systemFileName + "/";
|
|
}
|
|
// note : Zip does not support other think than file ...
|
|
if (s_APKArchive == nullptr) {
|
|
TK_ERROR("NOT Find the File in APK : '" << m_systemFileName << "'");
|
|
return;
|
|
}
|
|
if (s_APKArchive->exist(m_systemFileName) == true) {
|
|
m_typeNode=typeNode_file;
|
|
m_rights.setUserReadable(true);
|
|
TK_DBG_MODE("Find a File in APK : '" << m_systemFileName << "'");
|
|
return;
|
|
}
|
|
// TODO : Set the time of the file (time program compilation)
|
|
// TODO : Set the USER ID in the group and the user Id ...
|
|
if (m_systemFileName[m_systemFileName.size()-1] == '/') {
|
|
//Might be a folder ==> check if it existed in the start files ...
|
|
for (int iii=0; iii<s_APKArchive->size(); iii++) {
|
|
etk::String filename = s_APKArchive->getName(iii);
|
|
if (start_with(filename, m_systemFileName) == true) {
|
|
m_typeNode=etk::typeNode_folder;
|
|
m_rights.setUserReadable(true);
|
|
m_rights.setUserRunable(true);
|
|
TK_DBG_MODE("Find a Folder in APK : '" << m_systemFileName << "'");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// special case of the user does not set tyhe / at the end of the path ...
|
|
if (m_systemFileName[m_systemFileName.size()-1] != '/') {
|
|
etk::String tmpName = m_systemFileName + '/';
|
|
//Might be a folder ==> check if it existed in the start files ...
|
|
for (int iii=0; iii<s_APKArchive->size(); iii++) {
|
|
etk::String filename = s_APKArchive->getName(iii);
|
|
if (start_with(filename, tmpName) == true) {
|
|
m_typeNode = etk::typeNode_folder;
|
|
m_rights.setUserReadable(true);
|
|
m_rights.setUserRunable(true);
|
|
TK_DBG_MODE("Find a Folder in APK : '" << m_systemFileName << "'");
|
|
m_systemFileName += '/';
|
|
if (m_userFileName[m_userFileName.size()-1] != '/') {
|
|
m_userFileName += '/';
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
TK_WARNING("File existed ??? in APK : '" << m_systemFileName << "'");
|
|
return;
|
|
}
|
|
#endif
|
|
// tmpStat Buffer :
|
|
struct stat statProperty;
|
|
if (-1 == stat(m_systemFileName.c_str(), &statProperty)) {
|
|
//Normal case when the file does not exist ... ==> the it was in unknow mode ...
|
|
return;
|
|
}
|
|
|
|
switch (statProperty.st_mode & S_IFMT) {
|
|
case S_IFBLK: m_typeNode=etk::typeNode_block; break;
|
|
case S_IFCHR: m_typeNode=etk::typeNode_character; break;
|
|
case S_IFDIR: m_typeNode=etk::typeNode_folder; break;
|
|
case S_IFIFO: m_typeNode=etk::typeNode_fifo; break;
|
|
#ifndef __TARGET_OS__Windows
|
|
case S_IFLNK: m_typeNode=etk::typeNode_link; break;
|
|
#endif
|
|
case S_IFREG: m_typeNode=etk::typeNode_file; break;
|
|
#ifndef __TARGET_OS__Windows
|
|
case S_IFSOCK: m_typeNode=etk::typeNode_socket; break;
|
|
#endif
|
|
default: m_typeNode=etk::typeNode_unknow; break;
|
|
}
|
|
// Right
|
|
m_rights = statProperty.st_mode;
|
|
m_idOwner = (int32_t) statProperty.st_uid;
|
|
m_idGroup = (int32_t) statProperty.st_gid;
|
|
m_timeCreate = statProperty.st_ctime;
|
|
m_timeModify = statProperty.st_mtime;
|
|
m_timeAccess = statProperty.st_atime;
|
|
|
|
return;
|
|
}
|
|
|
|
bool etk::FSNode::setRight(etk::FSNodeRight _newRight) {
|
|
// TODO : ...
|
|
TK_ERROR("Can not set the new rights ...");
|
|
return false;
|
|
}
|
|
|
|
void etk::FSNode::setName(const etk::String& _newName) {
|
|
privateSetName(_newName);
|
|
}
|
|
|
|
etk::String etk::FSNode::getNameFolder() const {
|
|
size_t lastPos = m_systemFileName.rfind('/');
|
|
if (lastPos != etk::String::npos) {
|
|
return etk::String(m_systemFileName, 0, lastPos);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
etk::String etk::FSNode::getFileSystemName() const {
|
|
return m_systemFileName;
|
|
}
|
|
|
|
etk::String etk::FSNode::getName() const {
|
|
etk::String output("");
|
|
if (m_libSearch.size() > 0) {
|
|
output += "{";
|
|
output += m_libSearch;
|
|
output += "}";
|
|
}
|
|
switch (m_type) {
|
|
default:
|
|
case etk::FSNType_unknow:
|
|
output += "HOME:";
|
|
break;
|
|
case etk::FSNType_direct:
|
|
output += "/";
|
|
break;
|
|
case etk::FSNType_relatif:
|
|
output += "REL:";
|
|
break;
|
|
case etk::FSNType_home:
|
|
output += "~";
|
|
break;
|
|
case etk::FSNType_data:
|
|
output += "DATA:";
|
|
break;
|
|
case etk::FSNType_userData:
|
|
output += "USERDATA:";
|
|
break;
|
|
case etk::FSNType_cache:
|
|
output += "CACHE:";
|
|
break;
|
|
case etk::FSNType_theme:
|
|
case etk::FSNType_themeData:
|
|
output += "THEME:";
|
|
break;
|
|
}
|
|
output += m_userFileName;
|
|
return output;
|
|
}
|
|
|
|
etk::String etk::FSNode::getNameFile() const {
|
|
size_t lastPos = m_systemFileName.rfind('/');
|
|
if (lastPos != etk::String::npos) {
|
|
return etk::String(m_systemFileName, lastPos+1);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
etk::String etk::FSNode::getRelativeFolder() const {
|
|
etk::String tmppp = getName();
|
|
TK_DBG_MODE("get REF folder : " << tmppp );
|
|
switch (m_typeNode) {
|
|
case etk::typeNode_unknow:
|
|
case etk::typeNode_folder:
|
|
case etk::typeNode_link:
|
|
if (tmppp[tmppp.size()-1] == '/') {
|
|
TK_DBG_MODE(" ==> : " << tmppp );
|
|
return tmppp;
|
|
} else {
|
|
etk::String tmpVal = tmppp;
|
|
tmpVal += "/";
|
|
TK_DBG_MODE(" ==> : " << tmppp );
|
|
return tmpVal;
|
|
}
|
|
break;
|
|
case etk::typeNode_block:
|
|
case etk::typeNode_character:
|
|
case etk::typeNode_fifo:
|
|
case etk::typeNode_file:
|
|
case etk::typeNode_socket:
|
|
default:
|
|
break;
|
|
}
|
|
size_t lastPos = tmppp.rfind('/');
|
|
if (lastPos != etk::String::npos) {
|
|
TK_DBG_MODE(" ==> : " << etk::String(tmppp, 0, lastPos+1) );
|
|
return etk::String(tmppp, 0, lastPos+1);
|
|
}
|
|
lastPos = tmppp.rfind(':');
|
|
if (lastPos != etk::String::npos) {
|
|
TK_DBG_MODE(" ==> : " << etk::String(tmppp, 0, lastPos+1) );
|
|
return etk::String(tmppp, 0, lastPos+1);
|
|
}
|
|
TK_DBG_MODE(" ==> : ''" );
|
|
return "";
|
|
}
|
|
|
|
|
|
bool etk::FSNode::touch() {
|
|
TK_DEBUG("Touch FILE : " << getName());
|
|
//just open in write an close ==> this will update the time
|
|
if (fileOpenAppend() == false) {
|
|
return false;
|
|
}
|
|
bool ret = fileClose();
|
|
// update internal time and properties ...
|
|
updateFileSystemProperty();
|
|
return ret;
|
|
}
|
|
|
|
bool etk::FSNode::move(const etk::String& _path) {
|
|
etk::FSNode tmpDst(_path);
|
|
if (tmpDst.exist() == true) {
|
|
tmpDst.remove();
|
|
}
|
|
TK_DEBUG("Move : \"" << getFileSystemName() << "\" ==> \"" << tmpDst.getFileSystemName() << "\"");
|
|
// create path to be sure it exist ...
|
|
TK_VERBOSE("create path: '" << tmpDst.getNameFolder() << "'");
|
|
FSNODE_LOCAL_mkPath(tmpDst.getNameFolder().c_str() , 0755);
|
|
int32_t res = rename(getFileSystemName().c_str(), tmpDst.getFileSystemName().c_str());
|
|
if (res!=0) {
|
|
TK_ERROR("Can not move the file: '" << getFileSystemName() << "' ==> '" << tmpDst.getFileSystemName() << "'");
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool etk::FSNode::remove() {
|
|
if (getNodeType()==etk::typeNode_folder) {
|
|
// remove the folder
|
|
if( 0!=rmdir(m_systemFileName.c_str()) ) {
|
|
if (ENOTEMPTY == errno) {
|
|
TK_ERROR("The Directory is not empty...");
|
|
}
|
|
return false;
|
|
}
|
|
} else {
|
|
if( 0!=unlink(m_systemFileName.c_str()) ) {
|
|
return false;
|
|
}
|
|
}
|
|
// update internal time and properties ...
|
|
updateFileSystemProperty();
|
|
return true;
|
|
}
|
|
|
|
uint64_t etk::FSNode::timeCreated() const {
|
|
return m_timeCreate;
|
|
}
|
|
|
|
etk::String etk::FSNode::timeCreatedString() const {
|
|
time_t tmpVal = (int32_t)m_timeCreate;
|
|
etk::String tmpTime = ctime(&tmpVal);
|
|
if (tmpTime[tmpTime.size()-1] == '\n') {
|
|
tmpTime.erase(tmpTime.end()-1);
|
|
}
|
|
return tmpTime;
|
|
}
|
|
|
|
uint64_t etk::FSNode::timeModified() const {
|
|
return m_timeModify;
|
|
}
|
|
|
|
etk::String etk::FSNode::timeModifiedString() const {
|
|
time_t tmpVal = (int32_t)m_timeModify;
|
|
etk::String tmpTime = ctime(&tmpVal);
|
|
if (tmpTime[tmpTime.size()-1] == '\n') {
|
|
tmpTime.erase(tmpTime.end()-1);
|
|
}
|
|
return tmpTime;
|
|
}
|
|
|
|
uint64_t etk::FSNode::timeAccessed() const {
|
|
return m_timeAccess;
|
|
}
|
|
|
|
etk::String etk::FSNode::timeAccessedString() const {
|
|
time_t tmpVal = (int32_t)m_timeAccess;
|
|
etk::String tmpTime = ctime(&tmpVal);
|
|
if (tmpTime[tmpTime.size()-1] == '\n') {
|
|
tmpTime.erase(tmpTime.end()-1);
|
|
}
|
|
return tmpTime;
|
|
}
|
|
/*
|
|
Operator :
|
|
*/
|
|
const etk::FSNode& etk::FSNode::operator= (const etk::FSNode &_obj ) {
|
|
// avoid copy to itself
|
|
if( this == &_obj ) {
|
|
return *this;
|
|
}
|
|
if( nullptr != m_PointerFile
|
|
#ifdef HAVE_ZIP_DATA
|
|
|| nullptr != m_zipContent
|
|
#endif
|
|
) {
|
|
TK_ERROR("Missing close the file : " << *this);
|
|
fileClose();
|
|
m_PointerFile = nullptr;
|
|
}
|
|
#ifdef HAVE_ZIP_DATA
|
|
m_zipContent = nullptr;
|
|
m_zipReadingOffset = 0;
|
|
#endif
|
|
etk::String tmppp = _obj.getName();
|
|
privateSetName(tmppp);
|
|
return *this;
|
|
}
|
|
bool etk::FSNode::operator== (const etk::FSNode& _obj ) const {
|
|
if( this == &_obj ) {
|
|
return true;
|
|
}
|
|
if( _obj.m_userFileName == m_userFileName
|
|
&& _obj.m_systemFileName == m_systemFileName
|
|
&& _obj.m_type == m_type ) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool etk::FSNode::operator!= (const etk::FSNode& _obj ) const {
|
|
return !(*this == _obj);
|
|
}
|
|
|
|
etk::Stream& etk::operator <<(etk::Stream &_os, const etk::FSNode &_obj) {
|
|
if (_obj.m_libSearch.size() != 0) {
|
|
_os << "{" << _obj.m_libSearch << "}";
|
|
}
|
|
_os << "[" << _obj.m_type << "]->\"" << _obj.m_userFileName << "\"";
|
|
return _os;
|
|
}
|
|
|
|
etk::Stream& etk::operator <<(etk::Stream &_os, const enum etk::FSNType &_obj) {
|
|
switch (_obj)
|
|
{
|
|
case etk::FSNType_unknow:
|
|
_os << "FSNType_unknow";
|
|
break;
|
|
case etk::FSNType_direct:
|
|
_os << "FSNType_direct";
|
|
break;
|
|
case etk::FSNType_relatif:
|
|
_os << "FSNType_relatif";
|
|
break;
|
|
case etk::FSNType_home:
|
|
_os << "FSNType_home";
|
|
break;
|
|
case etk::FSNType_data:
|
|
_os << "FSNType_data";
|
|
break;
|
|
case etk::FSNType_userData:
|
|
_os << "FSNType_userData";
|
|
break;
|
|
case etk::FSNType_cache:
|
|
_os << "FSNType_cache";
|
|
break;
|
|
case etk::FSNType_theme:
|
|
_os << "FSNType_theme";
|
|
break;
|
|
case etk::FSNType_themeData:
|
|
_os << "FSNType_theme(DATA)";
|
|
break;
|
|
default:
|
|
_os << "FSN_TYPE_????";
|
|
break;
|
|
}
|
|
return _os;
|
|
}
|
|
|
|
etk::Stream& etk::operator <<(etk::Stream &_os, const enum etk::typeNode &_obj) {
|
|
switch (_obj) {
|
|
case etk::typeNode_unknow:
|
|
_os << "typeNode_unknow";
|
|
break;
|
|
case etk::typeNode_block:
|
|
_os << "typeNode_block";
|
|
break;
|
|
case etk::typeNode_character:
|
|
_os << "typeNode_character";
|
|
break;
|
|
case etk::typeNode_folder:
|
|
_os << "typeNode_folder";
|
|
break;
|
|
case etk::typeNode_fifo:
|
|
_os << "typeNode_fifo";
|
|
break;
|
|
case etk::typeNode_link:
|
|
_os << "typeNode_link";
|
|
break;
|
|
case etk::typeNode_file:
|
|
_os << "typeNode_file";
|
|
break;
|
|
case etk::typeNode_socket:
|
|
_os << "typeNode_socket";
|
|
break;
|
|
default:
|
|
_os << "typeNode_????";
|
|
break;
|
|
}
|
|
return _os;
|
|
}
|
|
|
|
/*
|
|
Folder specific :
|
|
*/
|
|
int64_t etk::FSNode::folderCount() {
|
|
#ifdef __TARGET_OS__Windows
|
|
/*
|
|
if (m_systemFileName.size() == 0) {
|
|
return getListDrive().size();
|
|
}
|
|
*/
|
|
#endif
|
|
int64_t counter=0;
|
|
DIR *dir = nullptr;
|
|
struct dirent *ent = nullptr;
|
|
dir = opendir(m_systemFileName.c_str());
|
|
if (dir != nullptr) {
|
|
// for each element in the drectory...
|
|
while ((ent = readdir(dir)) != nullptr) {
|
|
etk::String tmpName(ent->d_name);
|
|
if( tmpName == "."
|
|
|| tmpName == ".." ) {
|
|
// do nothing ...
|
|
continue;
|
|
}
|
|
// just increment counter :
|
|
counter++;
|
|
}
|
|
closedir(dir);
|
|
} else {
|
|
TK_ERROR("could not open directory : \"" << *this << "\"");
|
|
}
|
|
return counter;
|
|
}
|
|
|
|
etk::Vector<etk::FSNode *> etk::FSNode::folderGetSubList(bool _showHidenFile, bool _getFolderAndOther, bool _getFile, bool _temporaryFile) {
|
|
etk::String filter=".*";
|
|
if (_temporaryFile == true) {
|
|
filter = ".*(~|\\.bck|\\.tmp)";
|
|
}
|
|
return etk::FSNode::folderGetSubList(_showHidenFile, _getFolderAndOther, _getFile, filter);
|
|
}
|
|
|
|
etk::Vector<etk::FSNode *> etk::FSNode::folderGetSubList(bool _showHidenFile, bool _getFolderAndOther, bool _getFile, const etk::String& _filter) {
|
|
TK_TODO("implement filter ... ");
|
|
etk::Vector<etk::FSNode*> tmpp;
|
|
#ifdef __TARGET_OS__Windows
|
|
/*
|
|
if (m_systemFileName.size() == 0) {
|
|
etk::Vector<etk::String> listDrive = getListDrive();
|
|
for (auto &it : listDrive) {
|
|
tmpp.pushBack(new etk::FSNode(it));
|
|
}
|
|
return tmpp;
|
|
}
|
|
*/
|
|
#endif
|
|
// regenerate the next list :
|
|
etk::FSNode * tmpEmement = nullptr;
|
|
if (m_typeNode != etk::typeNode_folder ) {
|
|
return tmpp;
|
|
}
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
etk::Vector<etk::String> listAdded;
|
|
etk::String assetsName = baseFolderData;
|
|
etk::String FolderName = getNameFolder();
|
|
if (s_APKArchive==nullptr) {
|
|
return tmpp;
|
|
}
|
|
if (FolderName[FolderName.size()-1] != '/') {
|
|
FolderName += "/";
|
|
}
|
|
for (int iii=0; iii<s_APKArchive->size(); iii++) {
|
|
etk::String filename = s_APKArchive->getName(iii);
|
|
if (start_with(filename, FolderName) == true) {
|
|
//TK_INFO("pppppp '" << filename << "'");
|
|
//TK_INFO(" '" << FolderName << "'");
|
|
etk::String tmpString(filename, FolderName.size());
|
|
size_t pos = tmpString.find('/');
|
|
if (pos != etk::String::npos) {
|
|
// a simple folder :
|
|
tmpString = etk::String(tmpString, 0, pos);
|
|
}
|
|
//TK_INFO("plop '" << getName() << "' '" << tmpString << "'");
|
|
tmpString = getName() + tmpString;
|
|
bool findIt = false;
|
|
for (size_t jjj = 0; jjj < listAdded.size(); ++jjj) {
|
|
if (listAdded[jjj] == tmpString) {
|
|
findIt = true;
|
|
break;
|
|
}
|
|
}
|
|
if (findIt == false) {
|
|
listAdded.pushBack(tmpString);
|
|
tmpEmement = new etk::FSNode(tmpString);
|
|
if (nullptr == tmpEmement) {
|
|
TK_ERROR("allocation error ... of ewol::FSNode");
|
|
continue;
|
|
}
|
|
TK_VERBOSE("find element : '" << tmpString << "' --> " << *tmpEmement);
|
|
tmpp.pushBack(tmpEmement);
|
|
tmpEmement = nullptr;
|
|
}
|
|
}
|
|
}
|
|
return tmpp;
|
|
}
|
|
#endif
|
|
DIR *dir = nullptr;
|
|
struct dirent *ent = nullptr;
|
|
dir = opendir(m_systemFileName.c_str());
|
|
if (dir != nullptr) {
|
|
// for each element in the drectory...
|
|
while ((ent = readdir(dir)) != nullptr) {
|
|
etk::String tmpName(ent->d_name);
|
|
TK_VERBOSE(" search in folder\"" << tmpName << "\"");
|
|
if( tmpName == "."
|
|
|| tmpName == ".." ) {
|
|
// do nothing ...
|
|
continue;
|
|
}
|
|
if( false == start_with(tmpName, ".")
|
|
|| true == _showHidenFile) {
|
|
tmpEmement = new etk::FSNode(getRelativeFolder()+tmpName);
|
|
if (nullptr == tmpEmement) {
|
|
TK_ERROR("allocation error ... of ewol::FSNode");
|
|
continue;
|
|
}
|
|
if(tmpEmement->getNodeType() == etk::typeNode_file) {
|
|
if (true == _getFile) {
|
|
tmpp.pushBack(tmpEmement);
|
|
} else {
|
|
delete(tmpEmement);
|
|
tmpEmement = nullptr;
|
|
}
|
|
} else if (_getFolderAndOther) {
|
|
tmpp.pushBack(tmpEmement);
|
|
} else {
|
|
delete(tmpEmement);
|
|
tmpEmement = nullptr;
|
|
}
|
|
}
|
|
}
|
|
closedir(dir);
|
|
} else {
|
|
TK_ERROR("could not open directory : \"" << *this << "\"");
|
|
}
|
|
|
|
// reorder the files
|
|
sortElementList(tmpp);
|
|
|
|
return tmpp;
|
|
}
|
|
|
|
etk::Vector<etk::String> etk::FSNode::folderGetSub(bool _getFolder, bool _getFile, const etk::String& _filter) {
|
|
TK_TODO("implement filter ... ");
|
|
#ifdef __TARGET_OS__Windows
|
|
/*
|
|
if (m_systemFileName.size() == 0) {
|
|
return getListDrive();
|
|
}
|
|
*/
|
|
#endif
|
|
etk::Vector<etk::String> out;
|
|
// regenerate the next list :
|
|
etk::FSNode * tmpEmement = nullptr;
|
|
if (m_typeNode != etk::typeNode_folder ) {
|
|
return out;
|
|
}
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
etk::Vector<etk::String> listAdded;
|
|
etk::String assetsName = baseFolderData;
|
|
etk::String FolderName = getNameFolder();
|
|
if (s_APKArchive == nullptr) {
|
|
return out;
|
|
}
|
|
if (FolderName[FolderName.size()-1] != '/') {
|
|
FolderName += "/";
|
|
}
|
|
for (int32_t iii=0; iii<s_APKArchive->size(); iii++) {
|
|
etk::String filename = s_APKArchive->getName(iii);
|
|
if (start_with(filename, FolderName) == true) {
|
|
etk::String tmpString(filename, FolderName.size());
|
|
size_t pos = tmpString.find('/');
|
|
if (pos != etk::String::npos) {
|
|
// a simple folder :
|
|
tmpString = etk::String(tmpString, 0, pos+1);
|
|
}
|
|
tmpString = getName() + tmpString;
|
|
bool findIt = false;
|
|
for (size_t jjj = 0; jjj < listAdded.size(); ++jjj) {
|
|
if (listAdded[jjj] == tmpString) {
|
|
findIt = true;
|
|
break;
|
|
}
|
|
}
|
|
if (findIt == false) {
|
|
listAdded.pushBack(tmpString);
|
|
etk::FSNode tmpEmement(tmpString);
|
|
TK_VERBOSE("find element : '" << tmpString << "' --> " << tmpEmement);
|
|
out.pushBack(tmpEmement.getName());
|
|
}
|
|
}
|
|
}
|
|
std::sort(out.begin(), out.end());
|
|
return out;
|
|
}
|
|
#endif
|
|
DIR *dir = nullptr;
|
|
struct dirent *ent = nullptr;
|
|
dir = opendir(m_systemFileName.c_str());
|
|
if (dir != nullptr) {
|
|
// for each element in the drectory...
|
|
while ((ent = readdir(dir)) != nullptr) {
|
|
etk::String tmpName(ent->d_name);
|
|
TK_VERBOSE(" search in folder\"" << tmpName << "\"");
|
|
if( tmpName == "."
|
|
|| tmpName == ".." ) {
|
|
// do nothing ...
|
|
continue;
|
|
}
|
|
etk::FSNode tmpEmement(getRelativeFolder()+tmpName);
|
|
if(tmpEmement.getNodeType() == etk::typeNode_file) {
|
|
if (_getFile == true) {
|
|
out.pushBack(tmpEmement.getName());
|
|
}
|
|
} else if (_getFolder) {
|
|
out.pushBack(tmpEmement.getName());
|
|
}
|
|
}
|
|
closedir(dir);
|
|
} else {
|
|
TK_ERROR("could not open directory : \"" << *this << "\"");
|
|
}
|
|
// reorder the files
|
|
etk::sort(out);
|
|
return out;
|
|
}
|
|
|
|
etk::FSNode etk::FSNode::folderGetParent() {
|
|
etk::FSNode tmpp;
|
|
return tmpp;
|
|
}
|
|
|
|
void etk::FSNode::folderGetRecursiveFiles(etk::Vector<etk::String>& _output, bool _recursiveEnable) {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
etk::String assetsName = baseFolderData;
|
|
etk::String FolderName = getNameFolder();
|
|
if (s_APKArchive==nullptr) {
|
|
return;
|
|
}
|
|
for (int iii=0; iii<s_APKArchive->size(); iii++) {
|
|
etk::String filename = s_APKArchive->getName(iii);
|
|
if (start_with(filename, FolderName) == true) {
|
|
etk::String tmpString;
|
|
if(m_type == etk::FSNType_data) {
|
|
tmpString = "DATA:";
|
|
} else {
|
|
tmpString = "THEME:";
|
|
}
|
|
if (start_with(filename, assetsName) == true) {
|
|
filename.erase(0,assetsName.size());
|
|
}
|
|
tmpString += filename;
|
|
_output.pushBack(tmpString);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
// regenerate the next list :
|
|
etk::FSNode * tmpEmement;
|
|
DIR *dir = nullptr;
|
|
struct dirent *ent = nullptr;
|
|
dir = opendir(m_systemFileName.c_str());
|
|
//TK_DEBUG(" ** open Folder : " << m_systemFileName );
|
|
if (dir != nullptr) {
|
|
// for each element in the drectory...
|
|
while ((ent = readdir(dir)) != nullptr) {
|
|
etk::String tmpName(ent->d_name);
|
|
if( tmpName == "."
|
|
|| tmpName == ".." ) {
|
|
// do nothing ...
|
|
continue;
|
|
}
|
|
//TK_DEBUG(" find : " << ent->d_name << " ==> " << (GetRelativeFolder()+tmpName));
|
|
tmpEmement = new etk::FSNode(getRelativeFolder()+tmpName);
|
|
if (nullptr != tmpEmement) {
|
|
if(tmpEmement->getNodeType() == etk::typeNode_file) {
|
|
etk::String tmpVal = tmpEmement->getName();
|
|
_output.pushBack(tmpVal);
|
|
}
|
|
if(tmpEmement->getNodeType() == etk::typeNode_folder) {
|
|
if (true==_recursiveEnable) {
|
|
tmpEmement->folderGetRecursiveFiles(_output, _recursiveEnable);
|
|
}
|
|
}
|
|
delete(tmpEmement);
|
|
tmpEmement = nullptr;
|
|
} else {
|
|
TK_ERROR("allocation error ... of ewol::FSNode");
|
|
continue;
|
|
}
|
|
}
|
|
closedir(dir);
|
|
} else {
|
|
TK_ERROR("could not open directory : \"" << *this << "\"");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
File Specific :
|
|
*/
|
|
bool etk::FSNode::fileHasExtention() {
|
|
size_t lastPos = m_userFileName.rfind('.');
|
|
if( lastPos != etk::String::npos // Find a . at the fist position .jdlskjdfklj ==> hiden file
|
|
&& m_userFileName.size() != lastPos ) { // Remove file ended with .
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
etk::String etk::FSNode::fileGetExtention() {
|
|
size_t lastPos = m_userFileName.rfind('.');
|
|
if( lastPos != etk::String::npos // Find a . at the fist position .jdlskjdfklj ==> hiden file
|
|
&& m_userFileName.size() != lastPos ) { // Remove file ended with .
|
|
// Get the FileName
|
|
return etk::String(m_userFileName, lastPos+1);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
uint64_t etk::FSNode::fileSize() {
|
|
if (m_typeNode != etk::typeNode_file) {
|
|
TK_ERROR("Request size of a non file node : " << m_typeNode);
|
|
return 0;
|
|
}
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
if (loadDataZip() == true) {
|
|
return m_zipContent->getTheoricSize();
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
// Note : this is a proper methode to get the file size for Big files ... otherwithe the size is limited at 2^31 bytes
|
|
// tmpStat Buffer :
|
|
struct stat statProperty;
|
|
if (stat(m_systemFileName.c_str(), &statProperty) == -1) {
|
|
//Normal case when the file does not exist ... ==> the it was in unknow mode ...
|
|
TK_ERROR("mlkmlkmlkmlkmlkmlk");
|
|
return 0;
|
|
}
|
|
TK_VERBOSE(" file size : " << (int64_t)statProperty.st_size << " bytes");
|
|
if ((uint64_t)statProperty.st_size <= 0) {
|
|
return 0;
|
|
}
|
|
return (uint64_t)statProperty.st_size;
|
|
}
|
|
|
|
|
|
bool etk::FSNode::fileOpenRead() {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
if (loadDataZip() == false) {
|
|
return false;
|
|
}
|
|
std::unique_lock<std::mutex> lock(getNodeMutex());
|
|
s_APKArchive->open(m_systemFileName);
|
|
return m_zipContent->getTheoricSize() == m_zipContent->size();
|
|
}
|
|
#endif
|
|
if (m_PointerFile != nullptr) {
|
|
TK_CRITICAL("File Already open : " << *this);
|
|
return true;
|
|
}
|
|
TK_VERBOSE(" Read file : " << m_systemFileName);
|
|
m_PointerFile = fopen(m_systemFileName.c_str(),"rb");
|
|
if(m_PointerFile == nullptr) {
|
|
TK_ERROR("Can not find the file " << *this );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool etk::FSNode::fileOpenWrite() {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( etk::FSNType_data == m_type
|
|
|| etk::FSNType_themeData == m_type) {
|
|
return false;
|
|
}
|
|
#endif
|
|
if (m_PointerFile != nullptr) {
|
|
TK_CRITICAL("File Already open : " << *this);
|
|
return true;
|
|
}
|
|
FSNODE_LOCAL_mkPath(getNameFolder().c_str() , 0744);
|
|
TK_VERBOSE("Write file : " << m_systemFileName);
|
|
m_PointerFile = fopen(m_systemFileName.c_str(),"wb");
|
|
if(m_PointerFile == nullptr) {
|
|
TK_ERROR("Can not find the file " << *this);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool etk::FSNode::fileOpenAppend() {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( etk::FSNType_data == m_type
|
|
|| etk::FSNType_themeData == m_type) {
|
|
return false;
|
|
}
|
|
#endif
|
|
if (m_PointerFile != nullptr) {
|
|
TK_CRITICAL("File Already open : " << *this);
|
|
return true;
|
|
}
|
|
FSNODE_LOCAL_mkPath(getNameFolder().c_str() , 0744);
|
|
|
|
TK_VERBOSE("Append file : " << m_systemFileName);
|
|
|
|
m_PointerFile = fopen(m_systemFileName.c_str(),"ab");
|
|
if(m_PointerFile == nullptr) {
|
|
TK_ERROR("Can not find the file " << *this);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool etk::FSNode::fileIsOpen() {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( etk::FSNType_data == m_type
|
|
|| etk::FSNType_themeData == m_type) {
|
|
if (m_zipContent == nullptr) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
if (m_PointerFile == nullptr) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool etk::FSNode::fileClose() {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( etk::FSNType_data == m_type
|
|
|| etk::FSNType_themeData == m_type) {
|
|
if (m_zipContent == nullptr) {
|
|
TK_CRITICAL("File Already closed : " << *this);
|
|
return false;
|
|
}
|
|
s_APKArchive->close(m_systemFileName);
|
|
m_zipContent = nullptr;
|
|
m_zipReadingOffset = 0;
|
|
return true;
|
|
}
|
|
#endif
|
|
if (m_PointerFile == nullptr) {
|
|
TK_CRITICAL("File Already closed : " << *this);
|
|
return false;
|
|
}
|
|
fclose(m_PointerFile);
|
|
m_PointerFile = nullptr;
|
|
return true;
|
|
}
|
|
|
|
char* etk::FSNode::fileGets(char* _elementLine, int64_t _maxData) {
|
|
memset(_elementLine, 0, _maxData);
|
|
#ifdef HAVE_ZIP_DATA
|
|
char * element = _elementLine;
|
|
int64_t outSize = 0;
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {//char * tmpData = internalDataFiles[iii].data + m_readingOffset;
|
|
if (m_zipContent == nullptr) {
|
|
element[0] = '\0';
|
|
return nullptr;
|
|
}
|
|
if (m_zipReadingOffset >= m_zipContent->size()) {
|
|
element[0] = '\0';
|
|
return nullptr;
|
|
}
|
|
while (((char*)m_zipContent->data())[m_zipReadingOffset] != '\0') {
|
|
if( ((char*)m_zipContent->data())[m_zipReadingOffset] == '\n'
|
|
|| ((char*)m_zipContent->data())[m_zipReadingOffset] == '\r') {
|
|
*element = ((char*)m_zipContent->data())[m_zipReadingOffset];
|
|
element++;
|
|
m_zipReadingOffset++;
|
|
*element = '\0';
|
|
return _elementLine;
|
|
}
|
|
*element = ((char*)m_zipContent->data())[m_zipReadingOffset];
|
|
element++;
|
|
m_zipReadingOffset++;
|
|
if (m_zipReadingOffset>=m_zipContent->size()) {
|
|
*element = '\0';
|
|
return _elementLine;
|
|
}
|
|
// check maxData Size ...
|
|
if (outSize>=_maxData-1) {
|
|
*element = '\0';
|
|
return _elementLine;
|
|
}
|
|
outSize++;
|
|
}
|
|
if (outSize == 0) {
|
|
return nullptr;
|
|
} else {
|
|
// send last line
|
|
return _elementLine;
|
|
}
|
|
}
|
|
#endif
|
|
return fgets(_elementLine, _maxData, m_PointerFile);
|
|
}
|
|
|
|
char etk::FSNode::fileGet() {
|
|
char data='\0';
|
|
if (fileRead(&data, 1, 1)!=1) {
|
|
return '\0';
|
|
}
|
|
return data;
|
|
}
|
|
|
|
bool etk::FSNode::fileGets(etk::String& _output) {
|
|
_output.clear();
|
|
char tmp = fileGet();
|
|
while ( tmp != '\0'
|
|
&& tmp != '\n') {
|
|
_output += tmp;
|
|
tmp = fileGet();
|
|
}
|
|
if (tmp == '\0') {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int64_t etk::FSNode::fileRead(void* _data, int64_t _blockSize, int64_t _nbBlock) {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
if (m_zipContent == nullptr) {
|
|
((char*)_data)[0] = '\0';
|
|
return 0;
|
|
}
|
|
int32_t dataToRead = _blockSize * _nbBlock;
|
|
if (dataToRead + m_zipReadingOffset > m_zipContent->size()) {
|
|
_nbBlock = ((m_zipContent->size() - m_zipReadingOffset) / _blockSize);
|
|
dataToRead = _blockSize * _nbBlock;
|
|
}
|
|
memcpy(_data, &((char*)m_zipContent->data())[m_zipReadingOffset], dataToRead);
|
|
m_zipReadingOffset += dataToRead;
|
|
return _nbBlock;
|
|
}
|
|
#endif
|
|
if (m_PointerFile == nullptr) {
|
|
TK_ERROR("Can not read in a file that is not open : " << *this);
|
|
return 0;
|
|
}
|
|
return fread(_data, _blockSize, _nbBlock, m_PointerFile);
|
|
}
|
|
|
|
bool etk::FSNode::filePut(char _input) {
|
|
if (fileWrite(&_input, 1, 1) == 1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool etk::FSNode::filePuts(const etk::String& _input) {
|
|
if (fileWrite((void*)_input.c_str(), 1, _input.size()) == (int64_t)_input.size()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int64_t etk::FSNode::fileWrite(const void * _data, int64_t _blockSize, int64_t _nbBlock) {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
TK_CRITICAL("Can not write on data inside APK : " << *this);
|
|
return 0;
|
|
}
|
|
#endif
|
|
if (m_PointerFile == nullptr) {
|
|
TK_ERROR("Can not write in a file that is not open : " << *this);
|
|
return 0;
|
|
}
|
|
return fwrite(_data, _blockSize, _nbBlock, m_PointerFile);
|
|
}
|
|
/*
|
|
etk::FSNode& etk::FSNode::operator<< (const etk::Stream& _data) {
|
|
fileWrite(_data.str().c_str(), 1, _data.str().size());
|
|
return *this;
|
|
}
|
|
*/
|
|
etk::FSNode& etk::FSNode::operator<< (const etk::Stream& _data) {
|
|
fileWrite(_data.c_str(), 1, _data.size());
|
|
return *this;
|
|
}
|
|
etk::FSNode& etk::FSNode::operator<< (const etk::String& _data) {
|
|
fileWrite(_data.c_str(), 1, _data.size());
|
|
return *this;
|
|
}
|
|
etk::FSNode& etk::FSNode::operator<< (const char* _data) {
|
|
fileWrite(_data, 1, strlen(_data));
|
|
return *this;
|
|
}
|
|
etk::FSNode& etk::FSNode::operator<< (const int32_t _data) {
|
|
etk::String sss = etk::toString(_data);
|
|
fileWrite(sss.c_str(), 1, sss.size());
|
|
return *this;
|
|
}
|
|
etk::FSNode& etk::FSNode::operator<< (const uint32_t _data) {
|
|
etk::String sss = etk::toString(_data);
|
|
fileWrite(sss.c_str(), 1, sss.size());
|
|
return *this;
|
|
}
|
|
etk::FSNode& etk::FSNode::operator<< (const float _data) {
|
|
etk::String sss = etk::toString(_data);
|
|
fileWrite(sss.c_str(), 1, sss.size());
|
|
return *this;
|
|
}
|
|
|
|
bool etk::FSNode::fileSeek(long int _offset, enum etk::seekNode _origin)
|
|
{
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
if (nullptr == m_zipContent) {
|
|
return false;
|
|
}
|
|
int32_t positionEnd = 0;
|
|
switch(_origin) {
|
|
case etk::seekNode_end:
|
|
positionEnd = m_zipContent->size();
|
|
break;
|
|
case etk::seekNode_current:
|
|
positionEnd = m_zipReadingOffset;
|
|
break;
|
|
default:
|
|
positionEnd = 0;
|
|
break;
|
|
}
|
|
positionEnd += _offset;
|
|
if (positionEnd < 0) {
|
|
positionEnd = 0;
|
|
} else if (positionEnd > m_zipContent->size()) {
|
|
positionEnd = m_zipContent->size();
|
|
}
|
|
m_zipReadingOffset = positionEnd;
|
|
return true;
|
|
}
|
|
#endif
|
|
int originFS = 0;
|
|
switch(_origin) {
|
|
case etk::seekNode_end:
|
|
originFS = SEEK_END;
|
|
break;
|
|
case etk::seekNode_current:
|
|
originFS = SEEK_CUR;
|
|
break;
|
|
default:
|
|
originFS = 0;
|
|
break;
|
|
}
|
|
fseek(m_PointerFile, _offset, originFS);
|
|
if(ferror(m_PointerFile)) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
int64_t etk::FSNode::fileTell() {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
if (nullptr == m_zipContent) {
|
|
return false;
|
|
}
|
|
return m_zipReadingOffset;
|
|
}
|
|
#endif
|
|
return ftell(m_PointerFile);
|
|
|
|
}
|
|
|
|
void etk::FSNode::fileFlush() {
|
|
#ifdef HAVE_ZIP_DATA
|
|
if( m_type == etk::FSNType_data
|
|
|| m_type == etk::FSNType_themeData) {
|
|
return;
|
|
}
|
|
#endif
|
|
if (m_PointerFile != nullptr) {
|
|
fflush(m_PointerFile);
|
|
}
|
|
}
|
|
|
|
|
|
// TODO : Add an INIT to reset all allocated parameter :
|
|
static etk::Map<etk::String, etk::String> g_listTheme;
|
|
|
|
void etk::theme::setName(const etk::String& _refName, const etk::String& _folderName) {
|
|
TK_WARNING("Change theme : '" << _refName << "' : '" << _folderName << "'");
|
|
g_listTheme.set(_refName, _folderName);
|
|
}
|
|
|
|
etk::String etk::theme::getName(const etk::String& _refName) {
|
|
auto it = g_listTheme.find(_refName);
|
|
if (it != g_listTheme.end()) {
|
|
return it->second;
|
|
}
|
|
return _refName;
|
|
}
|
|
|
|
// get the list of all the theme folder availlable in the user Home/appl
|
|
etk::Vector<etk::String> etk::theme::list() {
|
|
etk::Vector<etk::String> keys;
|
|
for (auto &it : g_listTheme) {
|
|
keys.pushBack(it.first);
|
|
}
|
|
return keys;
|
|
}
|
|
|
|
static etk::Map<etk::String, etk::String> g_listThemeDefault;
|
|
void etk::theme::setNameDefault(const etk::String& _refName, const etk::String& _folderName) {
|
|
auto it = g_listThemeDefault.find(_refName);
|
|
if (it != g_listThemeDefault.end()) {
|
|
it->second = _folderName;
|
|
return;
|
|
}
|
|
g_listThemeDefault.set(_refName, _folderName);
|
|
}
|
|
|
|
etk::String etk::theme::getNameDefault(const etk::String& _refName) {
|
|
auto it = g_listThemeDefault.find(_refName);
|
|
if (it != g_listThemeDefault.end()) {
|
|
return it->second;
|
|
}
|
|
return "default";
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------
|
|
*
|
|
* Simple direct wrapper on the FileSystem node access :
|
|
*
|
|
* -------------------------------------------------------------------------- */
|
|
uint64_t etk::FSNodeGetSize(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
if (tmpNode.exist() == false) {
|
|
return 0;
|
|
}
|
|
return tmpNode.fileSize();
|
|
}
|
|
|
|
bool etk::FSNodeRemove(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
if (false==tmpNode.exist()) {
|
|
return false;
|
|
}
|
|
return tmpNode.remove();
|
|
}
|
|
|
|
int64_t etk::FSNodeGetCount(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
if (false==tmpNode.exist()) {
|
|
return -1;
|
|
}
|
|
return tmpNode.folderCount();
|
|
}
|
|
|
|
bool etk::FSNodeCreate(const etk::String& _path, etk::FSNodeRight _right, enum etk::typeNode _type) {
|
|
// TODO :
|
|
return false;
|
|
}
|
|
|
|
bool etk::FSNodeExist(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
return tmpNode.exist();
|
|
}
|
|
|
|
bool etk::FSNodeMove(const etk::String& _path1, const etk::String& _path2) {
|
|
etk::FSNode tmpNode(_path1);
|
|
if (tmpNode.exist() == false) {
|
|
TK_WARNING("try to move an un-existant file '" << _path1 << "'");
|
|
return false;
|
|
}
|
|
// no check error in every case
|
|
(void)etk::FSNodeRemove(_path2);
|
|
//move the node
|
|
return tmpNode.move(_path2);
|
|
}
|
|
|
|
etk::FSNodeRight etk::FSNodeGetRight(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
return tmpNode.getRight();
|
|
}
|
|
|
|
enum etk::typeNode etk::FSNodeGetType(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
return tmpNode.getNodeType();
|
|
}
|
|
|
|
uint64_t etk::FSNodeGetTimeCreated(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
return tmpNode.timeCreated();
|
|
}
|
|
|
|
uint64_t etk::FSNodeGetTimeModified(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
return tmpNode.timeModified();
|
|
}
|
|
|
|
uint64_t etk::FSNodeGetTimeAccessed(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
return tmpNode.timeAccessed();
|
|
}
|
|
|
|
bool etk::FSNodeTouch(const etk::String& _path) {
|
|
etk::FSNode tmpNode(_path);
|
|
return tmpNode.touch();
|
|
}
|
|
|
|
bool etk::FSNodeEcho(const etk::String& _path, const etk::String& _dataTowrite) {
|
|
etk::FSNode tmpNode(_path);
|
|
if (tmpNode.exist() == false) {
|
|
return false;
|
|
}
|
|
if (tmpNode.getNodeType() == typeNode_folder) {
|
|
return false;
|
|
}
|
|
if (tmpNode.fileOpenWrite() == false) {
|
|
return false;
|
|
}
|
|
// convert in UTF8 :
|
|
if ((int64_t)_dataTowrite.size() != tmpNode.fileWrite((char*)_dataTowrite.c_str(), 1, _dataTowrite.size())) {
|
|
tmpNode.fileClose();
|
|
return false;
|
|
}
|
|
return tmpNode.fileClose();
|
|
}
|
|
|
|
bool etk::FSNodeEchoAdd(const etk::String& _path, const etk::String& _dataTowrite) {
|
|
etk::FSNode tmpNode(_path);
|
|
if (tmpNode.exist() == false) {
|
|
return false;
|
|
}
|
|
if (tmpNode.getNodeType() == typeNode_folder) {
|
|
return false;
|
|
}
|
|
if (tmpNode.fileOpenAppend() == false) {
|
|
return false;
|
|
}
|
|
// convert in UTF8 :
|
|
if ((int64_t)_dataTowrite.size() != tmpNode.fileWrite((char*)_dataTowrite.c_str(), 1, _dataTowrite.size())) {
|
|
tmpNode.fileClose();
|
|
return false;
|
|
}
|
|
return tmpNode.fileClose();
|
|
}
|
|
|
|
void etk::FSNodeHistory(const etk::String& _path, int32_t _historyCount) {
|
|
// step 1 : Move the file to prevent writing error
|
|
//Get the first oldest save :
|
|
for (int32_t iii=_historyCount-1; iii>0 ; iii--) {
|
|
if (etk::FSNodeExist(_path + "-" + etk::toString(iii)) == true) {
|
|
etk::FSNodeMove(_path + "-" + etk::toString(iii), _path + "-" + etk::toString(iii+1));
|
|
}
|
|
}
|
|
if (etk::FSNodeExist(_path) == true) {
|
|
etk::FSNodeMove(_path, _path + "-1");
|
|
}
|
|
}
|
|
|
|
etk::String etk::FSNodeReadAllData(const etk::String& _path) {
|
|
etk::String output;
|
|
etk::FSNode node(_path);
|
|
if (node.fileOpenRead() == false) {
|
|
TK_ERROR("can not open file : '" << node << "'");
|
|
return "";
|
|
}
|
|
etk::String tmp;
|
|
while (node.fileGets(tmp) == true) {
|
|
output += tmp;
|
|
output += "\n";
|
|
}
|
|
output += tmp;
|
|
node.fileClose();
|
|
return output;
|
|
}
|
|
|
|
void etk::FSNodeWriteAllData(const etk::String& _path, const etk::String& _data) {
|
|
etk::FSNode node(_path);
|
|
if (node.fileOpenWrite() == false) {
|
|
TK_ERROR("can not open file : '" << node << "'");
|
|
return;
|
|
}
|
|
node.fileWrite(&_data[0], sizeof(char), _data.size());
|
|
node.fileClose();
|
|
}
|
|
|
|
etk::String etk::FSNodeGetRealName(const etk::String& _path) {
|
|
etk::FSNode node(_path);
|
|
return node.getFileSystemName();
|
|
}
|
|
|
|
etk::Vector<etk::String> etk::FSNodeExplodeMultiplePath(const etk::String& _path) {
|
|
etk::Vector<etk::String> out;
|
|
|
|
etk::String libSearch = "";
|
|
etk::String newName = _path;
|
|
if ( _path.size() > 0
|
|
&& _path[0] == '{') {
|
|
// special case: Reference of searching in subLib folder ==> library use-case
|
|
size_t firstPos = _path.find('}');
|
|
if (firstPos != etk::String::npos) {
|
|
// we find a theme name : We extracted it :
|
|
libSearch = etk::String(_path, 1, firstPos-1);
|
|
newName = etk::String(_path, firstPos+1);
|
|
} else {
|
|
TK_ERROR("start a path name with '{' without '}' : " << _path);
|
|
// remove in case the {
|
|
newName = etk::String(_path, 1);
|
|
}
|
|
}
|
|
if (libSearch.size() != 0) {
|
|
if (libSearch[0] != '@') {
|
|
out.pushBack(newName);
|
|
out.pushBack(etk::String("{@") + libSearch + "}" + newName);
|
|
return out;
|
|
}
|
|
out.pushBack(etk::String("{") + libSearch + "}" + newName);
|
|
return out;
|
|
}
|
|
out.pushBack(newName);
|
|
return out;
|
|
}
|
|
|