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,1119 @@
1
+ /*
2
+ * Tencent is pleased to support the open source community by making
3
+ * MMKV available.
4
+ *
5
+ * Copyright (C) 2020 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 "MMKV_IO.h"
22
+ #include "CodedInputData.h"
23
+ #include "CodedOutputData.h"
24
+ #include "InterProcessLock.h"
25
+ #include "MMBuffer.h"
26
+ #include "MMKVLog.h"
27
+ #include "MMKVMetaInfo.hpp"
28
+ #include "MemoryFile.h"
29
+ #include "MiniPBCoder.h"
30
+ #include "PBUtility.h"
31
+ #include "ScopedLock.hpp"
32
+ #include "ThreadLock.h"
33
+ #include "aes/AESCrypt.h"
34
+ #include "aes/openssl/openssl_aes.h"
35
+ #include "aes/openssl/openssl_md5.h"
36
+ #include "crc32/Checksum.h"
37
+ #include <algorithm>
38
+ #include <cassert>
39
+ #include <cstring>
40
+
41
+ #ifdef MMKV_IOS
42
+ # include "MMKV_OSX.h"
43
+ #endif
44
+
45
+ #ifdef MMKV_APPLE
46
+ # if __has_feature(objc_arc)
47
+ # error This file must be compiled with MRC. Use -fno-objc-arc flag.
48
+ # endif
49
+ #endif // MMKV_APPLE
50
+
51
+ using namespace std;
52
+ using namespace mmkv;
53
+ using KVHolderRet_t = std::pair<bool, KeyValueHolder>;
54
+
55
+ constexpr uint32_t Fixed32Size = pbFixed32Size();
56
+
57
+ MMKV_NAMESPACE_BEGIN
58
+
59
+ void MMKV::loadFromFile() {
60
+ if (m_metaFile->isFileValid()) {
61
+ m_metaInfo->read(m_metaFile->getMemory());
62
+ }
63
+ #ifndef MMKV_DISABLE_CRYPT
64
+ if (m_crypter) {
65
+ if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
66
+ m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
67
+ }
68
+ }
69
+ #endif
70
+ if (!m_file->isFileValid()) {
71
+ m_file->reloadFromFile();
72
+ }
73
+ if (!m_file->isFileValid()) {
74
+ MMKVError("file [%s] not valid", m_path.c_str());
75
+ } else {
76
+ // error checking
77
+ bool loadFromFile = false, needFullWriteback = false;
78
+ checkDataValid(loadFromFile, needFullWriteback);
79
+ MMKVInfo("loading [%s] with %zu actual size, file size %zu, InterProcess %d, meta info "
80
+ "version:%u",
81
+ m_mmapID.c_str(), m_actualSize, m_file->getFileSize(), m_isInterProcess, m_metaInfo->m_version);
82
+ auto ptr = (uint8_t *) m_file->getMemory();
83
+ // loading
84
+ if (loadFromFile && m_actualSize > 0) {
85
+ MMKVInfo("loading [%s] with crc %u sequence %u version %u", m_mmapID.c_str(), m_metaInfo->m_crcDigest,
86
+ m_metaInfo->m_sequence, m_metaInfo->m_version);
87
+ MMBuffer inputBuffer(ptr + Fixed32Size, m_actualSize, MMBufferNoCopy);
88
+ if (m_crypter) {
89
+ clearDictionary(m_dicCrypt);
90
+ } else {
91
+ clearDictionary(m_dic);
92
+ }
93
+ if (needFullWriteback) {
94
+ #ifndef MMKV_DISABLE_CRYPT
95
+ if (m_crypter) {
96
+ MiniPBCoder::greedyDecodeMap(*m_dicCrypt, inputBuffer, m_crypter);
97
+ } else
98
+ #endif
99
+ {
100
+ MiniPBCoder::greedyDecodeMap(*m_dic, inputBuffer);
101
+ }
102
+ } else {
103
+ #ifndef MMKV_DISABLE_CRYPT
104
+ if (m_crypter) {
105
+ MiniPBCoder::decodeMap(*m_dicCrypt, inputBuffer, m_crypter);
106
+ } else
107
+ #endif
108
+ {
109
+ MiniPBCoder::decodeMap(*m_dic, inputBuffer);
110
+ }
111
+ }
112
+ m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
113
+ m_output->seek(m_actualSize);
114
+ if (needFullWriteback) {
115
+ fullWriteback();
116
+ }
117
+ } else {
118
+ // file not valid or empty, discard everything
119
+ SCOPED_LOCK(m_exclusiveProcessLock);
120
+
121
+ m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
122
+ if (m_actualSize > 0) {
123
+ writeActualSize(0, 0, nullptr, IncreaseSequence);
124
+ sync(MMKV_SYNC);
125
+ } else {
126
+ writeActualSize(0, 0, nullptr, KeepSequence);
127
+ }
128
+ }
129
+ auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
130
+ MMKVInfo("loaded [%s] with %zu key-values", m_mmapID.c_str(), count);
131
+ }
132
+
133
+ m_needLoadFromFile = false;
134
+ }
135
+
136
+ // read from last m_position
137
+ void MMKV::partialLoadFromFile() {
138
+ m_metaInfo->read(m_metaFile->getMemory());
139
+
140
+ size_t oldActualSize = m_actualSize;
141
+ m_actualSize = readActualSize();
142
+ auto fileSize = m_file->getFileSize();
143
+ MMKVDebug("loading [%s] with file size %zu, oldActualSize %zu, newActualSize %zu", m_mmapID.c_str(), fileSize,
144
+ oldActualSize, m_actualSize);
145
+
146
+ if (m_actualSize > 0) {
147
+ if (m_actualSize < fileSize && m_actualSize + Fixed32Size <= fileSize) {
148
+ if (m_actualSize > oldActualSize) {
149
+ auto position = oldActualSize;
150
+ size_t addedSize = m_actualSize - position;
151
+ auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
152
+ // incremental update crc digest
153
+ m_crcDigest = (uint32_t) CRC32(m_crcDigest, basePtr + position, addedSize);
154
+ if (m_crcDigest == m_metaInfo->m_crcDigest) {
155
+ MMBuffer inputBuffer(basePtr, m_actualSize, MMBufferNoCopy);
156
+ #ifndef MMKV_DISABLE_CRYPT
157
+ if (m_crypter) {
158
+ MiniPBCoder::greedyDecodeMap(*m_dicCrypt, inputBuffer, m_crypter, position);
159
+ } else
160
+ #endif
161
+ {
162
+ MiniPBCoder::greedyDecodeMap(*m_dic, inputBuffer, position);
163
+ }
164
+ m_output->seek(addedSize);
165
+ m_hasFullWriteback = false;
166
+
167
+ auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
168
+ MMKVDebug("partial loaded [%s] with %zu values", m_mmapID.c_str(), count);
169
+ return;
170
+ } else {
171
+ MMKVError("m_crcDigest[%u] != m_metaInfo->m_crcDigest[%u]", m_crcDigest, m_metaInfo->m_crcDigest);
172
+ }
173
+ }
174
+ }
175
+ }
176
+ // something is wrong, do a full load
177
+ clearMemoryCache();
178
+ loadFromFile();
179
+ }
180
+
181
+ void MMKV::checkDataValid(bool &loadFromFile, bool &needFullWriteback) {
182
+ // try auto recover from last confirmed location
183
+ auto fileSize = m_file->getFileSize();
184
+ auto checkLastConfirmedInfo = [&] {
185
+ if (m_metaInfo->m_version >= MMKVVersionActualSize) {
186
+ // downgrade & upgrade support
187
+ uint32_t oldStyleActualSize = 0;
188
+ memcpy(&oldStyleActualSize, m_file->getMemory(), Fixed32Size);
189
+ if (oldStyleActualSize != m_actualSize) {
190
+ MMKVWarning("oldStyleActualSize %u not equal to meta actual size %lu", oldStyleActualSize,
191
+ m_actualSize);
192
+ if (oldStyleActualSize < fileSize && (oldStyleActualSize + Fixed32Size) <= fileSize) {
193
+ if (checkFileCRCValid(oldStyleActualSize, m_metaInfo->m_crcDigest)) {
194
+ MMKVInfo("looks like [%s] been downgrade & upgrade again", m_mmapID.c_str());
195
+ loadFromFile = true;
196
+ writeActualSize(oldStyleActualSize, m_metaInfo->m_crcDigest, nullptr, KeepSequence);
197
+ return;
198
+ }
199
+ } else {
200
+ MMKVWarning("oldStyleActualSize %u greater than file size %lu", oldStyleActualSize, fileSize);
201
+ }
202
+ }
203
+
204
+ auto lastActualSize = m_metaInfo->m_lastConfirmedMetaInfo.lastActualSize;
205
+ if (lastActualSize < fileSize && (lastActualSize + Fixed32Size) <= fileSize) {
206
+ auto lastCRCDigest = m_metaInfo->m_lastConfirmedMetaInfo.lastCRCDigest;
207
+ if (checkFileCRCValid(lastActualSize, lastCRCDigest)) {
208
+ loadFromFile = true;
209
+ writeActualSize(lastActualSize, lastCRCDigest, nullptr, KeepSequence);
210
+ } else {
211
+ MMKVError("check [%s] error: lastActualSize %u, lastActualCRC %u", m_mmapID.c_str(), lastActualSize,
212
+ lastCRCDigest);
213
+ }
214
+ } else {
215
+ MMKVError("check [%s] error: lastActualSize %u, file size is %u", m_mmapID.c_str(), lastActualSize,
216
+ fileSize);
217
+ }
218
+ }
219
+ };
220
+
221
+ m_actualSize = readActualSize();
222
+
223
+ if (m_actualSize < fileSize && (m_actualSize + Fixed32Size) <= fileSize) {
224
+ if (checkFileCRCValid(m_actualSize, m_metaInfo->m_crcDigest)) {
225
+ loadFromFile = true;
226
+ } else {
227
+ checkLastConfirmedInfo();
228
+
229
+ if (!loadFromFile) {
230
+ auto strategic = onMMKVCRCCheckFail(m_mmapID);
231
+ if (strategic == OnErrorRecover) {
232
+ loadFromFile = true;
233
+ needFullWriteback = true;
234
+ }
235
+ MMKVInfo("recover strategic for [%s] is %d", m_mmapID.c_str(), strategic);
236
+ }
237
+ }
238
+ } else {
239
+ MMKVError("check [%s] error: %zu size in total, file size is %zu", m_mmapID.c_str(), m_actualSize, fileSize);
240
+
241
+ checkLastConfirmedInfo();
242
+
243
+ if (!loadFromFile) {
244
+ auto strategic = onMMKVFileLengthError(m_mmapID);
245
+ if (strategic == OnErrorRecover) {
246
+ // make sure we don't over read the file
247
+ m_actualSize = fileSize - Fixed32Size;
248
+ loadFromFile = true;
249
+ needFullWriteback = true;
250
+ }
251
+ MMKVInfo("recover strategic for [%s] is %d", m_mmapID.c_str(), strategic);
252
+ }
253
+ }
254
+ }
255
+
256
+ void MMKV::checkLoadData() {
257
+ if (m_needLoadFromFile) {
258
+ SCOPED_LOCK(m_sharedProcessLock);
259
+
260
+ m_needLoadFromFile = false;
261
+ loadFromFile();
262
+ return;
263
+ }
264
+ if (!m_isInterProcess) {
265
+ return;
266
+ }
267
+
268
+ if (!m_metaFile->isFileValid()) {
269
+ return;
270
+ }
271
+ SCOPED_LOCK(m_sharedProcessLock);
272
+
273
+ MMKVMetaInfo metaInfo;
274
+ metaInfo.read(m_metaFile->getMemory());
275
+ if (m_metaInfo->m_sequence != metaInfo.m_sequence) {
276
+ MMKVInfo("[%s] oldSeq %u, newSeq %u", m_mmapID.c_str(), m_metaInfo->m_sequence, metaInfo.m_sequence);
277
+ SCOPED_LOCK(m_sharedProcessLock);
278
+
279
+ clearMemoryCache();
280
+ loadFromFile();
281
+ notifyContentChanged();
282
+ } else if (m_metaInfo->m_crcDigest != metaInfo.m_crcDigest) {
283
+ MMKVDebug("[%s] oldCrc %u, newCrc %u, new actualSize %u", m_mmapID.c_str(), m_metaInfo->m_crcDigest,
284
+ metaInfo.m_crcDigest, metaInfo.m_actualSize);
285
+ SCOPED_LOCK(m_sharedProcessLock);
286
+
287
+ size_t fileSize = m_file->getActualFileSize();
288
+ if (m_file->getFileSize() != fileSize) {
289
+ MMKVInfo("file size has changed [%s] from %zu to %zu", m_mmapID.c_str(), m_file->getFileSize(), fileSize);
290
+ clearMemoryCache();
291
+ loadFromFile();
292
+ } else {
293
+ partialLoadFromFile();
294
+ }
295
+ notifyContentChanged();
296
+ }
297
+ }
298
+
299
+ constexpr uint32_t ItemSizeHolder = 0x00ffffff;
300
+ constexpr uint32_t ItemSizeHolderSize = 4;
301
+
302
+ static pair<MMBuffer, size_t> prepareEncode(const MMKVMap &dic) {
303
+ // make some room for placeholder
304
+ size_t totalSize = ItemSizeHolderSize;
305
+ for (auto &itr : dic) {
306
+ auto &kvHolder = itr.second;
307
+ totalSize += kvHolder.computedKVSize + kvHolder.valueSize;
308
+ }
309
+ return make_pair(MMBuffer(), totalSize);
310
+ }
311
+
312
+ #ifndef MMKV_DISABLE_CRYPT
313
+ static pair<MMBuffer, size_t> prepareEncode(const MMKVMapCrypt &dic) {
314
+ MMKVVector vec;
315
+ size_t totalSize = 0;
316
+ // make some room for placeholder
317
+ uint32_t smallestOffet = 5 + 1; // 5 is the largest size needed to encode varint32
318
+ for (auto &itr : dic) {
319
+ auto &kvHolder = itr.second;
320
+ if (kvHolder.type == KeyValueHolderType_Offset) {
321
+ totalSize += kvHolder.pbKeyValueSize + kvHolder.keySize + kvHolder.valueSize;
322
+ smallestOffet = min(smallestOffet, kvHolder.offset);
323
+ } else {
324
+ vec.emplace_back(itr.first, kvHolder.toMMBuffer(nullptr, nullptr));
325
+ }
326
+ }
327
+ if (smallestOffet > 5) {
328
+ smallestOffet = ItemSizeHolderSize;
329
+ }
330
+ totalSize += smallestOffet;
331
+ if (vec.empty()) {
332
+ return make_pair(MMBuffer(), totalSize);
333
+ }
334
+ auto buffer = MiniPBCoder::encodeDataWithObject(vec);
335
+ // skip the pb size of buffer
336
+ auto sizeOfMap = CodedInputData(buffer.getPtr(), buffer.length()).readUInt32();
337
+ totalSize += sizeOfMap;
338
+ return make_pair(move(buffer), totalSize);
339
+ }
340
+ #endif
341
+
342
+ // since we use append mode, when -[setData: forKey:] many times, space may not be enough
343
+ // try a full rewrite to make space
344
+ bool MMKV::ensureMemorySize(size_t newSize) {
345
+ if (!isFileValid()) {
346
+ MMKVWarning("[%s] file not valid", m_mmapID.c_str());
347
+ return false;
348
+ }
349
+
350
+ if (newSize >= m_output->spaceLeft() || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
351
+ // try a full rewrite to make space
352
+ auto fileSize = m_file->getFileSize();
353
+ auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
354
+ auto sizeOfDic = preparedData.second;
355
+ size_t lenNeeded = sizeOfDic + Fixed32Size + newSize;
356
+ size_t dicCount = m_crypter ? m_dicCrypt->size() : m_dic->size();
357
+ size_t avgItemSize = lenNeeded / std::max<size_t>(1, dicCount);
358
+ size_t futureUsage = avgItemSize * std::max<size_t>(8, (dicCount + 1) / 2);
359
+ // 1. no space for a full rewrite, double it
360
+ // 2. or space is not large enough for future usage, double it to avoid frequently full rewrite
361
+ if (lenNeeded >= fileSize || (lenNeeded + futureUsage) >= fileSize) {
362
+ size_t oldSize = fileSize;
363
+ do {
364
+ fileSize *= 2;
365
+ } while (lenNeeded + futureUsage >= fileSize);
366
+ MMKVInfo("extending [%s] file size from %zu to %zu, incoming size:%zu, future usage:%zu", m_mmapID.c_str(),
367
+ oldSize, fileSize, newSize, futureUsage);
368
+
369
+ // if we can't extend size, rollback to old state
370
+ if (!m_file->truncate(fileSize)) {
371
+ return false;
372
+ }
373
+
374
+ // check if we fail to make more space
375
+ if (!isFileValid()) {
376
+ MMKVWarning("[%s] file not valid", m_mmapID.c_str());
377
+ return false;
378
+ }
379
+ }
380
+ return doFullWriteBack(move(preparedData), nullptr);
381
+ }
382
+ return true;
383
+ }
384
+
385
+ size_t MMKV::readActualSize() {
386
+ MMKV_ASSERT(m_file->getMemory());
387
+ MMKV_ASSERT(m_metaFile->isFileValid());
388
+
389
+ uint32_t actualSize = 0;
390
+ memcpy(&actualSize, m_file->getMemory(), Fixed32Size);
391
+
392
+ if (m_metaInfo->m_version >= MMKVVersionActualSize) {
393
+ if (m_metaInfo->m_actualSize != actualSize) {
394
+ MMKVWarning("[%s] actual size %u, meta actual size %u", m_mmapID.c_str(), actualSize,
395
+ m_metaInfo->m_actualSize);
396
+ }
397
+ return m_metaInfo->m_actualSize;
398
+ } else {
399
+ return actualSize;
400
+ }
401
+ }
402
+
403
+ void MMKV::oldStyleWriteActualSize(size_t actualSize) {
404
+ MMKV_ASSERT(m_file->getMemory());
405
+
406
+ m_actualSize = actualSize;
407
+ #ifdef MMKV_IOS
408
+ auto ret = guardForBackgroundWriting(m_file->getMemory(), Fixed32Size);
409
+ if (!ret.first) {
410
+ return;
411
+ }
412
+ #endif
413
+ memcpy(m_file->getMemory(), &actualSize, Fixed32Size);
414
+ }
415
+
416
+ bool MMKV::writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool increaseSequence) {
417
+ // backward compatibility
418
+ oldStyleWriteActualSize(size);
419
+
420
+ if (!m_metaFile->isFileValid()) {
421
+ return false;
422
+ }
423
+
424
+ bool needsFullWrite = false;
425
+ m_actualSize = size;
426
+ m_metaInfo->m_actualSize = static_cast<uint32_t>(size);
427
+ m_crcDigest = crcDigest;
428
+ m_metaInfo->m_crcDigest = crcDigest;
429
+ if (m_metaInfo->m_version < MMKVVersionSequence) {
430
+ m_metaInfo->m_version = MMKVVersionSequence;
431
+ needsFullWrite = true;
432
+ }
433
+ #ifndef MMKV_DISABLE_CRYPT
434
+ if (unlikely(iv)) {
435
+ memcpy(m_metaInfo->m_vector, iv, sizeof(m_metaInfo->m_vector));
436
+ if (m_metaInfo->m_version < MMKVVersionRandomIV) {
437
+ m_metaInfo->m_version = MMKVVersionRandomIV;
438
+ }
439
+ needsFullWrite = true;
440
+ }
441
+ #endif
442
+ if (unlikely(increaseSequence)) {
443
+ m_metaInfo->m_sequence++;
444
+ m_metaInfo->m_lastConfirmedMetaInfo.lastActualSize = static_cast<uint32_t>(size);
445
+ m_metaInfo->m_lastConfirmedMetaInfo.lastCRCDigest = crcDigest;
446
+ if (m_metaInfo->m_version < MMKVVersionActualSize) {
447
+ m_metaInfo->m_version = MMKVVersionActualSize;
448
+ }
449
+ needsFullWrite = true;
450
+ }
451
+ #ifdef MMKV_IOS
452
+ auto ret = guardForBackgroundWriting(m_metaFile->getMemory(), sizeof(MMKVMetaInfo));
453
+ if (!ret.first) {
454
+ return false;
455
+ }
456
+ #endif
457
+ if (unlikely(needsFullWrite)) {
458
+ m_metaInfo->write(m_metaFile->getMemory());
459
+ } else {
460
+ m_metaInfo->writeCRCAndActualSizeOnly(m_metaFile->getMemory());
461
+ }
462
+ return true;
463
+ }
464
+
465
+ MMBuffer MMKV::getDataForKey(MMKVKey_t key) {
466
+ checkLoadData();
467
+ #ifndef MMKV_DISABLE_CRYPT
468
+ if (m_crypter) {
469
+ auto itr = m_dicCrypt->find(key);
470
+ if (itr != m_dicCrypt->end()) {
471
+ auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
472
+ return itr->second.toMMBuffer(basePtr, m_crypter);
473
+ }
474
+ } else
475
+ #endif
476
+ {
477
+ auto itr = m_dic->find(key);
478
+ if (itr != m_dic->end()) {
479
+ auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
480
+ return itr->second.toMMBuffer(basePtr);
481
+ }
482
+ }
483
+ MMBuffer nan;
484
+ return nan;
485
+ }
486
+
487
+ #ifndef MMKV_DISABLE_CRYPT
488
+ // for Apple watch simulator
489
+ # if defined(TARGET_OS_SIMULATOR) && defined(TARGET_CPU_X86)
490
+ static AESCryptStatus t_status;
491
+ # else
492
+ thread_local AESCryptStatus t_status;
493
+ # endif
494
+ #endif // MMKV_DISABLE_CRYPT
495
+
496
+ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
497
+ if ((!isDataHolder && data.length() == 0) || isKeyEmpty(key)) {
498
+ return false;
499
+ }
500
+ SCOPED_LOCK(m_lock);
501
+ SCOPED_LOCK(m_exclusiveProcessLock);
502
+ checkLoadData();
503
+
504
+ #ifndef MMKV_DISABLE_CRYPT
505
+ if (m_crypter) {
506
+ if (isDataHolder) {
507
+ auto sizeNeededForData = pbRawVarint32Size((uint32_t) data.length()) + data.length();
508
+ if (!KeyValueHolderCrypt::isValueStoredAsOffset(sizeNeededForData)) {
509
+ data = MiniPBCoder::encodeDataWithObject(data);
510
+ isDataHolder = false;
511
+ }
512
+ }
513
+ auto itr = m_dicCrypt->find(key);
514
+ if (itr != m_dicCrypt->end()) {
515
+ # ifdef MMKV_APPLE
516
+ auto ret = appendDataWithKey(data, key, itr->second, isDataHolder);
517
+ # else
518
+ auto ret = appendDataWithKey(data, key, isDataHolder);
519
+ # endif
520
+ if (!ret.first) {
521
+ return false;
522
+ }
523
+ if (KeyValueHolderCrypt::isValueStoredAsOffset(ret.second.valueSize)) {
524
+ KeyValueHolderCrypt kvHolder(ret.second.keySize, ret.second.valueSize, ret.second.offset);
525
+ memcpy(&kvHolder.cryptStatus, &t_status, sizeof(t_status));
526
+ itr->second = move(kvHolder);
527
+ } else {
528
+ itr->second = KeyValueHolderCrypt(move(data));
529
+ }
530
+ } else {
531
+ auto ret = appendDataWithKey(data, key, isDataHolder);
532
+ if (!ret.first) {
533
+ return false;
534
+ }
535
+ if (KeyValueHolderCrypt::isValueStoredAsOffset(ret.second.valueSize)) {
536
+ auto r = m_dicCrypt->emplace(
537
+ key, KeyValueHolderCrypt(ret.second.keySize, ret.second.valueSize, ret.second.offset));
538
+ if (r.second) {
539
+ memcpy(&(r.first->second.cryptStatus), &t_status, sizeof(t_status));
540
+ }
541
+ } else {
542
+ m_dicCrypt->emplace(key, KeyValueHolderCrypt(move(data)));
543
+ }
544
+ }
545
+ } else
546
+ #endif // MMKV_DISABLE_CRYPT
547
+ {
548
+ auto itr = m_dic->find(key);
549
+ if (itr != m_dic->end()) {
550
+ auto ret = appendDataWithKey(data, itr->second, isDataHolder);
551
+ if (!ret.first) {
552
+ return false;
553
+ }
554
+ itr->second = std::move(ret.second);
555
+ } else {
556
+ auto ret = appendDataWithKey(data, key, isDataHolder);
557
+ if (!ret.first) {
558
+ return false;
559
+ }
560
+ m_dic->emplace(key, std::move(ret.second));
561
+ }
562
+ }
563
+ m_hasFullWriteback = false;
564
+ #ifdef MMKV_APPLE
565
+ [key retain];
566
+ #endif
567
+ return true;
568
+ }
569
+
570
+ bool MMKV::removeDataForKey(MMKVKey_t key) {
571
+ if (isKeyEmpty(key)) {
572
+ return false;
573
+ }
574
+ #ifndef MMKV_DISABLE_CRYPT
575
+ if (m_crypter) {
576
+ auto itr = m_dicCrypt->find(key);
577
+ if (itr != m_dicCrypt->end()) {
578
+ m_hasFullWriteback = false;
579
+ static MMBuffer nan;
580
+ # ifdef MMKV_APPLE
581
+ auto ret = appendDataWithKey(nan, key, itr->second);
582
+ if (ret.first) {
583
+ auto oldKey = itr->first;
584
+ m_dicCrypt->erase(itr);
585
+ [oldKey release];
586
+ }
587
+ # else
588
+ auto ret = appendDataWithKey(nan, key);
589
+ if (ret.first) {
590
+ m_dicCrypt->erase(itr);
591
+ }
592
+ # endif
593
+ return ret.first;
594
+ }
595
+ } else
596
+ #endif // MMKV_DISABLE_CRYPT
597
+ {
598
+ auto itr = m_dic->find(key);
599
+ if (itr != m_dic->end()) {
600
+ m_hasFullWriteback = false;
601
+ static MMBuffer nan;
602
+ auto ret = appendDataWithKey(nan, itr->second);
603
+ if (ret.first) {
604
+ #ifdef MMKV_APPLE
605
+ auto oldKey = itr->first;
606
+ m_dic->erase(itr);
607
+ [oldKey release];
608
+ #else
609
+ m_dic->erase(itr);
610
+ #endif
611
+ }
612
+ return ret.first;
613
+ }
614
+ }
615
+
616
+ return false;
617
+ }
618
+
619
+ KVHolderRet_t
620
+ MMKV::doAppendDataWithKey(const MMBuffer &data, const MMBuffer &keyData, bool isDataHolder, uint32_t originKeyLength) {
621
+ auto isKeyEncoded = (originKeyLength < keyData.length());
622
+ auto keyLength = static_cast<uint32_t>(keyData.length());
623
+ auto valueLength = static_cast<uint32_t>(data.length());
624
+ if (isDataHolder) {
625
+ valueLength += pbRawVarint32Size(valueLength);
626
+ }
627
+ // size needed to encode the key
628
+ size_t size = isKeyEncoded ? keyLength : (keyLength + pbRawVarint32Size(keyLength));
629
+ // size needed to encode the value
630
+ size += valueLength + pbRawVarint32Size(valueLength);
631
+
632
+ SCOPED_LOCK(m_exclusiveProcessLock);
633
+
634
+ bool hasEnoughSize = ensureMemorySize(size);
635
+ if (!hasEnoughSize || !isFileValid()) {
636
+ return make_pair(false, KeyValueHolder());
637
+ }
638
+
639
+ #ifdef MMKV_IOS
640
+ auto ret = guardForBackgroundWriting(m_output->curWritePointer(), size);
641
+ if (!ret.first) {
642
+ return make_pair(false, KeyValueHolder());
643
+ }
644
+ #endif
645
+ #ifndef MMKV_DISABLE_CRYPT
646
+ if (m_crypter) {
647
+ if (KeyValueHolderCrypt::isValueStoredAsOffset(valueLength)) {
648
+ m_crypter->getCurStatus(t_status);
649
+ }
650
+ }
651
+ #endif
652
+ try {
653
+ if (isKeyEncoded) {
654
+ m_output->writeRawData(keyData);
655
+ } else {
656
+ m_output->writeData(keyData);
657
+ }
658
+ if (isDataHolder) {
659
+ m_output->writeRawVarint32((int32_t) valueLength);
660
+ }
661
+ m_output->writeData(data); // note: write size of data
662
+ } catch (std::exception &e) {
663
+ MMKVError("%s", e.what());
664
+ return make_pair(false, KeyValueHolder());
665
+ }
666
+
667
+ auto offset = static_cast<uint32_t>(m_actualSize);
668
+ auto ptr = (uint8_t *) m_file->getMemory() + Fixed32Size + m_actualSize;
669
+ #ifndef MMKV_DISABLE_CRYPT
670
+ if (m_crypter) {
671
+ m_crypter->encrypt(ptr, ptr, size);
672
+ }
673
+ #endif
674
+ m_actualSize += size;
675
+ updateCRCDigest(ptr, size);
676
+
677
+ return make_pair(true, KeyValueHolder(originKeyLength, valueLength, offset));
678
+ }
679
+
680
+ KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, MMKVKey_t key, bool isDataHolder) {
681
+ #ifdef MMKV_APPLE
682
+ auto oData = [key dataUsingEncoding:NSUTF8StringEncoding];
683
+ auto keyData = MMBuffer(oData, MMBufferNoCopy);
684
+ #else
685
+ auto keyData = MMBuffer((void *) key.data(), key.size(), MMBufferNoCopy);
686
+ #endif
687
+ return doAppendDataWithKey(data, keyData, isDataHolder, static_cast<uint32_t>(keyData.length()));
688
+ }
689
+
690
+ KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, const KeyValueHolder &kvHolder, bool isDataHolder) {
691
+ SCOPED_LOCK(m_exclusiveProcessLock);
692
+
693
+ uint32_t keyLength = kvHolder.keySize;
694
+ // size needed to encode the key
695
+ size_t rawKeySize = keyLength + pbRawVarint32Size(keyLength);
696
+
697
+ // ensureMemorySize() might change kvHolder.offset, so have to do it early
698
+ {
699
+ auto valueLength = static_cast<uint32_t>(data.length());
700
+ if (isDataHolder) {
701
+ valueLength += pbRawVarint32Size(valueLength);
702
+ }
703
+ auto size = rawKeySize + valueLength + pbRawVarint32Size(valueLength);
704
+ bool hasEnoughSize = ensureMemorySize(size);
705
+ if (!hasEnoughSize) {
706
+ return make_pair(false, KeyValueHolder());
707
+ }
708
+ }
709
+ auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
710
+ MMBuffer keyData(basePtr + kvHolder.offset, rawKeySize, MMBufferNoCopy);
711
+
712
+ return doAppendDataWithKey(data, keyData, isDataHolder, keyLength);
713
+ }
714
+
715
+ bool MMKV::fullWriteback(AESCrypt *newCrypter) {
716
+ if (m_hasFullWriteback) {
717
+ return true;
718
+ }
719
+ if (m_needLoadFromFile) {
720
+ return true;
721
+ }
722
+ if (!isFileValid()) {
723
+ MMKVWarning("[%s] file not valid", m_mmapID.c_str());
724
+ return false;
725
+ }
726
+
727
+ if (m_crypter ? m_dicCrypt->empty() : m_dic->empty()) {
728
+ clearAll();
729
+ return true;
730
+ }
731
+
732
+ auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
733
+ auto sizeOfDic = preparedData.second;
734
+ SCOPED_LOCK(m_exclusiveProcessLock);
735
+ if (sizeOfDic > 0) {
736
+ auto fileSize = m_file->getFileSize();
737
+ if (sizeOfDic + Fixed32Size <= fileSize) {
738
+ return doFullWriteBack(move(preparedData), newCrypter);
739
+ } else {
740
+ assert(0);
741
+ assert(newCrypter == nullptr);
742
+ // ensureMemorySize will extend file & full rewrite, no need to write back again
743
+ return ensureMemorySize(sizeOfDic + Fixed32Size - fileSize);
744
+ }
745
+ }
746
+ return false;
747
+ }
748
+
749
+ // we don't need to really serialize the dictionary, just reuse what's already in the file
750
+ static void
751
+ memmoveDictionary(MMKVMap &dic, CodedOutputData *output, uint8_t *ptr, AESCrypt *encrypter, size_t totalSize) {
752
+ auto originOutputPtr = output->curWritePointer();
753
+ // make space to hold the fake size of dictionary's serialization result
754
+ auto writePtr = originOutputPtr + ItemSizeHolderSize;
755
+ // reuse what's already in the file
756
+ if (!dic.empty()) {
757
+ // sort by offset
758
+ vector<KeyValueHolder *> vec;
759
+ vec.reserve(dic.size());
760
+ for (auto &itr : dic) {
761
+ vec.push_back(&itr.second);
762
+ }
763
+ sort(vec.begin(), vec.end(), [](const auto &left, const auto &right) { return left->offset < right->offset; });
764
+
765
+ // merge nearby items to make memmove quicker
766
+ vector<pair<uint32_t, uint32_t>> dataSections; // pair(offset, size)
767
+ dataSections.emplace_back(vec.front()->offset, vec.front()->computedKVSize + vec.front()->valueSize);
768
+ for (size_t index = 1, total = vec.size(); index < total; index++) {
769
+ auto kvHolder = vec[index];
770
+ auto &lastSection = dataSections.back();
771
+ if (kvHolder->offset == lastSection.first + lastSection.second) {
772
+ lastSection.second += kvHolder->computedKVSize + kvHolder->valueSize;
773
+ } else {
774
+ dataSections.emplace_back(kvHolder->offset, kvHolder->computedKVSize + kvHolder->valueSize);
775
+ }
776
+ }
777
+ // do the move
778
+ auto basePtr = ptr + Fixed32Size;
779
+ for (auto &section : dataSections) {
780
+ // memmove() should handle this well: src == dst
781
+ memmove(writePtr, basePtr + section.first, section.second);
782
+ writePtr += section.second;
783
+ }
784
+ // update offset
785
+ if (!encrypter) {
786
+ auto offset = ItemSizeHolderSize;
787
+ for (auto kvHolder : vec) {
788
+ kvHolder->offset = offset;
789
+ offset += kvHolder->computedKVSize + kvHolder->valueSize;
790
+ }
791
+ }
792
+ }
793
+ // hold the fake size of dictionary's serialization result
794
+ output->writeRawVarint32(ItemSizeHolder);
795
+ auto writtenSize = static_cast<size_t>(writePtr - originOutputPtr);
796
+ #ifndef MMKV_DISABLE_CRYPT
797
+ if (encrypter) {
798
+ encrypter->encrypt(originOutputPtr, originOutputPtr, writtenSize);
799
+ }
800
+ #endif
801
+ assert(writtenSize == totalSize);
802
+ output->seek(writtenSize - ItemSizeHolderSize);
803
+ }
804
+
805
+ #ifndef MMKV_DISABLE_CRYPT
806
+
807
+ static void memmoveDictionary(MMKVMapCrypt &dic,
808
+ CodedOutputData *output,
809
+ uint8_t *ptr,
810
+ AESCrypt *decrypter,
811
+ AESCrypt *encrypter,
812
+ pair<MMBuffer, size_t> &preparedData) {
813
+ // reuse what's already in the file
814
+ vector<KeyValueHolderCrypt *> vec;
815
+ if (!dic.empty()) {
816
+ // sort by offset
817
+ vec.reserve(dic.size());
818
+ for (auto &itr : dic) {
819
+ if (itr.second.type == KeyValueHolderType_Offset) {
820
+ vec.push_back(&itr.second);
821
+ }
822
+ }
823
+ sort(vec.begin(), vec.end(), [](auto left, auto right) { return left->offset < right->offset; });
824
+ }
825
+ auto sizeHolder = ItemSizeHolder, sizeHolderSize = ItemSizeHolderSize;
826
+ if (!vec.empty()) {
827
+ auto smallestOffset = vec.front()->offset;
828
+ if (smallestOffset != ItemSizeHolderSize && smallestOffset <= 5) {
829
+ sizeHolderSize = smallestOffset;
830
+ assert(sizeHolderSize != 0);
831
+ static const uint32_t ItemSizeHolders[] = {0, 0x0f, 0xff, 0xffff, 0xffffff, 0xffffffff};
832
+ sizeHolder = ItemSizeHolders[sizeHolderSize];
833
+ }
834
+ }
835
+ output->writeRawVarint32(static_cast<int32_t>(sizeHolder));
836
+ auto writePtr = output->curWritePointer();
837
+ if (encrypter) {
838
+ encrypter->encrypt(writePtr - sizeHolderSize, writePtr - sizeHolderSize, sizeHolderSize);
839
+ }
840
+ if (!vec.empty()) {
841
+ // merge nearby items to make memmove quicker
842
+ vector<tuple<uint32_t, uint32_t, AESCryptStatus *>> dataSections; // pair(offset, size)
843
+ dataSections.push_back(vec.front()->toTuple());
844
+ for (size_t index = 1, total = vec.size(); index < total; index++) {
845
+ auto kvHolder = vec[index];
846
+ auto &lastSection = dataSections.back();
847
+ if (kvHolder->offset == get<0>(lastSection) + get<1>(lastSection)) {
848
+ get<1>(lastSection) += kvHolder->pbKeyValueSize + kvHolder->keySize + kvHolder->valueSize;
849
+ } else {
850
+ dataSections.push_back(kvHolder->toTuple());
851
+ }
852
+ }
853
+ // do the move
854
+ auto basePtr = ptr + Fixed32Size;
855
+ for (auto &section : dataSections) {
856
+ auto crypter = decrypter->cloneWithStatus(*get<2>(section));
857
+ crypter.decrypt(basePtr + get<0>(section), writePtr, get<1>(section));
858
+ writePtr += get<1>(section);
859
+ }
860
+ // update offset & AESCryptStatus
861
+ if (encrypter) {
862
+ auto offset = sizeHolderSize;
863
+ for (auto kvHolder : vec) {
864
+ kvHolder->offset = offset;
865
+ auto size = kvHolder->pbKeyValueSize + kvHolder->keySize + kvHolder->valueSize;
866
+ encrypter->getCurStatus(kvHolder->cryptStatus);
867
+ encrypter->encrypt(basePtr + offset, basePtr + offset, size);
868
+ offset += size;
869
+ }
870
+ }
871
+ }
872
+ auto &data = preparedData.first;
873
+ if (data.length() > 0) {
874
+ auto dataSize = CodedInputData(data.getPtr(), data.length()).readUInt32();
875
+ if (dataSize > 0) {
876
+ auto dataPtr = (uint8_t *) data.getPtr() + pbRawVarint32Size(dataSize);
877
+ if (encrypter) {
878
+ encrypter->encrypt(dataPtr, writePtr, dataSize);
879
+ } else {
880
+ memcpy(writePtr, dataPtr, dataSize);
881
+ }
882
+ writePtr += dataSize;
883
+ }
884
+ }
885
+ auto writtenSize = static_cast<size_t>(writePtr - output->curWritePointer());
886
+ assert(writtenSize + sizeHolderSize == preparedData.second);
887
+ output->seek(writtenSize);
888
+ }
889
+
890
+ # define InvalidCryptPtr ((AESCrypt *) (void *) (1))
891
+
892
+ #endif // MMKV_DISABLE_CRYPT
893
+
894
+ bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> preparedData, AESCrypt *newCrypter) {
895
+ auto ptr = (uint8_t *) m_file->getMemory();
896
+ auto totalSize = preparedData.second;
897
+ #ifdef MMKV_IOS
898
+ auto ret = guardForBackgroundWriting(ptr + Fixed32Size, totalSize);
899
+ if (!ret.first) {
900
+ return false;
901
+ }
902
+ #endif
903
+
904
+ #ifndef MMKV_DISABLE_CRYPT
905
+ uint8_t newIV[AES_KEY_LEN];
906
+ auto decrypter = m_crypter;
907
+ auto encrypter = (newCrypter == InvalidCryptPtr) ? nullptr : (newCrypter ? newCrypter : m_crypter);
908
+ if (encrypter) {
909
+ AESCrypt::fillRandomIV(newIV);
910
+ encrypter->resetIV(newIV, sizeof(newIV));
911
+ }
912
+ #endif
913
+
914
+ delete m_output;
915
+ m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
916
+ #ifndef MMKV_DISABLE_CRYPT
917
+ if (m_crypter) {
918
+ memmoveDictionary(*m_dicCrypt, m_output, ptr, decrypter, encrypter, preparedData);
919
+ } else {
920
+ #else
921
+ {
922
+ auto encrypter = m_crypter;
923
+ #endif
924
+ memmoveDictionary(*m_dic, m_output, ptr, encrypter, totalSize);
925
+ }
926
+
927
+ m_actualSize = totalSize;
928
+ #ifndef MMKV_DISABLE_CRYPT
929
+ if (encrypter) {
930
+ recaculateCRCDigestWithIV(newIV);
931
+ } else
932
+ #endif
933
+ {
934
+ recaculateCRCDigestWithIV(nullptr);
935
+ }
936
+ m_hasFullWriteback = true;
937
+ // make sure lastConfirmedMetaInfo is saved
938
+ sync(MMKV_SYNC);
939
+ return true;
940
+ }
941
+
942
+ #ifndef MMKV_DISABLE_CRYPT
943
+ bool MMKV::reKey(const string &cryptKey) {
944
+ SCOPED_LOCK(m_lock);
945
+ checkLoadData();
946
+
947
+ bool ret = false;
948
+ if (m_crypter) {
949
+ if (cryptKey.length() > 0) {
950
+ string oldKey = this->cryptKey();
951
+ if (cryptKey == oldKey) {
952
+ return true;
953
+ } else {
954
+ // change encryption key
955
+ MMKVInfo("reKey with new aes key");
956
+ auto newCrypt = new AESCrypt(cryptKey.data(), cryptKey.length());
957
+ m_hasFullWriteback = false;
958
+ ret = fullWriteback(newCrypt);
959
+ if (ret) {
960
+ delete m_crypter;
961
+ m_crypter = newCrypt;
962
+ } else {
963
+ delete newCrypt;
964
+ }
965
+ }
966
+ } else {
967
+ // decryption to plain text
968
+ MMKVInfo("reKey to no aes key");
969
+ m_hasFullWriteback = false;
970
+ ret = fullWriteback(InvalidCryptPtr);
971
+ if (ret) {
972
+ delete m_crypter;
973
+ m_crypter = nullptr;
974
+ if (!m_dic) {
975
+ m_dic = new MMKVMap();
976
+ }
977
+ }
978
+ }
979
+ } else {
980
+ if (cryptKey.length() > 0) {
981
+ // transform plain text to encrypted text
982
+ MMKVInfo("reKey to a aes key");
983
+ m_hasFullWriteback = false;
984
+ auto newCrypt = new AESCrypt(cryptKey.data(), cryptKey.length());
985
+ ret = fullWriteback(newCrypt);
986
+ if (ret) {
987
+ m_crypter = newCrypt;
988
+ if (!m_dicCrypt) {
989
+ m_dicCrypt = new MMKVMapCrypt();
990
+ }
991
+ } else {
992
+ delete newCrypt;
993
+ }
994
+ } else {
995
+ return true;
996
+ }
997
+ }
998
+ // m_dic or m_dicCrypt is not valid after reKey
999
+ if (ret) {
1000
+ clearMemoryCache();
1001
+ }
1002
+ return ret;
1003
+ }
1004
+ #endif
1005
+
1006
+ void MMKV::trim() {
1007
+ SCOPED_LOCK(m_lock);
1008
+ MMKVInfo("prepare to trim %s", m_mmapID.c_str());
1009
+
1010
+ checkLoadData();
1011
+
1012
+ if (m_actualSize == 0) {
1013
+ clearAll();
1014
+ return;
1015
+ } else if (m_file->getFileSize() <= DEFAULT_MMAP_SIZE) {
1016
+ return;
1017
+ }
1018
+ SCOPED_LOCK(m_exclusiveProcessLock);
1019
+
1020
+ fullWriteback();
1021
+ auto oldSize = m_file->getFileSize();
1022
+ auto fileSize = oldSize;
1023
+ while (fileSize > (m_actualSize + Fixed32Size) * 2) {
1024
+ fileSize /= 2;
1025
+ }
1026
+ fileSize = std::max<size_t>(fileSize, DEFAULT_MMAP_SIZE);
1027
+ if (oldSize == fileSize) {
1028
+ MMKVInfo("there's no need to trim %s with size %zu, actualSize %zu", m_mmapID.c_str(), fileSize, m_actualSize);
1029
+ return;
1030
+ }
1031
+
1032
+ MMKVInfo("trimming %s from %zu to %zu, actualSize %zu", m_mmapID.c_str(), oldSize, fileSize, m_actualSize);
1033
+
1034
+ if (!m_file->truncate(fileSize)) {
1035
+ return;
1036
+ }
1037
+ fileSize = m_file->getFileSize();
1038
+ auto ptr = (uint8_t *) m_file->getMemory();
1039
+ delete m_output;
1040
+ m_output = new CodedOutputData(ptr + pbFixed32Size(), fileSize - Fixed32Size);
1041
+ m_output->seek(m_actualSize);
1042
+
1043
+ MMKVInfo("finish trim %s from %zu to %zu", m_mmapID.c_str(), oldSize, fileSize);
1044
+ }
1045
+
1046
+ void MMKV::clearAll() {
1047
+ MMKVInfo("cleaning all key-values from [%s]", m_mmapID.c_str());
1048
+ SCOPED_LOCK(m_lock);
1049
+ SCOPED_LOCK(m_exclusiveProcessLock);
1050
+
1051
+ checkLoadData();
1052
+
1053
+ if (m_file->getFileSize() == DEFAULT_MMAP_SIZE && m_actualSize == 0) {
1054
+ MMKVInfo("nothing to clear for [%s]", m_mmapID.c_str());
1055
+ return;
1056
+ }
1057
+ m_file->truncate(DEFAULT_MMAP_SIZE);
1058
+
1059
+ #ifndef MMKV_DISABLE_CRYPT
1060
+ uint8_t newIV[AES_KEY_LEN];
1061
+ AESCrypt::fillRandomIV(newIV);
1062
+ if (m_crypter) {
1063
+ m_crypter->resetIV(newIV, sizeof(newIV));
1064
+ }
1065
+ writeActualSize(0, 0, newIV, IncreaseSequence);
1066
+ #else
1067
+ writeActualSize(0, 0, nullptr, IncreaseSequence);
1068
+ #endif
1069
+ m_metaFile->msync(MMKV_SYNC);
1070
+
1071
+ clearMemoryCache();
1072
+ loadFromFile();
1073
+ }
1074
+
1075
+ bool MMKV::isFileValid(const string &mmapID, MMKVPath_t *relatePath) {
1076
+ MMKVPath_t kvPath = mappedKVPathWithID(mmapID, MMKV_SINGLE_PROCESS, relatePath);
1077
+ if (!isFileExist(kvPath)) {
1078
+ return true;
1079
+ }
1080
+
1081
+ MMKVPath_t crcPath = crcPathWithID(mmapID, MMKV_SINGLE_PROCESS, relatePath);
1082
+ if (!isFileExist(crcPath)) {
1083
+ return false;
1084
+ }
1085
+
1086
+ uint32_t crcFile = 0;
1087
+ MMBuffer *data = readWholeFile(crcPath);
1088
+ if (data) {
1089
+ if (data->getPtr()) {
1090
+ MMKVMetaInfo metaInfo;
1091
+ metaInfo.read(data->getPtr());
1092
+ crcFile = metaInfo.m_crcDigest;
1093
+ }
1094
+ delete data;
1095
+ } else {
1096
+ return false;
1097
+ }
1098
+
1099
+ uint32_t crcDigest = 0;
1100
+ MMBuffer *fileData = readWholeFile(kvPath);
1101
+ if (fileData) {
1102
+ if (fileData->getPtr() && (fileData->length() >= Fixed32Size)) {
1103
+ uint32_t actualSize = 0;
1104
+ memcpy(&actualSize, fileData->getPtr(), Fixed32Size);
1105
+ if (actualSize > (fileData->length() - Fixed32Size)) {
1106
+ delete fileData;
1107
+ return false;
1108
+ }
1109
+
1110
+ crcDigest = (uint32_t) CRC32(0, (const uint8_t *) fileData->getPtr() + Fixed32Size, (uint32_t) actualSize);
1111
+ }
1112
+ delete fileData;
1113
+ return crcFile == crcDigest;
1114
+ } else {
1115
+ return false;
1116
+ }
1117
+ }
1118
+
1119
+ MMKV_NAMESPACE_END