From bc4c8e2551ebec9cee7ad3d7446f46a834f3957b Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Thu, 6 Oct 2016 21:02:30 +0200 Subject: [PATCH] [DEV] set Windows support zip data package --- etk/archive/Zip.cpp | 12 +-- etk/os/FSNode.cpp | 221 ++++++++++++++++++++++++++++++-------------- etk/os/FSNode.hpp | 4 +- 3 files changed, 160 insertions(+), 77 deletions(-) diff --git a/etk/archive/Zip.cpp b/etk/archive/Zip.cpp index c85495a..0536fe3 100644 --- a/etk/archive/Zip.cpp +++ b/etk/archive/Zip.cpp @@ -50,9 +50,9 @@ etk::archive::Zip::Zip(const std::string& _fileName, uint64_t _offset) : } etk::archive::Zip::~Zip() { - if (m_ctx!= NULL) { + if (m_ctx!= nullptr) { unzClose(m_ctx); - m_ctx = NULL; + m_ctx = nullptr; }; } @@ -66,7 +66,7 @@ void etk::archive::Zip::loadFile(const std::map::it char tmpFileName[FILENAME_MAX]; unz_file_info tmpFileInfo; /* Get info about current file. */ - if(unzGetCurrentFileInfo(m_ctx, &tmpFileInfo, tmpFileName, FILENAME_MAX, NULL, 0, NULL, 0) != UNZ_OK) { + if(unzGetCurrentFileInfo(m_ctx, &tmpFileInfo, tmpFileName, FILENAME_MAX, nullptr, 0, nullptr, 0) != UNZ_OK) { TK_ERROR("Could not read file info from the zip file '" << m_fileName << "'"); return; } @@ -80,19 +80,19 @@ void etk::archive::Zip::loadFile(const std::map::it // request the resize of the data : it->second.getDataVector().resize(it->second.getTheoricSize(), 0); void* data = it->second.data(); - if(NULL == data) { + if(data == nullptr) { TK_ERROR("Allocation error..."); return; } /* read the file */ do { error = unzReadCurrentFile(m_ctx, data, it->second.getTheoricSize()); - if ( error < 0 ) { + if (error < 0) { TK_ERROR("Could not read file '" << tmpFileName << "' into the zip file '" << m_fileName << "': " << error); unzCloseCurrentFile(m_ctx); return; } - } while ( error > 0 ); + } while (error > 0); //((char*)data)[m_content.GetValue(_id).GetTheoricSize()] = '\0'; // stop searching here unzCloseCurrentFile(m_ctx); diff --git a/etk/os/FSNode.cpp b/etk/os/FSNode.cpp index 72dcc95..cb3608a 100644 --- a/etk/os/FSNode.cpp +++ b/etk/os/FSNode.cpp @@ -122,6 +122,97 @@ std::string etk::simplifyPath(std::string _input) { 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 (nullptr==copypath) { + 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 std::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 std::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 std::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 std::string FSNODE_LOCAL_join(const std::string& _path1, const std::string& _path2) { + std::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; @@ -156,18 +247,34 @@ std::string etk::FSNodeGetApplicationName() { #ifdef HAVE_ZIP_DATA static etk::Archive* s_APKArchive = nullptr; - static void loadAPK(std::string& _apkPath) { - std::unique_lock lock(getNodeMutex()); - TK_INFO("Loading APK \"" << _apkPath << "\""); + static void loadAPK(const std::string& _apkPath) { #ifdef __TARGET_OS__Android + std::unique_lock lock(getNodeMutex()); + TK_INFO("Loading APK '" << _apkPath << "'"); s_APKArchive = etk::Archive::load(_apkPath); + TK_ASSERT(s_APKArchive != nullptr, "Error loading APK ... '" << _apkPath << "'"); #else - s_APKArchive = etk::Archive::loadPackage(_apkPath); + TK_INFO("Loading Intarnal data '" << _apkPath << "'"); + //s_APKArchive = etk::Archive::loadPackage(_apkPath); + s_APKArchive = etk::Archive::load(_apkPath); + TK_ASSERT(s_APKArchive != nullptr, "Error loading PKG ... '" << _apkPath << "'"); + #endif + #ifdef DEBUG + //Just for debug, print APK contents + s_APKArchive->display(); #endif - TK_ASSERT(s_APKArchive != nullptr, "Error loading APK ... \"" << _apkPath << "\""); - //Just for debug, print APK contents - s_APKArchive->display(); } + #ifdef __TARGET_OS__Windows + static void loadAPKBin(const std::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 : @@ -237,13 +344,10 @@ std::string getApplicationPath() { memset(binaryCompleatePath, 0, FILENAME_MAX); #ifdef __TARGET_OS__Windows GetModuleFileName(nullptr, binaryCompleatePath, FILENAME_MAX); - if (0==strlen(binaryCompleatePath)) { + if (strlen(binaryCompleatePath) == 0) { TK_CRITICAL("Can not get the binary position in the tree ==> this is really bad ..."); } else { binaryName = binaryCompleatePath; - #ifdef HAVE_ZIP_DATA - loadAPK(binaryName); - #endif } #else // check it to prevent test mode in local folder ... @@ -344,15 +448,39 @@ void etk::initDefaultFolder(const char* _applName) { TK_DBG_MODE("Find Basic running PATH : '" << baseRunPath << "'"); #ifndef __TARGET_OS__Android std::string binaryPath = getApplicationPath(); - binaryPath = replace(binaryPath, '\\', '/'); + binaryPath = etk::replace(binaryPath, '\\', '/'); size_t pos = binaryPath.rfind('/'); std::string binaryName(binaryPath, pos); + while( binaryName.size() >= 2 + && binaryName[1] == '/') { + binaryName = std::string(binaryName.begin()+1, binaryName.end()); + } binaryPath.erase(binaryPath.begin() + pos, binaryPath.end()); TK_INFO("Bianry name : '" << binaryPath << "' && '" << binaryName << "'" ); #ifdef __TARGET_OS__Windows - baseFolderData = binaryPath; - baseFolderData += "/data/"; - baseFolderData += std::string(binaryName.begin(), binaryName.end()-4); + // 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 += std::string(binaryName.begin()+1, binaryName.end()-4); baseFolderData += "/"; baseFolderDataUser = binaryPath; @@ -472,54 +600,6 @@ bool etk::FSNode::loadDataZip() { #endif - -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 (nullptr==copypath) { - 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); -} - etk::FSNode::FSNode(const std::string& _nodeName) : m_userFileName(""), m_type(etk::FSNType_unknow), @@ -593,7 +673,7 @@ void etk::FSNode::privateSetName(std::string _newName) { || nullptr != m_zipContent #endif ) { - TK_ERROR("Missing to close the file : \"" << *this << "\""); + TK_ERROR("Missing to close the file : '" << *this << "'"); fileClose(); } // set right at nullptr ... @@ -831,7 +911,7 @@ void etk::FSNode::generateFileSystemPath() { break; case etk::FSNType_data: { - TK_DBG_MODE("DATA lib : \"" << m_libSearch << "\" => \"" << m_userFileName << "\" forceLib = " << forceLibFolder); + TK_DBG_MODE("DATA lib : '" << m_libSearch << "' => '" << m_userFileName << "' forceLib = " << forceLibFolder); // search the correct folder: if (forceLibFolder == false) { // check in the application folder. @@ -923,12 +1003,12 @@ void etk::FSNode::generateFileSystemPath() { } // check in the user data : m_systemFileName = simplifyPath(baseFolderDataUser + "/../" + m_libSearch + "/theme/" + themeNameDefault + "/" + basicName); - if (true==directCheckFile(m_systemFileName)) { + 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 (true==directCheckFile(m_systemFileName, true)) { + if (directCheckFile(m_systemFileName, true) == true) { m_type = etk::FSNType_themeData; return; } @@ -966,7 +1046,7 @@ void etk::FSNode::updateFileSystemProperty() { // = Check if it was a folder : = // ---------------------------------------- std::string folderName = "/"; - if (true == end_with(m_systemFileName, folderName)) { + if (etk::end_with(m_systemFileName, folderName) == true) { folderName = m_systemFileName; } else { folderName = m_systemFileName + "/"; @@ -1473,12 +1553,15 @@ std::vector etk::FSNode::folderGetSubList(bool _showHidenFile, bo for (int iii=0; iiisize(); iii++) { std::string filename = s_APKArchive->getName(iii); if (start_with(filename, FolderName) == true) { - std::string tmpString(filename, FolderName.size()+1); + //TK_INFO("pppppp '" << filename << "'"); + //TK_INFO(" '" << FolderName << "'"); + std::string tmpString(filename, FolderName.size()); size_t pos = tmpString.find('/'); if (pos != std::string::npos) { // a simple folder : tmpString = std::string(tmpString, 0, pos); } + //TK_INFO("plop '" << getName() << "' '" << tmpString << "'"); tmpString = getName() + tmpString; bool findIt = false; for (size_t jjj = 0; jjj < listAdded.size(); ++jjj) { diff --git a/etk/os/FSNode.hpp b/etk/os/FSNode.hpp index e9682ff..2dcb202 100644 --- a/etk/os/FSNode.hpp +++ b/etk/os/FSNode.hpp @@ -20,11 +20,11 @@ #ifdef __TARGET_OS__Android #define HAVE_ZIP_DATA #endif -/* + #ifdef __TARGET_OS__Windows #define HAVE_ZIP_DATA #endif -*/ + #ifdef HAVE_ZIP_DATA namespace etk {