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.
Files changed (138) hide show
  1. package/LICENSE +219 -0
  2. package/MMKV/CHANGELOG.md +553 -0
  3. package/MMKV/Core/CMakeLists.txt +153 -0
  4. package/MMKV/Core/CodedInputData.cpp +228 -0
  5. package/MMKV/Core/CodedInputData.h +83 -0
  6. package/MMKV/Core/CodedInputDataCrypt.cpp +280 -0
  7. package/MMKV/Core/CodedInputDataCrypt.h +87 -0
  8. package/MMKV/Core/CodedInputDataCrypt_OSX.cpp +62 -0
  9. package/MMKV/Core/CodedInputData_OSX.cpp +92 -0
  10. package/MMKV/Core/CodedOutputData.cpp +174 -0
  11. package/MMKV/Core/CodedOutputData.h +82 -0
  12. package/MMKV/Core/Core.xcodeproj/project.pbxproj +702 -0
  13. package/MMKV/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  14. package/MMKV/Core/Core.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  15. package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +67 -0
  16. package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +67 -0
  17. package/MMKV/Core/InterProcessLock.cpp +186 -0
  18. package/MMKV/Core/InterProcessLock.h +119 -0
  19. package/MMKV/Core/InterProcessLock_Android.cpp +103 -0
  20. package/MMKV/Core/InterProcessLock_Win32.cpp +108 -0
  21. package/MMKV/Core/KeyValueHolder.cpp +236 -0
  22. package/MMKV/Core/KeyValueHolder.h +118 -0
  23. package/MMKV/Core/MMBuffer.cpp +185 -0
  24. package/MMKV/Core/MMBuffer.h +107 -0
  25. package/MMKV/Core/MMKV.cpp +1418 -0
  26. package/MMKV/Core/MMKV.h +386 -0
  27. package/MMKV/Core/MMKVLog.cpp +127 -0
  28. package/MMKV/Core/MMKVLog.h +86 -0
  29. package/MMKV/Core/MMKVLog_Android.cpp +79 -0
  30. package/MMKV/Core/MMKVMetaInfo.hpp +81 -0
  31. package/MMKV/Core/MMKVPredef.h +245 -0
  32. package/MMKV/Core/MMKV_Android.cpp +259 -0
  33. package/MMKV/Core/MMKV_IO.cpp +1119 -0
  34. package/MMKV/Core/MMKV_IO.h +57 -0
  35. package/MMKV/Core/MMKV_OSX.cpp +347 -0
  36. package/MMKV/Core/MMKV_OSX.h +51 -0
  37. package/MMKV/Core/MemoryFile.cpp +537 -0
  38. package/MMKV/Core/MemoryFile.h +182 -0
  39. package/MMKV/Core/MemoryFile_Android.cpp +211 -0
  40. package/MMKV/Core/MemoryFile_Linux.cpp +120 -0
  41. package/MMKV/Core/MemoryFile_OSX.cpp +142 -0
  42. package/MMKV/Core/MemoryFile_Win32.cpp +536 -0
  43. package/MMKV/Core/MiniPBCoder.cpp +366 -0
  44. package/MMKV/Core/MiniPBCoder.h +129 -0
  45. package/MMKV/Core/MiniPBCoder_OSX.cpp +228 -0
  46. package/MMKV/Core/PBEncodeItem.hpp +86 -0
  47. package/MMKV/Core/PBUtility.cpp +61 -0
  48. package/MMKV/Core/PBUtility.h +153 -0
  49. package/MMKV/Core/ScopedLock.hpp +69 -0
  50. package/MMKV/Core/ThreadLock.cpp +68 -0
  51. package/MMKV/Core/ThreadLock.h +78 -0
  52. package/MMKV/Core/ThreadLock_Win32.cpp +89 -0
  53. package/MMKV/Core/aes/AESCrypt.cpp +256 -0
  54. package/MMKV/Core/aes/AESCrypt.h +107 -0
  55. package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +1231 -0
  56. package/MMKV/Core/aes/openssl/openssl_aes.h +118 -0
  57. package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +1044 -0
  58. package/MMKV/Core/aes/openssl/openssl_aes_locl.h +38 -0
  59. package/MMKV/Core/aes/openssl/openssl_aesv8-armx.S +308 -0
  60. package/MMKV/Core/aes/openssl/openssl_arm_arch.h +84 -0
  61. package/MMKV/Core/aes/openssl/openssl_cfb128.cpp +97 -0
  62. package/MMKV/Core/aes/openssl/openssl_md32_common.h +254 -0
  63. package/MMKV/Core/aes/openssl/openssl_md5.h +49 -0
  64. package/MMKV/Core/aes/openssl/openssl_md5_dgst.cpp +166 -0
  65. package/MMKV/Core/aes/openssl/openssl_md5_locl.h +75 -0
  66. package/MMKV/Core/aes/openssl/openssl_md5_one.cpp +30 -0
  67. package/MMKV/Core/aes/openssl/openssl_opensslconf.h +271 -0
  68. package/MMKV/Core/core.vcxproj +186 -0
  69. package/MMKV/Core/core.vcxproj.filters +150 -0
  70. package/MMKV/Core/crc32/Checksum.h +67 -0
  71. package/MMKV/Core/crc32/crc32_armv8.cpp +132 -0
  72. package/MMKV/Core/crc32/zlib/crc32.cpp +55 -0
  73. package/MMKV/Core/crc32/zlib/crc32.h +48 -0
  74. package/MMKV/Core/crc32/zlib/zconf.h +380 -0
  75. package/MMKV/Core/crc32/zlib/zutil.h +25 -0
  76. package/MMKV/LICENSE.TXT +193 -0
  77. package/MMKV/README.md +288 -0
  78. package/README.md +221 -0
  79. package/android/CMakeLists.txt +71 -0
  80. package/android/build.gradle +371 -0
  81. package/android/gradle.properties +4 -0
  82. package/android/src/main/AndroidManifest.xml +4 -0
  83. package/android/src/main/cpp/MmkvHostObject.cpp +302 -0
  84. package/android/src/main/cpp/MmkvHostObject.h +26 -0
  85. package/android/src/main/cpp/cpp-adapter.cpp +65 -0
  86. package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +49 -0
  87. package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +26 -0
  88. package/cpp/TypedArray.cpp +341 -0
  89. package/cpp/TypedArray.h +175 -0
  90. package/ios/JSIUtils.h +50 -0
  91. package/ios/JSIUtils.mm +194 -0
  92. package/ios/Mmkv.xcodeproj/project.pbxproj +291 -0
  93. package/ios/MmkvHostObject.h +27 -0
  94. package/ios/MmkvHostObject.mm +299 -0
  95. package/ios/MmkvModule.h +5 -0
  96. package/ios/MmkvModule.mm +73 -0
  97. package/lib/commonjs/MMKV.js +146 -0
  98. package/lib/commonjs/MMKV.js.map +1 -0
  99. package/lib/commonjs/PlatformChecker.js +16 -0
  100. package/lib/commonjs/PlatformChecker.js.map +1 -0
  101. package/lib/commonjs/createMMKV.js +66 -0
  102. package/lib/commonjs/createMMKV.js.map +1 -0
  103. package/lib/commonjs/createMMKV.mock.js +40 -0
  104. package/lib/commonjs/createMMKV.mock.js.map +1 -0
  105. package/lib/commonjs/createMMKV.web.js +77 -0
  106. package/lib/commonjs/createMMKV.web.js.map +1 -0
  107. package/lib/commonjs/createTextEncoder.js +24 -0
  108. package/lib/commonjs/createTextEncoder.js.map +1 -0
  109. package/lib/commonjs/hooks.js +200 -0
  110. package/lib/commonjs/hooks.js.map +1 -0
  111. package/lib/commonjs/index.js +32 -0
  112. package/lib/commonjs/index.js.map +1 -0
  113. package/lib/module/MMKV.js +134 -0
  114. package/lib/module/MMKV.js.map +1 -0
  115. package/lib/module/PlatformChecker.js +9 -0
  116. package/lib/module/PlatformChecker.js.map +1 -0
  117. package/lib/module/createMMKV.js +55 -0
  118. package/lib/module/createMMKV.js.map +1 -0
  119. package/lib/module/createMMKV.mock.js +31 -0
  120. package/lib/module/createMMKV.mock.js.map +1 -0
  121. package/lib/module/createMMKV.web.js +67 -0
  122. package/lib/module/createMMKV.web.js.map +1 -0
  123. package/lib/module/createTextEncoder.js +17 -0
  124. package/lib/module/createTextEncoder.js.map +1 -0
  125. package/lib/module/hooks.js +181 -0
  126. package/lib/module/hooks.js.map +1 -0
  127. package/lib/module/index.js +3 -0
  128. package/lib/module/index.js.map +1 -0
  129. package/lib/typescript/MMKV.d.ts +137 -0
  130. package/lib/typescript/PlatformChecker.d.ts +1 -0
  131. package/lib/typescript/createMMKV.d.ts +6 -0
  132. package/lib/typescript/createMMKV.mock.d.ts +2 -0
  133. package/lib/typescript/createMMKV.web.d.ts +2 -0
  134. package/lib/typescript/createTextEncoder.d.ts +1 -0
  135. package/lib/typescript/hooks.d.ts +81 -0
  136. package/lib/typescript/index.d.ts +2 -0
  137. package/package.json +168 -0
  138. 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