react-native-mmkv-dz 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +219 -0
- package/MMKV/CHANGELOG.md +553 -0
- package/MMKV/Core/CMakeLists.txt +153 -0
- package/MMKV/Core/CodedInputData.cpp +228 -0
- package/MMKV/Core/CodedInputData.h +83 -0
- package/MMKV/Core/CodedInputDataCrypt.cpp +280 -0
- package/MMKV/Core/CodedInputDataCrypt.h +87 -0
- package/MMKV/Core/CodedInputDataCrypt_OSX.cpp +62 -0
- package/MMKV/Core/CodedInputData_OSX.cpp +92 -0
- package/MMKV/Core/CodedOutputData.cpp +174 -0
- package/MMKV/Core/CodedOutputData.h +82 -0
- package/MMKV/Core/Core.xcodeproj/project.pbxproj +702 -0
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +67 -0
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +67 -0
- package/MMKV/Core/InterProcessLock.cpp +186 -0
- package/MMKV/Core/InterProcessLock.h +119 -0
- package/MMKV/Core/InterProcessLock_Android.cpp +103 -0
- package/MMKV/Core/InterProcessLock_Win32.cpp +108 -0
- package/MMKV/Core/KeyValueHolder.cpp +236 -0
- package/MMKV/Core/KeyValueHolder.h +118 -0
- package/MMKV/Core/MMBuffer.cpp +185 -0
- package/MMKV/Core/MMBuffer.h +107 -0
- package/MMKV/Core/MMKV.cpp +1418 -0
- package/MMKV/Core/MMKV.h +386 -0
- package/MMKV/Core/MMKVLog.cpp +127 -0
- package/MMKV/Core/MMKVLog.h +86 -0
- package/MMKV/Core/MMKVLog_Android.cpp +79 -0
- package/MMKV/Core/MMKVMetaInfo.hpp +81 -0
- package/MMKV/Core/MMKVPredef.h +245 -0
- package/MMKV/Core/MMKV_Android.cpp +259 -0
- package/MMKV/Core/MMKV_IO.cpp +1119 -0
- package/MMKV/Core/MMKV_IO.h +57 -0
- package/MMKV/Core/MMKV_OSX.cpp +347 -0
- package/MMKV/Core/MMKV_OSX.h +51 -0
- package/MMKV/Core/MemoryFile.cpp +537 -0
- package/MMKV/Core/MemoryFile.h +182 -0
- package/MMKV/Core/MemoryFile_Android.cpp +211 -0
- package/MMKV/Core/MemoryFile_Linux.cpp +120 -0
- package/MMKV/Core/MemoryFile_OSX.cpp +142 -0
- package/MMKV/Core/MemoryFile_Win32.cpp +536 -0
- package/MMKV/Core/MiniPBCoder.cpp +366 -0
- package/MMKV/Core/MiniPBCoder.h +129 -0
- package/MMKV/Core/MiniPBCoder_OSX.cpp +228 -0
- package/MMKV/Core/PBEncodeItem.hpp +86 -0
- package/MMKV/Core/PBUtility.cpp +61 -0
- package/MMKV/Core/PBUtility.h +153 -0
- package/MMKV/Core/ScopedLock.hpp +69 -0
- package/MMKV/Core/ThreadLock.cpp +68 -0
- package/MMKV/Core/ThreadLock.h +78 -0
- package/MMKV/Core/ThreadLock_Win32.cpp +89 -0
- package/MMKV/Core/aes/AESCrypt.cpp +256 -0
- package/MMKV/Core/aes/AESCrypt.h +107 -0
- package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +1231 -0
- package/MMKV/Core/aes/openssl/openssl_aes.h +118 -0
- package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +1044 -0
- package/MMKV/Core/aes/openssl/openssl_aes_locl.h +38 -0
- package/MMKV/Core/aes/openssl/openssl_aesv8-armx.S +308 -0
- package/MMKV/Core/aes/openssl/openssl_arm_arch.h +84 -0
- package/MMKV/Core/aes/openssl/openssl_cfb128.cpp +97 -0
- package/MMKV/Core/aes/openssl/openssl_md32_common.h +254 -0
- package/MMKV/Core/aes/openssl/openssl_md5.h +49 -0
- package/MMKV/Core/aes/openssl/openssl_md5_dgst.cpp +166 -0
- package/MMKV/Core/aes/openssl/openssl_md5_locl.h +75 -0
- package/MMKV/Core/aes/openssl/openssl_md5_one.cpp +30 -0
- package/MMKV/Core/aes/openssl/openssl_opensslconf.h +271 -0
- package/MMKV/Core/core.vcxproj +186 -0
- package/MMKV/Core/core.vcxproj.filters +150 -0
- package/MMKV/Core/crc32/Checksum.h +67 -0
- package/MMKV/Core/crc32/crc32_armv8.cpp +132 -0
- package/MMKV/Core/crc32/zlib/crc32.cpp +55 -0
- package/MMKV/Core/crc32/zlib/crc32.h +48 -0
- package/MMKV/Core/crc32/zlib/zconf.h +380 -0
- package/MMKV/Core/crc32/zlib/zutil.h +25 -0
- package/MMKV/LICENSE.TXT +193 -0
- package/MMKV/README.md +288 -0
- package/README.md +221 -0
- package/android/CMakeLists.txt +71 -0
- package/android/build.gradle +371 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/cpp/MmkvHostObject.cpp +302 -0
- package/android/src/main/cpp/MmkvHostObject.h +26 -0
- package/android/src/main/cpp/cpp-adapter.cpp +65 -0
- package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +49 -0
- package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +26 -0
- package/cpp/TypedArray.cpp +341 -0
- package/cpp/TypedArray.h +175 -0
- package/ios/JSIUtils.h +50 -0
- package/ios/JSIUtils.mm +194 -0
- package/ios/Mmkv.xcodeproj/project.pbxproj +291 -0
- package/ios/MmkvHostObject.h +27 -0
- package/ios/MmkvHostObject.mm +299 -0
- package/ios/MmkvModule.h +5 -0
- package/ios/MmkvModule.mm +73 -0
- package/lib/commonjs/MMKV.js +146 -0
- package/lib/commonjs/MMKV.js.map +1 -0
- package/lib/commonjs/PlatformChecker.js +16 -0
- package/lib/commonjs/PlatformChecker.js.map +1 -0
- package/lib/commonjs/createMMKV.js +66 -0
- package/lib/commonjs/createMMKV.js.map +1 -0
- package/lib/commonjs/createMMKV.mock.js +40 -0
- package/lib/commonjs/createMMKV.mock.js.map +1 -0
- package/lib/commonjs/createMMKV.web.js +77 -0
- package/lib/commonjs/createMMKV.web.js.map +1 -0
- package/lib/commonjs/createTextEncoder.js +24 -0
- package/lib/commonjs/createTextEncoder.js.map +1 -0
- package/lib/commonjs/hooks.js +200 -0
- package/lib/commonjs/hooks.js.map +1 -0
- package/lib/commonjs/index.js +32 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/MMKV.js +134 -0
- package/lib/module/MMKV.js.map +1 -0
- package/lib/module/PlatformChecker.js +9 -0
- package/lib/module/PlatformChecker.js.map +1 -0
- package/lib/module/createMMKV.js +55 -0
- package/lib/module/createMMKV.js.map +1 -0
- package/lib/module/createMMKV.mock.js +31 -0
- package/lib/module/createMMKV.mock.js.map +1 -0
- package/lib/module/createMMKV.web.js +67 -0
- package/lib/module/createMMKV.web.js.map +1 -0
- package/lib/module/createTextEncoder.js +17 -0
- package/lib/module/createTextEncoder.js.map +1 -0
- package/lib/module/hooks.js +181 -0
- package/lib/module/hooks.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/MMKV.d.ts +137 -0
- package/lib/typescript/PlatformChecker.d.ts +1 -0
- package/lib/typescript/createMMKV.d.ts +6 -0
- package/lib/typescript/createMMKV.mock.d.ts +2 -0
- package/lib/typescript/createMMKV.web.d.ts +2 -0
- package/lib/typescript/createTextEncoder.d.ts +1 -0
- package/lib/typescript/hooks.d.ts +81 -0
- package/lib/typescript/index.d.ts +2 -0
- package/package.json +168 -0
- package/react-native-mmkv.podspec +32 -0
|
@@ -0,0 +1,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 §ion : 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 §ion : 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
|