123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- /****************************************************************************
- Copyright (c) 2010-2012 cocos2d-x.org
- Copyright (c) 2013-2017 Chukong Technologies Inc.
- http://www.cocos2d-x.org
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #include "platform/CCPlatformConfig.h"
- #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
- #include "platform/android/CCFileUtils-android.h"
- #include "platform/CCCommon.h"
- #include "platform/android/jni/JniHelper.h"
- #include "platform/android/jni/Java_org_cocos2dx_lib_Cocos2dxHelper.h"
- #include "android/asset_manager.h"
- #include "android/asset_manager_jni.h"
- #include "base/ZipUtils.h"
- #include "base/CCDirector.h"
- #include "base/CCEventDispatcher.h"
- #include "base/CCEventType.h"
- #include <stdlib.h>
- #include <sys/stat.h>
- #define LOG_TAG "CCFileUtils-android.cpp"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
- #define ASSETS_FOLDER_NAME "assets/"
- #define ASSETS_FOLDER_NAME_LENGTH 7
- using namespace std;
- NS_CC_BEGIN
- AAssetManager* FileUtilsAndroid::assetmanager = nullptr;
- ZipFile* FileUtilsAndroid::obbfile = nullptr;
- void FileUtilsAndroid::setassetmanager(AAssetManager* a) {
- if (nullptr == a) {
- LOGD("setassetmanager : received unexpected nullptr parameter");
- return;
- }
- cocos2d::FileUtilsAndroid::assetmanager = a;
- }
- FileUtils* FileUtils::getInstance()
- {
- if (s_sharedFileUtils == nullptr)
- {
- s_sharedFileUtils = new FileUtilsAndroid();
- if (!s_sharedFileUtils->init())
- {
- delete s_sharedFileUtils;
- s_sharedFileUtils = nullptr;
- CCLOG("ERROR: Could not init CCFileUtilsAndroid");
- }
- }
- return s_sharedFileUtils;
- }
- FileUtilsAndroid::FileUtilsAndroid()
- {
- }
- FileUtilsAndroid::~FileUtilsAndroid()
- {
- if (obbfile)
- {
- delete obbfile;
- obbfile = nullptr;
- }
- }
- bool FileUtilsAndroid::init()
- {
- _defaultResRootPath = ASSETS_FOLDER_NAME;
-
- std::string assetsPath(getApkPath());
- if (assetsPath.find("/obb/") != std::string::npos)
- {
- obbfile = new ZipFile(assetsPath);
- }
- return FileUtils::init();
- }
- std::string FileUtilsAndroid::getNewFilename(const std::string &filename) const
- {
- std::string newFileName = FileUtils::getNewFilename(filename);
- // ../xxx do not fix this path
- auto pos = newFileName.find("../");
- if (pos == std::string::npos || pos == 0)
- {
- return newFileName;
- }
- std::vector<std::string> v(3);
- v.resize(0);
- auto change = false;
- size_t size = newFileName.size();
- size_t idx = 0;
- bool noexit = true;
- while (noexit)
- {
- pos = newFileName.find('/', idx);
- std::string tmp;
- if (pos == std::string::npos)
- {
- tmp = newFileName.substr(idx, size - idx);
- noexit = false;
- }else
- {
- tmp = newFileName.substr(idx, pos - idx + 1);
- }
- auto t = v.size();
- if (t > 0 && v[t-1].compare("../") != 0 &&
- (tmp.compare("../") == 0 || tmp.compare("..") == 0))
- {
- v.pop_back();
- change = true;
- }else
- {
- v.push_back(tmp);
- }
- idx = pos + 1;
- }
- if (change)
- {
- newFileName.clear();
- for (auto &s : v)
- {
- newFileName.append(s);
- }
- }
- return newFileName;
- }
- bool FileUtilsAndroid::isFileExistInternal(const std::string& strFilePath) const
- {
- if (strFilePath.empty())
- {
- return false;
- }
- bool bFound = false;
- // Check whether file exists in apk.
- if (strFilePath[0] != '/')
- {
- const char* s = strFilePath.c_str();
- // Found "assets/" at the beginning of the path and we don't want it
- if (strFilePath.find(_defaultResRootPath) == 0) s += _defaultResRootPath.length();
-
- if (obbfile && obbfile->fileExists(s))
- {
- bFound = true;
- }
- else if (FileUtilsAndroid::assetmanager)
- {
- AAsset* aa = AAssetManager_open(FileUtilsAndroid::assetmanager, s, AASSET_MODE_UNKNOWN);
- if (aa)
- {
- bFound = true;
- AAsset_close(aa);
- } else {
- // CCLOG("[AssetManager] ... in APK %s, found = false!", strFilePath.c_str());
- }
- }
- }
- else
- {
- FILE *fp = fopen(strFilePath.c_str(), "r");
- if (fp)
- {
- bFound = true;
- fclose(fp);
- }
- }
- return bFound;
- }
- bool FileUtilsAndroid::isDirectoryExistInternal(const std::string& dirPath) const
- {
- if (dirPath.empty())
- {
- return false;
- }
- const char* s = dirPath.c_str();
-
- // find absolute path in flash memory
- if (s[0] == '/')
- {
- CCLOG("find in flash memory dirPath(%s)", s);
- struct stat st;
- if (stat(s, &st) == 0)
- {
- return S_ISDIR(st.st_mode);
- }
- }
- else
- {
- // find it in apk's assets dir
- // Found "assets/" at the beginning of the path and we don't want it
- CCLOG("find in apk dirPath(%s)", s);
- if (dirPath.find(ASSETS_FOLDER_NAME) == 0)
- {
- s += ASSETS_FOLDER_NAME_LENGTH;
- }
- if (FileUtilsAndroid::assetmanager)
- {
- AAssetDir* aa = AAssetManager_openDir(FileUtilsAndroid::assetmanager, s);
- if (aa && AAssetDir_getNextFileName(aa))
- {
- AAssetDir_close(aa);
- return true;
- }
- }
- }
-
- return false;
- }
- bool FileUtilsAndroid::isAbsolutePath(const std::string& strPath) const
- {
- // On Android, there are two situations for full path.
- // 1) Files in APK, e.g. assets/path/path/file.png
- // 2) Files not in APK, e.g. /data/data/org.cocos2dx.hellocpp/cache/path/path/file.png, or /sdcard/path/path/file.png.
- // So these two situations need to be checked on Android.
- if (strPath[0] == '/' || strPath.find(_defaultResRootPath) == 0)
- {
- return true;
- }
- return false;
- }
- FileUtils::Status FileUtilsAndroid::getContents(const std::string& filename, ResizableBuffer* buffer)
- {
- Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(EVENT_BEFORE_READ_FILE);
- static const std::string apkprefix("assets/");
- if (filename.empty())
- return FileUtils::Status::NotExists;
- string fullPath = fullPathForFilename(filename);
- if (fullPath[0] == '/')
- return FileUtils::getContents(fullPath, buffer);
- string relativePath = string();
- size_t position = fullPath.find(apkprefix);
- if (0 == position) {
- // "assets/" is at the beginning of the path and we don't want it
- relativePath += fullPath.substr(apkprefix.size());
- } else {
- relativePath = fullPath;
- }
-
- if (obbfile)
- {
- if (obbfile->getFileData(relativePath, buffer))
- return FileUtils::Status::OK;
- }
- if (nullptr == assetmanager) {
- LOGD("... FileUtilsAndroid::assetmanager is nullptr");
- return FileUtils::Status::NotInitialized;
- }
- AAsset* asset = AAssetManager_open(assetmanager, relativePath.data(), AASSET_MODE_UNKNOWN);
- if (nullptr == asset) {
- LOGD("asset is nullptr");
- return FileUtils::Status::OpenFailed;
- }
- auto size = AAsset_getLength(asset);
- buffer->resize(size);
- int readsize = AAsset_read(asset, buffer->buffer(), size);
- AAsset_close(asset);
- if (readsize < size) {
- if (readsize >= 0)
- buffer->resize(readsize);
- return FileUtils::Status::ReadFailed;
- }
- return FileUtils::Status::OK;
- }
- string FileUtilsAndroid::getWritablePath() const
- {
- // Fix for Nexus 10 (Android 4.2 multi-user environment)
- // the path is retrieved through Java Context.getCacheDir() method
- string dir("");
- string tmp = JniHelper::callStaticStringMethod("org/cocos2dx/lib/Cocos2dxHelper", "getCocos2dxWritablePath");
- if (tmp.length() > 0)
- {
- dir.append(tmp).append("/");
- return dir;
- }
- else
- {
- return "";
- }
- }
- NS_CC_END
- #endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|