From e9d8595617ed8852f9561256381f821bfc51e067 Mon Sep 17 00:00:00 2001 From: minggo Date: Tue, 18 Jun 2013 17:10:54 +0800 Subject: [PATCH] fixed #2124: make CCImage::initWithIamgeFileThreadSafe() thread safe --- cocos2dx/platform/CCImageCommon_cpp.h | 9 ++++ .../platform/android/CCFileUtilsAndroid.cpp | 40 ++++++++++----- .../platform/android/CCFileUtilsAndroid.h | 8 +++ cocos2dx/support/zip_support/ZipUtils.cpp | 49 +++++++++++++------ cocos2dx/support/zip_support/ZipUtils.h | 13 +++++ 5 files changed, 91 insertions(+), 28 deletions(-) diff --git a/cocos2dx/platform/CCImageCommon_cpp.h b/cocos2dx/platform/CCImageCommon_cpp.h index 0110ca0152..6411fcd6bc 100644 --- a/cocos2dx/platform/CCImageCommon_cpp.h +++ b/cocos2dx/platform/CCImageCommon_cpp.h @@ -33,6 +33,10 @@ THE SOFTWARE. #include "png.h" #include "jpeglib.h" #include "tiffio.h" +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) +#include "platform/android/CCFileUtilsAndroid.h" +#endif + #include #include @@ -136,7 +140,12 @@ bool CCImage::initWithImageFileThreadSafe(const char *fullpath, EImageFormat ima { bool bRet = false; unsigned long nSize = 0; +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) + CCFileUtilsAndroid *fileUitls = (CCFileUtilsAndroid*)CCFileUtils::sharedFileUtils(); + unsigned char *pBuffer = fileUitls->getFileDataForAsync(fullpath, "rb", &nSize); +#else unsigned char *pBuffer = CCFileUtils::sharedFileUtils()->getFileData(fullpath, "rb", &nSize); +#endif if (pBuffer != NULL && nSize > 0) { bRet = initWithImageData(pBuffer, nSize, imageType); diff --git a/cocos2dx/platform/android/CCFileUtilsAndroid.cpp b/cocos2dx/platform/android/CCFileUtilsAndroid.cpp index ede95e92a1..d0988e9bc4 100644 --- a/cocos2dx/platform/android/CCFileUtilsAndroid.cpp +++ b/cocos2dx/platform/android/CCFileUtilsAndroid.cpp @@ -111,29 +111,45 @@ bool CCFileUtilsAndroid::isAbsolutePath(const std::string& strPath) unsigned char* CCFileUtilsAndroid::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize) { - unsigned char * pData = 0; + return doGetFileData(pszFileName, pszMode, pSize, false); +} +unsigned char* CCFileUtilsAndroid::getFileDataForAsync(const char* pszFileName, const char* pszMode, unsigned long * pSize) +{ + return doGetFileData(pszFileName, pszMode, pSize, true); +} + +unsigned char* CCFileUtilsAndroid::doGetFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize, bool forAsync) +{ + unsigned char * pData = 0; + if ((! pszFileName) || (! pszMode) || 0 == strlen(pszFileName)) { return 0; } - + string fullPath = fullPathForFilename(pszFileName); - + if (fullPath[0] != '/') { - //CCLOG("GETTING FILE RELATIVE DATA: %s", pszFileName); - pData = s_pZipFile->getFileData(fullPath.c_str(), pSize); + if (forAsync) + { + pData = s_pZipFile->getFileData(fullPath.c_str(), pSize, s_pZipFile->_dataThread); + } + else + { + pData = s_pZipFile->getFileData(fullPath.c_str(), pSize); + } } else { - do + do { // read rrom other path than user set it //CCLOG("GETTING FILE ABSOLUTE DATA: %s", pszFileName); FILE *fp = fopen(fullPath.c_str(), pszMode); CC_BREAK_IF(!fp); - + unsigned long size; fseek(fp,0,SEEK_END); size = ftell(fp); @@ -141,21 +157,21 @@ unsigned char* CCFileUtilsAndroid::getFileData(const char* pszFileName, const ch pData = new unsigned char[size]; size = fread(pData,sizeof(unsigned char), size,fp); fclose(fp); - + if (pSize) { *pSize = size; - } - } while (0); + } + } while (0); } - + if (! pData) { std::string msg = "Get data from file("; msg.append(pszFileName).append(") failed!"); CCLOG(msg.c_str()); } - + return pData; } diff --git a/cocos2dx/platform/android/CCFileUtilsAndroid.h b/cocos2dx/platform/android/CCFileUtilsAndroid.h index ba8e54e8ef..3a9e4dbf25 100644 --- a/cocos2dx/platform/android/CCFileUtilsAndroid.h +++ b/cocos2dx/platform/android/CCFileUtilsAndroid.h @@ -52,6 +52,14 @@ public: virtual std::string getWritablePath(); virtual bool isFileExist(const std::string& strFilePath); virtual bool isAbsolutePath(const std::string& strPath); + + /** This function is android specific. It is used for CCTextureCache::addImageAsync(). + Don't use it in your codes. + */ + unsigned char* getFileDataForAsync(const char* pszFileName, const char* pszMode, unsigned long * pSize); + +private: + unsigned char* doGetFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize, bool forAsync); }; // end of platform group diff --git a/cocos2dx/support/zip_support/ZipUtils.cpp b/cocos2dx/support/zip_support/ZipUtils.cpp index 3fd54abc26..054ea57b11 100644 --- a/cocos2dx/support/zip_support/ZipUtils.cpp +++ b/cocos2dx/support/zip_support/ZipUtils.cpp @@ -456,9 +456,11 @@ public: ZipFile::ZipFile(const std::string &zipFile, const std::string &filter) : _data(new ZipFilePrivate) +, _dataThread(new ZipFilePrivate) { _data->zipFile = unzOpen(zipFile.c_str()); - if (_data->zipFile) + _dataThread->zipFile = unzOpen(zipFile.c_str()); + if (_data->zipFile && _dataThread->zipFile) { setFilter(filter); } @@ -470,31 +472,36 @@ ZipFile::~ZipFile() { unzClose(_data->zipFile); } + if (_dataThread && _dataThread->zipFile) + { + unzClose(_dataThread); + } CC_SAFE_DELETE(_data); + CC_SAFE_DELETE(_dataThread); } -bool ZipFile::setFilter(const std::string &filter) +bool ZipFile::setFilter(const std::string &filter, ZipFilePrivate *data) { bool ret = false; do { - CC_BREAK_IF(!_data); - CC_BREAK_IF(!_data->zipFile); + CC_BREAK_IF(!data); + CC_BREAK_IF(!data->zipFile); // clear existing file list - _data->fileList.clear(); + data->fileList.clear(); // UNZ_MAXFILENAMEINZIP + 1 - it is done so in unzLocateFile char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1]; unz_file_info64 fileInfo; // go through all files and store position information about the required files - int err = unzGoToFirstFile64(_data->zipFile, &fileInfo, + int err = unzGoToFirstFile64(data->zipFile, &fileInfo, szCurrentFileName, sizeof(szCurrentFileName) - 1); while (err == UNZ_OK) { unz_file_pos posInfo; - int posErr = unzGetFilePos(_data->zipFile, &posInfo); + int posErr = unzGetFilePos(data->zipFile, &posInfo); if (posErr == UNZ_OK) { std::string currentFileName = szCurrentFileName; @@ -505,11 +512,11 @@ bool ZipFile::setFilter(const std::string &filter) ZipEntryInfo entry; entry.pos = posInfo; entry.uncompressed_size = (uLong)fileInfo.uncompressed_size; - _data->fileList[currentFileName] = entry; + data->fileList[currentFileName] = entry; } } // next file - also get the information about it - err = unzGoToNextFile64(_data->zipFile, &fileInfo, + err = unzGoToNextFile64(data->zipFile, &fileInfo, szCurrentFileName, sizeof(szCurrentFileName) - 1); } ret = true; @@ -519,6 +526,11 @@ bool ZipFile::setFilter(const std::string &filter) return ret; } +bool ZipFile::setFilter(const std::string &filter) +{ + return (setFilter(filter, _data) && setFilter(filter, _dataThread)); +} + bool ZipFile::fileExists(const std::string &fileName) const { bool ret = false; @@ -533,6 +545,11 @@ bool ZipFile::fileExists(const std::string &fileName) const } unsigned char *ZipFile::getFileData(const std::string &fileName, unsigned long *pSize) +{ + return getFileData(fileName, pSize, _data); +} + +unsigned char *ZipFile::getFileData(const std::string &fileName, unsigned long *pSize, ZipFilePrivate *data) { unsigned char * pBuffer = NULL; if (pSize) @@ -542,29 +559,29 @@ unsigned char *ZipFile::getFileData(const std::string &fileName, unsigned long * do { - CC_BREAK_IF(!_data->zipFile); + CC_BREAK_IF(!data->zipFile); CC_BREAK_IF(fileName.empty()); - ZipFilePrivate::FileListContainer::const_iterator it = _data->fileList.find(fileName); - CC_BREAK_IF(it == _data->fileList.end()); + ZipFilePrivate::FileListContainer::const_iterator it = data->fileList.find(fileName); + CC_BREAK_IF(it == data->fileList.end()); ZipEntryInfo fileInfo = it->second; - int nRet = unzGoToFilePos(_data->zipFile, &fileInfo.pos); + int nRet = unzGoToFilePos(data->zipFile, &fileInfo.pos); CC_BREAK_IF(UNZ_OK != nRet); - nRet = unzOpenCurrentFile(_data->zipFile); + nRet = unzOpenCurrentFile(data->zipFile); CC_BREAK_IF(UNZ_OK != nRet); pBuffer = new unsigned char[fileInfo.uncompressed_size]; - int CC_UNUSED nSize = unzReadCurrentFile(_data->zipFile, pBuffer, fileInfo.uncompressed_size); + int CC_UNUSED nSize = unzReadCurrentFile(data->zipFile, pBuffer, fileInfo.uncompressed_size); CCAssert(nSize == 0 || nSize == (int)fileInfo.uncompressed_size, "the file size is wrong"); if (pSize) { *pSize = fileInfo.uncompressed_size; } - unzCloseCurrentFile(_data->zipFile); + unzCloseCurrentFile(data->zipFile); } while (0); return pBuffer; diff --git a/cocos2dx/support/zip_support/ZipUtils.h b/cocos2dx/support/zip_support/ZipUtils.h index 9a492e1cc6..60408390d6 100644 --- a/cocos2dx/support/zip_support/ZipUtils.h +++ b/cocos2dx/support/zip_support/ZipUtils.h @@ -27,6 +27,10 @@ THE SOFTWARE. #include #include "CCPlatformDefine.h" +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) +#include "platform/android/CCFileUtilsAndroid.h" +#endif + namespace cocos2d { /* XXX: pragma pack ??? */ @@ -166,6 +170,10 @@ namespace cocos2d class ZipFile { public: +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) + friend class CCFileUtilsAndroid; +#endif + /** * Constructor, open zip file and store file list. * @@ -211,8 +219,13 @@ namespace cocos2d unsigned char *getFileData(const std::string &fileName, unsigned long *pSize); private: + bool setFilter(const std::string &filer, ZipFilePrivate *data); + unsigned char *getFileData(const std::string &fileName, unsigned long *pSize, ZipFilePrivate *data); + /** Internal data like zip file pointer / file list array and so on */ ZipFilePrivate *_data; + /** Another data used not in main thread */ + ZipFilePrivate *_dataThread; }; } // end of namespace cocos2d #endif // __SUPPORT_ZIPUTILS_H__