2012-04-19 14:35:52 +08:00
|
|
|
/****************************************************************************
|
2012-09-24 21:22:20 +08:00
|
|
|
Copyright (c) 2010-2012 cocos2d-x.org
|
2018-01-29 16:25:32 +08:00
|
|
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
|
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
2020-02-04 22:28:54 +08:00
|
|
|
Copyright (c) 2017-2020 c4games.com.
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
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.
|
|
|
|
****************************************************************************/
|
2020-02-04 22:28:54 +08:00
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <io.h>
|
|
|
|
#include <direct.h>
|
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2014-05-17 05:36:00 +08:00
|
|
|
#include "base/CCUserDefault.h"
|
|
|
|
#include "platform/CCCommon.h"
|
|
|
|
#include "platform/CCFileUtils.h"
|
2019-11-24 23:15:56 +08:00
|
|
|
#include "pugixml/pugixml_imp.hpp"
|
2014-04-30 08:37:36 +08:00
|
|
|
#include "base/base64.h"
|
2014-07-14 23:05:16 +08:00
|
|
|
#include "base/ccUtils.h"
|
2013-03-05 14:53:37 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
#include "yasio/ibstream.hpp"
|
|
|
|
#include "yasio/obstream.hpp"
|
|
|
|
#include "yasio/detail/sz.hpp"
|
|
|
|
|
|
|
|
#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<HANDLE>(_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 USER_DEFAULT_FILENAME "UserDefault.bin"
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2020-02-06 01:08:51 +08:00
|
|
|
typedef int32_t udflen_t;
|
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
NS_CC_BEGIN
|
|
|
|
|
|
|
|
/**
|
2013-06-20 14:13:12 +08:00
|
|
|
* implements of UserDefault
|
2012-04-19 14:35:52 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-20 14:06:24 +08:00
|
|
|
UserDefault* UserDefault::_userDefault = nullptr;
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2020-02-06 01:08:51 +08:00
|
|
|
static void updateMapValue(std::unordered_map<std::string, std::string>& valueMap, const char* key, const char* value)
|
|
|
|
{
|
|
|
|
auto it = valueMap.find(key);
|
|
|
|
if (it != valueMap.end())
|
|
|
|
it->second = value;
|
|
|
|
else
|
|
|
|
valueMap.emplace(key, value);
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
UserDefault::~UserDefault()
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-06 01:08:51 +08:00
|
|
|
closeFileMapping();
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
UserDefault::UserDefault()
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-02-06 01:08:51 +08:00
|
|
|
void UserDefault::closeFileMapping()
|
|
|
|
{
|
|
|
|
_rwmmap.reset();
|
|
|
|
if (_fd != -1) {
|
|
|
|
posix_close(_fd);
|
|
|
|
_fd = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-12 06:24:23 +08:00
|
|
|
bool UserDefault::getBoolForKey(const char* pKey)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-07-12 06:24:23 +08:00
|
|
|
return getBoolForKey(pKey, false);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
bool UserDefault::getBoolForKey(const char* pKey, bool defaultValue)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-04 22:28:54 +08:00
|
|
|
auto it = this->_values.find(pKey);
|
|
|
|
if (it != this->_values.end())
|
|
|
|
return it->second == "1";
|
2013-01-26 10:41:27 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
return defaultValue;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
int UserDefault::getIntegerForKey(const char* pKey)
|
2012-11-16 14:11:21 +08:00
|
|
|
{
|
|
|
|
return getIntegerForKey(pKey, 0);
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
int UserDefault::getIntegerForKey(const char* pKey, int defaultValue)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-04 22:28:54 +08:00
|
|
|
auto it = this->_values.find(pKey);
|
|
|
|
if (it != this->_values.end())
|
|
|
|
return atoi(it->second.c_str());
|
2013-01-26 10:41:27 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
return defaultValue;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
float UserDefault::getFloatForKey(const char* pKey)
|
2012-11-16 14:11:21 +08:00
|
|
|
{
|
|
|
|
return getFloatForKey(pKey, 0.0f);
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
float UserDefault::getFloatForKey(const char* pKey, float defaultValue)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
float ret = (float)getDoubleForKey(pKey, (double)defaultValue);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
double UserDefault::getDoubleForKey(const char* pKey)
|
2012-11-16 14:11:21 +08:00
|
|
|
{
|
|
|
|
return getDoubleForKey(pKey, 0.0);
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
double UserDefault::getDoubleForKey(const char* pKey, double defaultValue)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-04 22:28:54 +08:00
|
|
|
auto it = this->_values.find(pKey);
|
|
|
|
if (it != this->_values.end())
|
|
|
|
return utils::atof(it->second.c_str());
|
2013-01-26 10:41:27 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
return defaultValue;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
std::string UserDefault::getStringForKey(const char* pKey)
|
2012-11-16 14:11:21 +08:00
|
|
|
{
|
|
|
|
return getStringForKey(pKey, "");
|
|
|
|
}
|
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
std::string UserDefault::getStringForKey(const char* pKey, const std::string & defaultValue)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-04 22:28:54 +08:00
|
|
|
auto it = this->_values.find(pKey);
|
|
|
|
if (it != this->_values.end())
|
|
|
|
return it->second;
|
2013-01-26 10:41:27 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
return defaultValue;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void UserDefault::setBoolForKey(const char* pKey, bool value)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2012-09-17 15:02:24 +08:00
|
|
|
// save bool value as string
|
2020-02-04 22:28:54 +08:00
|
|
|
setStringForKey(pKey, value ? "true" : "false");
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void UserDefault::setIntegerForKey(const char* pKey, int value)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
// check key
|
|
|
|
if (! pKey)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// format the value
|
|
|
|
char tmp[50];
|
|
|
|
memset(tmp, 0, 50);
|
|
|
|
sprintf(tmp, "%d", value);
|
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
setStringForKey(pKey, tmp);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void UserDefault::setFloatForKey(const char* pKey, float value)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
setDoubleForKey(pKey, value);
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void UserDefault::setDoubleForKey(const char* pKey, double value)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
// check key
|
|
|
|
if (! pKey)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// format the value
|
|
|
|
char tmp[50];
|
|
|
|
memset(tmp, 0, 50);
|
|
|
|
sprintf(tmp, "%f", value);
|
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
setStringForKey(pKey, tmp);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void UserDefault::setStringForKey(const char* pKey, const std::string & value)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-06 01:08:51 +08:00
|
|
|
// ignore empty key
|
|
|
|
if (! pKey || !*pKey)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-06 01:08:51 +08:00
|
|
|
updateMapValue(_values, pKey, value.c_str());
|
|
|
|
|
|
|
|
if (_rwmmap) {
|
|
|
|
yasio::obstream obs;
|
|
|
|
obs.write_v(pKey);
|
|
|
|
obs.write_v(value);
|
|
|
|
if ((_realSize + obs.length() + sizeof(udflen_t)) < _curMapSize)
|
|
|
|
{
|
|
|
|
// increase entities count
|
|
|
|
auto count = yasio::endian::ntohv(*(udflen_t*)_rwmmap->data());
|
|
|
|
*(udflen_t*)_rwmmap->data() = yasio::endian::htonv(count + 1);
|
|
|
|
|
|
|
|
// append entities
|
|
|
|
::memcpy(_rwmmap->data() + sizeof(udflen_t) + _realSize, obs.data(), obs.length());
|
|
|
|
_realSize += obs.length();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
flush();
|
|
|
|
}
|
|
|
|
}
|
2013-05-29 08:06:41 +08:00
|
|
|
}
|
|
|
|
|
2013-07-12 06:24:23 +08:00
|
|
|
UserDefault* UserDefault::getInstance()
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2015-04-20 03:07:48 +08:00
|
|
|
if (!_userDefault)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2014-08-28 07:31:57 +08:00
|
|
|
_userDefault = new (std::nothrow) UserDefault();
|
2020-02-04 22:28:54 +08:00
|
|
|
_userDefault->init();
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-07-12 06:24:23 +08:00
|
|
|
return _userDefault;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UserDefault::destroyInstance()
|
|
|
|
{
|
2013-12-20 14:06:24 +08:00
|
|
|
CC_SAFE_DELETE(_userDefault);
|
2013-07-12 06:24:23 +08:00
|
|
|
}
|
|
|
|
|
2015-04-20 03:07:48 +08:00
|
|
|
void UserDefault::setDelegate(UserDefault *delegate)
|
|
|
|
{
|
|
|
|
if (_userDefault)
|
|
|
|
delete _userDefault;
|
|
|
|
|
|
|
|
_userDefault = delegate;
|
|
|
|
}
|
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
void UserDefault::init()
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-04 22:28:54 +08:00
|
|
|
if (! _initialized)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-04 22:28:54 +08:00
|
|
|
_filePath = FileUtils::getInstance()->getWritablePath() + USER_DEFAULT_FILENAME;
|
2013-01-26 10:41:27 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2019-11-24 23:15:56 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
int filesize = posix_lseek(_fd, 0, SEEK_END);
|
|
|
|
posix_lseek(_fd, 0, SEEK_SET);
|
2013-01-26 10:41:27 +08:00
|
|
|
|
2020-02-06 01:08:51 +08:00
|
|
|
if (filesize < _curMapSize) { // construct a empty file mapping
|
2020-02-04 22:28:54 +08:00
|
|
|
posix_fsetsize(_fd, _curMapSize);
|
2020-02-06 01:08:51 +08:00
|
|
|
_rwmmap = std::make_shared<mio::mmap_sink>(posix_fd2fh(_fd), 0, _curMapSize);
|
2020-02-04 22:28:54 +08:00
|
|
|
}
|
2020-02-06 01:08:51 +08:00
|
|
|
else { /// load to memory _values
|
|
|
|
_rwmmap = std::make_shared<mio::mmap_sink>(posix_fd2fh(_fd), 0, mio::map_entire_file);
|
|
|
|
if (_rwmmap->is_mapped()) { // no error
|
|
|
|
yasio::ibstream_view ibs(_rwmmap->data(), _rwmmap->length());
|
|
|
|
|
|
|
|
if (ibs.length() > 0) {
|
|
|
|
// read count of keyvals.
|
|
|
|
int count = ibs.read_i<int>();
|
|
|
|
for (auto i = 0; i < count; ++i) {
|
|
|
|
auto key = ibs.read_v();
|
|
|
|
auto value = ibs.read_v();
|
|
|
|
updateMapValue(this->_values, key.data(), value.data());
|
|
|
|
}
|
|
|
|
_realSize = ibs.seek(0, SEEK_CUR) - sizeof(udflen_t);
|
2020-02-04 22:28:54 +08:00
|
|
|
}
|
|
|
|
}
|
2020-02-06 01:08:51 +08:00
|
|
|
else {
|
|
|
|
closeFileMapping();
|
|
|
|
::remove(_filePath.c_str());
|
|
|
|
log("[Warnning] UserDefault::init map file '%s' failed, we can't save data persisit this time, next time we will retry!", _filePath.c_str());
|
|
|
|
}
|
2020-02-04 22:28:54 +08:00
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
_initialized = true;
|
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-20 14:13:12 +08:00
|
|
|
void UserDefault::flush()
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2020-02-06 01:08:51 +08:00
|
|
|
// TODO: Win32 store to UserDefault.plain file
|
|
|
|
if (_rwmmap) {
|
|
|
|
yasio::obstream obs;
|
|
|
|
obs.write_i<int>(static_cast<int>(this->_values.size()));
|
|
|
|
for (auto& item : this->_values) {
|
|
|
|
obs.write_v(item.first);
|
|
|
|
obs.write_v(item.second);
|
|
|
|
}
|
2015-07-06 17:01:17 +08:00
|
|
|
|
2020-02-06 01:08:51 +08:00
|
|
|
if (obs.length() > _curMapSize) {
|
|
|
|
_rwmmap->unmap();
|
|
|
|
std::error_code error;
|
|
|
|
_curMapSize <<= 1; // X2
|
|
|
|
_rwmmap->map(posix_fd2fh(_fd), 0, _curMapSize, error);
|
|
|
|
}
|
2015-07-06 17:01:17 +08:00
|
|
|
|
2020-02-06 01:08:51 +08:00
|
|
|
if (_rwmmap->is_mapped())
|
|
|
|
{ // mapping status is good
|
|
|
|
::memcpy(_rwmmap->data(), obs.data(), obs.length());
|
|
|
|
_realSize = obs.length() - sizeof(udflen_t);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// close file mapping and do a simple workaround fix to don't do persist later at this time
|
|
|
|
closeFileMapping();
|
|
|
|
::remove(_filePath.c_str());
|
|
|
|
}
|
|
|
|
}
|
2020-02-04 22:28:54 +08:00
|
|
|
}
|
2015-07-06 17:01:17 +08:00
|
|
|
|
2020-02-04 22:28:54 +08:00
|
|
|
void UserDefault::deleteValueForKey(const char* key)
|
|
|
|
{
|
|
|
|
if(this->_values.erase(key) > 0)
|
|
|
|
flush();
|
2015-07-06 17:01:17 +08:00
|
|
|
}
|
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
NS_CC_END
|