react-native-mmkv 3.2.0 → 4.0.0-beta.0
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/android/CMakeLists.txt +18 -9
- package/android/build.gradle +6 -2
- package/cpp/{MMKVManagedBuffer.h → ManagedMMBuffer.h} +6 -6
- package/cpp/MmkvHostObject.cpp +22 -17
- package/cpp/MmkvHostObject.h +1 -2
- package/cpp/MmkvTypes.h +50 -0
- package/cpp/NativeMmkvModule.cpp +3 -3
- package/cpp/NativeMmkvModule.h +1 -8
- package/lib/commonjs/MMKV.js.map +1 -1
- package/lib/commonjs/Types.js.map +1 -1
- package/lib/commonjs/createMMKV.web.js +1 -1
- package/lib/commonjs/createMMKV.web.js.map +1 -1
- package/lib/module/MMKV.js.map +1 -1
- package/lib/module/Types.js.map +1 -1
- package/lib/module/createMMKV.web.js +1 -1
- package/lib/module/createMMKV.web.js.map +1 -1
- package/lib/typescript/src/MMKV.d.ts +1 -1
- package/lib/typescript/src/MMKV.d.ts.map +1 -1
- package/lib/typescript/src/Types.d.ts +7 -1
- package/lib/typescript/src/Types.d.ts.map +1 -1
- package/lib/typescript/src/hooks.d.ts +1 -1
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/package.json +22 -27
- package/react-native-mmkv.podspec +4 -10
- package/react-native.config.js +9 -0
- package/src/MMKV.ts +1 -1
- package/src/Types.ts +7 -1
- package/src/createMMKV.web.ts +1 -1
- package/src/hooks.ts +1 -1
- package/MMKV/Core/CMakeLists.txt +0 -172
- package/MMKV/Core/CodedInputData.cpp +0 -252
- package/MMKV/Core/CodedInputData.h +0 -87
- package/MMKV/Core/CodedInputDataCrypt.cpp +0 -280
- package/MMKV/Core/CodedInputDataCrypt.h +0 -87
- package/MMKV/Core/CodedInputDataCrypt_OSX.cpp +0 -62
- package/MMKV/Core/CodedInputData_OSX.cpp +0 -92
- package/MMKV/Core/CodedOutputData.cpp +0 -186
- package/MMKV/Core/CodedOutputData.h +0 -88
- package/MMKV/Core/Core.xcodeproj/project.pbxproj +0 -707
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +0 -67
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +0 -67
- package/MMKV/Core/InterProcessLock.cpp +0 -186
- package/MMKV/Core/InterProcessLock.h +0 -119
- package/MMKV/Core/InterProcessLock_Android.cpp +0 -103
- package/MMKV/Core/InterProcessLock_Win32.cpp +0 -108
- package/MMKV/Core/KeyValueHolder.cpp +0 -236
- package/MMKV/Core/KeyValueHolder.h +0 -122
- package/MMKV/Core/MMBuffer.cpp +0 -210
- package/MMKV/Core/MMBuffer.h +0 -111
- package/MMKV/Core/MMKV.cpp +0 -1702
- package/MMKV/Core/MMKV.h +0 -595
- package/MMKV/Core/MMKVLog.cpp +0 -127
- package/MMKV/Core/MMKVLog.h +0 -86
- package/MMKV/Core/MMKVLog_Android.cpp +0 -134
- package/MMKV/Core/MMKVMetaInfo.hpp +0 -99
- package/MMKV/Core/MMKVPredef.h +0 -293
- package/MMKV/Core/MMKV_Android.cpp +0 -261
- package/MMKV/Core/MMKV_IO.cpp +0 -1905
- package/MMKV/Core/MMKV_IO.h +0 -57
- package/MMKV/Core/MMKV_OSX.cpp +0 -423
- package/MMKV/Core/MMKV_OSX.h +0 -57
- package/MMKV/Core/MemoryFile.cpp +0 -603
- package/MMKV/Core/MemoryFile.h +0 -194
- package/MMKV/Core/MemoryFile_Android.cpp +0 -236
- package/MMKV/Core/MemoryFile_Linux.cpp +0 -125
- package/MMKV/Core/MemoryFile_OSX.cpp +0 -142
- package/MMKV/Core/MemoryFile_Win32.cpp +0 -554
- package/MMKV/Core/MiniPBCoder.cpp +0 -672
- package/MMKV/Core/MiniPBCoder.h +0 -151
- package/MMKV/Core/MiniPBCoder_OSX.cpp +0 -237
- package/MMKV/Core/PBEncodeItem.hpp +0 -104
- package/MMKV/Core/PBUtility.cpp +0 -61
- package/MMKV/Core/PBUtility.h +0 -148
- package/MMKV/Core/ScopedLock.hpp +0 -69
- package/MMKV/Core/ThreadLock.cpp +0 -75
- package/MMKV/Core/ThreadLock.h +0 -81
- package/MMKV/Core/ThreadLock_Win32.cpp +0 -89
- package/MMKV/Core/aes/AESCrypt.cpp +0 -273
- package/MMKV/Core/aes/AESCrypt.h +0 -112
- package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +0 -1243
- package/MMKV/Core/aes/openssl/openssl_aes.h +0 -130
- package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +0 -1044
- package/MMKV/Core/aes/openssl/openssl_aes_locl.h +0 -38
- package/MMKV/Core/aes/openssl/openssl_aesv8-armx.S +0 -308
- package/MMKV/Core/aes/openssl/openssl_arm_arch.h +0 -84
- package/MMKV/Core/aes/openssl/openssl_cfb128.cpp +0 -97
- package/MMKV/Core/aes/openssl/openssl_md32_common.h +0 -254
- package/MMKV/Core/aes/openssl/openssl_md5.h +0 -49
- package/MMKV/Core/aes/openssl/openssl_md5_dgst.cpp +0 -166
- package/MMKV/Core/aes/openssl/openssl_md5_locl.h +0 -75
- package/MMKV/Core/aes/openssl/openssl_md5_one.cpp +0 -30
- package/MMKV/Core/aes/openssl/openssl_opensslconf.h +0 -271
- package/MMKV/Core/core.vcxproj +0 -288
- package/MMKV/Core/core.vcxproj.filters +0 -150
- package/MMKV/Core/crc32/Checksum.h +0 -75
- package/MMKV/Core/crc32/crc32_armv8.cpp +0 -134
- package/MMKV/Core/crc32/zlib/CMakeLists.txt +0 -60
- package/MMKV/Core/crc32/zlib/crc32.cpp +0 -55
- package/MMKV/Core/crc32/zlib/crc32.h +0 -48
- package/MMKV/Core/crc32/zlib/zconf.h +0 -380
- package/MMKV/Core/crc32/zlib/zutil.h +0 -25
- package/MMKV/README.md +0 -354
package/MMKV/Core/MemoryFile.h
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* MMKV available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
|
6
|
-
* All rights reserved.
|
|
7
|
-
*
|
|
8
|
-
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
|
9
|
-
* this file except in compliance with the License. You may obtain a copy of
|
|
10
|
-
* the License at
|
|
11
|
-
*
|
|
12
|
-
* https://opensource.org/licenses/BSD-3-Clause
|
|
13
|
-
*
|
|
14
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
-
* See the License for the specific language governing permissions and
|
|
18
|
-
* limitations under the License.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
#ifndef MMKV_MAMERYFILE_H
|
|
22
|
-
#define MMKV_MAMERYFILE_H
|
|
23
|
-
#ifdef __cplusplus
|
|
24
|
-
|
|
25
|
-
#include "MMKVPredef.h"
|
|
26
|
-
#include <cstdint>
|
|
27
|
-
#include <functional>
|
|
28
|
-
|
|
29
|
-
#ifdef MMKV_ANDROID
|
|
30
|
-
MMKVPath_t ashmemMMKVPathWithID(const MMKVPath_t &mmapID);
|
|
31
|
-
|
|
32
|
-
namespace mmkv {
|
|
33
|
-
extern int g_android_api;
|
|
34
|
-
extern std::string g_android_tmpDir;
|
|
35
|
-
|
|
36
|
-
enum FileType : bool { MMFILE_TYPE_FILE = false, MMFILE_TYPE_ASHMEM = true };
|
|
37
|
-
} // namespace mmkv
|
|
38
|
-
#endif // MMKV_ANDROID
|
|
39
|
-
|
|
40
|
-
namespace mmkv {
|
|
41
|
-
|
|
42
|
-
enum class OpenFlag : uint32_t {
|
|
43
|
-
ReadOnly = 1 << 0,
|
|
44
|
-
WriteOnly = 1 << 1,
|
|
45
|
-
ReadWrite = ReadOnly | WriteOnly,
|
|
46
|
-
Create = 1 << 2,
|
|
47
|
-
Excel = 1 << 3, // fail if Create is set but the file already exist
|
|
48
|
-
Truncate = 1 << 4,
|
|
49
|
-
};
|
|
50
|
-
constexpr uint32_t OpenFlagRWMask = 0x3; // mask for Read Write mode
|
|
51
|
-
|
|
52
|
-
static inline OpenFlag operator | (OpenFlag left, OpenFlag right) {
|
|
53
|
-
return static_cast<OpenFlag>(static_cast<uint32_t>(left) | static_cast<uint32_t>(right));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
static inline bool operator & (OpenFlag left, OpenFlag right) {
|
|
57
|
-
return ((static_cast<uint32_t>(left) & static_cast<uint32_t>(right)) != 0);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
static inline OpenFlag operator & (OpenFlag left, uint32_t right) {
|
|
61
|
-
return static_cast<OpenFlag>(static_cast<uint32_t>(left) & right);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
template <typename T>
|
|
65
|
-
T roundUp(T numToRound, T multiple) {
|
|
66
|
-
return ((numToRound + multiple - 1) / multiple) * multiple;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
class File {
|
|
70
|
-
MMKVPath_t m_path;
|
|
71
|
-
MMKVFileHandle_t m_fd;
|
|
72
|
-
public:
|
|
73
|
-
const OpenFlag m_flag;
|
|
74
|
-
#ifndef MMKV_ANDROID
|
|
75
|
-
explicit File(MMKVPath_t path, OpenFlag flag);
|
|
76
|
-
#else
|
|
77
|
-
File(MMKVPath_t path, OpenFlag flag, size_t size = 0, FileType fileType = MMFILE_TYPE_FILE);
|
|
78
|
-
explicit File(MMKVFileHandle_t ashmemFD);
|
|
79
|
-
|
|
80
|
-
size_t m_size;
|
|
81
|
-
const FileType m_fileType;
|
|
82
|
-
#endif // MMKV_ANDROID
|
|
83
|
-
|
|
84
|
-
~File() { close(); }
|
|
85
|
-
|
|
86
|
-
bool open();
|
|
87
|
-
|
|
88
|
-
void close();
|
|
89
|
-
|
|
90
|
-
MMKVFileHandle_t getFd() { return m_fd; }
|
|
91
|
-
|
|
92
|
-
const MMKVPath_t &getPath() const { return m_path; }
|
|
93
|
-
|
|
94
|
-
#ifndef MMKV_WIN32
|
|
95
|
-
bool isFileValid() const { return m_fd >= 0; }
|
|
96
|
-
#else
|
|
97
|
-
bool isFileValid() const { return m_fd != INVALID_HANDLE_VALUE; }
|
|
98
|
-
#endif
|
|
99
|
-
|
|
100
|
-
// get the actual file size on disk
|
|
101
|
-
size_t getActualFileSize() const;
|
|
102
|
-
|
|
103
|
-
// just forbid it for possibly misuse
|
|
104
|
-
explicit File(const File &other) = delete;
|
|
105
|
-
File &operator=(const File &other) = delete;
|
|
106
|
-
|
|
107
|
-
friend class MemoryFile;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
class MemoryFile {
|
|
111
|
-
File m_diskFile;
|
|
112
|
-
#ifdef MMKV_WIN32
|
|
113
|
-
HANDLE m_fileMapping;
|
|
114
|
-
#endif
|
|
115
|
-
void *m_ptr;
|
|
116
|
-
size_t m_size;
|
|
117
|
-
const bool m_readOnly;
|
|
118
|
-
|
|
119
|
-
bool mmap();
|
|
120
|
-
|
|
121
|
-
void doCleanMemoryCache(bool forceClean);
|
|
122
|
-
|
|
123
|
-
public:
|
|
124
|
-
#ifndef MMKV_ANDROID
|
|
125
|
-
explicit MemoryFile(MMKVPath_t path, size_t expectedCapacity = 0, bool readOnly = false);
|
|
126
|
-
#else
|
|
127
|
-
MemoryFile(MMKVPath_t path, size_t size, FileType fileType, size_t expectedCapacity = 0, bool readOnly = false);
|
|
128
|
-
explicit MemoryFile(MMKVFileHandle_t ashmemFD);
|
|
129
|
-
|
|
130
|
-
const FileType m_fileType;
|
|
131
|
-
#endif // MMKV_ANDROID
|
|
132
|
-
|
|
133
|
-
~MemoryFile() { doCleanMemoryCache(true); }
|
|
134
|
-
|
|
135
|
-
size_t getFileSize() const { return m_size; }
|
|
136
|
-
|
|
137
|
-
// get the actual file size on disk
|
|
138
|
-
size_t getActualFileSize() const { return m_diskFile.getActualFileSize(); }
|
|
139
|
-
|
|
140
|
-
void *getMemory() { return m_ptr; }
|
|
141
|
-
|
|
142
|
-
const MMKVPath_t &getPath() { return m_diskFile.getPath(); }
|
|
143
|
-
|
|
144
|
-
MMKVFileHandle_t getFd() { return m_diskFile.getFd(); }
|
|
145
|
-
|
|
146
|
-
// the newly expanded file content will be zeroed
|
|
147
|
-
bool truncate(size_t size);
|
|
148
|
-
|
|
149
|
-
bool msync(SyncFlag syncFlag);
|
|
150
|
-
|
|
151
|
-
// call this if clearMemoryCache() has been called
|
|
152
|
-
void reloadFromFile(size_t expectedCapacity = 0);
|
|
153
|
-
|
|
154
|
-
void clearMemoryCache() { doCleanMemoryCache(false); }
|
|
155
|
-
|
|
156
|
-
#ifndef MMKV_WIN32
|
|
157
|
-
bool isFileValid() { return m_diskFile.isFileValid() && m_size > 0 && m_ptr; }
|
|
158
|
-
#else
|
|
159
|
-
bool isFileValid() { return m_diskFile.isFileValid() && m_size > 0 && m_fileMapping && m_ptr; }
|
|
160
|
-
#endif
|
|
161
|
-
|
|
162
|
-
// just forbid it for possibly misuse
|
|
163
|
-
explicit MemoryFile(const MemoryFile &other) = delete;
|
|
164
|
-
MemoryFile &operator=(const MemoryFile &other) = delete;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
class MMBuffer;
|
|
168
|
-
|
|
169
|
-
extern bool mkPath(const MMKVPath_t &path);
|
|
170
|
-
extern bool isFileExist(const MMKVPath_t &nsFilePath);
|
|
171
|
-
extern MMBuffer *readWholeFile(const MMKVPath_t &path);
|
|
172
|
-
extern bool zeroFillFile(MMKVFileHandle_t fd, size_t startPos, size_t size);
|
|
173
|
-
extern size_t getPageSize();
|
|
174
|
-
|
|
175
|
-
extern bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
|
|
176
|
-
|
|
177
|
-
// copy file by potentially renaming target file, might change file inode
|
|
178
|
-
extern bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
|
|
179
|
-
|
|
180
|
-
// copy file by source file content, keep file inode the same
|
|
181
|
-
extern bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
|
|
182
|
-
extern bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD);
|
|
183
|
-
extern bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate);
|
|
184
|
-
|
|
185
|
-
enum WalkType : uint32_t {
|
|
186
|
-
WalkFile = 1 << 0,
|
|
187
|
-
WalkFolder = 1 << 1,
|
|
188
|
-
};
|
|
189
|
-
extern void walkInDir(const MMKVPath_t &dirPath, WalkType type, const std::function<void(const MMKVPath_t&, WalkType)> &walker);
|
|
190
|
-
|
|
191
|
-
} // namespace mmkv
|
|
192
|
-
|
|
193
|
-
#endif
|
|
194
|
-
#endif //MMKV_MAMERYFILE_H
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* MMKV available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2019 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 "MemoryFile.h"
|
|
22
|
-
|
|
23
|
-
#ifdef MMKV_ANDROID
|
|
24
|
-
|
|
25
|
-
# include "MMBuffer.h"
|
|
26
|
-
# include "MMKVLog.h"
|
|
27
|
-
# include <cerrno>
|
|
28
|
-
# include <fcntl.h>
|
|
29
|
-
# include <sys/mman.h>
|
|
30
|
-
# include <sys/stat.h>
|
|
31
|
-
# include <unistd.h>
|
|
32
|
-
|
|
33
|
-
using namespace std;
|
|
34
|
-
|
|
35
|
-
constexpr char ASHMEM_NAME_DEF[] = "/dev/ashmem";
|
|
36
|
-
|
|
37
|
-
namespace mmkv {
|
|
38
|
-
|
|
39
|
-
// for Android Q limiting ashmem access
|
|
40
|
-
extern int ASharedMemory_create(const char *name, size_t size);
|
|
41
|
-
extern size_t ASharedMemory_getSize(int fd);
|
|
42
|
-
extern string ASharedMemory_getName(int fd);
|
|
43
|
-
|
|
44
|
-
File::File(MMKVPath_t path, OpenFlag flag, size_t size, FileType fileType)
|
|
45
|
-
: m_path(std::move(path)), m_fd(-1), m_flag(flag), m_size(0), m_fileType(fileType) {
|
|
46
|
-
if (m_fileType == MMFILE_TYPE_FILE) {
|
|
47
|
-
open();
|
|
48
|
-
} else {
|
|
49
|
-
// round up to (n * pagesize)
|
|
50
|
-
if (size < DEFAULT_MMAP_SIZE || (size % DEFAULT_MMAP_SIZE != 0)) {
|
|
51
|
-
size = ((size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
|
|
52
|
-
}
|
|
53
|
-
auto filename = m_path.c_str();
|
|
54
|
-
auto ptr = strstr(filename, ASHMEM_NAME_DEF);
|
|
55
|
-
if (ptr && ptr[sizeof(ASHMEM_NAME_DEF) - 1] == '/') {
|
|
56
|
-
filename = ptr + sizeof(ASHMEM_NAME_DEF);
|
|
57
|
-
}
|
|
58
|
-
m_fd = ASharedMemory_create(filename, size);
|
|
59
|
-
if (isFileValid()) {
|
|
60
|
-
m_size = size;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
File::File(MMKVFileHandle_t ashmemFD)
|
|
66
|
-
: m_path(), m_fd(ashmemFD), m_flag(OpenFlag::ReadWrite), m_size(0), m_fileType(MMFILE_TYPE_ASHMEM) {
|
|
67
|
-
if (isFileValid()) {
|
|
68
|
-
m_path = ASharedMemory_getName(m_fd);
|
|
69
|
-
m_size = ASharedMemory_getSize(m_fd);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
MemoryFile::MemoryFile(string path, size_t size, FileType fileType, size_t expectedCapacity, bool isReadOnly)
|
|
74
|
-
: m_diskFile(std::move(path), isReadOnly ? OpenFlag::ReadOnly : (OpenFlag::ReadWrite | OpenFlag::Create), size, fileType),
|
|
75
|
-
m_ptr(nullptr), m_size(0), m_fileType(fileType), m_readOnly(isReadOnly) {
|
|
76
|
-
if (m_fileType == MMFILE_TYPE_FILE) {
|
|
77
|
-
reloadFromFile(expectedCapacity);
|
|
78
|
-
} else {
|
|
79
|
-
if (m_diskFile.isFileValid()) {
|
|
80
|
-
m_size = m_diskFile.m_size;
|
|
81
|
-
auto ret = mmap();
|
|
82
|
-
if (!ret) {
|
|
83
|
-
doCleanMemoryCache(true);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
MemoryFile::MemoryFile(int ashmemFD)
|
|
90
|
-
: m_diskFile(ashmemFD), m_ptr(nullptr), m_size(0), m_fileType(MMFILE_TYPE_ASHMEM), m_readOnly(false) {
|
|
91
|
-
if (!m_diskFile.isFileValid()) {
|
|
92
|
-
MMKVError("fd %d invalid", ashmemFD);
|
|
93
|
-
} else {
|
|
94
|
-
m_size = m_diskFile.m_size;
|
|
95
|
-
MMKVInfo("ashmem name:%s, size:%zu", m_diskFile.m_path.c_str(), m_size);
|
|
96
|
-
auto ret = mmap();
|
|
97
|
-
if (!ret) {
|
|
98
|
-
doCleanMemoryCache(true);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
} // namespace mmkv
|
|
104
|
-
|
|
105
|
-
# pragma mark - ashmem
|
|
106
|
-
# include <dlfcn.h>
|
|
107
|
-
# include <sys/ioctl.h>
|
|
108
|
-
|
|
109
|
-
namespace mmkv {
|
|
110
|
-
|
|
111
|
-
constexpr auto ASHMEM_NAME_LEN = 256;
|
|
112
|
-
constexpr auto ASHMEM_IOC = 0x77;
|
|
113
|
-
# define ASHMEM_SET_NAME _IOW(ASHMEM_IOC, 1, char[ASHMEM_NAME_LEN])
|
|
114
|
-
# define ASHMEM_GET_NAME _IOR(ASHMEM_IOC, 2, char[ASHMEM_NAME_LEN])
|
|
115
|
-
# define ASHMEM_SET_SIZE _IOW(ASHMEM_IOC, 3, size_t)
|
|
116
|
-
# define ASHMEM_GET_SIZE _IO(ASHMEM_IOC, 4)
|
|
117
|
-
|
|
118
|
-
#ifndef MMKV_OHOS
|
|
119
|
-
int g_android_api = __ANDROID_API_L__;
|
|
120
|
-
#endif
|
|
121
|
-
std::string g_android_tmpDir = "/data/local/tmp/";
|
|
122
|
-
|
|
123
|
-
#ifndef MMKV_OHOS
|
|
124
|
-
void *loadLibrary() {
|
|
125
|
-
auto name = "libandroid.so";
|
|
126
|
-
static auto handle = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
|
|
127
|
-
if (handle == RTLD_DEFAULT) {
|
|
128
|
-
MMKVError("unable to load library %s", name);
|
|
129
|
-
}
|
|
130
|
-
return handle;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
typedef int (*AShmem_create_t)(const char *name, size_t size);
|
|
134
|
-
typedef size_t (*AShmem_getSize_t)(int fd);
|
|
135
|
-
|
|
136
|
-
#endif
|
|
137
|
-
|
|
138
|
-
int ASharedMemory_create(const char *name, size_t size) {
|
|
139
|
-
#ifndef MMKV_OHOS
|
|
140
|
-
if (g_android_api >= __ANDROID_API_O__ || g_android_api >= __ANDROID_API_M__) {
|
|
141
|
-
static auto handle = loadLibrary();
|
|
142
|
-
static AShmem_create_t funcPtr =
|
|
143
|
-
(handle != nullptr) ? reinterpret_cast<AShmem_create_t>(dlsym(handle, "ASharedMemory_create")) : nullptr;
|
|
144
|
-
if (funcPtr) {
|
|
145
|
-
int fd = funcPtr(name, size);
|
|
146
|
-
if (fd < 0) {
|
|
147
|
-
MMKVError("fail to ASharedMemory_create %s with size %zu, errno:%s", name, size, strerror(errno));
|
|
148
|
-
} else {
|
|
149
|
-
MMKVInfo("ASharedMemory_create %s with size %zu, fd:%d", name, size, fd);
|
|
150
|
-
return fd;
|
|
151
|
-
}
|
|
152
|
-
} else if (g_android_api >= __ANDROID_API_O__) {
|
|
153
|
-
MMKVWarning("fail to locate ASharedMemory_create() from loading libandroid.so");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
static AShmem_create_t regionFuncPtr =
|
|
157
|
-
(handle != nullptr) ? reinterpret_cast<AShmem_create_t>(dlsym(handle, "ashmem_create_region")) : nullptr;
|
|
158
|
-
if (regionFuncPtr) {
|
|
159
|
-
int fd = regionFuncPtr(name, size);
|
|
160
|
-
if (fd < 0) {
|
|
161
|
-
MMKVError("fail to ashmem_create_region %s with size %zu, errno:%s", name, size, strerror(errno));
|
|
162
|
-
} else {
|
|
163
|
-
MMKVInfo("ashmem_create_region %s with size %zu, fd:%d", name, size, fd);
|
|
164
|
-
return fd;
|
|
165
|
-
}
|
|
166
|
-
} else {
|
|
167
|
-
MMKVWarning("fail to locate ashmem_create_region() from loading libandroid.so");
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
#endif
|
|
171
|
-
int fd = open(ASHMEM_NAME_DEF, O_RDWR | O_CLOEXEC);
|
|
172
|
-
if (fd < 0) {
|
|
173
|
-
MMKVError("fail to open ashmem:%s, %s", name, strerror(errno));
|
|
174
|
-
} else {
|
|
175
|
-
if (ioctl(fd, ASHMEM_SET_NAME, name) != 0) {
|
|
176
|
-
MMKVError("fail to set ashmem name:%s, %s", name, strerror(errno));
|
|
177
|
-
} else if (ioctl(fd, ASHMEM_SET_SIZE, size) != 0) {
|
|
178
|
-
MMKVError("fail to set ashmem:%s, size %zu, %s", name, size, strerror(errno));
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return fd;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
size_t ASharedMemory_getSize(int fd) {
|
|
185
|
-
size_t size = 0;
|
|
186
|
-
#ifndef MMKV_OHOS
|
|
187
|
-
if (g_android_api >= __ANDROID_API_O__) {
|
|
188
|
-
static auto handle = loadLibrary();
|
|
189
|
-
static AShmem_getSize_t funcPtr =
|
|
190
|
-
(handle != nullptr) ? reinterpret_cast<AShmem_getSize_t>(dlsym(handle, "ASharedMemory_getSize")) : nullptr;
|
|
191
|
-
if (funcPtr) {
|
|
192
|
-
size = funcPtr(fd);
|
|
193
|
-
if (size == 0) {
|
|
194
|
-
MMKVError("fail to ASharedMemory_getSize:%d, %s", fd, strerror(errno));
|
|
195
|
-
}
|
|
196
|
-
} else {
|
|
197
|
-
MMKVWarning("fail to locate ASharedMemory_create() from loading libandroid.so");
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
#endif
|
|
201
|
-
if (size == 0) {
|
|
202
|
-
int tmp = ioctl(fd, ASHMEM_GET_SIZE, nullptr);
|
|
203
|
-
if (tmp < 0) {
|
|
204
|
-
MMKVError("fail to get ashmem size:%d, %s", fd, strerror(errno));
|
|
205
|
-
} else {
|
|
206
|
-
size = static_cast<size_t>(tmp);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return size;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
string ASharedMemory_getName(int fd) {
|
|
213
|
-
// Android Q doesn't have ASharedMemory_getName()
|
|
214
|
-
// I've make a request to Google, https://issuetracker.google.com/issues/130741665
|
|
215
|
-
// There's nothing we can do before it's supported officially by Google
|
|
216
|
-
#ifndef MMKV_OHOS
|
|
217
|
-
if (g_android_api >= __ANDROID_API_O__) {
|
|
218
|
-
return "";
|
|
219
|
-
}
|
|
220
|
-
#endif
|
|
221
|
-
|
|
222
|
-
char name[ASHMEM_NAME_LEN] = {0};
|
|
223
|
-
if (ioctl(fd, ASHMEM_GET_NAME, name) != 0) {
|
|
224
|
-
MMKVError("fail to get ashmem name:%d, %s", fd, strerror(errno));
|
|
225
|
-
return "";
|
|
226
|
-
}
|
|
227
|
-
return {name};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
} // namespace mmkv
|
|
231
|
-
|
|
232
|
-
MMKVPath_t ashmemMMKVPathWithID(const MMKVPath_t &mmapID) {
|
|
233
|
-
return MMKVPath_t(ASHMEM_NAME_DEF) + MMKV_PATH_SLASH + mmapID;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
#endif // MMKV_ANDROID
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* MMKV available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2021 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 "MemoryFile.h"
|
|
22
|
-
|
|
23
|
-
#if defined(MMKV_ANDROID) || defined(MMKV_LINUX)
|
|
24
|
-
# include "InterProcessLock.h"
|
|
25
|
-
# include "MMBuffer.h"
|
|
26
|
-
# include "MMKVLog.h"
|
|
27
|
-
# include "ScopedLock.hpp"
|
|
28
|
-
# include <cerrno>
|
|
29
|
-
# include <utility>
|
|
30
|
-
# include <fcntl.h>
|
|
31
|
-
# include <sys/mman.h>
|
|
32
|
-
# include <sys/stat.h>
|
|
33
|
-
# include <unistd.h>
|
|
34
|
-
# include <sys/file.h>
|
|
35
|
-
# include <dirent.h>
|
|
36
|
-
# include <cstring>
|
|
37
|
-
# include <sys/sendfile.h>
|
|
38
|
-
# include <sys/syscall.h>
|
|
39
|
-
|
|
40
|
-
#ifdef MMKV_ANDROID
|
|
41
|
-
#include <dlfcn.h>
|
|
42
|
-
typedef int (*renameat2_t)(int old_dir_fd, const char* old_path, int new_dir_fd, const char* new_path, unsigned flags);
|
|
43
|
-
#endif
|
|
44
|
-
|
|
45
|
-
#ifndef RENAME_EXCHANGE
|
|
46
|
-
#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
|
|
47
|
-
#endif
|
|
48
|
-
|
|
49
|
-
namespace mmkv {
|
|
50
|
-
|
|
51
|
-
extern bool getFileSize(int fd, size_t &size);
|
|
52
|
-
|
|
53
|
-
bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
54
|
-
bool renamed = false;
|
|
55
|
-
|
|
56
|
-
// try renameat2() first
|
|
57
|
-
#if defined(SYS_renameat2) && !defined(MMKV_OHOS)
|
|
58
|
-
#ifdef MMKV_ANDROID
|
|
59
|
-
static auto g_renameat2 = (renameat2_t) dlsym(RTLD_DEFAULT, "renameat2");
|
|
60
|
-
if (g_renameat2) {
|
|
61
|
-
renamed = (g_renameat2(AT_FDCWD, srcPath.c_str(), AT_FDCWD, dstPath.c_str(), RENAME_EXCHANGE) == 0);
|
|
62
|
-
}
|
|
63
|
-
if (!renamed && errno != ENOENT) {
|
|
64
|
-
MMKVWarning("fail on renameat2() [%s] to [%s], %d(%s)", srcPath.c_str(), dstPath.c_str(), errno,
|
|
65
|
-
strerror(errno));
|
|
66
|
-
}
|
|
67
|
-
#endif
|
|
68
|
-
if (!renamed) {
|
|
69
|
-
renamed = (syscall(SYS_renameat2, AT_FDCWD, srcPath.c_str(), AT_FDCWD, dstPath.c_str(), RENAME_EXCHANGE) == 0);
|
|
70
|
-
}
|
|
71
|
-
if (!renamed && errno != ENOENT) {
|
|
72
|
-
MMKVWarning("fail on syscall(SYS_renameat2) [%s] to [%s], %d(%s)", srcPath.c_str(), dstPath.c_str(), errno,
|
|
73
|
-
strerror(errno));
|
|
74
|
-
}
|
|
75
|
-
#endif // SYS_renameat2 && !MMKV_OHOS
|
|
76
|
-
|
|
77
|
-
if (!renamed) {
|
|
78
|
-
if (::rename(srcPath.c_str(), dstPath.c_str()) != 0) {
|
|
79
|
-
MMKVError("fail to rename [%s] to [%s], %d(%s)", srcPath.c_str(), dstPath.c_str(), errno, strerror(errno));
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
::unlink(srcPath.c_str());
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// do it by sendfile()
|
|
89
|
-
bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate) {
|
|
90
|
-
if (dstFD < 0) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
File srcFile(srcPath, OpenFlag::ReadOnly);
|
|
94
|
-
if (!srcFile.isFileValid()) {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
auto srcFileSize = srcFile.getActualFileSize();
|
|
98
|
-
|
|
99
|
-
lseek(dstFD, 0, SEEK_SET);
|
|
100
|
-
auto writtenSize = ::sendfile(dstFD, srcFile.getFd(), nullptr, srcFileSize);
|
|
101
|
-
auto ret = (writtenSize == srcFileSize);
|
|
102
|
-
if (!ret) {
|
|
103
|
-
if (writtenSize < 0) {
|
|
104
|
-
MMKVError("fail to sendfile() %s to fd[%d], %d(%s)", srcPath.c_str(), dstFD, errno, strerror(errno));
|
|
105
|
-
} else {
|
|
106
|
-
MMKVError("sendfile() %s to fd[%d], written %lld < %zu", srcPath.c_str(), dstFD, writtenSize, srcFileSize);
|
|
107
|
-
}
|
|
108
|
-
} else if (needTruncate) {
|
|
109
|
-
size_t dstFileSize = 0;
|
|
110
|
-
getFileSize(dstFD, dstFileSize);
|
|
111
|
-
if ((dstFileSize != srcFileSize) && (::ftruncate(dstFD, static_cast<off_t>(srcFileSize)) != 0)) {
|
|
112
|
-
MMKVError("fail to truncate [%d] to size [%zu], %d(%s)", dstFD, srcFileSize, errno, strerror(errno));
|
|
113
|
-
ret = false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (ret) {
|
|
118
|
-
MMKVInfo("copy content from %s to fd[%d] finish", srcPath.c_str(), dstFD);
|
|
119
|
-
}
|
|
120
|
-
return ret;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
} // namespace mmkv
|
|
124
|
-
|
|
125
|
-
#endif // defined(MMKV_ANDROID) || defined(MMKV_LINUX)
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* MMKV available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2019 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 "MemoryFile.h"
|
|
22
|
-
#include "MMKVLog.h"
|
|
23
|
-
|
|
24
|
-
#ifdef MMKV_IOS
|
|
25
|
-
|
|
26
|
-
using namespace std;
|
|
27
|
-
|
|
28
|
-
namespace mmkv {
|
|
29
|
-
|
|
30
|
-
void tryResetFileProtection(const string &path) {
|
|
31
|
-
@autoreleasepool {
|
|
32
|
-
NSString *nsPath = [NSString stringWithUTF8String:path.c_str()];
|
|
33
|
-
NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:nsPath error:nullptr];
|
|
34
|
-
NSString *protection = [attr valueForKey:NSFileProtectionKey];
|
|
35
|
-
MMKVInfo("protection on [%@] is %@", nsPath, protection);
|
|
36
|
-
if ([protection isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication] == NO) {
|
|
37
|
-
NSMutableDictionary *newAttr = [NSMutableDictionary dictionaryWithDictionary:attr];
|
|
38
|
-
[newAttr setObject:NSFileProtectionCompleteUntilFirstUserAuthentication forKey:NSFileProtectionKey];
|
|
39
|
-
NSError *err = nil;
|
|
40
|
-
[[NSFileManager defaultManager] setAttributes:newAttr ofItemAtPath:nsPath error:&err];
|
|
41
|
-
if (err != nil) {
|
|
42
|
-
MMKVError("fail to set attribute %@ on [%@]: %@", NSFileProtectionCompleteUntilFirstUserAuthentication,
|
|
43
|
-
nsPath, err);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
} // namespace mmkv
|
|
50
|
-
|
|
51
|
-
#endif // MMKV_IOS
|
|
52
|
-
|
|
53
|
-
#ifdef MMKV_APPLE
|
|
54
|
-
|
|
55
|
-
#include <copyfile.h>
|
|
56
|
-
#include <unistd.h>
|
|
57
|
-
|
|
58
|
-
namespace mmkv {
|
|
59
|
-
|
|
60
|
-
bool tryAtomicRename(const char *src, const char *dst) {
|
|
61
|
-
bool renamed = false;
|
|
62
|
-
|
|
63
|
-
// try atomic swap first
|
|
64
|
-
if (@available(iOS 10.0, watchOS 3.0, macOS 10.12, *)) {
|
|
65
|
-
// renameat2() equivalent
|
|
66
|
-
if (renamex_np(src, dst, RENAME_SWAP) == 0) {
|
|
67
|
-
renamed = true;
|
|
68
|
-
} else if (errno != ENOENT) {
|
|
69
|
-
MMKVError("fail to renamex_np %s to %s, %s", src, dst, strerror(errno));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!renamed) {
|
|
74
|
-
// try old style rename
|
|
75
|
-
if (rename(src, dst) != 0) {
|
|
76
|
-
MMKVError("fail to rename %s to %s, %s", src, dst, strerror(errno));
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
::unlink(src);
|
|
82
|
-
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
87
|
-
// prepare a temp file for atomic rename, avoid data corruption of suddent crash
|
|
88
|
-
NSString *uniqueFileName = [NSString stringWithFormat:@"mmkv_%zu", (size_t) NSDate.timeIntervalSinceReferenceDate];
|
|
89
|
-
NSString *tmpFile = [NSTemporaryDirectory() stringByAppendingPathComponent:uniqueFileName];
|
|
90
|
-
if (copyfile(srcPath.c_str(), tmpFile.UTF8String, nullptr, COPYFILE_UNLINK | COPYFILE_CLONE) != 0) {
|
|
91
|
-
MMKVError("fail to copyfile [%s] to [%s], %s", srcPath.c_str(), tmpFile.UTF8String, strerror(errno));
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
MMKVInfo("copyfile [%s] to [%s]", srcPath.c_str(), tmpFile.UTF8String);
|
|
95
|
-
|
|
96
|
-
if (tryAtomicRename(tmpFile.UTF8String, dstPath.c_str())) {
|
|
97
|
-
MMKVInfo("copyfile [%s] to [%s] finish.", srcPath.c_str(), dstPath.c_str());
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
unlink(tmpFile.UTF8String);
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
105
|
-
File dstFile(dstPath, OpenFlag::WriteOnly | OpenFlag::Create | OpenFlag::Truncate);
|
|
106
|
-
if (!dstFile.isFileValid()) {
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
if (copyFileContent(srcPath, dstFile.getFd())) {
|
|
110
|
-
MMKVInfo("copy content from %s to fd[%s] finish", srcPath.c_str(), dstPath.c_str());
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
MMKVError("fail to copyfile(): target file %s", dstPath.c_str());
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD) {
|
|
118
|
-
if (dstFD < 0) {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
File srcFile(srcPath, OpenFlag::ReadOnly);
|
|
123
|
-
if (!srcFile.isFileValid()) {
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// sendfile() equivalent
|
|
128
|
-
if (::fcopyfile(srcFile.getFd(), dstFD, nullptr, COPYFILE_ALL) == 0) {
|
|
129
|
-
MMKVInfo("copy content from %s to fd[%d] finish", srcPath.c_str(), dstFD);
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
MMKVError("fail to copyfile(): %d(%s), source file %s", errno, strerror(errno), srcPath.c_str());
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate) {
|
|
137
|
-
return copyFileContent(srcPath, dstFD);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
} // namespace mmkv
|
|
141
|
-
|
|
142
|
-
#endif // MMKV_APPLE
|