From 694b9adc1e24870ec715081bd7e7b03d06f6863a Mon Sep 17 00:00:00 2001 From: Vladimir Perminov Date: Sun, 19 Apr 2015 14:00:27 +0300 Subject: [PATCH] Add FileUtils::getSuitableFOpen win32 fopen only ansi encoding. if filePath contains utf8 characters fopen fail. AudioCache FileFormat::OGG bag, can't open file, if filePath contains utf8. Need make all filename for fopen correct encoding. Only Win32 FileUtils::getSuitableFOpen return StringUtf8ToAnsi(filename), other platform return filename all fopen use FileUtils::getSuitableFOpen --- cocos/audio/win32/AudioCache.cpp | 6 +- cocos/audio/win32/AudioPlayer.cpp | 6 +- cocos/base/CCConsole.cpp | 6 +- cocos/base/CCConsole.h | 2 - cocos/base/CCUserDefault.cpp | 4 +- cocos/platform/CCFileUtils.cpp | 11 ++- cocos/platform/CCFileUtils.h | 10 +++ cocos/platform/CCImage.cpp | 4 +- cocos/platform/win32/CCFileUtils-win32.cpp | 80 +++++++++++++++++++ cocos/platform/win32/CCFileUtils-win32.h | 11 +++ extensions/assets-manager/AssetsManager.cpp | 6 +- extensions/assets-manager/AssetsManagerEx.cpp | 2 +- extensions/assets-manager/Downloader.cpp | 4 +- 13 files changed, 130 insertions(+), 22 deletions(-) diff --git a/cocos/audio/win32/AudioCache.cpp b/cocos/audio/win32/AudioCache.cpp index caa838c764..4f9698e1fe 100644 --- a/cocos/audio/win32/AudioCache.cpp +++ b/cocos/audio/win32/AudioCache.cpp @@ -29,6 +29,7 @@ #include #include #include "base/CCConsole.h" +#include "platform/CCFileUtils.h" #include "mpg123.h" #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" @@ -96,8 +97,9 @@ void AudioCache::readDataTask() case FileFormat::OGG: { vf = new OggVorbis_File; - if (ov_fopen(_fileFullPath.c_str(), vf)){ - log("Input does not appear to be an Ogg bitstream.\n"); + int openCode; + if (openCode = ov_fopen(FileUtils::getInstance()->getSuitableFOpen(_fileFullPath).c_str(), vf)){ + log("Input does not appear to be an Ogg bitstream: %s. Code: 0x%x\n", _fileFullPath.c_str(), openCode); goto ExitThread; } diff --git a/cocos/audio/win32/AudioPlayer.cpp b/cocos/audio/win32/AudioPlayer.cpp index 58d75ab74e..e7225e5f04 100644 --- a/cocos/audio/win32/AudioPlayer.cpp +++ b/cocos/audio/win32/AudioPlayer.cpp @@ -27,6 +27,7 @@ #include "AudioPlayer.h" #include "AudioCache.h" #include "base/CCConsole.h" +#include "platform/CCFileUtils.h" #include "mpg123.h" #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" @@ -162,8 +163,9 @@ void AudioPlayer::rotateBufferThread(int offsetFrame) case AudioCache::FileFormat::OGG: { vorbisFile = new OggVorbis_File; - if (ov_fopen(_audioCache->_fileFullPath.c_str(), vorbisFile)){ - log("Input does not appear to be an Ogg bitstream.\n"); + int openCode; + if (openCode = ov_fopen(FileUtils::getInstance()->getSuitableFOpen(_audioCache->_fileFullPath).c_str(), vorbisFile)){ + log("Input does not appear to be an Ogg bitstream: %s. Code: 0x%x\n", _audioCache->_fileFullPath.c_str(), openCode); goto ExitBufferThread; } if (offsetFrame != 0) { diff --git a/cocos/base/CCConsole.cpp b/cocos/base/CCConsole.cpp index dfdab8199f..f31c7d1469 100644 --- a/cocos/base/CCConsole.cpp +++ b/cocos/base/CCConsole.cpp @@ -330,7 +330,6 @@ Console::Console() { _commands[commands[i].name] = commands[i]; } - _writablePath = FileUtils::getInstance()->getWritablePath(); } Console::~Console() @@ -870,9 +869,10 @@ void Console::commandUpload(int fd) } *ptr = 0; - std::string filepath = _writablePath + std::string(buf); + static std::string writablePath = FileUtils::getInstance()->getWritablePath(); + std::string filepath = writablePath + std::string(buf); - FILE* fp = fopen(filepath.c_str(), "wb"); + FILE* fp = fopen(FileUtils::getInstance()->getSuitableFOpen(filepath).c_str(), "wb"); if(!fp) { const char err[] = "can't create file!\n"; diff --git a/cocos/base/CCConsole.h b/cocos/base/CCConsole.h index 2ab3fc93b3..b61e52f594 100644 --- a/cocos/base/CCConsole.h +++ b/cocos/base/CCConsole.h @@ -140,8 +140,6 @@ protected: bool _running; bool _endThread; - std::string _writablePath; - std::map _commands; // strings generated by cocos2d sent to the remote console diff --git a/cocos/base/CCUserDefault.cpp b/cocos/base/CCUserDefault.cpp index f22d4216da..9a4dbeb9e5 100644 --- a/cocos/base/CCUserDefault.cpp +++ b/cocos/base/CCUserDefault.cpp @@ -132,7 +132,7 @@ static void setValueForKey(const char* pKey, const char* pValue) // save file and free doc if (doc) { - doc->SaveFile(UserDefault::getInstance()->getXMLFilePath().c_str()); + doc->SaveFile(FileUtils::getInstance()->getSuitableFOpen(UserDefault::getInstance()->getXMLFilePath()).c_str()); delete doc; } } @@ -484,7 +484,7 @@ bool UserDefault::createXMLFile() return false; } pDoc->LinkEndChild(pRootEle); - bRet = tinyxml2::XML_SUCCESS == pDoc->SaveFile(_filePath.c_str()); + bRet = tinyxml2::XML_SUCCESS == pDoc->SaveFile(FileUtils::getInstance()->getSuitableFOpen(_filePath).c_str()); if(pDoc) { diff --git a/cocos/platform/CCFileUtils.cpp b/cocos/platform/CCFileUtils.cpp index 687065359d..4b884942b1 100644 --- a/cocos/platform/CCFileUtils.cpp +++ b/cocos/platform/CCFileUtils.cpp @@ -403,7 +403,7 @@ bool FileUtils::writeToFile(ValueMap& dict, const std::string &fullPath) } rootEle->LinkEndChild(innerDict); - bool ret = tinyxml2::XML_SUCCESS == doc->SaveFile(fullPath.c_str()); + bool ret = tinyxml2::XML_SUCCESS == doc->SaveFile(getSuitableFOpen(fullPath).c_str()); delete doc; return ret; @@ -566,7 +566,7 @@ static Data getData(const std::string& filename, bool forString) { // Read the file from hardware std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filename); - FILE *fp = fopen(fullPath.c_str(), mode); + FILE *fp = fopen(FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str(), mode); CC_BREAK_IF(!fp); fseek(fp,0,SEEK_END); size = ftell(fp); @@ -629,7 +629,7 @@ unsigned char* FileUtils::getFileData(const std::string& filename, const char* m { // read the file from hardware const std::string fullPath = fullPathForFilename(filename); - FILE *fp = fopen(fullPath.c_str(), mode); + FILE *fp = fopen(getSuitableFOpen(fullPath).c_str(), mode); CC_BREAK_IF(!fp); fseek(fp,0,SEEK_END); @@ -1364,5 +1364,10 @@ bool FileUtils::isPopupNotify() const return s_popupNotify; } +std::string FileUtils::getSuitableFOpen(const std::string& filenameUtf8) const +{ + return filenameUtf8; +} + NS_CC_END diff --git a/cocos/platform/CCFileUtils.h b/cocos/platform/CCFileUtils.h index 62474c2a62..9967cb9b9f 100644 --- a/cocos/platform/CCFileUtils.h +++ b/cocos/platform/CCFileUtils.h @@ -330,6 +330,16 @@ public: // This method is used internally. virtual bool writeToFile(ValueMap& dict, const std::string& fullPath); + /** + * Windows fopen can't support UTF-8 filename + * Need convert all parameters fopen and other 3rd-party libs + * CC_PLATFORM_WP8 and CC_PLATFORM_WINRT the same needs? + * + * @param filename std::string name file for convertation from utf-8 + * @return std::string ansi filename in current locale + */ + virtual std::string getSuitableFOpen(const std::string& filenameUtf8) const; + // Converts the contents of a file to a ValueVector. // This method is used internally. virtual ValueVector getValueVectorFromFile(const std::string& filename); diff --git a/cocos/platform/CCImage.cpp b/cocos/platform/CCImage.cpp index 03f6ab82a0..f5bfde9e2f 100644 --- a/cocos/platform/CCImage.cpp +++ b/cocos/platform/CCImage.cpp @@ -2232,7 +2232,7 @@ bool Image::saveImageToPNG(const std::string& filePath, bool isToRGB) png_colorp palette; png_bytep *row_pointers; - fp = fopen(filePath.c_str(), "wb"); + fp = fopen(FileUtils::getInstance()->getSuitableFOpen(filePath).c_str(), "wb"); CC_BREAK_IF(nullptr == fp); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); @@ -2388,7 +2388,7 @@ bool Image::saveImageToJPG(const std::string& filePath) /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); - CC_BREAK_IF((outfile = fopen(filePath.c_str(), "wb")) == nullptr); + CC_BREAK_IF((outfile = fopen(FileUtils::getInstance()->getSuitableFOpen(filePath).c_str(), "wb")) == nullptr); jpeg_stdio_dest(&cinfo, outfile); diff --git a/cocos/platform/win32/CCFileUtils-win32.cpp b/cocos/platform/win32/CCFileUtils-win32.cpp index 7ed1ed8c1f..57bbefe353 100644 --- a/cocos/platform/win32/CCFileUtils-win32.cpp +++ b/cocos/platform/win32/CCFileUtils-win32.cpp @@ -56,6 +56,81 @@ static inline std::string convertPathFormatToUnixStyle(const std::string& path) return ret; } +static std::wstring StringUtf8ToWideChar(const std::string& strUtf8) +{ + std::wstring ret; + if (!strUtf8.empty()) + { + int nNum = MultiByteToWideChar(CP_UTF8, 0, strUtf8.c_str(), -1, nullptr, 0); + if (nNum) + { + WCHAR* wideCharString = new WCHAR[nNum + 1]; + wideCharString[0] = 0; + + nNum = MultiByteToWideChar(CP_UTF8, 0, strUtf8.c_str(), -1, wideCharString, nNum + 1); + + ret = wideCharString; + delete[] wideCharString; + } + else + { + CCLOG("Wrong convert to WideChar code:0x%x", GetLastError()); + } + } + return ret; +} + +static std::string StringWideCharToUtf8(const std::wstring& strWideChar) +{ + std::string ret; + if (!strWideChar.empty()) + { + int nNum = WideCharToMultiByte(CP_UTF8, 0, strWideChar.c_str(), -1, nullptr, 0, nullptr, FALSE); + if (nNum) + { + char* utf8String = new char[nNum + 1]; + utf8String[0] = 0; + + nNum = WideCharToMultiByte(CP_UTF8, 0, strWideChar.c_str(), -1, utf8String, nNum + 1, nullptr, FALSE); + + ret = utf8String; + delete[] utf8String; + } + else + { + CCLOG("Wrong convert to Utf8 code:0x%x", GetLastError()); + } + } + + return ret; +} + +static std::string StringUtf8ToAnsi(const std::string& strUtf8) +{ + std::string ret; + if (!strUtf8.empty()) + { + std::wstring strWideChar = NS_CC::StringUtf8ToWideChar(strUtf8); + int nNum = WideCharToMultiByte(CP_ACP, 0, strWideChar.c_str(), -1, nullptr, 0, nullptr, FALSE); + if (nNum) + { + char* ansiString = new char[nNum + 1]; + ansiString[0] = 0; + + nNum = WideCharToMultiByte(CP_ACP, 0, strWideChar.c_str(), -1, ansiString, nNum + 1, nullptr, FALSE); + + ret = ansiString; + delete[] ansiString; + } + else + { + CCLOG("Wrong convert to Ansi code:0x%x", GetLastError()); + } + } + + return ret; +} + static void _checkPath() { if (0 == s_resourcePath.length()) @@ -334,6 +409,11 @@ string FileUtilsWin32::getWritablePath() const return ret; } +std::string FileUtilsWin32::getSuitableFOpen(const std::string& filenameUtf8) const +{ + return StringUtf8ToAnsi(filenameUtf8); +} + NS_CC_END #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 diff --git a/cocos/platform/win32/CCFileUtils-win32.h b/cocos/platform/win32/CCFileUtils-win32.h index 17f6c1ec01..f45e96779d 100644 --- a/cocos/platform/win32/CCFileUtils-win32.h +++ b/cocos/platform/win32/CCFileUtils-win32.h @@ -54,6 +54,17 @@ public: protected: virtual bool isFileExistInternal(const std::string& strFilePath) const; + + + /** + * Windows fopen can't support UTF-8 filename + * Need convert all parameters fopen and other 3rd-party libs + * CC_PLATFORM_WP8 and CC_PLATFORM_WINRT the same needs? + * + * @param filename std::string name file for convertation from utf-8 + * @return std::string ansi filename in current locale + */ + virtual std::string getSuitableFOpen(const std::string& filenameUtf8) const override; /** * Gets resource file data diff --git a/extensions/assets-manager/AssetsManager.cpp b/extensions/assets-manager/AssetsManager.cpp index cfdc61fae1..9f34ea124b 100644 --- a/extensions/assets-manager/AssetsManager.cpp +++ b/extensions/assets-manager/AssetsManager.cpp @@ -359,7 +359,7 @@ bool AssetsManager::uncompress() { const string dir=_storagePath+fileNameStr.substr(0,index); - FILE *out = fopen(dir.c_str(), "r"); + FILE *out = fopen(FileUtils::getInstance()->getSuitableFOpen(dir).c_str(), "r"); if(!out) { @@ -398,7 +398,7 @@ bool AssetsManager::uncompress() } // Create a file to store current file. - FILE *out = fopen(fullPath.c_str(), "wb"); + FILE *out = fopen(FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str(), "wb"); if (! out) { CCLOG("can not open destination file %s", fullPath.c_str()); @@ -517,7 +517,7 @@ bool AssetsManager::downLoad() { // Create a file to save package. const string outFileName = _storagePath + TEMP_PACKAGE_FILE_NAME; - FILE *fp = fopen(outFileName.c_str(), "wb"); + FILE *fp = fopen(FileUtils::getInstance()->getSuitableFOpen(outFileName).c_str(), "wb"); if (! fp) { Director::getInstance()->getScheduler()->performFunctionInCocosThread([&, this]{ diff --git a/extensions/assets-manager/AssetsManagerEx.cpp b/extensions/assets-manager/AssetsManagerEx.cpp index 18798a1feb..25fcdcb157 100644 --- a/extensions/assets-manager/AssetsManagerEx.cpp +++ b/extensions/assets-manager/AssetsManagerEx.cpp @@ -355,7 +355,7 @@ bool AssetsManagerEx::decompress(const std::string &zip) } // Create a file to store current file. - FILE *out = fopen(fullPath.c_str(), "wb"); + FILE *out = fopen(FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str(), "wb"); if (!out) { CCLOG("AssetsManagerEx : can not create decompress destination file %s\n", fullPath.c_str()); diff --git a/extensions/assets-manager/Downloader.cpp b/extensions/assets-manager/Downloader.cpp index d35d8d21dd..2c724010fb 100644 --- a/extensions/assets-manager/Downloader.cpp +++ b/extensions/assets-manager/Downloader.cpp @@ -259,11 +259,11 @@ void Downloader::prepareDownload(const std::string &srcUrl, const std::string &s const std::string outFileName = storagePath + TEMP_EXT; if (_supportResuming && resumeDownload && _fileUtils->isFileExist(outFileName)) { - fDesc->fp = fopen(outFileName.c_str(), "ab"); + fDesc->fp = fopen(FileUtils::getInstance()->getSuitableFOpen(outFileName).c_str(), "ab"); } else { - fDesc->fp = fopen(outFileName.c_str(), "wb"); + fDesc->fp = fopen(FileUtils::getInstance()->getSuitableFOpen(outFileName).c_str(), "wb"); } if (!fDesc->fp) {