From b6cf5871cda367bf96b585d5b5ace050ac0422e2 Mon Sep 17 00:00:00 2001 From: halx99 Date: Tue, 4 Feb 2020 22:28:54 +0800 Subject: [PATCH] Refactor UserDefault, use file mapping & plain binary encode/decode for all platform --- cocos/base/CCUserDefault-android.cpp | 243 ----------- cocos/base/CCUserDefault-apple.mm | 254 ----------- cocos/base/CCUserDefault.cpp | 413 ++++++------------ cocos/base/CCUserDefault.h | 53 +-- cocos/base/CMakeLists.txt | 3 - .../UserDefaultTest/UserDefaultTest.cpp | 111 ++--- 6 files changed, 191 insertions(+), 886 deletions(-) delete mode 100644 cocos/base/CCUserDefault-android.cpp delete mode 100644 cocos/base/CCUserDefault-apple.mm diff --git a/cocos/base/CCUserDefault-android.cpp b/cocos/base/CCUserDefault-android.cpp deleted file mode 100644 index 4e11e1ae1a..0000000000 --- a/cocos/base/CCUserDefault-android.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/**************************************************************************** -Copyright (c) 2010-2012 cocos2d-x.org -Copyright (c) 2013-2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -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 "base/CCUserDefault.h" -#include "platform/CCPlatformConfig.h" -#include "base/ccUtils.h" -#include "platform/CCCommon.h" -#include "base/base64.h" -#include "platform/CCFileUtils.h" - -#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) -#include "platform/android/jni/JniHelper.h" - -static const std::string helperClassName = "org.cocos2dx.lib.Cocos2dxHelper"; - -using namespace std; -NS_CC_BEGIN - -/** - * implements of UserDefault - */ - -UserDefault* UserDefault::_userDefault = nullptr; -string UserDefault::_filePath = string(""); -bool UserDefault::_isFilePathInitialized = false; - -UserDefault::~UserDefault() -{ -} - -UserDefault::UserDefault() -{ -} - - - -void UserDefault::destroyInstance() -{ - CC_SAFE_DELETE(_userDefault); -} - -bool UserDefault::getBoolForKey(const char* pKey) -{ - return getBoolForKey(pKey, false); -} - -bool UserDefault::getBoolForKey(const char* pKey, bool defaultValue) -{ - return JniHelper::callStaticBooleanMethod(helperClassName, "getBoolForKey", pKey, defaultValue); -} - -int UserDefault::getIntegerForKey(const char* pKey) -{ - return getIntegerForKey(pKey, 0); -} - -int UserDefault::getIntegerForKey(const char* pKey, int defaultValue) -{ - return JniHelper::callStaticIntMethod(helperClassName, "getIntegerForKey", pKey, defaultValue); -} - -float UserDefault::getFloatForKey(const char* pKey) -{ - return getFloatForKey(pKey, 0.0f); -} - -float UserDefault::getFloatForKey(const char* pKey, float defaultValue) -{ - return JniHelper::callStaticFloatMethod(helperClassName, "getFloatForKey", pKey, defaultValue); -} - -double UserDefault::getDoubleForKey(const char* pKey) -{ - return getDoubleForKey(pKey, 0.0); -} - -double UserDefault::getDoubleForKey(const char* pKey, double defaultValue) -{ - return JniHelper::callStaticDoubleMethod(helperClassName, "getDoubleForKey", pKey, defaultValue); -} - -std::string UserDefault::getStringForKey(const char* pKey) -{ - return getStringForKey(pKey, ""); -} - -string UserDefault::getStringForKey(const char* pKey, const std::string & defaultValue) -{ - return JniHelper::callStaticStringMethod(helperClassName, "getStringForKey", pKey, defaultValue); -} - -Data UserDefault::getDataForKey(const char* pKey) -{ - return getDataForKey(pKey, Data::Null); -} - -Data UserDefault::getDataForKey(const char* pKey, const Data& defaultValue) -{ - char * encodedDefaultData = NULL; - unsigned int encodedDefaultDataLen = !defaultValue.isNull() ? base64Encode(defaultValue.getBytes(), defaultValue.getSize(), &encodedDefaultData) : 0; - - string encodedStr = JniHelper::callStaticStringMethod(helperClassName, "getStringForKey", pKey, (const char*)encodedDefaultData); - - if (encodedDefaultData) - free(encodedDefaultData); - - CCLOG("ENCODED STRING: --%s--%d", encodedStr.c_str(), (int)encodedStr.length()); - - unsigned char * decodedData = NULL; - int decodedDataLen = base64Decode((unsigned char*)encodedStr.c_str(), (unsigned int)encodedStr.length(), &decodedData); - - CCLOG("DECODED DATA: %s %d", decodedData, decodedDataLen); - - if (decodedData && decodedDataLen) { - Data ret; - ret.fastSet(decodedData, decodedDataLen); - return ret; - } - - return defaultValue; -} - - -void UserDefault::setBoolForKey(const char* pKey, bool value) -{ - JniHelper::callStaticVoidMethod(helperClassName, "setBoolForKey", pKey, value); -} - -void UserDefault::setIntegerForKey(const char* pKey, int value) -{ - JniHelper::callStaticVoidMethod(helperClassName, "setIntegerForKey", pKey, value); -} - -void UserDefault::setFloatForKey(const char* pKey, float value) -{ - JniHelper::callStaticVoidMethod(helperClassName, "setFloatForKey", pKey, value); -} - -void UserDefault::setDoubleForKey(const char* pKey, double value) -{ - JniHelper::callStaticVoidMethod(helperClassName, "setDoubleForKey", pKey, value); -} - -void UserDefault::setStringForKey(const char* pKey, const std::string& value) -{ - JniHelper::callStaticVoidMethod(helperClassName, "setStringForKey", pKey, value); -} - -void UserDefault::setDataForKey(const char* pKey, const Data& value) -{ - CCLOG("SET DATA FOR KEY: --%s--%d", value.getBytes(), (int)(value.getSize())); - char * encodedData = nullptr; - unsigned int encodedDataLen = base64Encode(value.getBytes(), value.getSize(), &encodedData); - - CCLOG("SET DATA ENCODED: --%s", encodedData); - - JniHelper::callStaticVoidMethod(helperClassName, "setStringForKey", pKey, (const char*)encodedData); - - if (encodedData) - free(encodedData); -} - - -UserDefault* UserDefault::getInstance() -{ - if (! _userDefault) - { - _userDefault = new (std::nothrow) UserDefault(); - } - - return _userDefault; -} - -bool UserDefault::isXMLFileExist() -{ - return FileUtils::getInstance()->isFileExist(_filePath); -} - -void UserDefault::initXMLFilePath() -{ -//~ #ifdef KEEP_COMPATABILITY -//~ if (! _isFilePathInitialized) -//~ { -//~ // UserDefault.xml is stored in /data/data// before v2.1.2 -//~ std::string packageName = JniHelper::callStaticStringMethod(helperClassName, "getCocos2dxPackageName"); -//~ _filePath += "/data/data/" + packageName + "/" + XML_FILE_NAME; -//~ _isFilePathInitialized = true; -//~ } -//~ #endif -} - -// create new xml file -bool UserDefault::createXMLFile() -{ - return false; -} - -const string& UserDefault::getXMLFilePath() -{ - return _filePath; -} - -void UserDefault::flush() -{ -} - -void UserDefault::deleteValueForKey(const char* key) -{ - // check the params - if (!key) - { - CCLOG("the key is invalid"); - } - - JniHelper::callStaticVoidMethod(helperClassName, "deleteValueForKey", key); - - flush(); -} -NS_CC_END - -#endif // (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) diff --git a/cocos/base/CCUserDefault-apple.mm b/cocos/base/CCUserDefault-apple.mm deleted file mode 100644 index 5cb2686342..0000000000 --- a/cocos/base/CCUserDefault-apple.mm +++ /dev/null @@ -1,254 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2013-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - 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_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) - -#import - -#include - -#import "base/CCUserDefault.h" -#import "platform/CCPlatformConfig.h" -#import "platform/CCPlatformMacros.h" -#import "base/base64.h" -#import "platform/CCFileUtils.h" - -using namespace std; - -NS_CC_BEGIN - -/** - * implements of UserDefault - */ - -UserDefault* UserDefault::_userDefault = nullptr; -string UserDefault::_filePath = string(""); -bool UserDefault::_isFilePathInitialized = false; - -UserDefault::~UserDefault() -{ -} - -UserDefault::UserDefault() -{ -} - -bool UserDefault::getBoolForKey(const char* pKey) -{ - return getBoolForKey(pKey, false); -} - -bool UserDefault::getBoolForKey(const char* pKey, bool defaultValue) -{ - bool ret = defaultValue; - - NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithUTF8String:pKey]]; - if (value) - { - ret = [value boolValue]; - } - - return ret; -} - -int UserDefault::getIntegerForKey(const char* pKey) -{ - return getIntegerForKey(pKey, 0); -} - -int UserDefault::getIntegerForKey(const char* pKey, int defaultValue) -{ - int ret = defaultValue; - - NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithUTF8String:pKey]]; - if (value) - { - ret = [value intValue]; - } - - return ret; -} - -float UserDefault::getFloatForKey(const char* pKey) -{ - return getFloatForKey(pKey, 0); -} - -float UserDefault::getFloatForKey(const char* pKey, float defaultValue) -{ - float ret = defaultValue; - - NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithUTF8String:pKey]]; - if (value) - { - ret = [value floatValue]; - } - - return ret; -} - -double UserDefault::getDoubleForKey(const char* pKey) -{ - return getDoubleForKey(pKey, 0); -} - -double UserDefault::getDoubleForKey(const char* pKey, double defaultValue) -{ - double ret = defaultValue; - - NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithUTF8String:pKey]]; - if (value) - { - ret = [value doubleValue]; - } - - return ret; -} - -std::string UserDefault::getStringForKey(const char* pKey) -{ - return getStringForKey(pKey, ""); -} - -string UserDefault::getStringForKey(const char* pKey, const std::string & defaultValue) -{ - NSString *str = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithUTF8String:pKey]]; - if (! str) - { - return defaultValue; - } - else - { - return [str UTF8String]; - } -} - -Data UserDefault::getDataForKey(const char* pKey) -{ - return getDataForKey(pKey, Data::Null); -} - -Data UserDefault::getDataForKey(const char* pKey, const Data& defaultValue) -{ - NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[NSString stringWithUTF8String:pKey]]; - if (! data) - { - return defaultValue; - } - else - { - Data ret; - ret.copy((unsigned char*)data.bytes, data.length); - return ret; - } -} - -void UserDefault::setBoolForKey(const char* pKey, bool value) -{ - [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:value] forKey:[NSString stringWithUTF8String:pKey]]; -} - -void UserDefault::setIntegerForKey(const char* pKey, int value) -{ - [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:value] forKey:[NSString stringWithUTF8String:pKey]]; -} - -void UserDefault::setFloatForKey(const char* pKey, float value) -{ - [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:value] forKey:[NSString stringWithUTF8String:pKey]]; -} - -void UserDefault::setDoubleForKey(const char* pKey, double value) -{ - [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:value] forKey:[NSString stringWithUTF8String:pKey]]; -} - -void UserDefault::setStringForKey(const char* pKey, const std::string & value) -{ - [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithUTF8String:value.c_str()] forKey:[NSString stringWithUTF8String:pKey]]; -} - -void UserDefault::setDataForKey(const char* pKey, const Data& value) { - [[NSUserDefaults standardUserDefaults] setObject:[NSData dataWithBytes: value.getBytes() length: value.getSize()] forKey:[NSString stringWithUTF8String:pKey]]; -} - -UserDefault* UserDefault::getInstance() -{ - if (! _userDefault) - { - _userDefault = new (std::nothrow) UserDefault(); - } - - return _userDefault; -} - -void UserDefault::destroyInstance() -{ - CC_SAFE_DELETE(_userDefault); -} - -bool UserDefault::isXMLFileExist() -{ - return FileUtils::getInstance()->isFileExist(_filePath); -} - -void UserDefault::initXMLFilePath() -{ -} - -// create new xml file -bool UserDefault::createXMLFile() -{ - return false; -} - -const string& UserDefault::getXMLFilePath() -{ - return _filePath; -} - -void UserDefault::flush() -{ - [[NSUserDefaults standardUserDefaults] synchronize]; -} - -void UserDefault::deleteValueForKey(const char* key) -{ - // check the params - if (!key) - { - CCLOG("the key is invalid"); - } - - [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithUTF8String:key]]; - - flush(); -} - -NS_CC_END - -#endif // (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) diff --git a/cocos/base/CCUserDefault.cpp b/cocos/base/CCUserDefault.cpp index 98e535eeca..dce3a05d18 100644 --- a/cocos/base/CCUserDefault.cpp +++ b/cocos/base/CCUserDefault.cpp @@ -2,6 +2,7 @@ Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2013-2016 Chukong Technologies Inc. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. +Copyright (c) 2017-2020 c4games.com. http://www.cocos2d-x.org @@ -23,6 +24,16 @@ 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. ****************************************************************************/ +#if defined(_WIN32) +#include +#include +#else +#include +#include +#endif +#include +#include + #include "base/CCUserDefault.h" #include "platform/CCCommon.h" #include "platform/CCFileUtils.h" @@ -30,104 +41,49 @@ THE SOFTWARE. #include "base/base64.h" #include "base/ccUtils.h" -#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_MAC && CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID) +#include "yasio/ibstream.hpp" +#include "yasio/obstream.hpp" +#include "yasio/detail/sz.hpp" -// root name of xml -#define USERDEFAULT_ROOT_NAME "userDefaultRoot" +#if defined(_WIN32) +#define O_READ_FLAGS O_BINARY | O_RDONLY, S_IREAD +#define O_WRITE_FLAGS O_CREAT | O_RDWR | O_BINARY, S_IWRITE | S_IREAD +#define O_APPEND_FLAGS O_APPEND | O_CREAT | O_RDWR | O_BINARY, S_IWRITE | S_IREAD +#define posix_open ::_open +#define posix_close ::_close +#define posix_lseek ::_lseek +#define posix_read ::_read +#define posix_write ::_write +#define posix_fd2fh(fd) reinterpret_cast(_get_osfhandle(fd)) +#define posix_fsetsize(fd, size) ::_chsize(fd, size) +#else +#define O_READ_FLAGS O_RDONLY, S_IRUSR +#define O_WRITE_FLAGS O_CREAT | O_RDWR, S_IRWXU +#define O_APPEND_FLAGS O_APPEND | O_CREAT | O_RDWR, S_IRWXU +#define posix_open ::open +#define posix_close ::close +#define posix_lseek ::lseek +#define posix_read ::read +#define posix_write ::write +#define posix_fd2fh(fd) (fd) +#define posix_fsetsize(fd, size) ::ftruncate(fd, size), ::lseek(fd, 0, SEEK_SET) +#endif -#define XML_FILE_NAME "UserDefault.xml" - -using namespace std; +#define USER_DEFAULT_FILENAME "UserDefault.bin" NS_CC_BEGIN -/** - * define the functions here because we don't want to - * export xmlNodePtr and other types in "CCUserDefault.h" - */ - -static pugi::xml_node getXMLNodeForKey(const char* pKey, pugi::xml_node& rootNode, pugi::xml_document& doc) -{ - pugi::xml_node curNode; - - // check the key value - if (! pKey) - { - return pugi::xml_node{}; - } - - do - { - std::string xmlBuffer = FileUtils::getInstance()->getStringFromFile(UserDefault::getInstance()->getXMLFilePath()); - - if (!xmlBuffer.empty()) - { - doc.load_buffer_inplace(&xmlBuffer.front(), xmlBuffer.size()); - - // get root node - rootNode = doc.document_element(); - } - - if (!rootNode) - { - // create root element - auto rootEle = doc.append_child(USERDEFAULT_ROOT_NAME); - if (!rootEle) - break; - - rootNode = rootEle; - } - - curNode = rootNode.child(pKey); - - } while (0); - - return curNode; -} - -static void setValueForKey(const char* pKey, const char* pValue) -{ - pugi::xml_node rootNode; - pugi::xml_document doc; - pugi::xml_node node; - // check the params - if (! pKey || ! pValue) - { - return; - } - // find the node - node = getXMLNodeForKey(pKey, rootNode, doc); - // if node exist, change the content - if (node) - { - node.set_value(pValue); - } - else - { - if (rootNode) - { - node = rootNode.append_child(pKey); - node.set_value(pValue); - } - } - - // save file and free doc - if (doc) - { - doc.save_file(UserDefault::getInstance()->getXMLFilePath().c_str(), " "); - } -} - /** * implements of UserDefault */ UserDefault* UserDefault::_userDefault = nullptr; -string UserDefault::_filePath = string(""); -bool UserDefault::_isFilePathInitialized = false; UserDefault::~UserDefault() { + _rwmmap.reset(); + if (_fd != -1) + posix_close(_fd); } UserDefault::UserDefault() @@ -141,25 +97,11 @@ bool UserDefault::getBoolForKey(const char* pKey) bool UserDefault::getBoolForKey(const char* pKey, bool defaultValue) { - const char* value = nullptr; - pugi::xml_node rootNode; - pugi::xml_document doc; - pugi::xml_node node; - node = getXMLNodeForKey(pKey, rootNode, doc); - // find the node - if (node) - { - value = (const char*)node.text().as_string(); - } + auto it = this->_values.find(pKey); + if (it != this->_values.end()) + return it->second == "1"; - bool ret = defaultValue; - - if (value) - { - ret = (! strcmp(value, "true")); - } - - return ret; + return defaultValue; } int UserDefault::getIntegerForKey(const char* pKey) @@ -169,25 +111,11 @@ int UserDefault::getIntegerForKey(const char* pKey) int UserDefault::getIntegerForKey(const char* pKey, int defaultValue) { - const char* value = nullptr; - pugi::xml_node rootNode; - pugi::xml_document doc; - pugi::xml_node node; - node = getXMLNodeForKey(pKey, rootNode, doc); - // find the node - if (node) - { - value = (const char*)(const char*)node.text().as_string(); - } + auto it = this->_values.find(pKey); + if (it != this->_values.end()) + return atoi(it->second.c_str()); - int ret = defaultValue; - - if (value) - { - ret = atoi(value); - } - - return ret; + return defaultValue; } float UserDefault::getFloatForKey(const char* pKey) @@ -209,25 +137,11 @@ double UserDefault::getDoubleForKey(const char* pKey) double UserDefault::getDoubleForKey(const char* pKey, double defaultValue) { - const char* value = nullptr; - pugi::xml_node rootNode; - pugi::xml_document doc; - pugi::xml_node node; - node = getXMLNodeForKey(pKey, rootNode, doc); - // find the node - if (node) - { - value = (const char*)(const char*)node.text().as_string(); - } + auto it = this->_values.find(pKey); + if (it != this->_values.end()) + return utils::atof(it->second.c_str()); - double ret = defaultValue; - - if (value) - { - ret = utils::atof(value); - } - - return ret; + return defaultValue; } std::string UserDefault::getStringForKey(const char* pKey) @@ -235,79 +149,19 @@ std::string UserDefault::getStringForKey(const char* pKey) return getStringForKey(pKey, ""); } -string UserDefault::getStringForKey(const char* pKey, const std::string & defaultValue) +std::string UserDefault::getStringForKey(const char* pKey, const std::string & defaultValue) { - const char* value = nullptr; - pugi::xml_node rootNode; - pugi::xml_document doc; - pugi::xml_node node; - node = getXMLNodeForKey(pKey, rootNode, doc); - // find the node - if (node) - { - value = (const char*)(const char*)node.text().as_string(); - } + auto it = this->_values.find(pKey); + if (it != this->_values.end()) + return it->second; - string ret = defaultValue; - - if (value) - { - ret = string(value); - } - - return ret; + return defaultValue; } -Data UserDefault::getDataForKey(const char* pKey) -{ - return getDataForKey(pKey, Data::Null); -} - -Data UserDefault::getDataForKey(const char* pKey, const Data& defaultValue) -{ - const char* encodedData = nullptr; - pugi::xml_node rootNode; - pugi::xml_document doc; - pugi::xml_node node; - node = getXMLNodeForKey(pKey, rootNode, doc); - // find the node - if (node) - { - encodedData = (const char*)(const char*)node.text().as_string(); - } - - Data ret; - - if (encodedData) - { - unsigned char * decodedData = nullptr; - int decodedDataLen = base64Decode((unsigned char*)encodedData, (unsigned int)strlen(encodedData), &decodedData); - - if (decodedData) { - ret.fastSet(decodedData, decodedDataLen); - } - } - else - { - ret = defaultValue; - } - - return ret; -} - - void UserDefault::setBoolForKey(const char* pKey, bool value) { // save bool value as string - - if (true == value) - { - setStringForKey(pKey, "true"); - } - else - { - setStringForKey(pKey, "false"); - } + setStringForKey(pKey, value ? "true" : "false"); } void UserDefault::setIntegerForKey(const char* pKey, int value) @@ -323,7 +177,7 @@ void UserDefault::setIntegerForKey(const char* pKey, int value) memset(tmp, 0, 50); sprintf(tmp, "%d", value); - setValueForKey(pKey, tmp); + setStringForKey(pKey, tmp); } void UserDefault::setFloatForKey(const char* pKey, float value) @@ -344,7 +198,7 @@ void UserDefault::setDoubleForKey(const char* pKey, double value) memset(tmp, 0, 50); sprintf(tmp, "%f", value); - setValueForKey(pKey, tmp); + setStringForKey(pKey, tmp); } void UserDefault::setStringForKey(const char* pKey, const std::string & value) @@ -355,40 +209,22 @@ void UserDefault::setStringForKey(const char* pKey, const std::string & value) return; } - setValueForKey(pKey, value.c_str()); -} + auto it = this->_values.find(pKey); -void UserDefault::setDataForKey(const char* pKey, const Data& value) { - // check key - if (! pKey) - { - return; - } + if (it != this->_values.end()) + it->second = value; + else + this->_values.emplace(pKey, value); - char *encodedData = nullptr; - - base64Encode(value.getBytes(), static_cast(value.getSize()), &encodedData); - - setValueForKey(pKey, encodedData); - - if (encodedData) - free(encodedData); + flush(); } UserDefault* UserDefault::getInstance() { if (!_userDefault) { - initXMLFilePath(); - - // only create xml file one time - // the file exists after the program exit - if ((!isXMLFileExist()) && (!createXMLFile())) - { - return nullptr; - } - _userDefault = new (std::nothrow) UserDefault(); + _userDefault->init(); } return _userDefault; @@ -407,76 +243,71 @@ void UserDefault::setDelegate(UserDefault *delegate) _userDefault = delegate; } - -bool UserDefault::isXMLFileExist() +void UserDefault::init() { - return FileUtils::getInstance()->isFileExist(_filePath); -} - -void UserDefault::initXMLFilePath() -{ - if (! _isFilePathInitialized) + if (! _initialized) { - _filePath += FileUtils::getInstance()->getWritablePath() + XML_FILE_NAME; - _isFilePathInitialized = true; + _filePath = FileUtils::getInstance()->getWritablePath() + USER_DEFAULT_FILENAME; + + // construct file mapping + _fd = posix_open(_filePath.c_str(), O_WRITE_FLAGS); + if (_fd == -1) { + log("[Warnning] UserDefault::init open storage file '%s' failed!", _filePath.c_str()); + return; + } + + int filesize = posix_lseek(_fd, 0, SEEK_END); + posix_lseek(_fd, 0, SEEK_SET); + + if (filesize < _curMapSize) { + posix_fsetsize(_fd, _curMapSize); + } + /// load to memory _values + _rwmmap = std::make_shared(posix_fd2fh(_fd), 0, _curMapSize); + if (_rwmmap->is_mapped()) { // no error + yasio::ibstream_view ibs(_rwmmap->data(), _rwmmap->length()); + + if (ibs.length() > 0) { + // count + // key/value --> string/string + int count = ibs.read_i7(); + for (auto i = 0; i < count; ++i) { + auto key = ibs.read_v(); + auto value = ibs.read_v(); + this->_values.emplace(key, value); + } + } + } + + _initialized = true; } } -// create new xml file -bool UserDefault::createXMLFile() -{ - bool bRet = false; - - pugi::xml_document doc; - doc.load_string(R"()" -"<" USERDEFAULT_ROOT_NAME " />", pugi::parse_full); - - bRet = doc.save_file(_filePath.c_str(), " "); - - return bRet; -} - -const string& UserDefault::getXMLFilePath() -{ - return _filePath; -} - void UserDefault::flush() { + // TODO: Win32 store to UserDefault.plain file? + yasio::obstream obs; + obs.write_i7(this->_values.size()); + for (auto& item : this->_values) { + obs.write_v(item.first); + obs.write_v(item.second); + } + + if (obs.length() > _curMapSize) { + _rwmmap->unmap(); + std::error_code error; + _curMapSize <<= 1; // X2 + _rwmmap->map(posix_fd2fh(_fd), 0, _curMapSize, error); + } + + if (_rwmmap->is_mapped()) + memcpy(_rwmmap->data(), obs.data(), obs.length()); } void UserDefault::deleteValueForKey(const char* key) { - pugi::xml_node rootNode; - pugi::xml_document doc; - pugi::xml_node node; - - // check the params - if (!key) - { - CCLOG("the key is invalid"); - return; - } - - // find the node - node = getXMLNodeForKey(key, rootNode, doc); - - // if node not exist, don't need to delete - if (!node) - { - return; - } - - // save file and free doc - if (doc) - { - rootNode.remove_child(node); - doc.save_file(UserDefault::getInstance()->getXMLFilePath().c_str(), " "); - } - - flush(); + if(this->_values.erase(key) > 0) + flush(); } NS_CC_END - -#endif // (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_PLATFORM != CC_PLATFORM_ANDROID) diff --git a/cocos/base/CCUserDefault.h b/cocos/base/CCUserDefault.h index a42ebb8d78..8153d39841 100644 --- a/cocos/base/CCUserDefault.h +++ b/cocos/base/CCUserDefault.h @@ -2,6 +2,7 @@ Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2013-2016 Chukong Technologies Inc. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. +Copyright (c) 2017-2020 c4games.com. http://www.cocos2d-x.org @@ -28,7 +29,9 @@ THE SOFTWARE. #include "platform/CCPlatformMacros.h" #include -#include "base/CCData.h" + +#include +#include "mio/mio.hpp" /** * @addtogroup base @@ -139,23 +142,6 @@ public: */ virtual std::string getStringForKey(const char* key, const std::string & defaultValue); - /** - * Get Data value by key, if the key doesn't exist, will return an empty Data. - * @param key The key to get value. - * @return Data value of the key. - * @js NA - */ - Data getDataForKey(const char* key); - - /** - * Get Data value by key, if the key doesn't exist, will return an empty Data. - * @param key The key to get value. - * @param defaultValue The default value to return if the key doesn't exist. - * @return Data value of the key. - * @js NA - */ - virtual Data getDataForKey(const char* key, const Data& defaultValue); - // set value methods /** @@ -193,13 +179,7 @@ public: * @js NA */ virtual void setStringForKey(const char* key, const std::string & value); - /** - * Set Data value by key. - * @param key The key to set. - * @param value A Data value to set to the key. - * @js NA - */ - virtual void setDataForKey(const char* key, const Data& value); + /** * You should invoke this function to save values set by setXXXForKey(). * @js NA @@ -235,28 +215,21 @@ public: */ static void setDelegate(UserDefault *delegate); - /** All supported platforms other iOS & Android use xml file to save values. This function is return the file path of the xml path. - * @js NA - */ - static const std::string& getXMLFilePath(); - /** All supported platforms other iOS & Android use xml file to save values. This function checks whether the xml file exists or not. - * @return True if the xml file exists, false if not. - * @js NA - */ - static bool isXMLFileExist(); - protected: UserDefault(); virtual ~UserDefault(); + void init(); private: - - static bool createXMLFile(); - static void initXMLFilePath(); + + std::unordered_map _values; static UserDefault* _userDefault; - static std::string _filePath; - static bool _isFilePathInitialized; + std::string _filePath; + int _fd = -1; // the file handle for data persistence + std::shared_ptr _rwmmap; + int _curMapSize = 4096; // init mapsize is 4K + bool _initialized = false; }; diff --git a/cocos/base/CMakeLists.txt b/cocos/base/CMakeLists.txt index 5c7f70e164..a7381bb58f 100644 --- a/cocos/base/CMakeLists.txt +++ b/cocos/base/CMakeLists.txt @@ -1,13 +1,11 @@ if(APPLE) set(COCOS_BASE_SPECIFIC_SRC - base/CCUserDefault-apple.mm base/CCController-apple.mm ) elseif(ANDROID) set(COCOS_BASE_SPECIFIC_SRC - base/CCUserDefault-android.cpp base/CCController-android.cpp ) elseif(LINUX OR WINDOWS) @@ -134,5 +132,4 @@ set(COCOS_BASE_SRC base/pvr.cpp base/s3tc.cpp ${COCOS_BASE_SPECIFIC_SRC} - ) diff --git a/tests/cpp-tests/Classes/UserDefaultTest/UserDefaultTest.cpp b/tests/cpp-tests/Classes/UserDefaultTest/UserDefaultTest.cpp index bf090ccec3..270286e559 100644 --- a/tests/cpp-tests/Classes/UserDefaultTest/UserDefaultTest.cpp +++ b/tests/cpp-tests/Classes/UserDefaultTest/UserDefaultTest.cpp @@ -1,5 +1,6 @@ /**************************************************************************** Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + Copyright (c) 2020 c4games.com. http://www.cocos2d-x.org @@ -58,50 +59,50 @@ UserDefaultTest::UserDefaultTest() doTest(); } -template -void logData(const char* key) -{ - Data data = UserDefault::getInstance()->getDataForKey(key); - T* buffer = (T*) data.getBytes(); - ssize_t length = data.getSize() / sizeof(T); +//template +//void logData(const char* key) +//{ +// Data data = UserDefault::getInstance()->getDataForKey(key); +// T* buffer = (T*) data.getBytes(); +// ssize_t length = data.getSize() / sizeof(T); +// +// std::ostringstream ss; +// ss << setprecision(2) << std::fixed; +// for (int i = 0; i < length; i++) +// { +// ss << buffer[i] << " "; +// } +// +// CCLOG("%s is %s", key, ss.str().c_str()); +//} - std::ostringstream ss; - ss << setprecision(2) << std::fixed; - for (int i = 0; i < length; i++) - { - ss << buffer[i] << " "; - } - - CCLOG("%s is %s", key, ss.str().c_str()); -} - -template -void setData(const char* key) -{ - Data data; - vector v; - - for (int i = 0; i <= 5; i++) - { - v.push_back(static_cast(i)); - } - data.copy((unsigned char*) v.data(), v.size() * sizeof(T)); - UserDefault::getInstance()->setDataForKey(key, data); -} - -template -void setData2(const char* key) -{ - Data data; - vector v; - - for (int i = 5; i >= 0; i--) - { - v.push_back(static_cast(i)); - } - data.copy((unsigned char*) v.data(), v.size() * sizeof(T)); - UserDefault::getInstance()->setDataForKey(key, data); -} +//template +//void setData(const char* key) +//{ +// Data data; +// vector v; +// +// for (int i = 0; i <= 5; i++) +// { +// v.push_back(static_cast(i)); +// } +// data.copy((unsigned char*) v.data(), v.size() * sizeof(T)); +// UserDefault::getInstance()->setDataForKey(key, data); +//} +// +//template +//void setData2(const char* key) +//{ +// Data data; +// vector v; +// +// for (int i = 5; i >= 0; i--) +// { +// v.push_back(static_cast(i)); +// } +// data.copy((unsigned char*) v.data(), v.size() * sizeof(T)); +// UserDefault::getInstance()->setDataForKey(key, data); +//} void UserDefaultTest::doTest() { @@ -116,15 +117,15 @@ void UserDefaultTest::doTest() UserDefault::getInstance()->setBoolForKey("bool", true); // test saving of Data buffers - setData("int_data"); - setData("float_data"); - setData("double_data"); +// setData("int_data"); +// setData("float_data"); +// setData("double_data"); printValue(); - logData("int_data"); - logData("float_data"); - logData("double_data"); +// logData("int_data"); +// logData("float_data"); +// logData("double_data"); //CCUserDefault::getInstance()->flush(); @@ -138,18 +139,18 @@ void UserDefaultTest::doTest() UserDefault::getInstance()->setDoubleForKey("double", 2.6); UserDefault::getInstance()->setBoolForKey("bool", false); - setData2("int_data"); - setData2("float_data"); - setData2("double_data"); +// setData2("int_data"); +// setData2("float_data"); +// setData2("double_data"); UserDefault::getInstance()->flush(); // print value printValue(); - logData("int_data"); - logData("float_data"); - logData("double_data"); +// logData("int_data"); +// logData("float_data"); +// logData("double_data"); this->_label->setString(this->_label->getString() + "\n" + "********************** after delete value ***********************");