123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- /****************************************************************************
- Copyright (c) 2010-2012 cocos2d-x.org
- Copyright (c) 2011 Zynga Inc.
- 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.
- ****************************************************************************/
- #import <Foundation/Foundation.h>
- #include "platform/apple/CCFileUtils-apple.h"
- #include <ftw.h>
- #include <string>
- #include <stack>
- #include "base/CCDirector.h"
- #include "platform/CCFileUtils.h"
- #include "platform/CCSAXParser.h"
- NS_CC_BEGIN
- struct FileUtilsApple::IMPL {
- IMPL(NSBundle* bundle):bundle_([NSBundle mainBundle]) {}
- void setBundle(NSBundle* bundle) {
- bundle_ = bundle;
- }
- NSBundle* getBundle() const {
- return bundle_;
- }
- private:
- NSBundle* bundle_;
- };
- static id convertCCValueToNSObject(const cocos2d::Value &value);
- static cocos2d::Value convertNSObjectToCCValue(id object);
- static void addNSObjectToCCMap(id nsKey, id nsValue, ValueMap& dict);
- static void addCCValueToNSDictionary(const std::string& key, const Value& value, NSMutableDictionary *dict);
- static void addNSObjectToCCVector(id item, ValueVector& array);
- static void addCCValueToNSArray(const Value& value, NSMutableArray *array);
- static id convertCCValueToNSObject(const cocos2d::Value &value)
- {
- switch (value.getType())
- {
- case Value::Type::NONE:
- return [NSNull null];
-
- case Value::Type::STRING:
- return [NSString stringWithCString:value.asString().c_str() encoding:NSUTF8StringEncoding];
-
- case Value::Type::BYTE:
- return [NSNumber numberWithInt:value.asByte()];
-
- case Value::Type::INTEGER:
- return [NSNumber numberWithInt:value.asInt()];
-
- case Value::Type::UNSIGNED:
- return [NSNumber numberWithUnsignedInt:value.asUnsignedInt()];
-
- case Value::Type::FLOAT:
- return [NSNumber numberWithFloat:value.asFloat()];
-
- case Value::Type::DOUBLE:
- return [NSNumber numberWithDouble:value.asDouble()];
-
- case Value::Type::BOOLEAN:
- return [NSNumber numberWithBool:value.asBool()];
-
- case Value::Type::VECTOR: {
- NSMutableArray *array = [NSMutableArray array];
- const ValueVector &vector = value.asValueVector();
- for (const auto &e : vector) {
- addCCValueToNSArray(e, array);
- }
- return array;
- }
-
- case Value::Type::MAP: {
- NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
- const ValueMap &map = value.asValueMap();
- for (auto& iter : map) {
- addCCValueToNSDictionary(iter.first, iter.second, dictionary);
- }
- return dictionary;
- }
-
- case Value::Type::INT_KEY_MAP:
- break;
- }
-
- return [NSNull null];
- }
- static cocos2d::Value convertNSObjectToCCValue(id item)
- {
- // add string value into array
- if ([item isKindOfClass:[NSString class]])
- {
- return Value([item UTF8String]);
- }
-
- // add number value into array(such as int, float, bool and so on)
- // the value is a number
- if ([item isKindOfClass:[NSNumber class]])
- {
- NSNumber* num = item;
- const char* numType = [num objCType];
- if(num == (void*)kCFBooleanFalse || num == (void*)kCFBooleanTrue)
- {
- bool v = [num boolValue];
- return Value(v);
- }
- else if(strcmp(numType, @encode(float)) == 0)
- {
- return Value([num floatValue]);
- }
- else if(strcmp(numType, @encode(double)) == 0)
- {
- return Value([num doubleValue]);
- }
- else
- {
- return Value([num intValue]);
- }
- }
-
-
- // add dictionary value into array
- if ([item isKindOfClass:[NSDictionary class]])
- {
- ValueMap dict;
- for (id subKey in [item allKeys])
- {
- id subValue = [item objectForKey:subKey];
- addNSObjectToCCMap(subKey, subValue, dict);
- }
-
- return Value(dict);
- }
-
- // add array value into array
- if ([item isKindOfClass:[NSArray class]])
- {
- ValueVector subArray;
- for (id subItem in item)
- {
- addNSObjectToCCVector(subItem, subArray);
- }
- return Value(subArray);
- }
-
- return Value::Null;
- }
- static void addNSObjectToCCVector(id item, ValueVector& array)
- {
- array.push_back(convertNSObjectToCCValue(item));
- }
- static void addCCValueToNSArray(const Value& value, NSMutableArray *array)
- {
- [array addObject:convertCCValueToNSObject(value)];
- }
- static void addNSObjectToCCMap(id nsKey, id nsValue, ValueMap& dict)
- {
- // the key must be a string
- CCASSERT([nsKey isKindOfClass:[NSString class]], "The key should be a string!");
- std::string key = [nsKey UTF8String];
- dict[key] = convertNSObjectToCCValue(nsValue);
- }
- static void addCCValueToNSDictionary(const std::string& key, const Value& value, NSMutableDictionary *dict)
- {
- NSString *NSkey = [NSString stringWithCString:key.c_str() encoding:NSUTF8StringEncoding];
- [dict setObject:convertCCValueToNSObject(value) forKey:NSkey];
- }
- FileUtilsApple::FileUtilsApple() : pimpl_(new IMPL([NSBundle mainBundle])) {
- }
- FileUtilsApple::~FileUtilsApple() = default;
- #if CC_FILEUTILS_APPLE_ENABLE_OBJC
- void FileUtilsApple::setBundle(NSBundle* bundle) {
- pimpl_->setBundle(bundle);
- }
- #endif
- #pragma mark - FileUtils
- static NSFileManager* s_fileManager = [NSFileManager defaultManager];
- FileUtils* FileUtils::getInstance()
- {
- if (s_sharedFileUtils == nullptr)
- {
- s_sharedFileUtils = new (std::nothrow) FileUtilsApple();
- if(!s_sharedFileUtils->init())
- {
- delete s_sharedFileUtils;
- s_sharedFileUtils = nullptr;
- CCLOG("ERROR: Could not init CCFileUtilsApple");
- }
- }
- return s_sharedFileUtils;
- }
- std::string FileUtilsApple::getWritablePath() const
- {
- if (_writablePath.length())
- {
- return _writablePath;
- }
- // save to document folder
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
- std::string strRet = [documentsDirectory UTF8String];
- strRet.append("/");
- return strRet;
- }
- bool FileUtilsApple::isFileExistInternal(const std::string& filePath) const
- {
- if (filePath.empty())
- {
- return false;
- }
- bool ret = false;
- if (filePath[0] != '/')
- {
- std::string path;
- std::string file;
- size_t pos = filePath.find_last_of("/");
- if (pos != std::string::npos)
- {
- file = filePath.substr(pos+1);
- path = filePath.substr(0, pos+1);
- }
- else
- {
- file = filePath;
- }
- NSString* fullpath = [pimpl_->getBundle() pathForResource:[NSString stringWithUTF8String:file.c_str()]
- ofType:nil
- inDirectory:[NSString stringWithUTF8String:path.c_str()]];
- if (fullpath != nil) {
- ret = true;
- }
- }
- else
- {
- // Search path is an absolute path.
- if ([s_fileManager fileExistsAtPath:[NSString stringWithUTF8String:filePath.c_str()]]) {
- ret = true;
- }
- }
- return ret;
- }
- static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
- {
- auto ret = remove(fpath);
- if (ret)
- {
- log("Fail to remove: %s ",fpath);
- }
- return ret;
- }
- bool FileUtilsApple::removeDirectory(const std::string& path)
- {
- if (path.empty())
- {
- CCLOGERROR("Fail to remove directory, path is empty!");
- return false;
- }
- if (nftw(path.c_str(),unlink_cb, 64, FTW_DEPTH | FTW_PHYS))
- return false;
- else
- return true;
- }
- std::string FileUtilsApple::getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) const
- {
- if (directory[0] != '/')
- {
- NSString* fullpath = [pimpl_->getBundle() pathForResource:[NSString stringWithUTF8String:filename.c_str()]
- ofType:nil
- inDirectory:[NSString stringWithUTF8String:directory.c_str()]];
- if (fullpath != nil) {
- return [fullpath UTF8String];
- }
- }
- else
- {
- std::string fullPath = directory+filename;
- // Search path is an absolute path.
- if ([s_fileManager fileExistsAtPath:[NSString stringWithUTF8String:fullPath.c_str()]]) {
- return fullPath;
- }
- }
- return "";
- }
- ValueMap FileUtilsApple::getValueMapFromFile(const std::string& filename)
- {
- auto d(FileUtils::getInstance()->getDataFromFile(filename));
- return getValueMapFromData(reinterpret_cast<char*>(d.getBytes()), static_cast<int>(d.getSize()));
- }
- ValueMap FileUtilsApple::getValueMapFromData(const char* filedata, int filesize)
- {
- NSData* file = [NSData dataWithBytes:filedata length:filesize];
- NSPropertyListFormat format;
- NSError* error;
- NSDictionary* dict = [NSPropertyListSerialization propertyListWithData:file options:NSPropertyListImmutable format:&format error:&error];
- ValueMap ret;
- if (dict != nil)
- {
- for (id key in [dict allKeys])
- {
- id value = [dict objectForKey:key];
- addNSObjectToCCMap(key, value, ret);
- }
- }
- return ret;
- }
- bool FileUtilsApple::writeToFile(const ValueMap& dict, const std::string &fullPath)
- {
- return writeValueMapToFile(dict, fullPath);
- }
- bool FileUtils::writeValueMapToFile(const ValueMap& dict, const std::string& fullPath)
- {
- valueMapCompact(const_cast<ValueMap&>(dict));
- //CCLOG("iOS||Mac Dictionary %d write to file %s", dict->_ID, fullPath.c_str());
- NSMutableDictionary *nsDict = [NSMutableDictionary dictionary];
- for (auto& iter : dict)
- {
- addCCValueToNSDictionary(iter.first, iter.second, nsDict);
- }
- NSString *file = [NSString stringWithUTF8String:fullPath.c_str()];
- // do it atomically
- return [nsDict writeToFile:file atomically:YES];
- }
- void FileUtilsApple::valueMapCompact(ValueMap& valueMap)
- {
- auto itr = valueMap.begin();
- while(itr != valueMap.end()){
- auto vtype = itr->second.getType();
- switch(vtype){
- case Value::Type::NONE:{
- itr = valueMap.erase(itr);
- continue;
- }
- break;
- case Value::Type::MAP:{
- valueMapCompact(itr->second.asValueMap());
- }
- break;
- case Value::Type::VECTOR:{
- valueVectorCompact(itr->second.asValueVector());
- }
- break;
- default:
- break;
- }
- ++itr;
- }
- }
- void FileUtilsApple::valueVectorCompact(ValueVector& valueVector)
- {
- auto itr = valueVector.begin();
- while(itr != valueVector.end()){
- auto vtype = (*itr).getType();
- switch(vtype){
- case Value::Type::NONE:{
- itr = valueVector.erase(itr);
- continue;
- }
- break;
- case Value::Type::MAP:{
- valueMapCompact((*itr).asValueMap());
- }
- break;
- case Value::Type::VECTOR:{
- valueVectorCompact((*itr).asValueVector());
- }
- break;
- default:
- break;
- }
- ++itr;
- }
- }
- bool FileUtils::writeValueVectorToFile(const ValueVector& vecData, const std::string& fullPath)
- {
- NSString* path = [NSString stringWithUTF8String:fullPath.c_str()];
- NSMutableArray* array = [NSMutableArray array];
- for (const auto &e : vecData)
- {
- addCCValueToNSArray(e, array);
- }
- [array writeToFile:path atomically:YES];
- return true;
- }
- ValueVector FileUtilsApple::getValueVectorFromFile(const std::string& filename)
- {
- // NSString* pPath = [NSString stringWithUTF8String:pFileName];
- // NSString* pathExtension= [pPath pathExtension];
- // pPath = [pPath stringByDeletingPathExtension];
- // pPath = [[NSBundle mainBundle] pathForResource:pPath ofType:pathExtension];
- // fixing cannot read data using Array::createWithContentsOfFile
- std::string fullPath = fullPathForFilename(filename);
- NSString* path = [NSString stringWithUTF8String:fullPath.c_str()];
- NSArray* array = [NSArray arrayWithContentsOfFile:path];
- ValueVector ret;
- for (id value in array)
- {
- addNSObjectToCCVector(value, ret);
- }
- return ret;
- }
- bool FileUtilsApple::createDirectory(const std::string& path)
- {
- CCASSERT(!path.empty(), "Invalid path");
-
- if (isDirectoryExist(path))
- return true;
-
- NSError* error;
-
- bool result = [s_fileManager createDirectoryAtPath:[NSString stringWithUTF8String:path.c_str()] withIntermediateDirectories:YES attributes:nil error:&error];
-
- if(!result && error != nil)
- {
- CCLOGERROR("Fail to create directory \"%s\": %s", path.c_str(), [error.localizedDescription UTF8String]);
- }
-
- return result;
- }
- NS_CC_END
|