fixed #2124: make CCImage::initWithIamgeFileThreadSafe() thread safe

This commit is contained in:
minggo 2013-06-18 17:10:54 +08:00
parent 25806536a2
commit e9d8595617
5 changed files with 91 additions and 28 deletions

View File

@ -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 <string>
#include <ctype.h>
@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -27,6 +27,10 @@ THE SOFTWARE.
#include <string>
#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__