react-native-mmkv-dz 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +219 -0
- package/MMKV/CHANGELOG.md +553 -0
- package/MMKV/Core/CMakeLists.txt +153 -0
- package/MMKV/Core/CodedInputData.cpp +228 -0
- package/MMKV/Core/CodedInputData.h +83 -0
- package/MMKV/Core/CodedInputDataCrypt.cpp +280 -0
- package/MMKV/Core/CodedInputDataCrypt.h +87 -0
- package/MMKV/Core/CodedInputDataCrypt_OSX.cpp +62 -0
- package/MMKV/Core/CodedInputData_OSX.cpp +92 -0
- package/MMKV/Core/CodedOutputData.cpp +174 -0
- package/MMKV/Core/CodedOutputData.h +82 -0
- package/MMKV/Core/Core.xcodeproj/project.pbxproj +702 -0
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +67 -0
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +67 -0
- package/MMKV/Core/InterProcessLock.cpp +186 -0
- package/MMKV/Core/InterProcessLock.h +119 -0
- package/MMKV/Core/InterProcessLock_Android.cpp +103 -0
- package/MMKV/Core/InterProcessLock_Win32.cpp +108 -0
- package/MMKV/Core/KeyValueHolder.cpp +236 -0
- package/MMKV/Core/KeyValueHolder.h +118 -0
- package/MMKV/Core/MMBuffer.cpp +185 -0
- package/MMKV/Core/MMBuffer.h +107 -0
- package/MMKV/Core/MMKV.cpp +1418 -0
- package/MMKV/Core/MMKV.h +386 -0
- package/MMKV/Core/MMKVLog.cpp +127 -0
- package/MMKV/Core/MMKVLog.h +86 -0
- package/MMKV/Core/MMKVLog_Android.cpp +79 -0
- package/MMKV/Core/MMKVMetaInfo.hpp +81 -0
- package/MMKV/Core/MMKVPredef.h +245 -0
- package/MMKV/Core/MMKV_Android.cpp +259 -0
- package/MMKV/Core/MMKV_IO.cpp +1119 -0
- package/MMKV/Core/MMKV_IO.h +57 -0
- package/MMKV/Core/MMKV_OSX.cpp +347 -0
- package/MMKV/Core/MMKV_OSX.h +51 -0
- package/MMKV/Core/MemoryFile.cpp +537 -0
- package/MMKV/Core/MemoryFile.h +182 -0
- package/MMKV/Core/MemoryFile_Android.cpp +211 -0
- package/MMKV/Core/MemoryFile_Linux.cpp +120 -0
- package/MMKV/Core/MemoryFile_OSX.cpp +142 -0
- package/MMKV/Core/MemoryFile_Win32.cpp +536 -0
- package/MMKV/Core/MiniPBCoder.cpp +366 -0
- package/MMKV/Core/MiniPBCoder.h +129 -0
- package/MMKV/Core/MiniPBCoder_OSX.cpp +228 -0
- package/MMKV/Core/PBEncodeItem.hpp +86 -0
- package/MMKV/Core/PBUtility.cpp +61 -0
- package/MMKV/Core/PBUtility.h +153 -0
- package/MMKV/Core/ScopedLock.hpp +69 -0
- package/MMKV/Core/ThreadLock.cpp +68 -0
- package/MMKV/Core/ThreadLock.h +78 -0
- package/MMKV/Core/ThreadLock_Win32.cpp +89 -0
- package/MMKV/Core/aes/AESCrypt.cpp +256 -0
- package/MMKV/Core/aes/AESCrypt.h +107 -0
- package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +1231 -0
- package/MMKV/Core/aes/openssl/openssl_aes.h +118 -0
- package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +1044 -0
- package/MMKV/Core/aes/openssl/openssl_aes_locl.h +38 -0
- package/MMKV/Core/aes/openssl/openssl_aesv8-armx.S +308 -0
- package/MMKV/Core/aes/openssl/openssl_arm_arch.h +84 -0
- package/MMKV/Core/aes/openssl/openssl_cfb128.cpp +97 -0
- package/MMKV/Core/aes/openssl/openssl_md32_common.h +254 -0
- package/MMKV/Core/aes/openssl/openssl_md5.h +49 -0
- package/MMKV/Core/aes/openssl/openssl_md5_dgst.cpp +166 -0
- package/MMKV/Core/aes/openssl/openssl_md5_locl.h +75 -0
- package/MMKV/Core/aes/openssl/openssl_md5_one.cpp +30 -0
- package/MMKV/Core/aes/openssl/openssl_opensslconf.h +271 -0
- package/MMKV/Core/core.vcxproj +186 -0
- package/MMKV/Core/core.vcxproj.filters +150 -0
- package/MMKV/Core/crc32/Checksum.h +67 -0
- package/MMKV/Core/crc32/crc32_armv8.cpp +132 -0
- package/MMKV/Core/crc32/zlib/crc32.cpp +55 -0
- package/MMKV/Core/crc32/zlib/crc32.h +48 -0
- package/MMKV/Core/crc32/zlib/zconf.h +380 -0
- package/MMKV/Core/crc32/zlib/zutil.h +25 -0
- package/MMKV/LICENSE.TXT +193 -0
- package/MMKV/README.md +288 -0
- package/README.md +221 -0
- package/android/CMakeLists.txt +71 -0
- package/android/build.gradle +371 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/cpp/MmkvHostObject.cpp +302 -0
- package/android/src/main/cpp/MmkvHostObject.h +26 -0
- package/android/src/main/cpp/cpp-adapter.cpp +65 -0
- package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +49 -0
- package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +26 -0
- package/cpp/TypedArray.cpp +341 -0
- package/cpp/TypedArray.h +175 -0
- package/ios/JSIUtils.h +50 -0
- package/ios/JSIUtils.mm +194 -0
- package/ios/Mmkv.xcodeproj/project.pbxproj +291 -0
- package/ios/MmkvHostObject.h +27 -0
- package/ios/MmkvHostObject.mm +299 -0
- package/ios/MmkvModule.h +5 -0
- package/ios/MmkvModule.mm +73 -0
- package/lib/commonjs/MMKV.js +146 -0
- package/lib/commonjs/MMKV.js.map +1 -0
- package/lib/commonjs/PlatformChecker.js +16 -0
- package/lib/commonjs/PlatformChecker.js.map +1 -0
- package/lib/commonjs/createMMKV.js +66 -0
- package/lib/commonjs/createMMKV.js.map +1 -0
- package/lib/commonjs/createMMKV.mock.js +40 -0
- package/lib/commonjs/createMMKV.mock.js.map +1 -0
- package/lib/commonjs/createMMKV.web.js +77 -0
- package/lib/commonjs/createMMKV.web.js.map +1 -0
- package/lib/commonjs/createTextEncoder.js +24 -0
- package/lib/commonjs/createTextEncoder.js.map +1 -0
- package/lib/commonjs/hooks.js +200 -0
- package/lib/commonjs/hooks.js.map +1 -0
- package/lib/commonjs/index.js +32 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/MMKV.js +134 -0
- package/lib/module/MMKV.js.map +1 -0
- package/lib/module/PlatformChecker.js +9 -0
- package/lib/module/PlatformChecker.js.map +1 -0
- package/lib/module/createMMKV.js +55 -0
- package/lib/module/createMMKV.js.map +1 -0
- package/lib/module/createMMKV.mock.js +31 -0
- package/lib/module/createMMKV.mock.js.map +1 -0
- package/lib/module/createMMKV.web.js +67 -0
- package/lib/module/createMMKV.web.js.map +1 -0
- package/lib/module/createTextEncoder.js +17 -0
- package/lib/module/createTextEncoder.js.map +1 -0
- package/lib/module/hooks.js +181 -0
- package/lib/module/hooks.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/MMKV.d.ts +137 -0
- package/lib/typescript/PlatformChecker.d.ts +1 -0
- package/lib/typescript/createMMKV.d.ts +6 -0
- package/lib/typescript/createMMKV.mock.d.ts +2 -0
- package/lib/typescript/createMMKV.web.d.ts +2 -0
- package/lib/typescript/createTextEncoder.d.ts +1 -0
- package/lib/typescript/hooks.d.ts +81 -0
- package/lib/typescript/index.d.ts +2 -0
- package/package.json +168 -0
- package/react-native-mmkv.podspec +32 -0
|
@@ -0,0 +1,1418 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tencent is pleased to support the open source community by making
|
|
3
|
+
* MMKV available.
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
|
6
|
+
* All rights reserved.
|
|
7
|
+
*
|
|
8
|
+
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
|
9
|
+
* this file except in compliance with the License. You may obtain a copy of
|
|
10
|
+
* the License at
|
|
11
|
+
*
|
|
12
|
+
* https://opensource.org/licenses/BSD-3-Clause
|
|
13
|
+
*
|
|
14
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
* See the License for the specific language governing permissions and
|
|
18
|
+
* limitations under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
#include "CodedInputData.h"
|
|
22
|
+
#include "CodedOutputData.h"
|
|
23
|
+
#include "InterProcessLock.h"
|
|
24
|
+
#include "KeyValueHolder.h"
|
|
25
|
+
#include "MMBuffer.h"
|
|
26
|
+
#include "MMKVLog.h"
|
|
27
|
+
#include "MMKVMetaInfo.hpp"
|
|
28
|
+
#include "MMKV_IO.h"
|
|
29
|
+
#include "MemoryFile.h"
|
|
30
|
+
#include "MiniPBCoder.h"
|
|
31
|
+
#include "PBUtility.h"
|
|
32
|
+
#include "ScopedLock.hpp"
|
|
33
|
+
#include "ThreadLock.h"
|
|
34
|
+
#include "aes/AESCrypt.h"
|
|
35
|
+
#include "aes/openssl/openssl_aes.h"
|
|
36
|
+
#include "aes/openssl/openssl_md5.h"
|
|
37
|
+
#include "crc32/Checksum.h"
|
|
38
|
+
#include <algorithm>
|
|
39
|
+
#include <cstdio>
|
|
40
|
+
#include <cstring>
|
|
41
|
+
#include <unordered_set>
|
|
42
|
+
//#include <unistd.h>
|
|
43
|
+
|
|
44
|
+
#if defined(__aarch64__) && defined(__linux)
|
|
45
|
+
# include <asm/hwcap.h>
|
|
46
|
+
# include <sys/auxv.h>
|
|
47
|
+
#endif
|
|
48
|
+
|
|
49
|
+
#ifdef MMKV_APPLE
|
|
50
|
+
# if __has_feature(objc_arc)
|
|
51
|
+
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
|
52
|
+
# endif
|
|
53
|
+
#endif // MMKV_APPLE
|
|
54
|
+
|
|
55
|
+
using namespace std;
|
|
56
|
+
using namespace mmkv;
|
|
57
|
+
|
|
58
|
+
unordered_map<string, MMKV *> *g_instanceDic;
|
|
59
|
+
ThreadLock *g_instanceLock;
|
|
60
|
+
MMKVPath_t g_rootDir;
|
|
61
|
+
static mmkv::ErrorHandler g_errorHandler;
|
|
62
|
+
size_t mmkv::DEFAULT_MMAP_SIZE;
|
|
63
|
+
|
|
64
|
+
#ifndef MMKV_WIN32
|
|
65
|
+
constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = "specialCharacter";
|
|
66
|
+
constexpr auto CRC_SUFFIX = ".crc";
|
|
67
|
+
#else
|
|
68
|
+
constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = L"specialCharacter";
|
|
69
|
+
constexpr auto CRC_SUFFIX = L".crc";
|
|
70
|
+
#endif
|
|
71
|
+
|
|
72
|
+
constexpr uint32_t Fixed32Size = pbFixed32Size();
|
|
73
|
+
|
|
74
|
+
MMKV_NAMESPACE_BEGIN
|
|
75
|
+
|
|
76
|
+
static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir);
|
|
77
|
+
bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix);
|
|
78
|
+
MMKVPath_t filename(const MMKVPath_t &path);
|
|
79
|
+
|
|
80
|
+
#ifndef MMKV_ANDROID
|
|
81
|
+
MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath)
|
|
82
|
+
: m_mmapID(mmapID)
|
|
83
|
+
, m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
|
|
84
|
+
, m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
|
|
85
|
+
, m_dic(nullptr)
|
|
86
|
+
, m_dicCrypt(nullptr)
|
|
87
|
+
, m_file(new MemoryFile(m_path))
|
|
88
|
+
, m_metaFile(new MemoryFile(m_crcPath))
|
|
89
|
+
, m_metaInfo(new MMKVMetaInfo())
|
|
90
|
+
, m_crypter(nullptr)
|
|
91
|
+
, m_lock(new ThreadLock())
|
|
92
|
+
, m_fileLock(new FileLock(m_metaFile->getFd()))
|
|
93
|
+
, m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
|
|
94
|
+
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
|
|
95
|
+
, m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0) {
|
|
96
|
+
m_actualSize = 0;
|
|
97
|
+
m_output = nullptr;
|
|
98
|
+
|
|
99
|
+
# ifndef MMKV_DISABLE_CRYPT
|
|
100
|
+
if (cryptKey && cryptKey->length() > 0) {
|
|
101
|
+
m_dicCrypt = new MMKVMapCrypt();
|
|
102
|
+
m_crypter = new AESCrypt(cryptKey->data(), cryptKey->length());
|
|
103
|
+
} else {
|
|
104
|
+
m_dic = new MMKVMap();
|
|
105
|
+
}
|
|
106
|
+
# else
|
|
107
|
+
m_dic = new MMKVMap();
|
|
108
|
+
# endif
|
|
109
|
+
|
|
110
|
+
m_needLoadFromFile = true;
|
|
111
|
+
m_hasFullWriteback = false;
|
|
112
|
+
|
|
113
|
+
m_crcDigest = 0;
|
|
114
|
+
|
|
115
|
+
m_lock->initialize();
|
|
116
|
+
m_sharedProcessLock->m_enable = m_isInterProcess;
|
|
117
|
+
m_exclusiveProcessLock->m_enable = m_isInterProcess;
|
|
118
|
+
|
|
119
|
+
// sensitive zone
|
|
120
|
+
{
|
|
121
|
+
SCOPED_LOCK(m_sharedProcessLock);
|
|
122
|
+
loadFromFile();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
#endif
|
|
126
|
+
|
|
127
|
+
MMKV::~MMKV() {
|
|
128
|
+
clearMemoryCache();
|
|
129
|
+
|
|
130
|
+
delete m_dic;
|
|
131
|
+
#ifndef MMKV_DISABLE_CRYPT
|
|
132
|
+
delete m_dicCrypt;
|
|
133
|
+
delete m_crypter;
|
|
134
|
+
#endif
|
|
135
|
+
delete m_file;
|
|
136
|
+
delete m_metaFile;
|
|
137
|
+
delete m_metaInfo;
|
|
138
|
+
delete m_lock;
|
|
139
|
+
delete m_fileLock;
|
|
140
|
+
delete m_sharedProcessLock;
|
|
141
|
+
delete m_exclusiveProcessLock;
|
|
142
|
+
#ifdef MMKV_ANDROID
|
|
143
|
+
delete m_fileModeLock;
|
|
144
|
+
delete m_sharedProcessModeLock;
|
|
145
|
+
delete m_exclusiveProcessModeLock;
|
|
146
|
+
#endif
|
|
147
|
+
|
|
148
|
+
MMKVInfo("destruct [%s]", m_mmapID.c_str());
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
MMKV *MMKV::defaultMMKV(MMKVMode mode, string *cryptKey) {
|
|
152
|
+
#ifndef MMKV_ANDROID
|
|
153
|
+
return mmkvWithID(DEFAULT_MMAP_ID, mode, cryptKey);
|
|
154
|
+
#else
|
|
155
|
+
return mmkvWithID(DEFAULT_MMAP_ID, DEFAULT_MMAP_SIZE, mode, cryptKey);
|
|
156
|
+
#endif
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
void initialize() {
|
|
160
|
+
g_instanceDic = new unordered_map<string, MMKV *>;
|
|
161
|
+
g_instanceLock = new ThreadLock();
|
|
162
|
+
g_instanceLock->initialize();
|
|
163
|
+
|
|
164
|
+
mmkv::DEFAULT_MMAP_SIZE = mmkv::getPageSize();
|
|
165
|
+
MMKVInfo("version %s, page size %d, arch %s", MMKV_VERSION, DEFAULT_MMAP_SIZE, MMKV_ABI);
|
|
166
|
+
|
|
167
|
+
// get CPU status of ARMv8 extensions (CRC32, AES)
|
|
168
|
+
#if defined(__aarch64__) && defined(__linux__)
|
|
169
|
+
auto hwcaps = getauxval(AT_HWCAP);
|
|
170
|
+
# ifndef MMKV_DISABLE_CRYPT
|
|
171
|
+
if (hwcaps & HWCAP_AES) {
|
|
172
|
+
openssl::AES_set_encrypt_key = openssl_aes_armv8_set_encrypt_key;
|
|
173
|
+
openssl::AES_set_decrypt_key = openssl_aes_armv8_set_decrypt_key;
|
|
174
|
+
openssl::AES_encrypt = openssl_aes_armv8_encrypt;
|
|
175
|
+
openssl::AES_decrypt = openssl_aes_armv8_decrypt;
|
|
176
|
+
MMKVInfo("armv8 AES instructions is supported");
|
|
177
|
+
} else {
|
|
178
|
+
MMKVInfo("armv8 AES instructions is not supported");
|
|
179
|
+
}
|
|
180
|
+
# endif // MMKV_DISABLE_CRYPT
|
|
181
|
+
# ifdef MMKV_USE_ARMV8_CRC32
|
|
182
|
+
if (hwcaps & HWCAP_CRC32) {
|
|
183
|
+
CRC32 = mmkv::armv8_crc32;
|
|
184
|
+
MMKVInfo("armv8 CRC32 instructions is supported");
|
|
185
|
+
} else {
|
|
186
|
+
MMKVInfo("armv8 CRC32 instructions is not supported");
|
|
187
|
+
}
|
|
188
|
+
# endif // MMKV_USE_ARMV8_CRC32
|
|
189
|
+
#endif // __aarch64__ && defined(__linux__)
|
|
190
|
+
|
|
191
|
+
#if defined(MMKV_DEBUG) && !defined(MMKV_DISABLE_CRYPT)
|
|
192
|
+
AESCrypt::testAESCrypt();
|
|
193
|
+
KeyValueHolderCrypt::testAESToMMBuffer();
|
|
194
|
+
#endif
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
ThreadOnceToken_t once_control = ThreadOnceUninitialized;
|
|
198
|
+
|
|
199
|
+
void MMKV::initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel) {
|
|
200
|
+
g_currentLogLevel = logLevel;
|
|
201
|
+
|
|
202
|
+
ThreadLock::ThreadOnce(&once_control, initialize);
|
|
203
|
+
|
|
204
|
+
g_rootDir = rootDir;
|
|
205
|
+
mkPath(g_rootDir);
|
|
206
|
+
|
|
207
|
+
MMKVInfo("root dir: " MMKV_PATH_FORMAT, g_rootDir.c_str());
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const MMKVPath_t &MMKV::getRootDir() {
|
|
211
|
+
return g_rootDir;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
#ifndef MMKV_ANDROID
|
|
215
|
+
MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath) {
|
|
216
|
+
|
|
217
|
+
if (mmapID.empty()) {
|
|
218
|
+
return nullptr;
|
|
219
|
+
}
|
|
220
|
+
SCOPED_LOCK(g_instanceLock);
|
|
221
|
+
|
|
222
|
+
auto mmapKey = mmapedKVKey(mmapID, rootPath);
|
|
223
|
+
auto itr = g_instanceDic->find(mmapKey);
|
|
224
|
+
if (itr != g_instanceDic->end()) {
|
|
225
|
+
MMKV *kv = itr->second;
|
|
226
|
+
return kv;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (rootPath) {
|
|
230
|
+
MMKVPath_t specialPath = (*rootPath) + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
231
|
+
if (!isFileExist(specialPath)) {
|
|
232
|
+
mkPath(specialPath);
|
|
233
|
+
}
|
|
234
|
+
MMKVInfo("prepare to load %s (id %s) from rootPath %s", mmapID.c_str(), mmapKey.c_str(), rootPath->c_str());
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
auto kv = new MMKV(mmapID, mode, cryptKey, rootPath);
|
|
238
|
+
kv->m_mmapKey = mmapKey;
|
|
239
|
+
(*g_instanceDic)[mmapKey] = kv;
|
|
240
|
+
return kv;
|
|
241
|
+
}
|
|
242
|
+
#endif
|
|
243
|
+
|
|
244
|
+
void MMKV::onExit() {
|
|
245
|
+
SCOPED_LOCK(g_instanceLock);
|
|
246
|
+
|
|
247
|
+
for (auto &pair : *g_instanceDic) {
|
|
248
|
+
MMKV *kv = pair.second;
|
|
249
|
+
kv->sync();
|
|
250
|
+
kv->clearMemoryCache();
|
|
251
|
+
delete kv;
|
|
252
|
+
pair.second = nullptr;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
delete g_instanceDic;
|
|
256
|
+
g_instanceDic = nullptr;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const string &MMKV::mmapID() const {
|
|
260
|
+
return m_mmapID;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
mmkv::ContentChangeHandler g_contentChangeHandler = nullptr;
|
|
264
|
+
|
|
265
|
+
void MMKV::notifyContentChanged() {
|
|
266
|
+
if (g_contentChangeHandler) {
|
|
267
|
+
g_contentChangeHandler(m_mmapID);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
void MMKV::checkContentChanged() {
|
|
272
|
+
SCOPED_LOCK(m_lock);
|
|
273
|
+
checkLoadData();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
void MMKV::registerContentChangeHandler(mmkv::ContentChangeHandler handler) {
|
|
277
|
+
g_contentChangeHandler = handler;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
void MMKV::unRegisterContentChangeHandler() {
|
|
281
|
+
g_contentChangeHandler = nullptr;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
void MMKV::clearMemoryCache() {
|
|
285
|
+
SCOPED_LOCK(m_lock);
|
|
286
|
+
if (m_needLoadFromFile) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
MMKVInfo("clearMemoryCache [%s]", m_mmapID.c_str());
|
|
290
|
+
m_needLoadFromFile = true;
|
|
291
|
+
m_hasFullWriteback = false;
|
|
292
|
+
|
|
293
|
+
clearDictionary(m_dic);
|
|
294
|
+
#ifndef MMKV_DISABLE_CRYPT
|
|
295
|
+
clearDictionary(m_dicCrypt);
|
|
296
|
+
if (m_crypter) {
|
|
297
|
+
if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
|
|
298
|
+
m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
|
|
299
|
+
} else {
|
|
300
|
+
m_crypter->resetIV();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
#endif
|
|
304
|
+
|
|
305
|
+
delete m_output;
|
|
306
|
+
m_output = nullptr;
|
|
307
|
+
|
|
308
|
+
m_file->clearMemoryCache();
|
|
309
|
+
m_actualSize = 0;
|
|
310
|
+
m_metaInfo->m_crcDigest = 0;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
void MMKV::close() {
|
|
314
|
+
MMKVInfo("close [%s]", m_mmapID.c_str());
|
|
315
|
+
SCOPED_LOCK(g_instanceLock);
|
|
316
|
+
m_lock->lock();
|
|
317
|
+
|
|
318
|
+
#ifndef MMKV_ANDROID
|
|
319
|
+
auto itr = g_instanceDic->find(m_mmapKey);
|
|
320
|
+
#else
|
|
321
|
+
auto itr = g_instanceDic->find(m_mmapID);
|
|
322
|
+
#endif
|
|
323
|
+
if (itr != g_instanceDic->end()) {
|
|
324
|
+
g_instanceDic->erase(itr);
|
|
325
|
+
}
|
|
326
|
+
delete this;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
#ifndef MMKV_DISABLE_CRYPT
|
|
330
|
+
|
|
331
|
+
string MMKV::cryptKey() const {
|
|
332
|
+
SCOPED_LOCK(m_lock);
|
|
333
|
+
|
|
334
|
+
if (m_crypter) {
|
|
335
|
+
char key[AES_KEY_LEN];
|
|
336
|
+
m_crypter->getKey(key);
|
|
337
|
+
return {key, strnlen(key, AES_KEY_LEN)};
|
|
338
|
+
}
|
|
339
|
+
return "";
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
void MMKV::checkReSetCryptKey(const string *cryptKey) {
|
|
343
|
+
SCOPED_LOCK(m_lock);
|
|
344
|
+
|
|
345
|
+
if (m_crypter) {
|
|
346
|
+
if (cryptKey && cryptKey->length() > 0) {
|
|
347
|
+
string oldKey = this->cryptKey();
|
|
348
|
+
if (oldKey != *cryptKey) {
|
|
349
|
+
MMKVInfo("setting new aes key");
|
|
350
|
+
delete m_crypter;
|
|
351
|
+
auto ptr = cryptKey->data();
|
|
352
|
+
m_crypter = new AESCrypt(ptr, cryptKey->length());
|
|
353
|
+
|
|
354
|
+
checkLoadData();
|
|
355
|
+
} else {
|
|
356
|
+
// nothing to do
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
MMKVInfo("reset aes key");
|
|
360
|
+
delete m_crypter;
|
|
361
|
+
m_crypter = nullptr;
|
|
362
|
+
|
|
363
|
+
checkLoadData();
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
if (cryptKey && cryptKey->length() > 0) {
|
|
367
|
+
MMKVInfo("setting new aes key");
|
|
368
|
+
auto ptr = cryptKey->data();
|
|
369
|
+
m_crypter = new AESCrypt(ptr, cryptKey->length());
|
|
370
|
+
|
|
371
|
+
checkLoadData();
|
|
372
|
+
} else {
|
|
373
|
+
// nothing to do
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
#endif // MMKV_DISABLE_CRYPT
|
|
379
|
+
|
|
380
|
+
bool MMKV::isFileValid() {
|
|
381
|
+
return m_file->isFileValid();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// crc
|
|
385
|
+
|
|
386
|
+
// assuming m_file is valid
|
|
387
|
+
bool MMKV::checkFileCRCValid(size_t actualSize, uint32_t crcDigest) {
|
|
388
|
+
auto ptr = (uint8_t *) m_file->getMemory();
|
|
389
|
+
if (ptr) {
|
|
390
|
+
m_crcDigest = (uint32_t) CRC32(0, (const uint8_t *) ptr + Fixed32Size, (uint32_t) actualSize);
|
|
391
|
+
|
|
392
|
+
if (m_crcDigest == crcDigest) {
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
MMKVError("check crc [%s] fail, crc32:%u, m_crcDigest:%u", m_mmapID.c_str(), crcDigest, m_crcDigest);
|
|
396
|
+
}
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
void MMKV::recaculateCRCDigestWithIV(const void *iv) {
|
|
401
|
+
auto ptr = (const uint8_t *) m_file->getMemory();
|
|
402
|
+
if (ptr) {
|
|
403
|
+
m_crcDigest = 0;
|
|
404
|
+
m_crcDigest = (uint32_t) CRC32(0, ptr + Fixed32Size, (uint32_t) m_actualSize);
|
|
405
|
+
writeActualSize(m_actualSize, m_crcDigest, iv, IncreaseSequence);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
void MMKV::updateCRCDigest(const uint8_t *ptr, size_t length) {
|
|
410
|
+
if (ptr == nullptr) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
m_crcDigest = (uint32_t) CRC32(m_crcDigest, ptr, (uint32_t) length);
|
|
414
|
+
|
|
415
|
+
writeActualSize(m_actualSize, m_crcDigest, nullptr, KeepSequence);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// set & get
|
|
419
|
+
|
|
420
|
+
bool MMKV::set(bool value, MMKVKey_t key) {
|
|
421
|
+
if (isKeyEmpty(key)) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
size_t size = pbBoolSize();
|
|
425
|
+
MMBuffer data(size);
|
|
426
|
+
CodedOutputData output(data.getPtr(), size);
|
|
427
|
+
output.writeBool(value);
|
|
428
|
+
|
|
429
|
+
return setDataForKey(move(data), key);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
bool MMKV::set(int32_t value, MMKVKey_t key) {
|
|
433
|
+
if (isKeyEmpty(key)) {
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
size_t size = pbInt32Size(value);
|
|
437
|
+
MMBuffer data(size);
|
|
438
|
+
CodedOutputData output(data.getPtr(), size);
|
|
439
|
+
output.writeInt32(value);
|
|
440
|
+
|
|
441
|
+
return setDataForKey(move(data), key);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
bool MMKV::set(uint32_t value, MMKVKey_t key) {
|
|
445
|
+
if (isKeyEmpty(key)) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
size_t size = pbUInt32Size(value);
|
|
449
|
+
MMBuffer data(size);
|
|
450
|
+
CodedOutputData output(data.getPtr(), size);
|
|
451
|
+
output.writeUInt32(value);
|
|
452
|
+
|
|
453
|
+
return setDataForKey(move(data), key);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
bool MMKV::set(int64_t value, MMKVKey_t key) {
|
|
457
|
+
if (isKeyEmpty(key)) {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
size_t size = pbInt64Size(value);
|
|
461
|
+
MMBuffer data(size);
|
|
462
|
+
CodedOutputData output(data.getPtr(), size);
|
|
463
|
+
output.writeInt64(value);
|
|
464
|
+
|
|
465
|
+
return setDataForKey(move(data), key);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
bool MMKV::set(uint64_t value, MMKVKey_t key) {
|
|
469
|
+
if (isKeyEmpty(key)) {
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
size_t size = pbUInt64Size(value);
|
|
473
|
+
MMBuffer data(size);
|
|
474
|
+
CodedOutputData output(data.getPtr(), size);
|
|
475
|
+
output.writeUInt64(value);
|
|
476
|
+
|
|
477
|
+
return setDataForKey(move(data), key);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
bool MMKV::set(float value, MMKVKey_t key) {
|
|
481
|
+
if (isKeyEmpty(key)) {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
size_t size = pbFloatSize();
|
|
485
|
+
MMBuffer data(size);
|
|
486
|
+
CodedOutputData output(data.getPtr(), size);
|
|
487
|
+
output.writeFloat(value);
|
|
488
|
+
|
|
489
|
+
return setDataForKey(move(data), key);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
bool MMKV::set(double value, MMKVKey_t key) {
|
|
493
|
+
if (isKeyEmpty(key)) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
size_t size = pbDoubleSize();
|
|
497
|
+
MMBuffer data(size);
|
|
498
|
+
CodedOutputData output(data.getPtr(), size);
|
|
499
|
+
output.writeDouble(value);
|
|
500
|
+
|
|
501
|
+
return setDataForKey(move(data), key);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
#ifndef MMKV_APPLE
|
|
505
|
+
|
|
506
|
+
bool MMKV::set(const char *value, MMKVKey_t key) {
|
|
507
|
+
if (!value) {
|
|
508
|
+
removeValueForKey(key);
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
return setDataForKey(MMBuffer((void *) value, strlen(value), MMBufferNoCopy), key, true);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
bool MMKV::set(const string &value, MMKVKey_t key) {
|
|
515
|
+
if (isKeyEmpty(key)) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
return setDataForKey(MMBuffer((void *) value.data(), value.length(), MMBufferNoCopy), key, true);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
bool MMKV::set(const MMBuffer &value, MMKVKey_t key) {
|
|
522
|
+
if (isKeyEmpty(key)) {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
// delay write the size needed for encoding value
|
|
526
|
+
// avoid memory copying
|
|
527
|
+
return setDataForKey(MMBuffer(value.getPtr(), value.length(), MMBufferNoCopy), key, true);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
bool MMKV::set(const vector<string> &v, MMKVKey_t key) {
|
|
531
|
+
if (isKeyEmpty(key)) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
auto data = MiniPBCoder::encodeDataWithObject(v);
|
|
535
|
+
return setDataForKey(move(data), key);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
bool MMKV::getString(MMKVKey_t key, string &result) {
|
|
539
|
+
if (isKeyEmpty(key)) {
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
SCOPED_LOCK(m_lock);
|
|
543
|
+
auto data = getDataForKey(key);
|
|
544
|
+
if (data.length() > 0) {
|
|
545
|
+
try {
|
|
546
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
547
|
+
result = input.readString();
|
|
548
|
+
return true;
|
|
549
|
+
} catch (std::exception &exception) {
|
|
550
|
+
MMKVError("%s", exception.what());
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
bool MMKV::getBytes(MMKVKey_t key, mmkv::MMBuffer &result) {
|
|
557
|
+
if (isKeyEmpty(key)) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
SCOPED_LOCK(m_lock);
|
|
561
|
+
auto data = getDataForKey(key);
|
|
562
|
+
if (data.length() > 0) {
|
|
563
|
+
try {
|
|
564
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
565
|
+
result = move(input.readData());
|
|
566
|
+
return true;
|
|
567
|
+
} catch (std::exception &exception) {
|
|
568
|
+
MMKVError("%s", exception.what());
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
MMBuffer MMKV::getBytes(MMKVKey_t key) {
|
|
575
|
+
if (isKeyEmpty(key)) {
|
|
576
|
+
return MMBuffer();
|
|
577
|
+
}
|
|
578
|
+
SCOPED_LOCK(m_lock);
|
|
579
|
+
auto data = getDataForKey(key);
|
|
580
|
+
if (data.length() > 0) {
|
|
581
|
+
try {
|
|
582
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
583
|
+
return input.readData();
|
|
584
|
+
} catch (std::exception &exception) {
|
|
585
|
+
MMKVError("%s", exception.what());
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return MMBuffer();
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
bool MMKV::getVector(MMKVKey_t key, vector<string> &result) {
|
|
592
|
+
if (isKeyEmpty(key)) {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
SCOPED_LOCK(m_lock);
|
|
596
|
+
auto data = getDataForKey(key);
|
|
597
|
+
if (data.length() > 0) {
|
|
598
|
+
try {
|
|
599
|
+
result = MiniPBCoder::decodeVector(data);
|
|
600
|
+
return true;
|
|
601
|
+
} catch (std::exception &exception) {
|
|
602
|
+
MMKVError("%s", exception.what());
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
#endif // MMKV_APPLE
|
|
609
|
+
|
|
610
|
+
bool MMKV::getBool(MMKVKey_t key, bool defaultValue, bool *hasValue) {
|
|
611
|
+
if (isKeyEmpty(key)) {
|
|
612
|
+
if (hasValue != nullptr) {
|
|
613
|
+
*hasValue = false;
|
|
614
|
+
}
|
|
615
|
+
return defaultValue;
|
|
616
|
+
}
|
|
617
|
+
SCOPED_LOCK(m_lock);
|
|
618
|
+
auto data = getDataForKey(key);
|
|
619
|
+
if (data.length() > 0) {
|
|
620
|
+
try {
|
|
621
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
622
|
+
if (hasValue != nullptr) {
|
|
623
|
+
*hasValue = true;
|
|
624
|
+
}
|
|
625
|
+
return input.readBool();
|
|
626
|
+
} catch (std::exception &exception) {
|
|
627
|
+
MMKVError("%s", exception.what());
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (hasValue != nullptr) {
|
|
631
|
+
*hasValue = false;
|
|
632
|
+
}
|
|
633
|
+
return defaultValue;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
int32_t MMKV::getInt32(MMKVKey_t key, int32_t defaultValue, bool *hasValue) {
|
|
637
|
+
if (isKeyEmpty(key)) {
|
|
638
|
+
if (hasValue != nullptr) {
|
|
639
|
+
*hasValue = false;
|
|
640
|
+
}
|
|
641
|
+
return defaultValue;
|
|
642
|
+
}
|
|
643
|
+
SCOPED_LOCK(m_lock);
|
|
644
|
+
auto data = getDataForKey(key);
|
|
645
|
+
if (data.length() > 0) {
|
|
646
|
+
try {
|
|
647
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
648
|
+
if (hasValue != nullptr) {
|
|
649
|
+
*hasValue = true;
|
|
650
|
+
}
|
|
651
|
+
return input.readInt32();
|
|
652
|
+
} catch (std::exception &exception) {
|
|
653
|
+
MMKVError("%s", exception.what());
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (hasValue != nullptr) {
|
|
657
|
+
*hasValue = false;
|
|
658
|
+
}
|
|
659
|
+
return defaultValue;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
uint32_t MMKV::getUInt32(MMKVKey_t key, uint32_t defaultValue, bool *hasValue) {
|
|
663
|
+
if (isKeyEmpty(key)) {
|
|
664
|
+
if (hasValue != nullptr) {
|
|
665
|
+
*hasValue = false;
|
|
666
|
+
}
|
|
667
|
+
return defaultValue;
|
|
668
|
+
}
|
|
669
|
+
SCOPED_LOCK(m_lock);
|
|
670
|
+
auto data = getDataForKey(key);
|
|
671
|
+
if (data.length() > 0) {
|
|
672
|
+
try {
|
|
673
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
674
|
+
if (hasValue != nullptr) {
|
|
675
|
+
*hasValue = true;
|
|
676
|
+
}
|
|
677
|
+
return input.readUInt32();
|
|
678
|
+
} catch (std::exception &exception) {
|
|
679
|
+
MMKVError("%s", exception.what());
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (hasValue != nullptr) {
|
|
683
|
+
*hasValue = false;
|
|
684
|
+
}
|
|
685
|
+
return defaultValue;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
int64_t MMKV::getInt64(MMKVKey_t key, int64_t defaultValue, bool *hasValue) {
|
|
689
|
+
if (isKeyEmpty(key)) {
|
|
690
|
+
if (hasValue != nullptr) {
|
|
691
|
+
*hasValue = false;
|
|
692
|
+
}
|
|
693
|
+
return defaultValue;
|
|
694
|
+
}
|
|
695
|
+
SCOPED_LOCK(m_lock);
|
|
696
|
+
auto data = getDataForKey(key);
|
|
697
|
+
if (data.length() > 0) {
|
|
698
|
+
try {
|
|
699
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
700
|
+
if (hasValue != nullptr) {
|
|
701
|
+
*hasValue = true;
|
|
702
|
+
}
|
|
703
|
+
return input.readInt64();
|
|
704
|
+
} catch (std::exception &exception) {
|
|
705
|
+
MMKVError("%s", exception.what());
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (hasValue != nullptr) {
|
|
709
|
+
*hasValue = false;
|
|
710
|
+
}
|
|
711
|
+
return defaultValue;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
uint64_t MMKV::getUInt64(MMKVKey_t key, uint64_t defaultValue, bool *hasValue) {
|
|
715
|
+
if (isKeyEmpty(key)) {
|
|
716
|
+
if (hasValue != nullptr) {
|
|
717
|
+
*hasValue = false;
|
|
718
|
+
}
|
|
719
|
+
return defaultValue;
|
|
720
|
+
}
|
|
721
|
+
SCOPED_LOCK(m_lock);
|
|
722
|
+
auto data = getDataForKey(key);
|
|
723
|
+
if (data.length() > 0) {
|
|
724
|
+
try {
|
|
725
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
726
|
+
if (hasValue != nullptr) {
|
|
727
|
+
*hasValue = true;
|
|
728
|
+
}
|
|
729
|
+
return input.readUInt64();
|
|
730
|
+
} catch (std::exception &exception) {
|
|
731
|
+
MMKVError("%s", exception.what());
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (hasValue != nullptr) {
|
|
735
|
+
*hasValue = false;
|
|
736
|
+
}
|
|
737
|
+
return defaultValue;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
float MMKV::getFloat(MMKVKey_t key, float defaultValue, bool *hasValue) {
|
|
741
|
+
if (isKeyEmpty(key)) {
|
|
742
|
+
if (hasValue != nullptr) {
|
|
743
|
+
*hasValue = false;
|
|
744
|
+
}
|
|
745
|
+
return defaultValue;
|
|
746
|
+
}
|
|
747
|
+
SCOPED_LOCK(m_lock);
|
|
748
|
+
auto data = getDataForKey(key);
|
|
749
|
+
if (data.length() > 0) {
|
|
750
|
+
try {
|
|
751
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
752
|
+
if (hasValue != nullptr) {
|
|
753
|
+
*hasValue = true;
|
|
754
|
+
}
|
|
755
|
+
return input.readFloat();
|
|
756
|
+
} catch (std::exception &exception) {
|
|
757
|
+
MMKVError("%s", exception.what());
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
if (hasValue != nullptr) {
|
|
761
|
+
*hasValue = false;
|
|
762
|
+
}
|
|
763
|
+
return defaultValue;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
double MMKV::getDouble(MMKVKey_t key, double defaultValue, bool *hasValue) {
|
|
767
|
+
if (isKeyEmpty(key)) {
|
|
768
|
+
if (hasValue != nullptr) {
|
|
769
|
+
*hasValue = false;
|
|
770
|
+
}
|
|
771
|
+
return defaultValue;
|
|
772
|
+
}
|
|
773
|
+
SCOPED_LOCK(m_lock);
|
|
774
|
+
auto data = getDataForKey(key);
|
|
775
|
+
if (data.length() > 0) {
|
|
776
|
+
try {
|
|
777
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
778
|
+
if (hasValue != nullptr) {
|
|
779
|
+
*hasValue = true;
|
|
780
|
+
}
|
|
781
|
+
return input.readDouble();
|
|
782
|
+
} catch (std::exception &exception) {
|
|
783
|
+
MMKVError("%s", exception.what());
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (hasValue != nullptr) {
|
|
787
|
+
*hasValue = false;
|
|
788
|
+
}
|
|
789
|
+
return defaultValue;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
size_t MMKV::getValueSize(MMKVKey_t key, bool actualSize) {
|
|
793
|
+
if (isKeyEmpty(key)) {
|
|
794
|
+
return 0;
|
|
795
|
+
}
|
|
796
|
+
SCOPED_LOCK(m_lock);
|
|
797
|
+
auto data = getDataForKey(key);
|
|
798
|
+
if (actualSize) {
|
|
799
|
+
try {
|
|
800
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
801
|
+
auto length = input.readInt32();
|
|
802
|
+
if (length >= 0) {
|
|
803
|
+
auto s_length = static_cast<size_t>(length);
|
|
804
|
+
if (pbRawVarint32Size(length) + s_length == data.length()) {
|
|
805
|
+
return s_length;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
} catch (std::exception &exception) {
|
|
809
|
+
MMKVError("%s", exception.what());
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return data.length();
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
int32_t MMKV::writeValueToBuffer(MMKVKey_t key, void *ptr, int32_t size) {
|
|
816
|
+
if (isKeyEmpty(key) || size < 0) {
|
|
817
|
+
return -1;
|
|
818
|
+
}
|
|
819
|
+
auto s_size = static_cast<size_t>(size);
|
|
820
|
+
|
|
821
|
+
SCOPED_LOCK(m_lock);
|
|
822
|
+
auto data = getDataForKey(key);
|
|
823
|
+
try {
|
|
824
|
+
CodedInputData input(data.getPtr(), data.length());
|
|
825
|
+
auto length = input.readInt32();
|
|
826
|
+
auto offset = pbRawVarint32Size(length);
|
|
827
|
+
if (length >= 0) {
|
|
828
|
+
auto s_length = static_cast<size_t>(length);
|
|
829
|
+
if (offset + s_length == data.length()) {
|
|
830
|
+
if (s_length <= s_size) {
|
|
831
|
+
memcpy(ptr, (uint8_t *) data.getPtr() + offset, s_length);
|
|
832
|
+
return length;
|
|
833
|
+
}
|
|
834
|
+
} else {
|
|
835
|
+
if (data.length() <= s_size) {
|
|
836
|
+
memcpy(ptr, data.getPtr(), data.length());
|
|
837
|
+
return static_cast<int32_t>(data.length());
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
} catch (std::exception &exception) {
|
|
842
|
+
MMKVError("%s", exception.what());
|
|
843
|
+
}
|
|
844
|
+
return -1;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// enumerate
|
|
848
|
+
|
|
849
|
+
bool MMKV::containsKey(MMKVKey_t key) {
|
|
850
|
+
SCOPED_LOCK(m_lock);
|
|
851
|
+
checkLoadData();
|
|
852
|
+
|
|
853
|
+
if (m_crypter) {
|
|
854
|
+
return m_dicCrypt->find(key) != m_dicCrypt->end();
|
|
855
|
+
} else {
|
|
856
|
+
return m_dic->find(key) != m_dic->end();
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
size_t MMKV::count() {
|
|
861
|
+
SCOPED_LOCK(m_lock);
|
|
862
|
+
checkLoadData();
|
|
863
|
+
if (m_crypter) {
|
|
864
|
+
return m_dicCrypt->size();
|
|
865
|
+
} else {
|
|
866
|
+
return m_dic->size();
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
size_t MMKV::totalSize() {
|
|
871
|
+
SCOPED_LOCK(m_lock);
|
|
872
|
+
checkLoadData();
|
|
873
|
+
return m_file->getFileSize();
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
size_t MMKV::actualSize() {
|
|
877
|
+
SCOPED_LOCK(m_lock);
|
|
878
|
+
checkLoadData();
|
|
879
|
+
return m_actualSize;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
void MMKV::removeValueForKey(MMKVKey_t key) {
|
|
883
|
+
if (isKeyEmpty(key)) {
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
SCOPED_LOCK(m_lock);
|
|
887
|
+
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
888
|
+
checkLoadData();
|
|
889
|
+
|
|
890
|
+
removeDataForKey(key);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
#ifndef MMKV_APPLE
|
|
894
|
+
|
|
895
|
+
vector<string> MMKV::allKeys() {
|
|
896
|
+
SCOPED_LOCK(m_lock);
|
|
897
|
+
checkLoadData();
|
|
898
|
+
|
|
899
|
+
vector<string> keys;
|
|
900
|
+
if (m_crypter) {
|
|
901
|
+
for (const auto &itr : *m_dicCrypt) {
|
|
902
|
+
keys.push_back(itr.first);
|
|
903
|
+
}
|
|
904
|
+
} else {
|
|
905
|
+
for (const auto &itr : *m_dic) {
|
|
906
|
+
keys.push_back(itr.first);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return keys;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
void MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
|
|
913
|
+
if (arrKeys.empty()) {
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
if (arrKeys.size() == 1) {
|
|
917
|
+
return removeValueForKey(arrKeys[0]);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
SCOPED_LOCK(m_lock);
|
|
921
|
+
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
922
|
+
checkLoadData();
|
|
923
|
+
|
|
924
|
+
size_t deleteCount = 0;
|
|
925
|
+
if (m_crypter) {
|
|
926
|
+
for (const auto &key : arrKeys) {
|
|
927
|
+
auto itr = m_dicCrypt->find(key);
|
|
928
|
+
if (itr != m_dicCrypt->end()) {
|
|
929
|
+
m_dicCrypt->erase(itr);
|
|
930
|
+
deleteCount++;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
} else {
|
|
934
|
+
for (const auto &key : arrKeys) {
|
|
935
|
+
auto itr = m_dic->find(key);
|
|
936
|
+
if (itr != m_dic->end()) {
|
|
937
|
+
m_dic->erase(itr);
|
|
938
|
+
deleteCount++;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
if (deleteCount > 0) {
|
|
943
|
+
m_hasFullWriteback = false;
|
|
944
|
+
|
|
945
|
+
fullWriteback();
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
#endif // MMKV_APPLE
|
|
950
|
+
|
|
951
|
+
// file
|
|
952
|
+
|
|
953
|
+
void MMKV::sync(SyncFlag flag) {
|
|
954
|
+
SCOPED_LOCK(m_lock);
|
|
955
|
+
if (m_needLoadFromFile || !isFileValid()) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
959
|
+
|
|
960
|
+
m_file->msync(flag);
|
|
961
|
+
m_metaFile->msync(flag);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
void MMKV::lock() {
|
|
965
|
+
m_exclusiveProcessLock->lock();
|
|
966
|
+
}
|
|
967
|
+
void MMKV::unlock() {
|
|
968
|
+
m_exclusiveProcessLock->unlock();
|
|
969
|
+
}
|
|
970
|
+
bool MMKV::try_lock() {
|
|
971
|
+
return m_exclusiveProcessLock->try_lock();
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// backup
|
|
975
|
+
|
|
976
|
+
static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
977
|
+
File crcFile(srcPath, OpenFlag::ReadOnly);
|
|
978
|
+
if (!crcFile.isFileValid()) {
|
|
979
|
+
return false;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
bool ret = false;
|
|
983
|
+
{
|
|
984
|
+
#ifdef MMKV_WIN32
|
|
985
|
+
MMKVInfo("backup one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
986
|
+
#else
|
|
987
|
+
MMKVInfo("backup one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
988
|
+
#endif
|
|
989
|
+
FileLock fileLock(crcFile.getFd());
|
|
990
|
+
InterProcessLock lock(&fileLock, SharedLockType);
|
|
991
|
+
SCOPED_LOCK(&lock);
|
|
992
|
+
|
|
993
|
+
ret = copyFile(srcPath, dstPath);
|
|
994
|
+
if (ret) {
|
|
995
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
996
|
+
auto dstCRCPath = dstPath + CRC_SUFFIX;
|
|
997
|
+
ret = copyFile(srcCRCPath, dstCRCPath);
|
|
998
|
+
}
|
|
999
|
+
MMKVInfo("finish backup one mmkv[%s]", mmapKey.c_str());
|
|
1000
|
+
}
|
|
1001
|
+
return ret;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
bool MMKV::backupOneToDirectory(const string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath) {
|
|
1005
|
+
// we have to lock the creation of MMKV instance, regardless of in cache or not
|
|
1006
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1007
|
+
MMKV *kv = nullptr;
|
|
1008
|
+
if (!compareFullPath) {
|
|
1009
|
+
auto itr = g_instanceDic->find(mmapKey);
|
|
1010
|
+
if (itr != g_instanceDic->end()) {
|
|
1011
|
+
kv = itr->second;
|
|
1012
|
+
}
|
|
1013
|
+
} else {
|
|
1014
|
+
// mmapKey is actually filename, we can't simply call find()
|
|
1015
|
+
for (auto &pair : *g_instanceDic) {
|
|
1016
|
+
if (pair.second->m_path == srcPath) {
|
|
1017
|
+
kv = pair.second;
|
|
1018
|
+
break;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
// get one in cache, do it the easy way
|
|
1023
|
+
if (kv) {
|
|
1024
|
+
#ifdef MMKV_WIN32
|
|
1025
|
+
MMKVInfo("backup one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1026
|
+
#else
|
|
1027
|
+
MMKVInfo("backup one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1028
|
+
#endif
|
|
1029
|
+
SCOPED_LOCK(kv->m_lock);
|
|
1030
|
+
SCOPED_LOCK(kv->m_sharedProcessLock);
|
|
1031
|
+
|
|
1032
|
+
kv->sync();
|
|
1033
|
+
auto ret = copyFile(kv->m_path, dstPath);
|
|
1034
|
+
if (ret) {
|
|
1035
|
+
auto dstCRCPath = dstPath + CRC_SUFFIX;
|
|
1036
|
+
ret = copyFile(kv->m_crcPath, dstCRCPath);
|
|
1037
|
+
}
|
|
1038
|
+
MMKVInfo("finish backup one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
|
|
1039
|
+
return ret;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// no luck with cache, do it the hard way
|
|
1043
|
+
bool ret = backupOneToDirectoryByFilePath(mmapKey, srcPath, dstPath);
|
|
1044
|
+
return ret;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
bool MMKV::backupOneToDirectory(const string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
|
|
1048
|
+
auto rootPath = srcDir ? srcDir : &g_rootDir;
|
|
1049
|
+
if (*rootPath == dstDir) {
|
|
1050
|
+
return true;
|
|
1051
|
+
}
|
|
1052
|
+
mkPath(dstDir);
|
|
1053
|
+
auto encodePath = encodeFilePath(mmapID, dstDir);
|
|
1054
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH + encodePath;
|
|
1055
|
+
auto mmapKey = mmapedKVKey(mmapID, rootPath);
|
|
1056
|
+
#ifdef MMKV_ANDROID
|
|
1057
|
+
// historically Android mistakenly use mmapKey as mmapID
|
|
1058
|
+
auto srcPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath);
|
|
1059
|
+
#else
|
|
1060
|
+
auto srcPath = *rootPath + MMKV_PATH_SLASH + encodePath;
|
|
1061
|
+
#endif
|
|
1062
|
+
return backupOneToDirectory(mmapKey, dstPath, srcPath, false);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix) {
|
|
1066
|
+
if (str.length() >= suffix.length()) {
|
|
1067
|
+
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
|
|
1068
|
+
} else {
|
|
1069
|
+
return false;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
MMKVPath_t filename(const MMKVPath_t &path) {
|
|
1074
|
+
auto startPos = path.rfind(MMKV_PATH_SLASH);
|
|
1075
|
+
startPos++; // don't need to check for npos, because npos+1 == 0
|
|
1076
|
+
auto filename = path.substr(startPos);
|
|
1077
|
+
return filename;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir) {
|
|
1081
|
+
unordered_set<MMKVPath_t> mmapIDSet;
|
|
1082
|
+
unordered_set<MMKVPath_t> mmapIDCRCSet;
|
|
1083
|
+
walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
|
|
1084
|
+
if (endsWith(filePath, CRC_SUFFIX)) {
|
|
1085
|
+
mmapIDCRCSet.insert(filePath);
|
|
1086
|
+
} else {
|
|
1087
|
+
mmapIDSet.insert(filePath);
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
size_t count = 0;
|
|
1092
|
+
if (!mmapIDSet.empty()) {
|
|
1093
|
+
mkPath(dstDir);
|
|
1094
|
+
auto compareFullPath = isInSpecialDir;
|
|
1095
|
+
for (auto &srcPath : mmapIDSet) {
|
|
1096
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1097
|
+
if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
|
|
1098
|
+
#ifdef MMKV_WIN32
|
|
1099
|
+
MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str());
|
|
1100
|
+
#else
|
|
1101
|
+
MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
|
|
1102
|
+
#endif
|
|
1103
|
+
continue;
|
|
1104
|
+
}
|
|
1105
|
+
auto basename = filename(srcPath);
|
|
1106
|
+
const auto &strBasename = MMKVPath_t2String(basename);
|
|
1107
|
+
auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &srcDir);
|
|
1108
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH + basename;
|
|
1109
|
+
if (backupOneToDirectory(mmapKey, dstPath, srcPath, compareFullPath)) {
|
|
1110
|
+
count++;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return count;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
|
|
1118
|
+
auto rootPath = srcDir ? srcDir : &g_rootDir;
|
|
1119
|
+
if (*rootPath == dstDir) {
|
|
1120
|
+
return true;
|
|
1121
|
+
}
|
|
1122
|
+
auto count = backupAllToDirectory(dstDir, *rootPath, false);
|
|
1123
|
+
|
|
1124
|
+
auto specialSrcDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1125
|
+
if (isFileExist(specialSrcDir)) {
|
|
1126
|
+
auto specialDstDir = dstDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1127
|
+
count += backupAllToDirectory(specialDstDir, specialSrcDir, true);
|
|
1128
|
+
}
|
|
1129
|
+
return count;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// restore
|
|
1133
|
+
|
|
1134
|
+
static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
1135
|
+
auto dstCRCPath = dstPath + CRC_SUFFIX;
|
|
1136
|
+
File dstCRCFile(move(dstCRCPath), OpenFlag::ReadWrite | OpenFlag::Create);
|
|
1137
|
+
if (!dstCRCFile.isFileValid()) {
|
|
1138
|
+
return false;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
bool ret = false;
|
|
1142
|
+
{
|
|
1143
|
+
#ifdef MMKV_WIN32
|
|
1144
|
+
MMKVInfo("restore one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1145
|
+
#else
|
|
1146
|
+
MMKVInfo("restore one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1147
|
+
#endif
|
|
1148
|
+
FileLock fileLock(dstCRCFile.getFd());
|
|
1149
|
+
InterProcessLock lock(&fileLock, ExclusiveLockType);
|
|
1150
|
+
SCOPED_LOCK(&lock);
|
|
1151
|
+
|
|
1152
|
+
ret = copyFileContent(srcPath, dstPath);
|
|
1153
|
+
if (ret) {
|
|
1154
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1155
|
+
ret = copyFileContent(srcCRCPath, dstCRCFile.getFd());
|
|
1156
|
+
}
|
|
1157
|
+
MMKVInfo("finish restore one mmkv[%s]", mmapKey.c_str());
|
|
1158
|
+
}
|
|
1159
|
+
return ret;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// We can't simply replace the existing file, because other processes might have already open it.
|
|
1163
|
+
// They won't know a difference when the file has been replaced.
|
|
1164
|
+
// We have to let them know by overriding the existing file with new content.
|
|
1165
|
+
bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath) {
|
|
1166
|
+
// we have to lock the creation of MMKV instance, regardless of in cache or not
|
|
1167
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1168
|
+
MMKV *kv = nullptr;
|
|
1169
|
+
if (!compareFullPath) {
|
|
1170
|
+
auto itr = g_instanceDic->find(mmapKey);
|
|
1171
|
+
if (itr != g_instanceDic->end()) {
|
|
1172
|
+
kv = itr->second;
|
|
1173
|
+
}
|
|
1174
|
+
} else {
|
|
1175
|
+
// mmapKey is actually filename, we can't simply call find()
|
|
1176
|
+
for (auto &pair : *g_instanceDic) {
|
|
1177
|
+
if (pair.second->m_path == dstPath) {
|
|
1178
|
+
kv = pair.second;
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
// get one in cache, do it the easy way
|
|
1184
|
+
if (kv) {
|
|
1185
|
+
#ifdef MMKV_WIN32
|
|
1186
|
+
MMKVInfo("restore one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1187
|
+
#else
|
|
1188
|
+
MMKVInfo("restore one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1189
|
+
#endif
|
|
1190
|
+
SCOPED_LOCK(kv->m_lock);
|
|
1191
|
+
SCOPED_LOCK(kv->m_exclusiveProcessLock);
|
|
1192
|
+
|
|
1193
|
+
kv->sync();
|
|
1194
|
+
auto ret = copyFileContent(srcPath, kv->m_file->getFd());
|
|
1195
|
+
if (ret) {
|
|
1196
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1197
|
+
ret = copyFileContent(srcCRCPath, kv->m_metaFile->getFd());
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// reload data after restore
|
|
1201
|
+
kv->clearMemoryCache();
|
|
1202
|
+
kv->loadFromFile();
|
|
1203
|
+
if (kv->m_isInterProcess) {
|
|
1204
|
+
kv->notifyContentChanged();
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
MMKVInfo("finish restore one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
|
|
1208
|
+
return ret;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// no luck with cache, do it the hard way
|
|
1212
|
+
bool ret = restoreOneFromDirectoryByFilePath(mmapKey, srcPath, dstPath);
|
|
1213
|
+
return ret;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
bool MMKV::restoreOneFromDirectory(const string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
|
|
1217
|
+
auto rootPath = dstDir ? dstDir : &g_rootDir;
|
|
1218
|
+
if (*rootPath == srcDir) {
|
|
1219
|
+
return true;
|
|
1220
|
+
}
|
|
1221
|
+
mkPath(*rootPath);
|
|
1222
|
+
auto encodePath = encodeFilePath(mmapID, *rootPath);
|
|
1223
|
+
auto srcPath = srcDir + MMKV_PATH_SLASH + encodePath;
|
|
1224
|
+
auto mmapKey = mmapedKVKey(mmapID, rootPath);
|
|
1225
|
+
#ifdef MMKV_ANDROID
|
|
1226
|
+
// historically Android mistakenly use mmapKey as mmapID
|
|
1227
|
+
auto dstPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath);
|
|
1228
|
+
#else
|
|
1229
|
+
auto dstPath = *rootPath + MMKV_PATH_SLASH + encodePath;
|
|
1230
|
+
#endif
|
|
1231
|
+
return restoreOneFromDirectory(mmapKey, srcPath, dstPath, false);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t &dstDir, bool isInSpecialDir) {
|
|
1235
|
+
unordered_set<MMKVPath_t> mmapIDSet;
|
|
1236
|
+
unordered_set<MMKVPath_t> mmapIDCRCSet;
|
|
1237
|
+
walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
|
|
1238
|
+
if (endsWith(filePath, CRC_SUFFIX)) {
|
|
1239
|
+
mmapIDCRCSet.insert(filePath);
|
|
1240
|
+
} else {
|
|
1241
|
+
mmapIDSet.insert(filePath);
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
|
|
1245
|
+
size_t count = 0;
|
|
1246
|
+
if (!mmapIDSet.empty()) {
|
|
1247
|
+
mkPath(dstDir);
|
|
1248
|
+
auto compareFullPath = isInSpecialDir;
|
|
1249
|
+
for (auto &srcPath : mmapIDSet) {
|
|
1250
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1251
|
+
if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
|
|
1252
|
+
#ifdef MMKV_WIN32
|
|
1253
|
+
MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str());
|
|
1254
|
+
#else
|
|
1255
|
+
MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
|
|
1256
|
+
#endif
|
|
1257
|
+
continue;
|
|
1258
|
+
}
|
|
1259
|
+
auto basename = filename(srcPath);
|
|
1260
|
+
const auto &strBasename = MMKVPath_t2String(basename);
|
|
1261
|
+
auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &dstDir);
|
|
1262
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH + basename;
|
|
1263
|
+
if (restoreOneFromDirectory(mmapKey, srcPath, dstPath, compareFullPath)) {
|
|
1264
|
+
count++;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
return count;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
|
|
1272
|
+
auto rootPath = dstDir ? dstDir : &g_rootDir;
|
|
1273
|
+
if (*rootPath == srcDir) {
|
|
1274
|
+
return true;
|
|
1275
|
+
}
|
|
1276
|
+
auto count = restoreAllFromDirectory(srcDir, *rootPath, true);
|
|
1277
|
+
|
|
1278
|
+
auto specialSrcDir = srcDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1279
|
+
if (isFileExist(specialSrcDir)) {
|
|
1280
|
+
auto specialDstDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1281
|
+
count += restoreAllFromDirectory(specialSrcDir, specialDstDir, false);
|
|
1282
|
+
}
|
|
1283
|
+
return count;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// callbacks
|
|
1287
|
+
|
|
1288
|
+
void MMKV::registerErrorHandler(ErrorHandler handler) {
|
|
1289
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1290
|
+
g_errorHandler = handler;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
void MMKV::unRegisterErrorHandler() {
|
|
1294
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1295
|
+
g_errorHandler = nullptr;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
void MMKV::registerLogHandler(LogHandler handler) {
|
|
1299
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1300
|
+
g_logHandler = handler;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
void MMKV::unRegisterLogHandler() {
|
|
1304
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1305
|
+
g_logHandler = nullptr;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
void MMKV::setLogLevel(MMKVLogLevel level) {
|
|
1309
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1310
|
+
g_currentLogLevel = level;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
static void mkSpecialCharacterFileDirectory() {
|
|
1314
|
+
MMKVPath_t path = g_rootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1315
|
+
mkPath(path);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
template <typename T>
|
|
1319
|
+
static string md5(const basic_string<T> &value) {
|
|
1320
|
+
uint8_t md[MD5_DIGEST_LENGTH] = {};
|
|
1321
|
+
char tmp[3] = {}, buf[33] = {};
|
|
1322
|
+
openssl::MD5((const uint8_t *) value.c_str(), value.size() * (sizeof(T) / sizeof(uint8_t)), md);
|
|
1323
|
+
for (auto ch : md) {
|
|
1324
|
+
snprintf(tmp, sizeof(tmp), "%2.2x", ch);
|
|
1325
|
+
strcat(buf, tmp);
|
|
1326
|
+
}
|
|
1327
|
+
return {buf};
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
static MMKVPath_t encodeFilePath(const string &mmapID) {
|
|
1331
|
+
const char *specialCharacters = "\\/:*?\"<>|";
|
|
1332
|
+
string encodedID;
|
|
1333
|
+
bool hasSpecialCharacter = false;
|
|
1334
|
+
for (auto ch : mmapID) {
|
|
1335
|
+
if (strchr(specialCharacters, ch) != nullptr) {
|
|
1336
|
+
encodedID = md5(mmapID);
|
|
1337
|
+
hasSpecialCharacter = true;
|
|
1338
|
+
break;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if (hasSpecialCharacter) {
|
|
1342
|
+
static ThreadOnceToken_t once_control = ThreadOnceUninitialized;
|
|
1343
|
+
ThreadLock::ThreadOnce(&once_control, mkSpecialCharacterFileDirectory);
|
|
1344
|
+
return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
|
|
1345
|
+
} else {
|
|
1346
|
+
return string2MMKVPath_t(mmapID);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir) {
|
|
1351
|
+
const char *specialCharacters = "\\/:*?\"<>|";
|
|
1352
|
+
string encodedID;
|
|
1353
|
+
bool hasSpecialCharacter = false;
|
|
1354
|
+
for (auto ch : mmapID) {
|
|
1355
|
+
if (strchr(specialCharacters, ch) != nullptr) {
|
|
1356
|
+
encodedID = md5(mmapID);
|
|
1357
|
+
hasSpecialCharacter = true;
|
|
1358
|
+
break;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
if (hasSpecialCharacter) {
|
|
1362
|
+
MMKVPath_t path = rootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1363
|
+
mkPath(path);
|
|
1364
|
+
|
|
1365
|
+
return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
|
|
1366
|
+
} else {
|
|
1367
|
+
return string2MMKVPath_t(mmapID);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
string mmapedKVKey(const string &mmapID, const MMKVPath_t *rootPath) {
|
|
1372
|
+
if (rootPath && g_rootDir != (*rootPath)) {
|
|
1373
|
+
return md5(*rootPath + MMKV_PATH_SLASH + string2MMKVPath_t(mmapID));
|
|
1374
|
+
}
|
|
1375
|
+
return mmapID;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
MMKVPath_t mappedKVPathWithID(const string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath) {
|
|
1379
|
+
#ifndef MMKV_ANDROID
|
|
1380
|
+
if (rootPath) {
|
|
1381
|
+
#else
|
|
1382
|
+
if (mode & MMKV_ASHMEM) {
|
|
1383
|
+
return ashmemMMKVPathWithID(encodeFilePath(mmapID));
|
|
1384
|
+
} else if (rootPath) {
|
|
1385
|
+
#endif
|
|
1386
|
+
return *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID);
|
|
1387
|
+
}
|
|
1388
|
+
return g_rootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
MMKVPath_t crcPathWithID(const string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath) {
|
|
1392
|
+
#ifndef MMKV_ANDROID
|
|
1393
|
+
if (rootPath) {
|
|
1394
|
+
#else
|
|
1395
|
+
if (mode & MMKV_ASHMEM) {
|
|
1396
|
+
return ashmemMMKVPathWithID(encodeFilePath(mmapID)) + CRC_SUFFIX;
|
|
1397
|
+
} else if (rootPath) {
|
|
1398
|
+
#endif
|
|
1399
|
+
return *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID) + CRC_SUFFIX;
|
|
1400
|
+
}
|
|
1401
|
+
return g_rootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID) + CRC_SUFFIX;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
MMKVRecoverStrategic onMMKVCRCCheckFail(const string &mmapID) {
|
|
1405
|
+
if (g_errorHandler) {
|
|
1406
|
+
return g_errorHandler(mmapID, MMKVErrorType::MMKVCRCCheckFail);
|
|
1407
|
+
}
|
|
1408
|
+
return OnErrorDiscard;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
MMKVRecoverStrategic onMMKVFileLengthError(const string &mmapID) {
|
|
1412
|
+
if (g_errorHandler) {
|
|
1413
|
+
return g_errorHandler(mmapID, MMKVErrorType::MMKVFileLength);
|
|
1414
|
+
}
|
|
1415
|
+
return OnErrorDiscard;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
MMKV_NAMESPACE_END
|