已开启
修复了kv4cj转arkts接口出现的三个问题 #11
LH米乐创建于 6月25日
修复了kv4cj转arkts接口出现的三个问题 #11
已开启
共 560 个文件变更+61613-8
| @@ -0,0 +1 @@ | |||
| 1 | +third_party/MMKV-1.3.6/OpenHarmony/dependencies/hvigor-4.3.0.tgz filter=lfs diff=lfs merge=lfs -text | ||
| @@ -1,14 +1,27 @@ | |||
| 1 | .git/ | 1 | .git/ |
| 2 | -.gitee/ | ||
| 3 | -.vscode/ | ||
| 4 | *.macrocall | 2 | *.macrocall |
| 5 | *.cj.macrocall | 3 | *.cj.macrocall |
| 6 | .cache | 4 | .cache |
| 7 | lib | 5 | lib |
| 8 | target | 6 | target |
| 9 | cjpm.lock | 7 | cjpm.lock |
| 10 | -ci_test | 8 | +test/report |
| 11 | -test_temp | 9 | +/node_modules |
| 12 | -test/log | 10 | +/oh_modules |
| 13 | -test/tmp | 11 | +/local.properties |
| 14 | -test/report | 12 | +/.idea |
| 13 | +**/build | ||
| 14 | +/.hvigor | ||
| 15 | +.cxx | ||
| 16 | +/.clangd | ||
| 17 | +/.clang-format | ||
| 18 | +/.clang-tidy | ||
| 19 | +**/.test | ||
| 20 | +/.appanalyzer | ||
| 21 | +**/cj_res | ||
| 22 | +**/*.cj.macrocall | ||
| 23 | +**/ability_mainability_entry.cj | ||
| 24 | +**/module_**_entry.cj | ||
| 25 | +**/IDL_Dependencies_List~ | ||
| 26 | +**/build-script-cache | ||
| 27 | +oh-package-lock.json5 | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | +{ | ||
| 2 | + "app": { | ||
| 3 | + "bundleName": "com.example.kv4cj", | ||
| 4 | + "vendor": "example", | ||
| 5 | + "versionCode": 1000000, | ||
| 6 | + "versionName": "1.0.0", | ||
| 7 | + "icon": "$media:layered_image", | ||
| 8 | + "label": "$string:app_name" | ||
| 9 | + } | ||
| 10 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +{ | ||
| 2 | + "string": [ | ||
| 3 | + { | ||
| 4 | + "name": "app_name", | ||
| 5 | + "value": "kv4cj" | ||
| 6 | + } | ||
| 7 | + ] | ||
| 8 | +} | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | +{ | ||
| 2 | + "layered-image": | ||
| 3 | + { | ||
| 4 | + "background" : "$media:background", | ||
| 5 | + "foreground" : "$media:foreground" | ||
| 6 | + } | ||
| 7 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +/node_modules | ||
| 2 | +/oh_modules | ||
| 3 | +/.preview | ||
| 4 | +/build | ||
| 5 | +/.cxx | ||
| 6 | +/.test | ||
| 7 | +**/IDL_Dependencies_List~ | ||
| 8 | +**/build-script-cache | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | +/** | ||
| 2 | + * Use these variables when you tailor your ArkTS code. They must be of the const type. | ||
| 3 | + */ | ||
| 4 | +export const HAR_VERSION = '1.0.0'; | ||
| 5 | +export const BUILD_MODE_NAME = 'debug'; | ||
| 6 | +export const DEBUG = true; | ||
| 7 | +export const TARGET_NAME = 'default'; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * BuildProfile Class is used only for compatibility purposes. | ||
| 11 | + */ | ||
| 12 | +export default class BuildProfile { | ||
| 13 | + static readonly HAR_VERSION = HAR_VERSION; | ||
| 14 | + static readonly BUILD_MODE_NAME = BUILD_MODE_NAME; | ||
| 15 | + static readonly DEBUG = DEBUG; | ||
| 16 | + static readonly TARGET_NAME = TARGET_NAME; | ||
| 17 | +} | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | +{ | ||
| 2 | + "apiType": "stageMode", | ||
| 3 | + "buildOption": { | ||
| 4 | + "externalNativeOptions": { | ||
| 5 | + "path": "./src/main/cpp/CMakeLists.txt", | ||
| 6 | + "arguments": "-DOHOS_STL=c++_static", | ||
| 7 | + "cppFlags": "-DMMKV_STL_SHARED=0 -funwind-tables -fasynchronous-unwind-tables -O2", | ||
| 8 | + "abiFilters": ["arm64-v8a", "x86_64"], | ||
| 9 | + }, | ||
| 10 | + "cangjieOptions": { | ||
| 11 | + "path": "./cjpm.toml", | ||
| 12 | + "abiFilters": ["arm64-v8a", "x86_64"], | ||
| 13 | + "strictCheckDependencies": false | ||
| 14 | + } | ||
| 15 | + }, | ||
| 16 | + "buildOptionSet": [ | ||
| 17 | + ], | ||
| 18 | + "targets": [ | ||
| 19 | + { | ||
| 20 | + "name": "default" | ||
| 21 | + }, | ||
| 22 | + { | ||
| 23 | + "name": "ohosTest" | ||
| 24 | + } | ||
| 25 | + ] | ||
| 26 | +} | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | +[package] | ||
| 2 | + cjc-version = "0.48.2" | ||
| 3 | + compile-option = "--dy-std --cfg=\"${COMPILE_CONDITION}\"" | ||
| 4 | + description = "CangjieUI Application" | ||
| 5 | + link-option = "" | ||
| 6 | + name = "kv4cj" | ||
| 7 | + output-type = "dynamic" | ||
| 8 | + src-dir = "./src/main/cangjie" | ||
| 9 | + target-dir = "" | ||
| 10 | + version = "1.0.0" | ||
| 11 | + package-configuration = {} | ||
| 12 | + scripts = {} | ||
| 13 | + | ||
| 14 | +[profile] | ||
| 15 | + build = {incremental = true, lto = ""} | ||
| 16 | + customized-option = {debug = "-g -Woff all -Won apilevel-check", release = "--fast-math -O2 -s -Woff all -Won apilevel-check"} | ||
| 17 | + test = {} | ||
| 18 | + | ||
| 19 | +[target.aarch64-linux-ohos] | ||
| 20 | + compile-option = "-B \"${DEVECO_CANGJIE_HOME}/compiler/third_party/llvm/bin\" -B \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/clang/15.0.4/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/aarch64-linux-ohos\" -L \"${DEVECO_CANGJIE_HOME}/build/linux_ohos_aarch64_llvm/openssl\" --sysroot \"${DEVECO_OH_NATIVE_HOME}/sysroot\"" | ||
| 21 | +[target.aarch64-linux-ohos.bin-dependencies] | ||
| 22 | + path-option = ["${AARCH64_LIBS}", "${AARCH64_MACRO_LIBS}", "${AARCH64_KIT_LIBS}"] | ||
| 23 | + package-option = {} | ||
| 24 | + | ||
| 25 | +[target.x86_64-linux-ohos] | ||
| 26 | + compile-option = "-B \"${DEVECO_CANGJIE_HOME}/compiler/third_party/llvm/bin\" -B \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/clang/15.0.4/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/x86_64-linux-ohos\" -L \"${DEVECO_CANGJIE_HOME}/build/linux_ohos_x86_64_llvm/openssl\" --sysroot \"${DEVECO_OH_NATIVE_HOME}/sysroot\"" | ||
| 27 | +[target.x86_64-linux-ohos.bin-dependencies] | ||
| 28 | + path-option = ["${X86_64_OHOS_LIBS}", "${X86_64_OHOS_MACRO_LIBS}", "${X86_64_OHOS_KIT_LIBS}"] | ||
| 29 | + | ||
| 30 | +[target.x86_64-unknown-windows-gnu.bin-dependencies] | ||
| 31 | + path-option = ["${X86_64_LIBS}", "${X86_64_MACRO_LIBS}"] | ||
| 32 | + package-option = {} | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +import { harTasks } from '@ohos/hvigor-ohos-plugin'; | ||
| 2 | + | ||
| 3 | +export default { | ||
| 4 | + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ | ||
| 5 | + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ | ||
| 6 | +} | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | +{ | ||
| 2 | + "name": "@cangjie-tpc/mmkv4cj", | ||
| 3 | + "version": "1.0.0", | ||
| 4 | + "description": "", | ||
| 5 | + "main": "", | ||
| 6 | + "author": "cangjie-tpc", | ||
| 7 | + "types": "", | ||
| 8 | + "license": "BSD 3-Clause", | ||
| 9 | + "repository": "https://gitcode.com/Cangjie-TPC/kv4cj", | ||
| 10 | + "homepage": "https://gitcode.com/Cangjie-TPC/kv4cj", | ||
| 11 | + "dependencies": {} | ||
| 12 | +} | ||
| @@ -0,0 +1,1017 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package kv4cj | ||
| 6 | + | ||
| 7 | +public type MMKVMode = UInt32 | ||
| 8 | +/** | ||
| 9 | + * Single-process mode. The default mode on an MMKV instance. | ||
| 10 | + */ | ||
| 11 | +public let MMKV_SINGLE_PROCESS: MMKVMode = 0x1 | ||
| 12 | +/** | ||
| 13 | + * Multi-process mode. | ||
| 14 | + * To enable multi-process accessing of an MMKV instance, you must set this mode whenever you getting that instance. | ||
| 15 | + */ | ||
| 16 | +public let MMKV_MULTI_PROCESS: MMKVMode = 0x2 | ||
| 17 | + | ||
| 18 | +@C | ||
| 19 | +struct ByteArray { | ||
| 20 | + var len: UIntNative = 0 | ||
| 21 | + var data: CPointer<Byte> = CPointer<Byte>() | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +@C | ||
| 25 | +struct DataList { | ||
| 26 | + var size: UIntNative = 0 | ||
| 27 | + var data: CPointer<UIntNative> = CPointer<UIntNative>() | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +public struct NativeBuffer { | ||
| 31 | + public var pointer: CPointer<Unit> = CPointer<Unit>() | ||
| 32 | + public var size: Int32 = 0 | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +public class MMKV { | ||
| 36 | + var mmkv: UInt64 | ||
| 37 | + let sizeofSize_t: Int64 = unsafe { getSizeofSize_t() } | ||
| 38 | + private static var gCallbackHandler: MMKVHandler = MMKVHandler() | ||
| 39 | + private static var rootDir: ?String = None | ||
| 40 | + | ||
| 41 | + init(kv: UInt64) { | ||
| 42 | + this.mmkv = kv | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * Initialize MMKV with customize settings. | ||
| 47 | + * You must call one of the initializeMMKV() methods on App startup process before using MMKV. | ||
| 48 | + * @param rootDir The root folder of MMKV, defaults to $(FilesDir)/mmkv. | ||
| 49 | + */ | ||
| 50 | + public static func initializeMMKV(rootDir: String): Unit { | ||
| 51 | + initializeMMKV(rootDir, MMKVLogInfo, gCallbackHandler) | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * Initialize MMKV with customize settings. | ||
| 56 | + * You must call one of the initializeMMKV() methods on App startup process before using MMKV. | ||
| 57 | + * @param rootDir The root folder of MMKV. | ||
| 58 | + * @param logLevel The log level of MMKV, defaults to {@link MMKVLogLevel#LevelInfo}. | ||
| 59 | + */ | ||
| 60 | + public static func initializeMMKV(rootDir: String, logLevel: MMKVLogLevel): Unit { | ||
| 61 | + checkLogLevel(logLevel) | ||
| 62 | + initializeMMKV(rootDir, logLevel, gCallbackHandler) | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Initialize MMKV with customize settings. | ||
| 67 | + * You must call one of the initializeMMKV() methods on App startup process before using MMKV. | ||
| 68 | + * @param rootDir The root folder of MMKV. | ||
| 69 | + * @param handler The log Redirecting handler. | ||
| 70 | + */ | ||
| 71 | + public static func initializeMMKV(rootDir: String, handler: MMKVHandler): Unit { | ||
| 72 | + gCallbackHandler = handler | ||
| 73 | + initializeMMKV(rootDir, MMKVLogInfo, gCallbackHandler) | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * Initialize MMKV with customize settings. | ||
| 78 | + * You must call one of the initializeMMKV() methods on App startup process before using MMKV. | ||
| 79 | + * @param rootDir The root folder of MMKV. | ||
| 80 | + * @param logLevel The log level of MMKV, defaults to {@link MMKVLogLevel#LevelInfo}. | ||
| 81 | + * @param handler The log Redirecting handler. | ||
| 82 | + */ | ||
| 83 | + public static func initializeMMKV(rootDir: String, logLevel: MMKVLogLevel, handler: MMKVHandler): Unit { | ||
| 84 | + checkLogLevel(logLevel) | ||
| 85 | + gCallbackHandler = handler | ||
| 86 | + unsafe { | ||
| 87 | + let cstr = LibC.mallocCString(rootDir) | ||
| 88 | + initializeMMKV_c(cstr, logLevel, gCallbackHandler) | ||
| 89 | + LibC.free(cstr) | ||
| 90 | + } | ||
| 91 | + MMKV.rootDir = rootDir | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * Notify MMKV that App is about to exit. It's totally fine not calling it at all. | ||
| 96 | + */ | ||
| 97 | + public static func onExit(): Unit { | ||
| 98 | + unsafe { onExit_c() } | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + private static func checkLogLevel(level: MMKVLogLevel): Unit { | ||
| 102 | + if (level < MMKVLogDebug || level > MMKVLogNone) { | ||
| 103 | + throw MMKVException("Log level ${level} is illegal value!") | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + private static func checkMMKVMode(mode: MMKVMode): Unit { | ||
| 108 | + if (mode < MMKV_SINGLE_PROCESS || mode > MMKV_MULTI_PROCESS) { | ||
| 109 | + throw MMKVException("MMKVMode [${mode}] is illegal value!") | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + private static func checkMMKVHandle(kv: UInt64, mmapID: String): MMKV { | ||
| 114 | + if (kv == 0) { | ||
| 115 | + throw MMKVException("Fail to create an MMKV instance [${mmapID}] in native.") | ||
| 116 | + } | ||
| 117 | + return MMKV(kv) | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + private static func checkRootDir(): Unit { | ||
| 121 | + match (rootDir) { | ||
| 122 | + case None => throw MMKVException("You should Call MMKV.initializeMMKV() first.") | ||
| 123 | + case Some(_) => return | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + /** | ||
| 128 | + * Create the default MMKV instance in single-process mode. | ||
| 129 | + * @return An MMKV instance. | ||
| 130 | + */ | ||
| 131 | + public static func defaultMMKV(): MMKV { | ||
| 132 | + checkRootDir() | ||
| 133 | + let mode: UInt32 = MMKV_SINGLE_PROCESS | ||
| 134 | + let cryptKey = CPointer<UInt8>() | ||
| 135 | + let kv: UInt64 = unsafe { defaultMMKV_c(mode, CString(cryptKey)) } | ||
| 136 | + return checkMMKVHandle(kv, "mmkv.default") | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + /** | ||
| 140 | + * Create the default MMKV instance in customize process mode, with an encryption key. | ||
| 141 | + * @param mode The process mode of the MMKV instance. | ||
| 142 | + * @return An MMKV instance. | ||
| 143 | + */ | ||
| 144 | + public static func defaultMMKV(mode: MMKVMode): MMKV { | ||
| 145 | + checkRootDir() | ||
| 146 | + checkMMKVMode(mode) | ||
| 147 | + let cryptKey = CPointer<UInt8>() | ||
| 148 | + let kv: UInt64 = unsafe { defaultMMKV_c(mode, CString(cryptKey)) } | ||
| 149 | + return checkMMKVHandle(kv, "mmkv.default") | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + /** | ||
| 153 | + * Create the default MMKV instance in customize process mode, with an encryption key. | ||
| 154 | + * @param mode The process mode of the MMKV instance. | ||
| 155 | + * @param cryptKey The encryption key of the MMKV instance (no more than 16 bytes). | ||
| 156 | + * @return An MMKV instance. | ||
| 157 | + */ | ||
| 158 | + public static func defaultMMKV(mode: MMKVMode, cryptKey: String): MMKV { | ||
| 159 | + checkRootDir() | ||
| 160 | + checkMMKVMode(mode) | ||
| 161 | + var kv: UInt64 = 0 | ||
| 162 | + unsafe { | ||
| 163 | + let cstr = LibC.mallocCString(cryptKey) | ||
| 164 | + kv = defaultMMKV_c(mode, cstr) | ||
| 165 | + LibC.free(cstr) | ||
| 166 | + } | ||
| 167 | + return checkMMKVHandle(kv, "mmkv.default") | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + /** | ||
| 171 | + * Create an MMKV instance with an unique ID (in single-process mode). | ||
| 172 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 173 | + * @return An MMKV instance. | ||
| 174 | + */ | ||
| 175 | + public static func mmkvWithID(mmapID: String): MMKV { | ||
| 176 | + checkRootDir() | ||
| 177 | + var kv: UInt64 = 0 | ||
| 178 | + let mode: UInt32 = MMKV_SINGLE_PROCESS | ||
| 179 | + let cryptKey = CString(CPointer<UInt8>()) | ||
| 180 | + let rootPath = CString(CPointer<UInt8>()) | ||
| 181 | + unsafe { | ||
| 182 | + let cstr = LibC.mallocCString(mmapID) | ||
| 183 | + kv = mmkvWithID_c(cstr, mode, cryptKey, rootPath) | ||
| 184 | + LibC.free(cstr) | ||
| 185 | + } | ||
| 186 | + return checkMMKVHandle(kv, mmapID) | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + /** | ||
| 190 | + * Create an MMKV instance in single-process or multi-process mode. | ||
| 191 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 192 | + * @param mode The process mode of the MMKV instance. | ||
| 193 | + * @return An MMKV instance. | ||
| 194 | + */ | ||
| 195 | + public static func mmkvWithID(mmapID: String, mode: MMKVMode): MMKV { | ||
| 196 | + checkRootDir() | ||
| 197 | + checkMMKVMode(mode) | ||
| 198 | + var kv: UInt64 = 0 | ||
| 199 | + let cryptKey = CString(CPointer<UInt8>()) | ||
| 200 | + let rootPath = CString(CPointer<UInt8>()) | ||
| 201 | + unsafe { | ||
| 202 | + let cstr = LibC.mallocCString(mmapID) | ||
| 203 | + kv = mmkvWithID_c(cstr, mode, cryptKey, rootPath) | ||
| 204 | + LibC.free(cstr) | ||
| 205 | + } | ||
| 206 | + return checkMMKVHandle(kv, mmapID) | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + /** | ||
| 210 | + * Create an MMKV instance in customize process mode, with an encryption key. | ||
| 211 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 212 | + * @param mode The process mode of the MMKV instance. | ||
| 213 | + * @param cryptKey The encryption key of the MMKV instance (no more than 16 bytes). | ||
| 214 | + * @return An MMKV instance. | ||
| 215 | + */ | ||
| 216 | + public static func mmkvWithID(mmapID: String, mode: MMKVMode, cryptKey: String): MMKV { | ||
| 217 | + checkRootDir() | ||
| 218 | + checkMMKVMode(mode) | ||
| 219 | + var kv: UInt64 = 0 | ||
| 220 | + let rootPath = CString(CPointer<UInt8>()) | ||
| 221 | + unsafe { | ||
| 222 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 223 | + let cstrCryptKey = LibC.mallocCString(cryptKey) | ||
| 224 | + kv = mmkvWithID_c(cstrMmapID, mode, cstrCryptKey, rootPath) | ||
| 225 | + LibC.free(cstrMmapID) | ||
| 226 | + LibC.free(cstrCryptKey) | ||
| 227 | + } | ||
| 228 | + return checkMMKVHandle(kv, mmapID) | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + /** | ||
| 232 | + * Create an MMKV instance in customize folder. | ||
| 233 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 234 | + * @param rootPath The folder of the MMKV instance. | ||
| 235 | + * @return An MMKV instance. | ||
| 236 | + */ | ||
| 237 | + public static func mmkvWithID(mmapID: String, rootPath: String): MMKV { | ||
| 238 | + checkRootDir() | ||
| 239 | + var kv: UInt64 = 0 | ||
| 240 | + let mode: UInt32 = MMKV_SINGLE_PROCESS | ||
| 241 | + let cryptKey = CString(CPointer<UInt8>()) | ||
| 242 | + unsafe { | ||
| 243 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 244 | + let cstrRootPath = LibC.mallocCString(rootPath) | ||
| 245 | + kv = mmkvWithID_c(cstrMmapID, mode, cryptKey, cstrRootPath) | ||
| 246 | + LibC.free(cstrMmapID) | ||
| 247 | + LibC.free(cstrRootPath) | ||
| 248 | + } | ||
| 249 | + return checkMMKVHandle(kv, mmapID) | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + /** | ||
| 253 | + * Create an MMKV instance with customize settings all in one. | ||
| 254 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 255 | + * @param mode The process mode of the MMKV instance. | ||
| 256 | + * @param cryptKey The encryption key of the MMKV instance (no more than 16 bytes). | ||
| 257 | + * @param rootPath The folder of the MMKV instance. | ||
| 258 | + * @return An MMKV instance. | ||
| 259 | + */ | ||
| 260 | + public static func mmkvWithID(mmapID: String, mode: MMKVMode, cryptKey: String, rootPath: String): MMKV { | ||
| 261 | + checkRootDir() | ||
| 262 | + checkMMKVMode(mode) | ||
| 263 | + var kv: UInt64 = 0 | ||
| 264 | + unsafe { | ||
| 265 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 266 | + let cstrCryptKey = LibC.mallocCString(cryptKey) | ||
| 267 | + let cstrRootPath = LibC.mallocCString(rootPath) | ||
| 268 | + kv = mmkvWithID_c(cstrMmapID, mode, cstrCryptKey, cstrRootPath) | ||
| 269 | + LibC.free(cstrMmapID) | ||
| 270 | + LibC.free(cstrCryptKey) | ||
| 271 | + LibC.free(cstrRootPath) | ||
| 272 | + } | ||
| 273 | + return checkMMKVHandle(kv, mmapID) | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + public func set(key: String, value: Bool): Bool { | ||
| 277 | + var ret: Bool | ||
| 278 | + unsafe { | ||
| 279 | + let cstr = LibC.mallocCString(key) | ||
| 280 | + ret = setBool_c(mmkv, cstr, value) | ||
| 281 | + LibC.free(cstr) | ||
| 282 | + } | ||
| 283 | + return ret | ||
| 284 | + } | ||
| 285 | + | ||
| 286 | + public func set(key: String, value: Int32): Bool { | ||
| 287 | + var ret: Bool | ||
| 288 | + unsafe { | ||
| 289 | + let cstr = LibC.mallocCString(key) | ||
| 290 | + ret = setInt32_t_c(mmkv, cstr, value) | ||
| 291 | + LibC.free(cstr) | ||
| 292 | + } | ||
| 293 | + return ret | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + public func set(key: String, value: UInt32): Bool { | ||
| 297 | + var ret: Bool | ||
| 298 | + unsafe { | ||
| 299 | + let cstr = LibC.mallocCString(key) | ||
| 300 | + ret = setUint32_t_c(mmkv, cstr, value) | ||
| 301 | + LibC.free(cstr) | ||
| 302 | + } | ||
| 303 | + return ret | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + public func set(key: String, value: Int64): Bool { | ||
| 307 | + var ret: Bool | ||
| 308 | + unsafe { | ||
| 309 | + let cstr = LibC.mallocCString(key) | ||
| 310 | + ret = setInt64_t_c(mmkv, cstr, value) | ||
| 311 | + LibC.free(cstr) | ||
| 312 | + } | ||
| 313 | + return ret | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + public func set(key: String, value: UInt64): Bool { | ||
| 317 | + var ret: Bool | ||
| 318 | + unsafe { | ||
| 319 | + let cstr = LibC.mallocCString(key) | ||
| 320 | + ret = setUint64_t_c(mmkv, cstr, value) | ||
| 321 | + LibC.free(cstr) | ||
| 322 | + } | ||
| 323 | + return ret | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + public func set(key: String, value: Float32): Bool { | ||
| 327 | + var ret: Bool | ||
| 328 | + unsafe { | ||
| 329 | + let cstr = LibC.mallocCString(key) | ||
| 330 | + ret = setFloat_c(mmkv, cstr, value) | ||
| 331 | + LibC.free(cstr) | ||
| 332 | + } | ||
| 333 | + return ret | ||
| 334 | + } | ||
| 335 | + | ||
| 336 | + public func set(key: String, value: Float64): Bool { | ||
| 337 | + var ret: Bool | ||
| 338 | + unsafe { | ||
| 339 | + let cstr = LibC.mallocCString(key) | ||
| 340 | + ret = setDouble_c(mmkv, cstr, value) | ||
| 341 | + LibC.free(cstr) | ||
| 342 | + } | ||
| 343 | + return ret | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + public func set(key: String, value: String): Bool { | ||
| 347 | + var ret: Bool | ||
| 348 | + unsafe { | ||
| 349 | + let cstrKey = LibC.mallocCString(key) | ||
| 350 | + let cstrValue =LibC.mallocCString(value) | ||
| 351 | + ret = setString_c(mmkv, cstrKey, cstrValue) | ||
| 352 | + LibC.free(cstrKey) | ||
| 353 | + LibC.free(cstrValue) | ||
| 354 | + } | ||
| 355 | + return ret | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + public func set(key: String, value: Array<Byte>): Bool { | ||
| 359 | + let ptrValue = unsafe { acquireArrayRawData(value) } | ||
| 360 | + var ptrArr = CPointer<ByteArray>(unsafe { malloc(UIntNative(sizeofSize_t * 2)) }) // arr | ||
| 361 | + if (ptrArr.isNull()) { | ||
| 362 | + throw MMKVException("Malloc failed!") | ||
| 363 | + } | ||
| 364 | + var arr = ByteArray() | ||
| 365 | + arr.len = UIntNative(value.size) | ||
| 366 | + arr.data = CPointer<Byte>(ptrValue.pointer) | ||
| 367 | + unsafe { ptrArr.write(arr) } | ||
| 368 | + | ||
| 369 | + var ret: Bool | ||
| 370 | + unsafe { | ||
| 371 | + let cstr = LibC.mallocCString(key) | ||
| 372 | + ret = setBytes_c(mmkv, cstr, ptrArr) | ||
| 373 | + LibC.free(cstr) | ||
| 374 | + releaseArrayRawData(ptrValue) | ||
| 375 | + free(CPointer<Unit>(ptrArr)) | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + return ret | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + public func set(key: String, value: HashSet<String>): Bool { | ||
| 382 | + var pDataList: CPointer<DataList> = CPointer<DataList>() | ||
| 383 | + | ||
| 384 | + if (!value.isEmpty()) { | ||
| 385 | + var itset = value.iterator() | ||
| 386 | + let size = value.size | ||
| 387 | + pDataList = CPointer<DataList>(unsafe { malloc(UIntNative(sizeofSize_t * (size + 1))) }) | ||
| 388 | + if (pDataList.isNull()) { | ||
| 389 | + throw MMKVException("Malloc failed!") | ||
| 390 | + } | ||
| 391 | + var pList = CPointer<UIntNative>(pDataList) | ||
| 392 | + unsafe { pList.write(0, UIntNative(size)) } | ||
| 393 | + for (i in 0..size) { | ||
| 394 | + var element = itset.next() | ||
| 395 | + match (element) { | ||
| 396 | + case Some(v) => | ||
| 397 | + unsafe { | ||
| 398 | + let cstr = LibC.mallocCString(v) | ||
| 399 | + var ptr = cstr.getChars() | ||
| 400 | + pList.write(i + 1, ptr.toUIntNative()) | ||
| 401 | + } | ||
| 402 | + case None => break | ||
| 403 | + } | ||
| 404 | + } | ||
| 405 | + } else { | ||
| 406 | + pDataList = CPointer<DataList>(unsafe { malloc(UIntNative(sizeofSize_t * 2)) }) | ||
| 407 | + if (pDataList.isNull()) { | ||
| 408 | + throw MMKVException("Malloc failed!") | ||
| 409 | + } | ||
| 410 | + let dataList = DataList() | ||
| 411 | + unsafe { pDataList.write(dataList) } | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + var ret: Bool | ||
| 415 | + unsafe { | ||
| 416 | + let cstr = LibC.mallocCString(key) | ||
| 417 | + ret = setStringSet_c(mmkv, cstr, pDataList) | ||
| 418 | + LibC.free(cstr) | ||
| 419 | + } | ||
| 420 | + | ||
| 421 | + if (!value.isEmpty()) { | ||
| 422 | + for (i in 0..value.size) { | ||
| 423 | + var pList = CPointer<CPointer<UIntNative>>(pDataList) | ||
| 424 | + unsafe { pList.read(i + 1).asResource().close() } | ||
| 425 | + } | ||
| 426 | + } | ||
| 427 | + unsafe{ free(CPointer<Unit>(pDataList)) } | ||
| 428 | + | ||
| 429 | + return ret | ||
| 430 | + | ||
| 431 | + } | ||
| 432 | + | ||
| 433 | + public func getBool(key: String, defaultValue!: Bool = false): Bool { | ||
| 434 | + var ret: Bool | ||
| 435 | + unsafe { | ||
| 436 | + let cstr = LibC.mallocCString(key) | ||
| 437 | + ret = getBool_c(mmkv, cstr, defaultValue) | ||
| 438 | + LibC.free(cstr) | ||
| 439 | + } | ||
| 440 | + return ret | ||
| 441 | + } | ||
| 442 | + | ||
| 443 | + public func getInt32(key: String, defaultValue!: Int32 = 0): Int32 { | ||
| 444 | + var ret: Int32 | ||
| 445 | + unsafe { | ||
| 446 | + let cstr = LibC.mallocCString(key) | ||
| 447 | + ret = getInt32_c(mmkv, cstr, defaultValue) | ||
| 448 | + LibC.free(cstr) | ||
| 449 | + } | ||
| 450 | + return ret | ||
| 451 | + } | ||
| 452 | + | ||
| 453 | + public func getUInt32(key: String, defaultValue!: UInt32 = 0): UInt32 { | ||
| 454 | + var ret: UInt32 | ||
| 455 | + unsafe { | ||
| 456 | + let cstr = LibC.mallocCString(key) | ||
| 457 | + ret = getUInt32_c(mmkv, cstr, defaultValue) | ||
| 458 | + LibC.free(cstr) | ||
| 459 | + } | ||
| 460 | + return ret | ||
| 461 | + } | ||
| 462 | + | ||
| 463 | + public func getInt64(key: String, defaultValue!: Int64 = 0): Int64 { | ||
| 464 | + var ret: Int64 | ||
| 465 | + unsafe { | ||
| 466 | + let cstr = LibC.mallocCString(key) | ||
| 467 | + ret = getInt64_c(mmkv, cstr, defaultValue) | ||
| 468 | + LibC.free(cstr) | ||
| 469 | + } | ||
| 470 | + return ret | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | + public func getUInt64(key: String, defaultValue!: UInt64 = 0): UInt64 { | ||
| 474 | + var ret: UInt64 | ||
| 475 | + unsafe { | ||
| 476 | + let cstr = LibC.mallocCString(key) | ||
| 477 | + ret = getUInt64_c(mmkv, cstr, defaultValue) | ||
| 478 | + LibC.free(cstr) | ||
| 479 | + } | ||
| 480 | + return ret | ||
| 481 | + } | ||
| 482 | + | ||
| 483 | + public func getFloat32(key: String, defaultValue!: Float32 = 0.0): Float32 { | ||
| 484 | + var ret: Float32 | ||
| 485 | + unsafe { | ||
| 486 | + let cstr = LibC.mallocCString(key) | ||
| 487 | + ret = getFloat_c(mmkv, cstr, defaultValue) | ||
| 488 | + LibC.free(cstr) | ||
| 489 | + } | ||
| 490 | + return ret | ||
| 491 | + } | ||
| 492 | + | ||
| 493 | + public func getFloat64(key: String, defaultValue!: Float64 = 0.0): Float64 { | ||
| 494 | + var ret: Float64 | ||
| 495 | + unsafe { | ||
| 496 | + let cstr = LibC.mallocCString(key) | ||
| 497 | + ret = getDouble_c(mmkv, cstr, defaultValue) | ||
| 498 | + LibC.free(cstr) | ||
| 499 | + } | ||
| 500 | + return ret | ||
| 501 | + } | ||
| 502 | + | ||
| 503 | + public func getString(key: String, defaultValue!: String = ""): String { | ||
| 504 | + var ptr: CString | ||
| 505 | + unsafe { | ||
| 506 | + let cstr = LibC.mallocCString(key) | ||
| 507 | + ptr = getString_c(mmkv, cstr) | ||
| 508 | + LibC.free(cstr) | ||
| 509 | + } | ||
| 510 | + | ||
| 511 | + if (!ptr.isNull()) { | ||
| 512 | + var str = ptr.toString() | ||
| 513 | + unsafe { ptr.asResource().close() } | ||
| 514 | + return str | ||
| 515 | + } else { | ||
| 516 | + return defaultValue | ||
| 517 | + } | ||
| 518 | + } | ||
| 519 | + | ||
| 520 | + public func getBytes(key: String, defaultValue!: Array<Byte> = Array<Byte>()): Array<Byte> { | ||
| 521 | + var array: Array<Byte> = Array<Byte>() | ||
| 522 | + var ptrArr: CPointer<ByteArray> | ||
| 523 | + unsafe { | ||
| 524 | + let cstr = LibC.mallocCString(key) | ||
| 525 | + ptrArr = getBytes_c(mmkv, cstr) | ||
| 526 | + LibC.free(cstr) | ||
| 527 | + } | ||
| 528 | + if (ptrArr.isNotNull()) { | ||
| 529 | + var arr = unsafe { ptrArr.read() } | ||
| 530 | + var len: Int64 = Int64(arr.len) | ||
| 531 | + var ptrArrData = CPointer<Byte>(arr.data) | ||
| 532 | + | ||
| 533 | + array = Array<Byte>(len, repeat: 0) | ||
| 534 | + for (i in 0..len) { | ||
| 535 | + array[i] = unsafe { ptrArrData.read(i) } | ||
| 536 | + } | ||
| 537 | + | ||
| 538 | + if (len > 0) { | ||
| 539 | + unsafe { free(CPointer<Unit>(ptrArrData)) } | ||
| 540 | + } | ||
| 541 | + unsafe { free(CPointer<Unit>(ptrArr)) } | ||
| 542 | + | ||
| 543 | + return array | ||
| 544 | + } else { | ||
| 545 | + return defaultValue | ||
| 546 | + } | ||
| 547 | + } | ||
| 548 | + | ||
| 549 | + public func getStringSet(key: String, defaultValue!: HashSet<String> = HashSet<String>()): HashSet<String> { | ||
| 550 | + var set = HashSet<String>() | ||
| 551 | + var pDataList: CPointer<DataList> | ||
| 552 | + unsafe { | ||
| 553 | + let cstr = LibC.mallocCString(key) | ||
| 554 | + pDataList = getStringSet_c(mmkv, cstr) | ||
| 555 | + LibC.free(cstr) | ||
| 556 | + } | ||
| 557 | + if (pDataList.isNotNull()) { | ||
| 558 | + var dataList = unsafe { pDataList.read() } | ||
| 559 | + let size: Int64 = Int64(dataList.size) | ||
| 560 | + var ptr = unsafe { CPointer<CPointer<UIntNative>>(pDataList) + 1 } | ||
| 561 | + for (i in 0..size) { | ||
| 562 | + var pcstr = unsafe { CPointer<UInt8>(ptr.read(i)) } | ||
| 563 | + set.add(CString(pcstr).toString()) | ||
| 564 | + unsafe { free(CPointer<Unit>(pcstr)) } | ||
| 565 | + } | ||
| 566 | + | ||
| 567 | + unsafe { free(CPointer<Unit>(pDataList)) } | ||
| 568 | + | ||
| 569 | + return set | ||
| 570 | + } else { | ||
| 571 | + return defaultValue | ||
| 572 | + } | ||
| 573 | + } | ||
| 574 | + | ||
| 575 | + /** | ||
| 576 | + * Batch remove some keys from the MMKV instance. | ||
| 577 | + * @param arrKeys The keys to be removed. | ||
| 578 | + */ | ||
| 579 | + public func removeValuesForKeys(arrKeys: Array<String>): Unit { | ||
| 580 | + if (!arrKeys.isEmpty()) { | ||
| 581 | + var size: Int64 = arrKeys.size | ||
| 582 | + var ptr: CPointer<UIntNative> = CPointer<UIntNative>(unsafe { malloc(UIntNative(sizeofSize_t * (size + 1))) }) | ||
| 583 | + if (ptr.isNull()) { | ||
| 584 | + throw MMKVException("Malloc failed!") | ||
| 585 | + } | ||
| 586 | + unsafe { ptr.write(0, UIntNative(size)) } | ||
| 587 | + for (i in 0..size) { | ||
| 588 | + unsafe { | ||
| 589 | + let cstr = LibC.mallocCString(arrKeys[i]) | ||
| 590 | + ptr.write(i + 1, cstr.getChars().toUIntNative()) | ||
| 591 | + } | ||
| 592 | + } | ||
| 593 | + var dataList: CPointer<DataList> = CPointer<DataList>(ptr) | ||
| 594 | + unsafe { removeValuesForKeys_c(mmkv, dataList) } | ||
| 595 | + unsafe { | ||
| 596 | + let p = CPointer<CPointer<UIntNative>>(ptr) | ||
| 597 | + for (i in 0..size) { | ||
| 598 | + p.read(i + 1).asResource().close() | ||
| 599 | + } | ||
| 600 | + free(CPointer<Unit>(ptr)) | ||
| 601 | + } | ||
| 602 | + } | ||
| 603 | + } | ||
| 604 | + | ||
| 605 | + public func removeValueForKey(key: String): Unit { | ||
| 606 | + unsafe { | ||
| 607 | + let cstr = LibC.mallocCString(key) | ||
| 608 | + removeValueForKey_c(mmkv, cstr) | ||
| 609 | + LibC.free(cstr) | ||
| 610 | + } | ||
| 611 | + } | ||
| 612 | + | ||
| 613 | + /** | ||
| 614 | + * Clear all the key-values inside the MMKV instance. | ||
| 615 | + */ | ||
| 616 | + public func clearAll(): Unit { | ||
| 617 | + unsafe { clearAll_c(mmkv) } | ||
| 618 | + } | ||
| 619 | + | ||
| 620 | + /** | ||
| 621 | + * The {@link #totalSize()} of an MMKV instance won't reduce after deleting key-values, | ||
| 622 | + * call this method after lots of deleting if you care about disk usage. | ||
| 623 | + * Note that {@link #clearAll()} has a similar effect. | ||
| 624 | + */ | ||
| 625 | + public func trim(): Unit { | ||
| 626 | + unsafe { trim_c(mmkv) } | ||
| 627 | + } | ||
| 628 | + | ||
| 629 | + /** | ||
| 630 | + * Call this method if the MMKV instance is no longer needed in the near future. | ||
| 631 | + * Any subsequent call to any MMKV instances with the same ID is undefined behavior. | ||
| 632 | + */ | ||
| 633 | + public func close(): Unit { | ||
| 634 | + unsafe { close_c(mmkv) } | ||
| 635 | + mmkv = 0 | ||
| 636 | + } | ||
| 637 | + | ||
| 638 | + /** | ||
| 639 | + * Save all mmap memory to file synchronously. | ||
| 640 | + * You don't need to call this, really, I mean it. | ||
| 641 | + * Unless you worry about the device running out of battery. | ||
| 642 | + */ | ||
| 643 | + public func sync(): Unit { | ||
| 644 | + unsafe { sync_c(mmkv, true) } | ||
| 645 | + } | ||
| 646 | + | ||
| 647 | + /** | ||
| 648 | + * Save all mmap memory to file asynchronously. | ||
| 649 | + * No need to call this unless you worry about the device running out of battery. | ||
| 650 | + */ | ||
| 651 | + public func async(): Unit { | ||
| 652 | + unsafe { sync_c(mmkv, false) } | ||
| 653 | + } | ||
| 654 | + | ||
| 655 | + /** | ||
| 656 | + * Clear memory cache of the MMKV instance. | ||
| 657 | + * You can call it on memory warning. | ||
| 658 | + * Any subsequent call to the MMKV instance will trigger all key-values loading from the file again. | ||
| 659 | + */ | ||
| 660 | + public func clearMemoryCache(): Unit { | ||
| 661 | + unsafe { clearMemoryCache_c(mmkv) } | ||
| 662 | + } | ||
| 663 | + | ||
| 664 | + /** | ||
| 665 | + * @return The root folder of MMKV, defaults to $(FilesDir)/mmkv. | ||
| 666 | + */ | ||
| 667 | + public static func getRootDir(): String { | ||
| 668 | + return rootDir.getOrThrow() | ||
| 669 | + } | ||
| 670 | + | ||
| 671 | + /** | ||
| 672 | + * backup one MMKV instance to dstDir | ||
| 673 | + * @param mmapID the MMKV ID to backup | ||
| 674 | + * @param dstDir the backup destination directory | ||
| 675 | + */ | ||
| 676 | + public static func backupOneToDirectory(mmapID: String, dstDir: String): Bool { | ||
| 677 | + let ret: Bool | ||
| 678 | + unsafe { | ||
| 679 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 680 | + let cstrDstDir = LibC.mallocCString(dstDir) | ||
| 681 | + ret = backupOne(cstrMmapID, cstrDstDir, CString(CPointer<UInt8>())) | ||
| 682 | + LibC.free(cstrMmapID) | ||
| 683 | + LibC.free(cstrDstDir) | ||
| 684 | + } | ||
| 685 | + return ret | ||
| 686 | + } | ||
| 687 | + | ||
| 688 | + /** | ||
| 689 | + * backup one MMKV instance to dstDir | ||
| 690 | + * @param mmapID the MMKV ID to backup | ||
| 691 | + * @param rootPath the customize root path of the MMKV, if null then backup from the root dir of MMKV | ||
| 692 | + * @param dstDir the backup destination directory | ||
| 693 | + */ | ||
| 694 | + public static func backupOneToDirectory(mmapID: String, dstDir: String, rootPath: String): Bool { | ||
| 695 | + let ret: Bool | ||
| 696 | + unsafe { | ||
| 697 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 698 | + let cstrDstDir = LibC.mallocCString(dstDir) | ||
| 699 | + let cstrRootPath = LibC.mallocCString(rootPath) | ||
| 700 | + ret = backupOne(cstrMmapID, cstrDstDir, cstrRootPath) | ||
| 701 | + LibC.free(cstrMmapID) | ||
| 702 | + LibC.free(cstrDstDir) | ||
| 703 | + LibC.free(cstrRootPath) | ||
| 704 | + } | ||
| 705 | + return ret | ||
| 706 | + } | ||
| 707 | + | ||
| 708 | + /** | ||
| 709 | + * restore one MMKV instance from srcDir | ||
| 710 | + * @param mmapID the MMKV ID to restore | ||
| 711 | + * @param srcDir the restore source directory | ||
| 712 | + */ | ||
| 713 | + public static func restoreOneFromDirectory(mmapID: String, srcDir: String): Bool { | ||
| 714 | + let ret: Bool | ||
| 715 | + unsafe { | ||
| 716 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 717 | + let cstrSrcDir = LibC.mallocCString(srcDir) | ||
| 718 | + ret = restoreOne(cstrMmapID, cstrSrcDir, CString(CPointer<UInt8>())) | ||
| 719 | + LibC.free(cstrMmapID) | ||
| 720 | + LibC.free(cstrSrcDir) | ||
| 721 | + } | ||
| 722 | + return ret | ||
| 723 | + } | ||
| 724 | + | ||
| 725 | + /** | ||
| 726 | + * restore one MMKV instance from srcDir | ||
| 727 | + * @param mmapID the MMKV ID to restore | ||
| 728 | + * @param srcDir the restore source directory | ||
| 729 | + * @param rootPath the customize root path of the MMKV, if null then restore to the root dir of MMKV | ||
| 730 | + */ | ||
| 731 | + public static func restoreOneFromDirectory(mmapID: String, srcDir: String, rootPath: String): Bool { | ||
| 732 | + let ret: Bool | ||
| 733 | + unsafe { | ||
| 734 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 735 | + let cstrSrcDir = LibC.mallocCString(srcDir) | ||
| 736 | + let cstrRootPath = LibC.mallocCString(rootPath) | ||
| 737 | + ret = restoreOne(cstrMmapID, cstrSrcDir, cstrRootPath) | ||
| 738 | + LibC.free(cstrMmapID) | ||
| 739 | + LibC.free(cstrSrcDir) | ||
| 740 | + LibC.free(cstrRootPath) | ||
| 741 | + } | ||
| 742 | + return ret | ||
| 743 | + } | ||
| 744 | + | ||
| 745 | + /** | ||
| 746 | + * backup all MMKV instance to dstDir | ||
| 747 | + * @param dstDir the backup destination directory | ||
| 748 | + * @return count of MMKV successfully backuped | ||
| 749 | + */ | ||
| 750 | + public static func backupAllToDirectory(dstDir: String): UInt64 { | ||
| 751 | + let ret: UInt64 | ||
| 752 | + unsafe { | ||
| 753 | + let cstrDstDir = LibC.mallocCString(dstDir) | ||
| 754 | + ret = backupAll(cstrDstDir, CString(CPointer<UInt8>())) | ||
| 755 | + LibC.free(cstrDstDir) | ||
| 756 | + } | ||
| 757 | + return ret | ||
| 758 | + } | ||
| 759 | + | ||
| 760 | + /** | ||
| 761 | + * backup all MMKV instance to dstDir | ||
| 762 | + * @param dstDir the backup destination directory | ||
| 763 | + * @param rootPath the customize root path of the MMKV, if null then backup from the root dir of MMKV | ||
| 764 | + * @return count of MMKV successfully backuped | ||
| 765 | + */ | ||
| 766 | + public static func backupAllToDirectory(dstDir: String, rootPath: String): UInt64 { | ||
| 767 | + let ret: UInt64 | ||
| 768 | + unsafe { | ||
| 769 | + let cstrDstDir = LibC.mallocCString(dstDir) | ||
| 770 | + let cstrRootPath = LibC.mallocCString(rootPath) | ||
| 771 | + ret = backupAll(cstrDstDir, cstrRootPath) | ||
| 772 | + LibC.free(cstrDstDir) | ||
| 773 | + LibC.free(cstrRootPath) | ||
| 774 | + } | ||
| 775 | + return ret | ||
| 776 | + } | ||
| 777 | + | ||
| 778 | + /** | ||
| 779 | + * restore all MMKV instance from srcDir | ||
| 780 | + * @param srcDir the restore source directory | ||
| 781 | + * @return count of MMKV successfully restored | ||
| 782 | + */ | ||
| 783 | + public static func restoreAllFromDirectory(srcDir: String): UInt64 { | ||
| 784 | + let ret: UInt64 | ||
| 785 | + unsafe { | ||
| 786 | + let cstrSrcDir = LibC.mallocCString(srcDir) | ||
| 787 | + ret = restoreAll(cstrSrcDir, CString(CPointer<UInt8>())) | ||
| 788 | + LibC.free(cstrSrcDir) | ||
| 789 | + } | ||
| 790 | + return ret | ||
| 791 | + } | ||
| 792 | + | ||
| 793 | + /** | ||
| 794 | + * restore all MMKV instance from srcDir | ||
| 795 | + * @param srcDir the restore source directory | ||
| 796 | + * @param rootPath the customize root path of the MMKV, if null then restore to the root dir of MMKV | ||
| 797 | + * @return count of MMKV successfully restored | ||
| 798 | + */ | ||
| 799 | + public static func restoreAllFromDirectory(srcDir: String, rootPath: String): UInt64 { | ||
| 800 | + let ret: UInt64 | ||
| 801 | + unsafe { | ||
| 802 | + let cstrSrcDir = LibC.mallocCString(srcDir) | ||
| 803 | + let cstrRootPath = LibC.mallocCString(rootPath) | ||
| 804 | + ret = restoreAll(cstrSrcDir, cstrRootPath) | ||
| 805 | + LibC.free(cstrSrcDir) | ||
| 806 | + LibC.free(cstrRootPath) | ||
| 807 | + } | ||
| 808 | + return ret | ||
| 809 | + } | ||
| 810 | + | ||
| 811 | + /** | ||
| 812 | + * Set the log level of MMKV. | ||
| 813 | + * @param level Defaults to {@link MMKVLogLevel#LevelInfo}. | ||
| 814 | + */ | ||
| 815 | + public static func setLogLevel(level: MMKVLogLevel): Unit { | ||
| 816 | + checkLogLevel(level) | ||
| 817 | + unsafe { setLogLevel_c(level) } | ||
| 818 | + } | ||
| 819 | + | ||
| 820 | + /** | ||
| 821 | + * Register a handler for MMKV log redirecting, and error handling. | ||
| 822 | + * @deprecated This method is deprecated. | ||
| 823 | + * Use the {@link #initialize(Context, String, LibLoader, MMKVLogLevel, MMKVHandler)} method instead. | ||
| 824 | + */ | ||
| 825 | + public static func registerHandler(handler: MMKVHandler): Unit { | ||
| 826 | + gCallbackHandler = handler | ||
| 827 | + unsafe { setCallbackHandler(gCallbackHandler) } | ||
| 828 | + } | ||
| 829 | + | ||
| 830 | + /** | ||
| 831 | + * Unregister the handler for MMKV. | ||
| 832 | + */ | ||
| 833 | + public static func unregiserHandler(): Unit { | ||
| 834 | + gCallbackHandler = MMKVHandler() | ||
| 835 | + unsafe { setCallbackHandler(gCallbackHandler) } | ||
| 836 | + } | ||
| 837 | + | ||
| 838 | + /** | ||
| 839 | + * Check whether the MMKV file is valid or not. | ||
| 840 | + * Note: Don't use this to check the existence of the instance, the result is undefined on nonexistent files. | ||
| 841 | + */ | ||
| 842 | + public static func isFileValid(mmapID: String): Bool { | ||
| 843 | + let ret: Bool | ||
| 844 | + unsafe { | ||
| 845 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 846 | + ret = isFileValid_c(cstrMmapID, CString(CPointer<UInt8>())) | ||
| 847 | + LibC.free(cstrMmapID) | ||
| 848 | + } | ||
| 849 | + return ret | ||
| 850 | + } | ||
| 851 | + | ||
| 852 | + /** | ||
| 853 | + * Check whether the MMKV file is valid or not on customize folder. | ||
| 854 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 855 | + * @param rootPath The folder of the MMKV instance, defaults to $(FilesDir)/mmkv. | ||
| 856 | + */ | ||
| 857 | + public static func isFileValid(mmapID: String, rootPath: String): Bool { | ||
| 858 | + let ret: Bool | ||
| 859 | + unsafe { | ||
| 860 | + let cstrMmapID = LibC.mallocCString(mmapID) | ||
| 861 | + let cstrRootPath = LibC.mallocCString(rootPath) | ||
| 862 | + ret = isFileValid_c(cstrMmapID, cstrRootPath) | ||
| 863 | + LibC.free(cstrMmapID) | ||
| 864 | + LibC.free(cstrRootPath) | ||
| 865 | + } | ||
| 866 | + return ret | ||
| 867 | + } | ||
| 868 | + | ||
| 869 | + public static func pageSize(): Int64 { | ||
| 870 | + unsafe { pageSize_c() } | ||
| 871 | + } | ||
| 872 | + | ||
| 873 | + public func creatBuffer(size: UIntNative): NativeBuffer { | ||
| 874 | + var CPtrAddr: CPointer<Unit> = unsafe { malloc(size) } | ||
| 875 | + if (CPtrAddr.isNull()) { | ||
| 876 | + throw MMKVException("Malloc failed!") | ||
| 877 | + } | ||
| 878 | + var buffer: NativeBuffer = NativeBuffer() | ||
| 879 | + buffer.pointer = CPtrAddr | ||
| 880 | + buffer.size = Int32(size) | ||
| 881 | + return buffer | ||
| 882 | + } | ||
| 883 | + | ||
| 884 | + public func destoryBuffer(buffer: NativeBuffer): Unit { | ||
| 885 | + unsafe { free(buffer.pointer) } | ||
| 886 | + } | ||
| 887 | + | ||
| 888 | + /** | ||
| 889 | + * Write the value of the key to the native buffer. | ||
| 890 | + * @return The size written. Return -1 on any error. | ||
| 891 | + */ | ||
| 892 | + public func writeValueToBuffer(key: String, buffer: NativeBuffer): Int32 { | ||
| 893 | + unsafe { | ||
| 894 | + var cstr = LibC.mallocCString(key) | ||
| 895 | + var ret = writeValueToBuffer_c(mmkv, cstr, buffer.pointer, buffer.size) | ||
| 896 | + LibC.free(cstr) | ||
| 897 | + return ret | ||
| 898 | + } | ||
| 899 | + } | ||
| 900 | + | ||
| 901 | + /** | ||
| 902 | + * Get the size consumption of the key's value. | ||
| 903 | + * Note: might be a little bigger than value's length. | ||
| 904 | + * @param key The key of the value. | ||
| 905 | + * @param actualSize whether or not actual Size | ||
| 906 | + */ | ||
| 907 | + public func getValueSize(key: String, actualSize: Bool): UInt64 { | ||
| 908 | + unsafe { | ||
| 909 | + var cstr = LibC.mallocCString(key) | ||
| 910 | + var ret = getValueSize_c(mmkv, cstr, actualSize) | ||
| 911 | + LibC.free(cstr) | ||
| 912 | + return ret | ||
| 913 | + } | ||
| 914 | + } | ||
| 915 | + | ||
| 916 | + /** | ||
| 917 | + * Check whether or not MMKV contains the key. | ||
| 918 | + * @param key The key of the value. | ||
| 919 | + */ | ||
| 920 | + public func containsKey(key: String): Bool { | ||
| 921 | + unsafe { | ||
| 922 | + var cstr = LibC.mallocCString(key) | ||
| 923 | + var ret = containsKey_c(mmkv, cstr) | ||
| 924 | + LibC.free(cstr) | ||
| 925 | + return ret | ||
| 926 | + } | ||
| 927 | + } | ||
| 928 | + | ||
| 929 | + /** | ||
| 930 | + * @return The total count of all the keys. | ||
| 931 | + */ | ||
| 932 | + public func count(): UInt64 { | ||
| 933 | + return unsafe {count_c(mmkv)} | ||
| 934 | + } | ||
| 935 | + | ||
| 936 | + /** | ||
| 937 | + * Get the size of the underlying file. Align to the disk block size, typically 4K for an Android device. | ||
| 938 | + */ | ||
| 939 | + public func totalSize(): UInt64 { | ||
| 940 | + return unsafe {totalSize_c(mmkv)} | ||
| 941 | + } | ||
| 942 | + | ||
| 943 | + /** | ||
| 944 | + * Get the actual used size of the MMKV instance. | ||
| 945 | + * This size might increase and decrease as MMKV doing insertion and full write back. | ||
| 946 | + */ | ||
| 947 | + public func actualSize(): UInt64 { | ||
| 948 | + return unsafe {actualSize_c(mmkv)} | ||
| 949 | + } | ||
| 950 | + | ||
| 951 | + /** | ||
| 952 | + * @return All the keys. | ||
| 953 | + */ | ||
| 954 | + public func allKeys():HashSet<String> { | ||
| 955 | + var set = HashSet<String>() | ||
| 956 | + let pDataList: CPointer<DataList> = unsafe { allKeys_c(mmkv) } | ||
| 957 | + if (pDataList.isNotNull()) { | ||
| 958 | + var dataList = unsafe { pDataList.read() } | ||
| 959 | + let len: Int64 = Int64(dataList.size) | ||
| 960 | + var ptr = unsafe { CPointer<CPointer<UIntNative>>(pDataList) + 1 } | ||
| 961 | + for (i in 0..len) { | ||
| 962 | + var pcstr = unsafe { CPointer<UInt8>(ptr.read(i)) } | ||
| 963 | + set.add(CString(pcstr).toString()) | ||
| 964 | + unsafe { free(CPointer<Unit>(pcstr)) } | ||
| 965 | + } | ||
| 966 | + | ||
| 967 | + unsafe { free(CPointer<Unit>(pDataList)) } | ||
| 968 | + return set | ||
| 969 | + } else { | ||
| 970 | + return set //HashSet<None<String>> | ||
| 971 | + } | ||
| 972 | + } | ||
| 973 | + | ||
| 974 | + /** | ||
| 975 | + * @return The unique ID of the MMKV instance. | ||
| 976 | + */ | ||
| 977 | + public func mmapID(): String { | ||
| 978 | + var ret_str: CString = unsafe {mmapID_c(mmkv)} | ||
| 979 | + return ret_str.toString() | ||
| 980 | + } | ||
| 981 | + | ||
| 982 | + /** | ||
| 983 | + * @return The encryption key (no more than 16 bytes). | ||
| 984 | + */ | ||
| 985 | + public func cryptKey(): String { | ||
| 986 | + var ret_str: CString = unsafe {cryptKey_c(mmkv)} | ||
| 987 | + return ret_str.toString() | ||
| 988 | + } | ||
| 989 | + | ||
| 990 | + /** | ||
| 991 | + * Transform plain text into encrypted text, or vice versa by passing a null encryption key. | ||
| 992 | + * You can also change existing crypt key with a different cryptKey. | ||
| 993 | + * @param cryptKey The new encryption key (no more than 16 bytes). | ||
| 994 | + * @return True if success, otherwise False. | ||
| 995 | + */ | ||
| 996 | + public func reKey(cryptKey: String): Bool { | ||
| 997 | + unsafe { | ||
| 998 | + var cstr = LibC.mallocCString(cryptKey) | ||
| 999 | + var ret = reKey_c(mmkv, cstr) | ||
| 1000 | + LibC.free(cstr) | ||
| 1001 | + return ret | ||
| 1002 | + } | ||
| 1003 | + } | ||
| 1004 | + | ||
| 1005 | + /** | ||
| 1006 | + * Just reset the encryption key (will not encrypt or decrypt anything). | ||
| 1007 | + * Usually you should call this method after another process has {@link #reKey(String)} the multi-process MMKV instance. | ||
| 1008 | + * @param cryptKey The new encryption key (no more than 16 bytes). | ||
| 1009 | + */ | ||
| 1010 | + public func checkReSetCryptKey(cryptKey: String): Unit { | ||
| 1011 | + unsafe { | ||
| 1012 | + var cstr = LibC.mallocCString(cryptKey) | ||
| 1013 | + checkReSetCryptKey_c(mmkv, cstr) | ||
| 1014 | + LibC.free(cstr) | ||
| 1015 | + } | ||
| 1016 | + } | ||
| 1017 | +} | ||
| @@ -0,0 +1,71 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package kv4cj | ||
| 6 | + | ||
| 7 | +public type MMKVLogLevel = Int32 | ||
| 8 | +public let MMKVLogDebug: MMKVLogLevel = 0 // not available for release/product build | ||
| 9 | +public let MMKVLogInfo: MMKVLogLevel = 1 // default level | ||
| 10 | +public let MMKVLogWarning: MMKVLogLevel = 2 | ||
| 11 | +public let MMKVLogError: MMKVLogLevel = 3 | ||
| 12 | +public let MMKVLogNone: MMKVLogLevel = 4 // special level used to disable all log messages | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * The recover strategic of MMKV on errors. {@link MMKV#registerHandler} | ||
| 16 | + */ | ||
| 17 | +public type MMKVRecoverStrategic = Int32 | ||
| 18 | +/** | ||
| 19 | + * The default strategic is to discard everything on errors. | ||
| 20 | + */ | ||
| 21 | +public let OnErrorDiscard: MMKVRecoverStrategic = 0 | ||
| 22 | +/** | ||
| 23 | + * The recover strategic will try to recover as much data as possible. | ||
| 24 | + */ | ||
| 25 | +public let OnErrorRecover: MMKVRecoverStrategic = 1 | ||
| 26 | + | ||
| 27 | +public type MMKVErrorType = Int32 | ||
| 28 | +public let MMKVCRCCheckFail: MMKVErrorType = 0 | ||
| 29 | +public let MMKVFileLength: MMKVErrorType = 1 | ||
| 30 | + | ||
| 31 | +public type LogHandler = CFunc<(MMKVLogLevel, CString, Int32, CString, CString) -> Unit> | ||
| 32 | +public type ErrorHandler = CFunc<(CString) -> Int32> | ||
| 33 | +public type ContentChangeHandler = CFunc<(CString) -> Unit> | ||
| 34 | + | ||
| 35 | +/** | ||
| 36 | + * Callback handler for MMKV. | ||
| 37 | + * Callback is called on the operating thread of the MMKV instance. | ||
| 38 | + */ | ||
| 39 | +@C | ||
| 40 | +public struct MMKVHandler { | ||
| 41 | + /** | ||
| 42 | + * Log Redirecting. | ||
| 43 | + * @param level The level of this log. | ||
| 44 | + * @param file The file name of this log. | ||
| 45 | + * @param line The line of code of this log. | ||
| 46 | + * @param function The function name of this log. | ||
| 47 | + * @param message The content of this log. | ||
| 48 | + */ | ||
| 49 | + public var mmkvLog: LogHandler = CFunc<(MMKVLogLevel, CString, Int32, CString, CString) -> Unit>(CPointer<Int8>()) | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * By default MMKV will discard all data on crc32-check failure. {@link MMKVRecoverStrategic#OnErrorDiscard} | ||
| 53 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 54 | + * @return Return {@link MMKVRecoverStrategic#OnErrorRecover} to recover any data on the file. | ||
| 55 | + */ | ||
| 56 | + public var onMMKVCRCCheckFail: ErrorHandler = CFunc<(CString) -> MMKVRecoverStrategic>(CPointer<Int8>()) | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * By default MMKV will discard all data on file length mismatch. {@link MMKVRecoverStrategic#OnErrorDiscard} | ||
| 60 | + * @param mmapID The unique ID of the MMKV instance. | ||
| 61 | + * @return Return {@link MMKVRecoverStrategic#OnErrorRecover} to recover any data on the file. | ||
| 62 | + */ | ||
| 63 | + public var onMMKVFileLengthError: ErrorHandler = CFunc<(CString) -> MMKVRecoverStrategic>(CPointer<Int8>()) | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Inter-process content change notification. | ||
| 67 | + * Triggered by any method call, such as getXXX() or setXXX() or {@link MMKV#onMMKVContentChange()}. | ||
| 68 | + * @param mmapID The unique ID of the changed MMKV instance. | ||
| 69 | + */ | ||
| 70 | + public var onMMKVContentChange: ContentChangeHandler = CFunc<(CString) -> Unit>(CPointer<Int8>()) | ||
| 71 | +} | ||
| @@ -0,0 +1,74 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package kv4cj | ||
| 6 | + | ||
| 7 | +foreign { | ||
| 8 | + func initializeMMKV_c(rootDir: CString, logLevel: MMKVLogLevel, handler: MMKVHandler): Unit | ||
| 9 | + func onExit_c(): Unit | ||
| 10 | + func defaultMMKV_c(mode: UInt32, cryptKey: CString): UInt64 | ||
| 11 | + func mmkvWithID_c(mmapID: CString, mode: UInt32, cryptKey: CString, rootPath: CString): UInt64 | ||
| 12 | + | ||
| 13 | + func setBool_c(kv: UInt64, key: CString, value: Bool): Bool | ||
| 14 | + func setInt32_t_c(mmkv: UInt64, key: CString, value: Int32): Bool | ||
| 15 | + func setUint32_t_c(mmkv: UInt64, key: CString, value: UInt32): Bool | ||
| 16 | + func setInt64_t_c(mmkv: UInt64, key: CString, value: Int64): Bool | ||
| 17 | + func setUint64_t_c(mmkv: UInt64, key: CString, value: UInt64): Bool | ||
| 18 | + func setFloat_c(mmkv: UInt64, key: CString, value: Float32): Bool | ||
| 19 | + func setDouble_c(mmkv: UInt64, key: CString, value: Float64): Bool | ||
| 20 | + func setString_c(mmkv: UInt64, key: CString, value: CString): Bool | ||
| 21 | + func setBytes_c(kv: UInt64, key: CString, value: CPointer<ByteArray>): Bool | ||
| 22 | + func setStringSet_c(kv: UInt64, key: CString, value: CPointer<DataList>): Bool | ||
| 23 | + | ||
| 24 | + func getBool_c(kv: UInt64, key: CString, defaultValue: Bool): Bool | ||
| 25 | + func getInt32_c(mmkv: UInt64, key: CString, defaultValue: Int32): Int32 | ||
| 26 | + func getUInt32_c(mmkv: UInt64, key: CString, defaultValue: UInt32): UInt32 | ||
| 27 | + func getInt64_c(mmkv: UInt64, key: CString, defaultValue: Int64): Int64 | ||
| 28 | + func getUInt64_c(mmkv: UInt64, key: CString, defaultValue: UInt64): UInt64 | ||
| 29 | + func getFloat_c(mmkv: UInt64, key: CString, defaultValue: Float32): Float32 | ||
| 30 | + func getDouble_c(mmkv: UInt64, key: CString, defaultValue: Float64): Float64 | ||
| 31 | + func getString_c(mmkv: UInt64, key: CString): CString | ||
| 32 | + func getBytes_c(kv: UInt64, key: CString): CPointer<ByteArray> | ||
| 33 | + func getStringSet_c(kv: UInt64, key: CString): CPointer<DataList> | ||
| 34 | + | ||
| 35 | + func removeValuesForKeys_c(kv: UInt64, arrKeys: CPointer<DataList>): Unit | ||
| 36 | + func removeValueForKey_c(kv: UInt64, key: CString): Unit | ||
| 37 | + func clearAll_c(kv: UInt64): Unit | ||
| 38 | + func trim_c(kv: UInt64): Unit | ||
| 39 | + func close_c(kv: UInt64): Unit | ||
| 40 | + func sync_c(kv: UInt64, sync: Bool): Unit | ||
| 41 | + func clearMemoryCache_c(kv: UInt64): Unit | ||
| 42 | + | ||
| 43 | + func lock_c(kv: UInt64): Unit | ||
| 44 | + func unlock_c(kv: UInt64): Unit | ||
| 45 | + func tryLock_c(kv: UInt64): Bool | ||
| 46 | + | ||
| 47 | + func backupOne(mmapID: CString, dstDir: CString, srcDir: CString): Bool | ||
| 48 | + func restoreOne(mmapID: CString, srcDir: CString, dstDir: CString): Bool | ||
| 49 | + func backupAll(dstDir: CString, srcDir: CString): UInt64 | ||
| 50 | + func restoreAll(srcDir: CString, dstDir: CString): UInt64 | ||
| 51 | + | ||
| 52 | + func setLogLevel_c(level: MMKVLogLevel): Unit | ||
| 53 | + func setCallbackHandler(handler: MMKVHandler): Unit | ||
| 54 | + func isFileValid_c(mmapID: CString, rootPath: CString): Bool | ||
| 55 | + func pageSize_c(): Int64 | ||
| 56 | + | ||
| 57 | + func writeValueToBuffer_c(mmkv: UInt64, key: CString, ptr: CPointer<Unit>, size: Int32): Int32 | ||
| 58 | + func getValueSize_c(mmkv: UInt64, key: CString, actualSize: Bool): UInt64 | ||
| 59 | + func containsKey_c(mmkv: UInt64, key: CString): Bool | ||
| 60 | + func count_c(mmkv: UInt64): UInt64 | ||
| 61 | + func totalSize_c(mmkv: UInt64): UInt64 | ||
| 62 | + func actualSize_c(mmkv: UInt64): UInt64 | ||
| 63 | + func allKeys_c(mmkv: UInt64): CPointer<DataList> | ||
| 64 | + func mmapID_c(mmkv: UInt64): CString | ||
| 65 | + | ||
| 66 | + func cryptKey_c(mmkv: UInt64): CString | ||
| 67 | + func reKey_c(mmkv: UInt64, cryptKey: CString): Bool | ||
| 68 | + func checkReSetCryptKey_c(mmkv: UInt64, cryptKey: CString): Bool | ||
| 69 | + | ||
| 70 | + | ||
| 71 | + func getSizeofSize_t(): Int64 | ||
| 72 | + func malloc(size: UIntNative): CPointer<Unit> | ||
| 73 | + func free(ptr: CPointer<Unit>): Unit | ||
| 74 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package kv4cj | ||
| 6 | + | ||
| 7 | +internal import std.core.* | ||
| 8 | +internal import std.collection.* | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +package kv4cj | ||
| 6 | + | ||
| 7 | +/* | ||
| 8 | + * The class is MMKV exception handling | ||
| 9 | + */ | ||
| 10 | +public class MMKVException <: Exception { | ||
| 11 | + private var messages: String = "" | ||
| 12 | + public init() { | ||
| 13 | + super() | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + public init(messages: String) { | ||
| 17 | + super(messages) | ||
| 18 | + this.messages = messages | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public override func toString(): String { | ||
| 22 | + return "MMKVException: ${messages}" | ||
| 23 | + } | ||
| 24 | +} | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | +# the minimum version of CMake. | ||
| 2 | +cmake_minimum_required(VERSION 3.4.1) | ||
| 3 | +project(mmkv4cj) | ||
| 4 | + | ||
| 5 | +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 6 | + | ||
| 7 | +add_subdirectory(../../../../third_party/MMKV-1.3.6/Core Core) | ||
| 8 | + | ||
| 9 | +if(DEFINED PACKAGE_FIND_FILE) | ||
| 10 | + include(${PACKAGE_FIND_FILE}) | ||
| 11 | +endif() | ||
| 12 | + | ||
| 13 | +include_directories(${NATIVERENDER_ROOT_PATH} | ||
| 14 | + ${NATIVERENDER_ROOT_PATH}/include) | ||
| 15 | + | ||
| 16 | +add_library(mmkv4cj SHARED native-mmkv.cpp) | ||
| 17 | + | ||
| 18 | +set_target_properties(mmkv4cj PROPERTIES | ||
| 19 | + CXX_STANDARD 20 | ||
| 20 | + CXX_EXTENSIONS OFF | ||
| 21 | + POSITION_INDEPENDENT_CODE ON | ||
| 22 | + ) | ||
| 23 | + | ||
| 24 | +#add_compile_definitions(_WIN32) | ||
| 25 | + | ||
| 26 | +target_link_libraries(mmkv4cj PUBLIC | ||
| 27 | + libhilog_ndk.z.so | ||
| 28 | + core) | ||
| @@ -0,0 +1,813 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. | ||
| 3 | + * Description: MMKV for Cangjie API | ||
| 4 | + * Author: xwx1230846 | ||
| 5 | + * Create: 2023-04-12 | ||
| 6 | + * Notes: 2023-04-12 Create | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +extern "C" { | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +using namespace std; | ||
| 23 | +using namespace mmkv; | ||
| 24 | + | ||
| 25 | +static MMKVHandler gCallbackHandler; | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +static wchar_t *char2wchar(const char *cchar) | ||
| 29 | +{ | ||
| 30 | + wchar_t *m_wchar = nullptr; | ||
| 31 | + int len = MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), NULL, 0); | ||
| 32 | + if (len >= 0) { | ||
| 33 | + m_wchar= new wchar_t[len + 1]; | ||
| 34 | + } | ||
| 35 | + MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), m_wchar, len); | ||
| 36 | + m_wchar[len]= '\0'; | ||
| 37 | + return m_wchar; | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | + | ||
| 41 | +int64_t getSizeofSize_t() | ||
| 42 | +{ | ||
| 43 | + return sizeof(size_t); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +static void mmkvLog(MMKVLogLevel level, const char *file, int line, const char *function, MMKVLog_t message) | ||
| 47 | +{ | ||
| 48 | + if (gCallbackHandler.logHandler) { | ||
| 49 | + gCallbackHandler.logHandler(level, file, line, function, message.c_str()); | ||
| 50 | + } | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +static MMKVRecoverStrategic onMMKVError(const std::string &mmapID, MMKVErrorType errorType) | ||
| 54 | +{ | ||
| 55 | + if (errorType == MMKVCRCCheckFail) { | ||
| 56 | + if (gCallbackHandler.onMMKVCRCCheckFail) { | ||
| 57 | + MMKVRecoverStrategic ret = gCallbackHandler.onMMKVCRCCheckFail(mmapID.c_str()); | ||
| 58 | + return ret; | ||
| 59 | + } | ||
| 60 | + } else { | ||
| 61 | + if (gCallbackHandler.onMMKVFileLengthError) { | ||
| 62 | + MMKVRecoverStrategic ret = gCallbackHandler.onMMKVFileLengthError(mmapID.c_str()); | ||
| 63 | + return ret; | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + return OnErrorDiscard; | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +static void onMMKVContentChange(const string &mmapID) | ||
| 70 | +{ | ||
| 71 | + if (gCallbackHandler.onMMKVContentChange) { | ||
| 72 | + gCallbackHandler.onMMKVContentChange(mmapID.c_str()); | ||
| 73 | + } | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +void initializeMMKV_c(char *rootDir, int logLevel, MMKVHandler handler) | ||
| 77 | +{ | ||
| 78 | + | ||
| 79 | + wstring strRootDir(char2wchar(rootDir)); | ||
| 80 | + | ||
| 81 | + string strRootDir(rootDir); | ||
| 82 | + | ||
| 83 | + gCallbackHandler = handler; | ||
| 84 | + if (gCallbackHandler.logHandler) { | ||
| 85 | + MMKV::initializeMMKV(strRootDir, (MMKVLogLevel)logLevel, mmkvLog); | ||
| 86 | + } else { | ||
| 87 | + MMKV::initializeMMKV(strRootDir, (MMKVLogLevel)logLevel, nullptr); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + if (gCallbackHandler.onMMKVCRCCheckFail || gCallbackHandler.onMMKVFileLengthError) { | ||
| 91 | + MMKV::registerErrorHandler(onMMKVError); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + if (gCallbackHandler.onMMKVContentChange) { | ||
| 95 | + MMKV::registerContentChangeHandler(onMMKVContentChange); | ||
| 96 | + } | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +void onExit_c() | ||
| 100 | +{ | ||
| 101 | + MMKV::onExit(); | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +MMKV *defaultMMKV_c(MMKVMode mode, char *cryptKey) | ||
| 105 | +{ | ||
| 106 | + MMKV *kv = nullptr; | ||
| 107 | + | ||
| 108 | + if (cryptKey != NULL) { | ||
| 109 | + if (strlen(cryptKey) > 0) { | ||
| 110 | + string strCryptKey(cryptKey); | ||
| 111 | + kv = MMKV::defaultMMKV(mode, &strCryptKey); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + if (!kv) { | ||
| 116 | + kv = MMKV::defaultMMKV((MMKVMode) mode, nullptr); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + return kv; | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +MMKV *mmkvWithID_c(char *mmapID, MMKVMode mode, char *cryptKey, char *rootPath) | ||
| 123 | +{ | ||
| 124 | + MMKV *kv = nullptr; | ||
| 125 | + if (!mmapID) { | ||
| 126 | + return kv; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + string strMmapID(mmapID); | ||
| 130 | + | ||
| 131 | + if (cryptKey && strlen(cryptKey) > 0) { | ||
| 132 | + string strCryptKey(cryptKey); | ||
| 133 | + if (rootPath) { | ||
| 134 | + | ||
| 135 | + wstring strRootPath(char2wchar(rootPath)); | ||
| 136 | + | ||
| 137 | + string strRootPath(rootPath); | ||
| 138 | + | ||
| 139 | + kv = MMKV::mmkvWithID(strMmapID, mmkv::DEFAULT_MMAP_SIZE, (MMKVMode)mode, &strCryptKey, &strRootPath); | ||
| 140 | + } else { | ||
| 141 | + kv = MMKV::mmkvWithID(strMmapID, mmkv::DEFAULT_MMAP_SIZE, (MMKVMode)mode, &strCryptKey, nullptr); | ||
| 142 | + } | ||
| 143 | + } else { | ||
| 144 | + if (rootPath) { | ||
| 145 | + | ||
| 146 | + wstring strRootPath(char2wchar(rootPath)); | ||
| 147 | + | ||
| 148 | + string strRootPath(rootPath); | ||
| 149 | + | ||
| 150 | + kv = MMKV::mmkvWithID(strMmapID, mmkv::DEFAULT_MMAP_SIZE, (MMKVMode)mode, nullptr, &strRootPath); | ||
| 151 | + } else { | ||
| 152 | + kv = MMKV::mmkvWithID(strMmapID, mmkv::DEFAULT_MMAP_SIZE, (MMKVMode)mode, nullptr, nullptr); | ||
| 153 | + } | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + return kv; | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +bool setBool_c(MMKV *kv, char *key, bool value) | ||
| 160 | +{ | ||
| 161 | + if (kv && key) { | ||
| 162 | + string str_key(key); | ||
| 163 | + return kv->set(value, str_key); | ||
| 164 | + } | ||
| 165 | + return false; | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | +bool setInt32_t_c(MMKV *kv, char* key, int32_t value) | ||
| 169 | +{ | ||
| 170 | + if (kv && key) { | ||
| 171 | + string str_key(key); | ||
| 172 | + return kv->set(value, str_key); | ||
| 173 | + } | ||
| 174 | + return false; | ||
| 175 | +} | ||
| 176 | + | ||
| 177 | +bool setUint32_t_c(MMKV *kv, char* key, uint32_t value) | ||
| 178 | +{ | ||
| 179 | + if (kv && key) { | ||
| 180 | + string str_key(key); | ||
| 181 | + return kv->set(value, str_key); | ||
| 182 | + } | ||
| 183 | + return false; | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +bool setInt64_t_c(MMKV *kv, char* key, int64_t value) | ||
| 187 | +{ | ||
| 188 | + if (kv && key) { | ||
| 189 | + string str_key(key); | ||
| 190 | + return kv->set(value, str_key); | ||
| 191 | + } | ||
| 192 | + return false; | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +bool setUint64_t_c(MMKV *kv, char* key, uint64_t value) | ||
| 196 | +{ | ||
| 197 | + if (kv && key) { | ||
| 198 | + string str_key(key); | ||
| 199 | + return kv->set(value, str_key); | ||
| 200 | + } | ||
| 201 | + return false; | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +bool setFloat_c(MMKV *kv, char* key, float value) | ||
| 205 | +{ | ||
| 206 | + if (kv && key) { | ||
| 207 | + string str_key(key); | ||
| 208 | + return kv->set(value, str_key); | ||
| 209 | + } | ||
| 210 | + return false; | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +bool setDouble_c(MMKV *kv, char* key, double value) | ||
| 214 | +{ | ||
| 215 | + if (kv && key) { | ||
| 216 | + string str_key(key); | ||
| 217 | + return kv->set(value, str_key); | ||
| 218 | + } | ||
| 219 | + return false; | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +bool setString_c(MMKV *kv, char* key, char* value) | ||
| 223 | +{ | ||
| 224 | + if (kv && key) { | ||
| 225 | + string str_key(key); | ||
| 226 | + string str_value(value); | ||
| 227 | + return kv->set(str_value, str_key); | ||
| 228 | + } | ||
| 229 | + return false; | ||
| 230 | +} | ||
| 231 | + | ||
| 232 | +bool setBytes_c(MMKV *kv, char *key, byteArray *value) | ||
| 233 | +{ | ||
| 234 | + if (kv && key) { | ||
| 235 | + if (value) { | ||
| 236 | + MMBuffer buffer(0); | ||
| 237 | + buffer = MMBuffer(value->data, value->len); | ||
| 238 | + return kv->set(buffer, key); | ||
| 239 | + } else { | ||
| 240 | + kv->removeValueForKey(key); | ||
| 241 | + return true; | ||
| 242 | + } | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + return false; | ||
| 246 | +} | ||
| 247 | + | ||
| 248 | +bool setStringSet_c(MMKV *kv, char *key, DataList *value) | ||
| 249 | +{ | ||
| 250 | + vector<string> keys; | ||
| 251 | + | ||
| 252 | + if (kv && key) { | ||
| 253 | + if (value) { | ||
| 254 | + keys.reserve(value->size); | ||
| 255 | + for (size_t i = 0; i < value->size; i++) { | ||
| 256 | + string str(value->data[i].charArrayData); | ||
| 257 | + keys.push_back(str); | ||
| 258 | + } | ||
| 259 | + return kv->set(keys, key); | ||
| 260 | + } else { | ||
| 261 | + kv->removeValueForKey(key); | ||
| 262 | + return true; | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + return false; | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | +bool getBool_c(MMKV *kv, char *key, bool defaultValue) | ||
| 270 | +{ | ||
| 271 | + if (kv && key) { | ||
| 272 | + string str_key(key); | ||
| 273 | + return kv->getBool(str_key, defaultValue); | ||
| 274 | + } | ||
| 275 | + return defaultValue; | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | +int32_t getInt32_c(MMKV *kv, char *key, int32_t defaultValue) | ||
| 279 | +{ | ||
| 280 | + if (kv && key) { | ||
| 281 | + string str_key(key); | ||
| 282 | + return kv->getInt32(str_key, defaultValue); | ||
| 283 | + } | ||
| 284 | + return defaultValue; | ||
| 285 | +} | ||
| 286 | + | ||
| 287 | +uint32_t getUInt32_c(MMKV *kv, char *key, uint32_t defaultValue) | ||
| 288 | +{ | ||
| 289 | + if (kv && key) { | ||
| 290 | + string str_key(key); | ||
| 291 | + return kv->getUInt32(str_key, defaultValue); | ||
| 292 | + } | ||
| 293 | + return defaultValue; | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +int64_t getInt64_c(MMKV *kv, char *key, int64_t defaultValue) | ||
| 297 | +{ | ||
| 298 | + if (kv && key) { | ||
| 299 | + string str_key(key); | ||
| 300 | + return kv->getInt64(str_key, defaultValue); | ||
| 301 | + } | ||
| 302 | + return defaultValue; | ||
| 303 | +} | ||
| 304 | + | ||
| 305 | +uint64_t getUInt64_c(MMKV *kv, char *key, uint64_t defaultValue) | ||
| 306 | +{ | ||
| 307 | + if (kv && key) { | ||
| 308 | + string str_key(key); | ||
| 309 | + return kv->getUInt64(str_key, defaultValue); | ||
| 310 | + } | ||
| 311 | + return defaultValue; | ||
| 312 | +} | ||
| 313 | + | ||
| 314 | +float getFloat_c(MMKV *kv, char *key, float defaultValue) | ||
| 315 | +{ | ||
| 316 | + if (kv && key) { | ||
| 317 | + string str_key(key); | ||
| 318 | + return kv->getFloat(str_key, defaultValue); | ||
| 319 | + } | ||
| 320 | + return defaultValue; | ||
| 321 | +} | ||
| 322 | + | ||
| 323 | +double getDouble_c(MMKV *kv, char *key, double defaultValue) | ||
| 324 | +{ | ||
| 325 | + if (kv && key) { | ||
| 326 | + string str_key(key); | ||
| 327 | + return kv->getDouble(str_key, defaultValue); | ||
| 328 | + } | ||
| 329 | + return defaultValue; | ||
| 330 | +} | ||
| 331 | + | ||
| 332 | +char *getString_c(MMKV *kv, char *key) | ||
| 333 | +{ | ||
| 334 | + if (kv && key) { | ||
| 335 | + string str_key(key); | ||
| 336 | + string str_value; | ||
| 337 | + | ||
| 338 | + if (kv->getString(str_key, str_value)) { | ||
| 339 | + char *value = (char *)malloc(str_value.length() + 1); | ||
| 340 | + if (value == NULL) { | ||
| 341 | + return NULL; | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + | ||
| 345 | + if (strcpy_s(value, str_value.length() + 1, str_value.c_str()) != 0) { | ||
| 346 | + free(value); | ||
| 347 | + return NULL; | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + if (!strncpy(value, str_value.c_str(), str_value.length() + 1)) { | ||
| 351 | + free(value); | ||
| 352 | + return NULL; | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + return value; | ||
| 356 | + } | ||
| 357 | + } | ||
| 358 | + return NULL; | ||
| 359 | +} | ||
| 360 | + | ||
| 361 | +byteArray *getBytes_c(MMKV *kv, char *key) | ||
| 362 | +{ | ||
| 363 | + if (kv && key) { | ||
| 364 | + string strKey(key); | ||
| 365 | + MMBuffer value = kv->getBytes(strKey); | ||
| 366 | + byteArray *array = (byteArray *)malloc(sizeof(byteArray)); | ||
| 367 | + if (value.length() > 0) { | ||
| 368 | + array->data = malloc(value.length()); | ||
| 369 | + if (array->data == NULL) { | ||
| 370 | + return NULL; | ||
| 371 | + } | ||
| 372 | + | ||
| 373 | + memcpy_s(array->data, value.length(), value.getPtr(), value.length()); | ||
| 374 | + | ||
| 375 | + memcpy(array->data, value.getPtr(), value.length()); | ||
| 376 | + | ||
| 377 | + array->len = value.length(); | ||
| 378 | + return array; | ||
| 379 | + } | ||
| 380 | + } | ||
| 381 | + return NULL; | ||
| 382 | +} | ||
| 383 | + | ||
| 384 | +static void freeData(DataList *array, size_t cnt) | ||
| 385 | +{ | ||
| 386 | + for (size_t i = 0; i < cnt; i++) { | ||
| 387 | + free(array->data[i].charArrayData); | ||
| 388 | + } | ||
| 389 | +} | ||
| 390 | + | ||
| 391 | +static DataList *vector2array(const vector<string> &arr) | ||
| 392 | +{ | ||
| 393 | + DataList *array; | ||
| 394 | + size_t size; | ||
| 395 | + | ||
| 396 | + if (arr.size() == 0) { | ||
| 397 | + array = (DataList *)malloc(sizeof(DataList)); | ||
| 398 | + if (array == NULL) { | ||
| 399 | + return NULL; | ||
| 400 | + } | ||
| 401 | + } else { | ||
| 402 | + size = arr.size() + 1; | ||
| 403 | + array = (DataList *)malloc(size * getSizeofSize_t()); | ||
| 404 | + if (array == NULL) { | ||
| 405 | + return NULL; | ||
| 406 | + } | ||
| 407 | + } | ||
| 408 | + | ||
| 409 | + array->size = arr.size(); | ||
| 410 | + for (size_t i = 0; i < arr.size(); i++) { | ||
| 411 | + char *cstr = (char *)malloc(arr[i].length() + 1); | ||
| 412 | + | ||
| 413 | + if (strcpy_s(cstr, arr[i].length() + 1, arr[i].c_str()) != 0) { | ||
| 414 | + free(cstr); | ||
| 415 | + freeData(array, i); | ||
| 416 | + free(array); | ||
| 417 | + return NULL; | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + if (!strncpy(cstr, arr[i].c_str(), arr[i].length() + 1)) { | ||
| 421 | + free(cstr); | ||
| 422 | + freeData(array, i); | ||
| 423 | + free(array); | ||
| 424 | + return NULL; | ||
| 425 | + } | ||
| 426 | + | ||
| 427 | + array->data[i].charArrayData = cstr; | ||
| 428 | + } | ||
| 429 | + | ||
| 430 | + return array; | ||
| 431 | +} | ||
| 432 | + | ||
| 433 | +DataList *getStringSet_c(MMKV *kv, char *key) | ||
| 434 | +{ | ||
| 435 | + if (kv && key) { | ||
| 436 | + string strKey(key); | ||
| 437 | + vector<string> value; | ||
| 438 | + bool hasValue = kv->getVector(strKey, value); | ||
| 439 | + if (hasValue) { | ||
| 440 | + return vector2array(value); | ||
| 441 | + } | ||
| 442 | + } | ||
| 443 | + | ||
| 444 | + return NULL; | ||
| 445 | +} | ||
| 446 | + | ||
| 447 | +static vector<string> array2vector(DataList *arrList) | ||
| 448 | +{ | ||
| 449 | + vector<string> keys; | ||
| 450 | + if (arrList) { | ||
| 451 | + size_t size = arrList->size; | ||
| 452 | + keys.reserve(size); | ||
| 453 | + for (size_t i = 0; i < size; i++) { | ||
| 454 | + keys.push_back(arrList->data[i].charArrayData); | ||
| 455 | + } | ||
| 456 | + } | ||
| 457 | + | ||
| 458 | + return keys; | ||
| 459 | +} | ||
| 460 | + | ||
| 461 | +void removeValuesForKeys_c(MMKV *kv, DataList *arrKeys) | ||
| 462 | +{ | ||
| 463 | + if (kv && arrKeys) { | ||
| 464 | + vector<string> keys = array2vector(arrKeys); | ||
| 465 | + if (!keys.empty()) { | ||
| 466 | + kv->removeValuesForKeys(keys); | ||
| 467 | + } | ||
| 468 | + } | ||
| 469 | +} | ||
| 470 | + | ||
| 471 | +void removeValueForKey_c(MMKV *kv, char *key) | ||
| 472 | +{ | ||
| 473 | + if (kv) { | ||
| 474 | + kv->removeValueForKey(key); | ||
| 475 | + } | ||
| 476 | +} | ||
| 477 | + | ||
| 478 | +void clearAll_c(MMKV *kv) | ||
| 479 | +{ | ||
| 480 | + if (kv) { | ||
| 481 | + kv->clearAll(); | ||
| 482 | + } | ||
| 483 | +} | ||
| 484 | + | ||
| 485 | +// MMKV's size won't reduce after deleting key-values | ||
| 486 | +// call this method after lots of deleting if you care about disk usage | ||
| 487 | +// note that `clearAll` has the similar effect of `trim` | ||
| 488 | +void trim_c(MMKV *kv) | ||
| 489 | +{ | ||
| 490 | + if (kv) { | ||
| 491 | + kv->trim(); | ||
| 492 | + } | ||
| 493 | +} | ||
| 494 | + | ||
| 495 | +// call this method if the instance is no longer needed in the near future | ||
| 496 | +// any subsequent call to the instance is undefined behavior | ||
| 497 | +void close_c(MMKV *kv) | ||
| 498 | +{ | ||
| 499 | + if (kv) { | ||
| 500 | + kv->close(); | ||
| 501 | + } | ||
| 502 | +} | ||
| 503 | + | ||
| 504 | +void sync_c(MMKV *kv, bool sync) | ||
| 505 | +{ | ||
| 506 | + if (kv) { | ||
| 507 | + kv->sync((SyncFlag)sync); | ||
| 508 | + } | ||
| 509 | +} | ||
| 510 | + | ||
| 511 | +// call this method if you are facing memory-warning | ||
| 512 | +// any subsequent call to the instance will load all key-values from file again | ||
| 513 | +void clearMemoryCache_c(MMKV *kv) | ||
| 514 | +{ | ||
| 515 | + if (kv) { | ||
| 516 | + kv->clearMemoryCache(); | ||
| 517 | + } | ||
| 518 | +} | ||
| 519 | + | ||
| 520 | +void lock_c(MMKV *kv) | ||
| 521 | +{ | ||
| 522 | + if (kv) { | ||
| 523 | + kv->lock(); | ||
| 524 | + } | ||
| 525 | +} | ||
| 526 | + | ||
| 527 | +void unlock_c(MMKV *kv) | ||
| 528 | +{ | ||
| 529 | + if (kv) { | ||
| 530 | + kv->unlock(); | ||
| 531 | + } | ||
| 532 | +} | ||
| 533 | + | ||
| 534 | +bool tryLock_c(MMKV *kv) | ||
| 535 | +{ | ||
| 536 | + if (kv) { | ||
| 537 | + return kv->try_lock(); | ||
| 538 | + } | ||
| 539 | + | ||
| 540 | + return false; | ||
| 541 | +} | ||
| 542 | + | ||
| 543 | +static MMKVPath_t getString(char *value) | ||
| 544 | +{ | ||
| 545 | + | ||
| 546 | + return char2wchar(value); | ||
| 547 | + | ||
| 548 | + return value; | ||
| 549 | + | ||
| 550 | +} | ||
| 551 | + | ||
| 552 | +// backup one MMKV instance from srcDir to dstDir | ||
| 553 | +// if srcDir is null, then backup from the root dir of MMKV | ||
| 554 | +bool backupOne(char *mmapID, char *dstDir, char *srcDir) | ||
| 555 | +{ | ||
| 556 | + MMKVPath_t strdstDir = getString(dstDir); | ||
| 557 | + if (srcDir) { | ||
| 558 | + MMKVPath_t root = getString(srcDir); | ||
| 559 | + if (root.length() > 0) { | ||
| 560 | + return MMKV::backupOneToDirectory(mmapID, strdstDir, &root); | ||
| 561 | + } | ||
| 562 | + } | ||
| 563 | + return MMKV::backupOneToDirectory(mmapID, strdstDir); | ||
| 564 | +} | ||
| 565 | + | ||
| 566 | +// restore one MMKV instance from srcDir to dstDir | ||
| 567 | +// if dstDir is null, then restore to the root dir of MMKV | ||
| 568 | +bool restoreOne(char *mmapID, char *srcDir, char *dstDir) | ||
| 569 | +{ | ||
| 570 | + MMKVPath_t strSrcDir = getString(srcDir); | ||
| 571 | + if (dstDir) { | ||
| 572 | + MMKVPath_t root = getString(dstDir); | ||
| 573 | + if (root.length() > 0) { | ||
| 574 | + return MMKV::restoreOneFromDirectory(mmapID, strSrcDir, &root); | ||
| 575 | + } | ||
| 576 | + } | ||
| 577 | + return MMKV::restoreOneFromDirectory(mmapID, strSrcDir); | ||
| 578 | +} | ||
| 579 | + | ||
| 580 | +// backup all MMKV instance from srcDir to dstDir | ||
| 581 | +// if srcDir is null, then backup from the root dir of MMKV | ||
| 582 | +// return count of MMKV successfully backuped | ||
| 583 | +size_t backupAll(char *dstDir, char *srcDir) | ||
| 584 | +{ | ||
| 585 | + // historically Android mistakenly use mmapKey as mmapID | ||
| 586 | + // makes everything tricky with customize root | ||
| 587 | + MMKVPath_t strdstDir = getString(dstDir); | ||
| 588 | + if (srcDir) { | ||
| 589 | + MMKVPath_t root = getString(srcDir); | ||
| 590 | + if (root.length() > 0) { | ||
| 591 | + return MMKV::backupAllToDirectory(strdstDir, &root); | ||
| 592 | + } | ||
| 593 | + } | ||
| 594 | + return MMKV::backupAllToDirectory(strdstDir); | ||
| 595 | +} | ||
| 596 | + | ||
| 597 | +// restore all MMKV instance from srcDir to dstDir | ||
| 598 | +// if dstDir is null, then restore to the root dir of MMKV | ||
| 599 | +// return count of MMKV successfully restored | ||
| 600 | +size_t restoreAll(char *srcDir, char *dstDir) | ||
| 601 | +{ | ||
| 602 | + // historically Android mistakenly use mmapKey as mmapID | ||
| 603 | + // makes everything tricky with customize root | ||
| 604 | + MMKVPath_t strSrcDir = getString(srcDir); | ||
| 605 | + if (dstDir) { | ||
| 606 | + MMKVPath_t root = getString(dstDir); | ||
| 607 | + if (root.length() > 0) { | ||
| 608 | + return MMKV::restoreAllFromDirectory(strSrcDir, &root); | ||
| 609 | + } | ||
| 610 | + } | ||
| 611 | + return MMKV::restoreAllFromDirectory(strSrcDir); | ||
| 612 | +} | ||
| 613 | + | ||
| 614 | +// check if content been changed by other process | ||
| 615 | +void checkContentChanged_c(MMKV *kv) | ||
| 616 | +{ | ||
| 617 | + if (kv) { | ||
| 618 | + kv->checkContentChanged(); | ||
| 619 | + } | ||
| 620 | +} | ||
| 621 | + | ||
| 622 | +// MMKVLogInfo by default | ||
| 623 | +// pass MMKVLogNone to disable all logging | ||
| 624 | +void setLogLevel_c(MMKVLogLevel level) | ||
| 625 | +{ | ||
| 626 | + MMKV::setLogLevel(level); | ||
| 627 | +} | ||
| 628 | + | ||
| 629 | +void setCallbackHandler(MMKVHandler handler) | ||
| 630 | +{ | ||
| 631 | + gCallbackHandler = handler; | ||
| 632 | + if (gCallbackHandler.logHandler) { | ||
| 633 | + MMKV::registerLogHandler(mmkvLog); | ||
| 634 | + } else { | ||
| 635 | + MMKV::unRegisterLogHandler(); | ||
| 636 | + } | ||
| 637 | + | ||
| 638 | + if (gCallbackHandler.onMMKVCRCCheckFail || gCallbackHandler.onMMKVFileLengthError) { | ||
| 639 | + MMKV::registerErrorHandler(onMMKVError); | ||
| 640 | + } else { | ||
| 641 | + MMKV::unRegisterErrorHandler(); | ||
| 642 | + } | ||
| 643 | + | ||
| 644 | + if (gCallbackHandler.onMMKVContentChange) { | ||
| 645 | + MMKV::registerContentChangeHandler(onMMKVContentChange); | ||
| 646 | + } else { | ||
| 647 | + MMKV::unRegisterContentChangeHandler(); | ||
| 648 | + } | ||
| 649 | +} | ||
| 650 | + | ||
| 651 | +// detect if the MMKV file is valid or not | ||
| 652 | +// Note: Don't use this to check the existence of the instance, | ||
| 653 | +// the return value is undefined if the file was never created. | ||
| 654 | +bool isFileValid_c(const char *mmapID, char *relatePath) | ||
| 655 | +{ | ||
| 656 | + const string strMmapID(mmapID); | ||
| 657 | + if (relatePath) { | ||
| 658 | + | ||
| 659 | + wstring strRelatePath(char2wchar(relatePath)); | ||
| 660 | + | ||
| 661 | + string strRelatePath(relatePath); | ||
| 662 | + | ||
| 663 | + return MMKV::isFileValid(strMmapID, &strRelatePath); | ||
| 664 | + } else { | ||
| 665 | + return MMKV::isFileValid(strMmapID, nullptr); | ||
| 666 | + } | ||
| 667 | +} | ||
| 668 | + | ||
| 669 | +size_t pageSize_c() | ||
| 670 | +{ | ||
| 671 | + return DEFAULT_MMAP_SIZE; | ||
| 672 | +} | ||
| 673 | + | ||
| 674 | +const char *version_c() | ||
| 675 | +{ | ||
| 676 | + return MMKV_VERSION; | ||
| 677 | +} | ||
| 678 | + | ||
| 679 | +int32_t writeValueToBuffer_c(MMKV *kv, char* key, void *ptr, int32_t size) | ||
| 680 | +{ | ||
| 681 | + if (kv && key && ptr != NULL) { | ||
| 682 | + string strkey(key); | ||
| 683 | + return kv->writeValueToBuffer(strkey, ptr, size); | ||
| 684 | + } | ||
| 685 | + return -1; | ||
| 686 | +} | ||
| 687 | + | ||
| 688 | +size_t getValueSize_c(MMKV *kv, char* key, bool actualSize) | ||
| 689 | +{ | ||
| 690 | + if (kv && key) { | ||
| 691 | + string strkey(key); | ||
| 692 | + return kv->getValueSize(strkey, actualSize); | ||
| 693 | + } | ||
| 694 | + return 0; | ||
| 695 | +} | ||
| 696 | + | ||
| 697 | +bool containsKey_c(MMKV *kv, char* key) | ||
| 698 | +{ | ||
| 699 | + if (kv && key) { | ||
| 700 | + string strkey(key); | ||
| 701 | + return kv->containsKey(strkey); | ||
| 702 | + } | ||
| 703 | + return false; | ||
| 704 | +} | ||
| 705 | + | ||
| 706 | +size_t count_c(MMKV* kv) | ||
| 707 | +{ | ||
| 708 | + if (kv) { | ||
| 709 | + return kv->count(); | ||
| 710 | + } | ||
| 711 | + return 0; | ||
| 712 | +} | ||
| 713 | + | ||
| 714 | +size_t totalSize_c(MMKV* kv) | ||
| 715 | +{ | ||
| 716 | + if (kv) { | ||
| 717 | + return kv->totalSize(); | ||
| 718 | + } | ||
| 719 | + return 0; | ||
| 720 | +} | ||
| 721 | + | ||
| 722 | +size_t actualSize_c(MMKV* kv) | ||
| 723 | +{ | ||
| 724 | + if (kv) { | ||
| 725 | + return kv->actualSize(); | ||
| 726 | + } | ||
| 727 | + return 0; | ||
| 728 | +} | ||
| 729 | + | ||
| 730 | +DataList *allKeys_c(MMKV* kv) | ||
| 731 | +{ | ||
| 732 | + if (kv) { | ||
| 733 | + vector<string> value = kv->allKeys(); | ||
| 734 | + return vector2array(value); | ||
| 735 | + } | ||
| 736 | + return NULL; | ||
| 737 | +} | ||
| 738 | + | ||
| 739 | +char* mmapID_c(MMKV* kv) | ||
| 740 | +{ | ||
| 741 | + if (kv) { | ||
| 742 | + string str_mmid = kv->mmapID(); | ||
| 743 | + char* char_mmid = (char*)malloc(str_mmid.length() + 1); | ||
| 744 | + if (char_mmid != NULL) { | ||
| 745 | + | ||
| 746 | + if (strcpy_s(char_mmid, str_mmid.length() + 1, str_mmid.c_str()) != 0) { | ||
| 747 | + free(char_mmid); | ||
| 748 | + return NULL; | ||
| 749 | + } | ||
| 750 | + | ||
| 751 | + if (!strncpy(char_mmid, str_mmid.c_str(), str_mmid.length() + 1)) { | ||
| 752 | + free(char_mmid); | ||
| 753 | + return NULL; | ||
| 754 | + } | ||
| 755 | + | ||
| 756 | + return char_mmid; | ||
| 757 | + } | ||
| 758 | + } | ||
| 759 | + return NULL; | ||
| 760 | +} | ||
| 761 | + | ||
| 762 | +char *cryptKey_c(MMKV* kv) | ||
| 763 | +{ | ||
| 764 | + if (kv) { | ||
| 765 | + string str_cryptkey = kv->cryptKey(); | ||
| 766 | + char *char_cryptkey = (char*)malloc(str_cryptkey.length() + 1); | ||
| 767 | + if (char_cryptkey != NULL) { | ||
| 768 | + | ||
| 769 | + if (strcpy_s(char_cryptkey, str_cryptkey.length() + 1, str_cryptkey.c_str()) != 0) { | ||
| 770 | + free(char_cryptkey); | ||
| 771 | + return NULL; | ||
| 772 | + } | ||
| 773 | + | ||
| 774 | + if (!strncpy(char_cryptkey, str_cryptkey.c_str(), str_cryptkey.length() + 1)) { | ||
| 775 | + free(char_cryptkey); | ||
| 776 | + return NULL; | ||
| 777 | + } | ||
| 778 | + | ||
| 779 | + return char_cryptkey; | ||
| 780 | + } | ||
| 781 | + } | ||
| 782 | + return NULL; | ||
| 783 | +} | ||
| 784 | + | ||
| 785 | +bool reKey_c(MMKV *kv, char *cryptKey) | ||
| 786 | +{ | ||
| 787 | + if (kv) { | ||
| 788 | + if (cryptKey) { | ||
| 789 | + string str_cryptKey0(cryptKey); | ||
| 790 | + return kv->reKey(str_cryptKey0); | ||
| 791 | + } else { | ||
| 792 | + string str_cryptKey1(""); | ||
| 793 | + return kv->reKey(str_cryptKey1); | ||
| 794 | + } | ||
| 795 | + } | ||
| 796 | + return false; | ||
| 797 | +} | ||
| 798 | + | ||
| 799 | +void checkReSetCryptKey_c(MMKV *kv, char *cryptKey) | ||
| 800 | +{ | ||
| 801 | + if (kv) { | ||
| 802 | + if (cryptKey) { | ||
| 803 | + string str_cryptKey(cryptKey); | ||
| 804 | + kv->checkReSetCryptKey(&str_cryptKey); | ||
| 805 | + } else { | ||
| 806 | + kv->checkReSetCryptKey(NULL); | ||
| 807 | + } | ||
| 808 | + } | ||
| 809 | +} | ||
| 810 | + | ||
| 811 | + | ||
| 812 | +} | ||
| 813 | + | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. | ||
| 3 | + * Description: MMKV for Cangjie API | ||
| 4 | + * Author: xwx1230846 | ||
| 5 | + * Create: 2023-04-12 | ||
| 6 | + * Notes: 2023-04-12 Create | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +extern "C" { | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +extern int memcpy_s(void *dest, uint32_t destsz, const void *src, uint32_t count); | ||
| 23 | +extern int strcpy_s(char *dest, uint32_t destsz, const char *src); | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +typedef struct { | ||
| 27 | + size_t len; | ||
| 28 | + void *data; | ||
| 29 | +}byteArray; | ||
| 30 | + | ||
| 31 | +typedef struct { | ||
| 32 | + size_t size; | ||
| 33 | + union data_t { | ||
| 34 | + byteArray *byteArrayData; | ||
| 35 | + char *charArrayData; | ||
| 36 | + }data[1]; | ||
| 37 | +}DataList; | ||
| 38 | + | ||
| 39 | +typedef void (*LogHandler4Cj)(MMKVLogLevel level, const char *file, int line, const char *function, | ||
| 40 | + const char *message); | ||
| 41 | +typedef MMKVRecoverStrategic (*ErrorHandler4Cj)(const char *mmapID); | ||
| 42 | +typedef void (*ContentChangeHandler4Cj)(const char *mmapID); | ||
| 43 | + | ||
| 44 | +typedef struct { | ||
| 45 | + LogHandler4Cj logHandler; | ||
| 46 | + ErrorHandler4Cj onMMKVCRCCheckFail; | ||
| 47 | + ErrorHandler4Cj onMMKVFileLengthError; | ||
| 48 | + ContentChangeHandler4Cj onMMKVContentChange; | ||
| 49 | +}MMKVHandler; | ||
| 50 | + | ||
| 51 | +extern int64_t getSizeofSize_t(); | ||
| 52 | + | ||
| 53 | + | ||
| 54 | +} | ||
| 55 | + | ||
| @@ -0,0 +1 @@ | |||
| 1 | +export {} | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +{ | ||
| 2 | + "name": "libmmkv4cj.so", | ||
| 3 | + "types": "./Index.d.ts", | ||
| 4 | + "version": "1.0.0", | ||
| 5 | + "description": "MMKV native library for Cangjie" | ||
| 6 | +} | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | +{ | ||
| 2 | + "module": { | ||
| 3 | + "name": "MMKV", | ||
| 4 | + "type": "har", | ||
| 5 | + "deviceTypes": [ | ||
| 6 | + "default" | ||
| 7 | + ] | ||
| 8 | + } | ||
| 9 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +{ | ||
| 2 | + "string": [ | ||
| 3 | + { | ||
| 4 | + "name": "page_show", | ||
| 5 | + "value": "page from npm package" | ||
| 6 | + } | ||
| 7 | + ] | ||
| 8 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +{ | ||
| 2 | + "string": [ | ||
| 3 | + { | ||
| 4 | + "name": "page_show", | ||
| 5 | + "value": "page from npm package" | ||
| 6 | + } | ||
| 7 | + ] | ||
| 8 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +{ | ||
| 2 | + "string": [ | ||
| 3 | + { | ||
| 4 | + "name": "page_show", | ||
| 5 | + "value": "page from npm package" | ||
| 6 | + } | ||
| 7 | + ] | ||
| 8 | +} | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | +package ohos_app_cangjie_MMKV_test | ||
| 2 | + | ||
| 3 | +internal import ohos.ability.AbilityStage | ||
| 4 | + | ||
| 5 | +class MyAbilityStage <: AbilityStage { | ||
| 6 | + public override func onCreate(): Unit { | ||
| 7 | + AppLog.info("MyAbilityStage onCreated.") | ||
| 8 | + } | ||
| 9 | +} | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | +[package] | ||
| 2 | + cjc-version = "0.48.2" | ||
| 3 | + compile-option = "--dy-std --cfg=\"${COMPILE_CONDITION}\"" | ||
| 4 | + description = "CangjieUI Application" | ||
| 5 | + link-option = "" | ||
| 6 | + name = "ohos_app_cangjie_MMKV_test" | ||
| 7 | + output-type = "dynamic" | ||
| 8 | + src-dir = "." | ||
| 9 | + target-dir = "" | ||
| 10 | + version = "1.0.0" | ||
| 11 | + package-configuration = {} | ||
| 12 | + scripts = {} | ||
| 13 | + | ||
| 14 | +[dependencies] | ||
| 15 | + [dependencies.ohos_app_cangjie_MMKV] | ||
| 16 | + path = "../../../" | ||
| 17 | + version = "1.0.0" | ||
| 18 | + | ||
| 19 | +[profile] | ||
| 20 | + [profile.build] | ||
| 21 | + incremental = true | ||
| 22 | + lto = "" | ||
| 23 | + [profile.customized-option] | ||
| 24 | + debug = "-g -Woff all -Won apilevel-check" | ||
| 25 | + release = "--fast-math -O2 -s -Woff all -Won apilevel-check" | ||
| 26 | + withoutCoverage = "--cfg=\"coverage=false\"" | ||
| 27 | + withCoverage = "--cfg=\"coverage=true\"" | ||
| 28 | + [profile.test] | ||
| 29 | + | ||
| 30 | +[target.aarch64-linux-ohos] | ||
| 31 | + compile-option = "-B \"${DEVECO_CANGJIE_HOME}/compiler/third_party/llvm/bin\" -B \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/clang/15.0.4/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/aarch64-linux-ohos\" -L \"${DEVECO_CANGJIE_HOME}/build/linux_ohos_aarch64_llvm/openssl\" --sysroot \"${DEVECO_OH_NATIVE_HOME}/sysroot\"" | ||
| 32 | +[target.aarch64-linux-ohos.bin-dependencies] | ||
| 33 | + path-option = ["${AARCH64_LIBS}", "${AARCH64_MACRO_LIBS}", "${AARCH64_KIT_LIBS}"] | ||
| 34 | + package-option = {} | ||
| 35 | + | ||
| 36 | +[target.x86_64-linux-ohos] | ||
| 37 | + compile-option = "-B \"${DEVECO_CANGJIE_HOME}/compiler/third_party/llvm/bin\" -B \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/clang/15.0.4/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/x86_64-linux-ohos\" -L \"${DEVECO_CANGJIE_HOME}/build/linux_ohos_x86_64_llvm/openssl\" --sysroot \"${DEVECO_OH_NATIVE_HOME}/sysroot\"" | ||
| 38 | +[target.x86_64-linux-ohos.bin-dependencies] | ||
| 39 | + path-option = ["${X86_64_OHOS_LIBS}", "${X86_64_OHOS_MACRO_LIBS}", "${X86_64_OHOS_KIT_LIBS}"] | ||
| 40 | + | ||
| 41 | +[target.x86_64-unknown-windows-gnu.bin-dependencies] | ||
| 42 | + path-option = ["${X86_64_LIBS}", "${X86_64_MACRO_LIBS}"] | ||
| 43 | + package-option = {} | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | +/** | ||
| 2 | + * Created on 2025/2/26 | ||
| 3 | + */ | ||
| 4 | +package ohos_app_cangjie_MMKV_test | ||
| 5 | + | ||
| 6 | +import std.unittest.expectEqual | ||
| 7 | +import std.unittest.testmacro.Expect | ||
| 8 | + | ||
| 9 | +func unittest() { | ||
| 10 | + let a = "abc" | ||
| 11 | + let b = "b" | ||
| 12 | + @Expect(a.contains(b)) | ||
| 13 | + @Expect(a, a) | ||
| 14 | +} | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | +package ohos_app_cangjie_MMKV_test | ||
| 2 | + | ||
| 3 | +import std.unittest.TestClass | ||
| 4 | +import std.unittest.TestPackage | ||
| 5 | +import std.unittest.TestSuite | ||
| 6 | +import std.unittest.UnitTestCase | ||
| 7 | +import std.unittest.common.Configuration | ||
| 8 | +import std.unittest.testmacro.Test | ||
| 9 | +import std.unittest.testmacro.TestCase | ||
| 10 | + | ||
| 11 | +@Test | ||
| 12 | +class TestExample00 { | ||
| 13 | + @TestCase | ||
| 14 | + func test00(): Unit { | ||
| 15 | + unittest() | ||
| 16 | + } | ||
| 17 | +} | ||
| @@ -0,0 +1,36 @@ | |||
| 1 | +package ohos_app_cangjie_MMKV_test | ||
| 2 | + | ||
| 3 | +internal import ohos.base.LengthProp | ||
| 4 | +internal import ohos.component.Column | ||
| 5 | +internal import ohos.component.Row | ||
| 6 | +internal import ohos.component.Text | ||
| 7 | +internal import ohos.component.CustomView | ||
| 8 | +internal import ohos.component.CJEntry | ||
| 9 | +internal import ohos.component.loadNativeView | ||
| 10 | +internal import ohos.component.FontWeight | ||
| 11 | +internal import ohos.state_manage.SubscriberManager | ||
| 12 | +internal import ohos.state_manage.ObservedProperty | ||
| 13 | +internal import ohos.state_manage.LocalStorage | ||
| 14 | +import ohos.state_macro_manage.Entry | ||
| 15 | +import ohos.state_macro_manage.Component | ||
| 16 | +import ohos.state_macro_manage.State | ||
| 17 | + | ||
| 18 | +@Entry | ||
| 19 | +@Component | ||
| 20 | +class MMKVView { | ||
| 21 | + @State | ||
| 22 | + var message: String = "Hello World" | ||
| 23 | + | ||
| 24 | + func build() { | ||
| 25 | + Row { | ||
| 26 | + Column { | ||
| 27 | + Text(this.message) | ||
| 28 | + .fontSize(50) | ||
| 29 | + .fontWeight(FontWeight.Bold) | ||
| 30 | + .onClick { | ||
| 31 | + evt => this.message = "Hello Cangjie" | ||
| 32 | + } | ||
| 33 | + }.width(100.percent) | ||
| 34 | + }.height(100.percent) | ||
| 35 | + } | ||
| 36 | +} | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | +package ohos_app_cangjie_MMKV_test | ||
| 2 | + | ||
| 3 | +import ohos_app_cangjie_MMKV_test.unittest_support.registerTestSuite | ||
| 4 | + | ||
| 5 | +private let register = testsuite() | ||
| 6 | + | ||
| 7 | +func testsuite() { | ||
| 8 | + registerTestSuite {TestExample00()} | ||
| 9 | +} | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | +package ohos_app_cangjie_MMKV_test | ||
| 2 | + | ||
| 3 | +internal import ohos.base.AppLog | ||
| 4 | +internal import ohos.ability.Want | ||
| 5 | +internal import ohos.ability.UIAbility | ||
| 6 | +internal import ohos.ability.LaunchParam | ||
| 7 | +internal import ohos.ability.LaunchReason | ||
| 8 | +internal import ohos.window.WindowStage | ||
| 9 | + | ||
| 10 | +class MainAbility <: UIAbility { | ||
| 11 | + public init() { | ||
| 12 | + super() | ||
| 13 | + registerSelf() | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + public override func onCreate(want: Want, launchParam: LaunchParam): Unit { | ||
| 17 | + AppLog.info("MainAbility OnCreated.${want.abilityName}") | ||
| 18 | + match (launchParam.launchReason) { | ||
| 19 | + case LaunchReason.START_ABILITY => AppLog.info("START_ABILITY") | ||
| 20 | + case _ => () | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + public override func onWindowStageCreate(windowStage: WindowStage): Unit { | ||
| 25 | + AppLog.info("MainAbility onWindowStageCreate.") | ||
| 26 | + windowStage.loadContent("MMKVView") | ||
| 27 | + } | ||
| 28 | +} | ||
| @@ -0,0 +1,247 @@ | |||
| 1 | +package ohos_app_cangjie_MMKV_test.unittest_support | ||
| 2 | + | ||
| 3 | +import ohos.test_runner.TestRunner | ||
| 4 | +import ohos.hilog.HilogChannel | ||
| 5 | +import ohos.ability_delegator_registry.AbilityDelegatorRegistry | ||
| 6 | +import std.unittest.XmlReporter | ||
| 7 | +import std.fs.Path | ||
| 8 | +import std.fs.Directory | ||
| 9 | +import std.collection.filter | ||
| 10 | +import std.fs.FileInfo | ||
| 11 | +import std.collection.first | ||
| 12 | +import std.fs.File | ||
| 13 | +import std.collection.forEach | ||
| 14 | +import std.convert.Parsable | ||
| 15 | +import ohos.bundle_manager.BundleManager | ||
| 16 | +import ohos.bundle_manager.BundleFlag | ||
| 17 | +import std.collection.any | ||
| 18 | +import std.collection.HashMap | ||
| 19 | +import std.unittest.TestClass | ||
| 20 | +import std.collection.ArrayList | ||
| 21 | +import std.unittest.TestSuite | ||
| 22 | +import ohos.ability.Want | ||
| 23 | +import std.process.Process | ||
| 24 | +import ohos.ui_test.UITest | ||
| 25 | +import std.unittest.common.Configuration | ||
| 26 | + | ||
| 27 | +@When[coverage == "true"] | ||
| 28 | +foreign func __gcov_dump(): Unit | ||
| 29 | + | ||
| 30 | +@When[coverage == "true"] | ||
| 31 | +public func gcov_dump(coveragePath: String): Unit { | ||
| 32 | + let logger = HilogChannel(0, 0, "CangjieTest") | ||
| 33 | + logger.info("execute test with coverage") | ||
| 34 | + unsafe { __gcov_dump() } | ||
| 35 | + let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() | ||
| 36 | + abilityDelegator.print("GENERATE_COVERAGE: ${coveragePath}") | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +@When[coverage == "false"] | ||
| 40 | +public func gcov_dump(coveragePath: String): Unit { | ||
| 41 | + let logger = HilogChannel(0, 0, "CangjieTest") | ||
| 42 | + logger.info("execute test without coverage") | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +public func registerTestSuite(testClassInstanceGenerator: () -> TestClass): Unit { | ||
| 46 | + OpenHarmonyTestRunner | ||
| 47 | + .testClassInstanceGenerators | ||
| 48 | + .add(testClassInstanceGenerator) | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +public class OpenHarmonyTestRunner <: TestRunner { | ||
| 52 | + private static let logger = HilogChannel(0, 0, "CangjieTest") | ||
| 53 | + public static let testSuiteMap = HashMap<String, TestSuite>() | ||
| 54 | + public static let testClassInstanceGenerators = ArrayList<() -> TestClass>() | ||
| 55 | + private static func getDetailedInfoOf(e: Exception): String { | ||
| 56 | + let sb = StringBuilder("exception: ${e.toString()}\n") | ||
| 57 | + e.getStackTrace() |> | ||
| 58 | + forEach { | ||
| 59 | + s => sb.append(" at ${s.declaringClass}.${s.methodName}(${s.fileName}:${s.lineNumber})\n") | ||
| 60 | + } | ||
| 61 | + sb.toString() | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + private func executeTestClass(testClassName: String): Unit { | ||
| 65 | + let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() | ||
| 66 | + logger.info("EXECUTE_CLASS_START: \"${testClassName}\"") | ||
| 67 | + abilityDelegator.print("EXECUTE_CLASS_START: \"${testClassName}\"") | ||
| 68 | + let testSuite = match (OpenHarmonyTestRunner | ||
| 69 | + .testSuiteMap | ||
| 70 | + .get(testClassName)) { | ||
| 71 | + case None => return | ||
| 72 | + case Some(testClassInstanceGenerator) => testClassInstanceGenerator | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + testSuite | ||
| 76 | + .runTests() | ||
| 77 | + .reportTo(XmlReporter(Path("/data/storage/el1/base"))) | ||
| 78 | + | ||
| 79 | + let testReportXmlFileName = "test-default.${testClassName}.xml" | ||
| 80 | + match (Directory.readFrom("/data/storage/el1/base/tests") |> | ||
| 81 | + filter {fileInfo => fileInfo.name == testReportXmlFileName} |> first) { | ||
| 82 | + case None => logger.error("${testReportXmlFileName} not found.") | ||
| 83 | + case Some(testReportXmlFileInfo) => | ||
| 84 | + let testReportXmlFilePath = testReportXmlFileInfo.path | ||
| 85 | + let testReportXmlFileContent = File.readFrom(testReportXmlFilePath) | ||
| 86 | + let xmlReport = String.fromUtf8(testReportXmlFileContent) | ||
| 87 | + logger.info("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}") | ||
| 88 | + logger.info(xmlReport) | ||
| 89 | + abilityDelegator.print("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}") | ||
| 90 | + abilityDelegator.print(xmlReport) | ||
| 91 | + logger.info("EXECUTE_CLASS_END: \"${testClassName}\"") | ||
| 92 | + abilityDelegator.print("EXECUTE_CLASS_END: \"${testClassName}\"") | ||
| 93 | + reportTestReport("test-default.${testClassName}.xml") | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + private func executeAllTestClasses(): Unit { | ||
| 97 | + for (testClassName in OpenHarmonyTestRunner | ||
| 98 | + .testSuiteMap | ||
| 99 | + .keys()) { | ||
| 100 | + executeTestClass(testClassName) | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + private func executeTestCase(testClassName: String, testCaseName: String): Unit { | ||
| 104 | + let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() | ||
| 105 | + abilityDelegator.print("EXECUTE_CLASS_START: \"${testClassName}\"") | ||
| 106 | + logger.info("EXECUTE_METHOD_START: \"${testClassName}#${testCaseName}\"") | ||
| 107 | + let testSuite = match (OpenHarmonyTestRunner | ||
| 108 | + .testSuiteMap | ||
| 109 | + .get(testClassName)) { | ||
| 110 | + case None => return | ||
| 111 | + case Some(testClassInstanceGenerator) => testClassInstanceGenerator | ||
| 112 | + } | ||
| 113 | + let configuration = Configuration() | ||
| 114 | + configuration.setByName("filter", "${testClassName}.${testCaseName}") | ||
| 115 | + testSuite | ||
| 116 | + .runTests(configuration) | ||
| 117 | + .reportTo(XmlReporter(Path("/data/storage/el1/base"))) | ||
| 118 | + | ||
| 119 | + let testReportXmlFileName = "test-default.${testClassName}.xml" | ||
| 120 | + match (Directory.readFrom("/data/storage/el1/base/tests") |> | ||
| 121 | + filter {fileInfo => fileInfo.name == testReportXmlFileName} |> first) { | ||
| 122 | + case None => logger.error("${testReportXmlFileName} not found.") | ||
| 123 | + case Some(testReportXmlFileInfo) => | ||
| 124 | + let testReportXmlFilePath = testReportXmlFileInfo.path | ||
| 125 | + let testReportXmlFileContent = File.readFrom(testReportXmlFilePath) | ||
| 126 | + let xmlReport = String.fromUtf8(testReportXmlFileContent) | ||
| 127 | + logger.info("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}") | ||
| 128 | + logger.info(xmlReport) | ||
| 129 | + abilityDelegator.print("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}") | ||
| 130 | + abilityDelegator.print(xmlReport) | ||
| 131 | + logger.info("EXECUTE_METHOD_END: \"${testClassName}#${testCaseName}\"") | ||
| 132 | + abilityDelegator.print("EXECUTE_CLASS_END: \"${testClassName}\"") | ||
| 133 | + reportTestReport("test-default.${testClassName}.xml") | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | + private func reportTestReport(testReportName: String): Unit { | ||
| 137 | + let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() | ||
| 138 | + let abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() | ||
| 139 | + let bundleName = abilityDelegatorArguments.bundleName | ||
| 140 | + abilityDelegator.print("REPORT_TEST_RESULT: /data/app/el1/100/base/${bundleName}/tests/${testReportName}") | ||
| 141 | + } | ||
| 142 | + public override func onPrepare(): Unit { | ||
| 143 | + logger.info("OpenHarmonyTestRunner onPrepare") | ||
| 144 | + for (testClassInstanceGenerator in OpenHarmonyTestRunner.testClassInstanceGenerators) { | ||
| 145 | + let testClassInstance = try { | ||
| 146 | + testClassInstanceGenerator() | ||
| 147 | + } catch (e: Exception) { | ||
| 148 | + logger.error("exception occurred during testsuite generation:\n${getDetailedInfoOf(e)}") | ||
| 149 | + continue | ||
| 150 | + } | ||
| 151 | + let testSuite = testClassInstance.asTestSuite() | ||
| 152 | + let testSuiteName = testSuite.name | ||
| 153 | + logger.info("Registering TestSuite ${testSuiteName}") | ||
| 154 | + OpenHarmonyTestRunner | ||
| 155 | + .testSuiteMap | ||
| 156 | + .add(testSuiteName, testSuite) | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | + public override func onRun(): Unit { | ||
| 160 | + logger.info("OpenHarmonyTestRunner onRun") | ||
| 161 | + let abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() | ||
| 162 | + let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() | ||
| 163 | + UITest.setup() | ||
| 164 | + logger.info("bundleName = ${abilityDelegatorArguments.bundleName}") | ||
| 165 | + logger.info("abilityDelegatorArguments.testRunnerClassName = ${abilityDelegatorArguments.testRunnerClassName}") | ||
| 166 | + logger.info("abilityDelegatorArguments.testCaseNames = ${abilityDelegatorArguments.testCaseNames}") | ||
| 167 | + logger.info("abilityDelegatorArguments.parameters = ${abilityDelegatorArguments.parameters}") | ||
| 168 | + logger.info("Started running tests.") | ||
| 169 | + abilityDelegator.print("OpenHarmonyTestRunner onRun") | ||
| 170 | + let parameters = abilityDelegatorArguments.parameters | ||
| 171 | + let bundleName = abilityDelegatorArguments.bundleName | ||
| 172 | + let bundleInfo = BundleManager.getBundleInfoForSelf( | ||
| 173 | + BundleFlag | ||
| 174 | + .GET_BUNDLE_INFO_WITH_HAP_MODULE | ||
| 175 | + .getValue() | BundleFlag | ||
| 176 | + .GET_BUNDLE_INFO_WITH_APPLICATION | ||
| 177 | + .getValue()) | ||
| 178 | + let moduleName = match (parameters.get("-m")) { | ||
| 179 | + case None => | ||
| 180 | + abilityDelegator.finishTest("Module name was not specified.", -1) | ||
| 181 | + return | ||
| 182 | + case Some(moduleName) => | ||
| 183 | + if (bundleInfo.hapModulesInfo |> any {hapModuleInfo => hapModuleInfo.name == moduleName}) { | ||
| 184 | + moduleName | ||
| 185 | + } else { | ||
| 186 | + abilityDelegator.finishTest( | ||
| 187 | + "No module with name \"${moduleName}\" was found in bundle ${bundleName}.", -1) | ||
| 188 | + return | ||
| 189 | + } | ||
| 190 | + } | ||
| 191 | + let abilityName = match (bundleInfo.hapModulesInfo |> filter {hapModuleInfo => hapModuleInfo.name == moduleName} |> | ||
| 192 | + first) { | ||
| 193 | + case None => | ||
| 194 | + abilityDelegator.finishTest("No module with name \"${moduleName}\" was found in bundle ${bundleName}.", | ||
| 195 | + -1) | ||
| 196 | + return | ||
| 197 | + case Some(hapModuleInfo) => | ||
| 198 | + let mainElementName = hapModuleInfo.mainElementName | ||
| 199 | + logger.info("mainElementName = ${mainElementName}") | ||
| 200 | + mainElementName | ||
| 201 | + } | ||
| 202 | + let want = Want(bundleName: bundleName, moduleName: moduleName, abilityName: abilityName) | ||
| 203 | + abilityDelegator | ||
| 204 | + .startAbility(want) | ||
| 205 | + .get() | ||
| 206 | + let timeOut = match (parameters.get("-s timeout")) { | ||
| 207 | + case None => None<Int64> | ||
| 208 | + case Some(timeOutText) => match (Int64.tryParse(timeOutText)) { | ||
| 209 | + case None => | ||
| 210 | + abilityDelegator.finishTest("The parameter \"timeout\": ${timeOutText} is invalid", -1) | ||
| 211 | + return | ||
| 212 | + case Some(timeOutValue) => timeOutValue | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + spawn { | ||
| 216 | + try { | ||
| 217 | + match (parameters.get("-s class")) { | ||
| 218 | + case None => executeAllTestClasses() | ||
| 219 | + case Some(text) => text.split(",", removeEmpty: true) |> | ||
| 220 | + forEach { | ||
| 221 | + t: String => | ||
| 222 | + let pair = t.split("#", removeEmpty: true) | ||
| 223 | + let testClassName = match (pair.get(0)) { | ||
| 224 | + case None => return | ||
| 225 | + case Some(text) => text.trimAscii() | ||
| 226 | + } | ||
| 227 | + match (pair.get(1)) { | ||
| 228 | + case None => executeTestClass(testClassName) | ||
| 229 | + case Some(testCaseName) => executeTestCase(testClassName, testCaseName) | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | + } | ||
| 233 | + } catch (e: Exception) { | ||
| 234 | + logger.error("an exception occurred:\n${getDetailedInfoOf(e)}") | ||
| 235 | + } | ||
| 236 | + var coverage = false | ||
| 237 | + Process | ||
| 238 | + .current | ||
| 239 | + .setEnv("GCOV_PREFIX", "/data/storage/el1/base/cov") | ||
| 240 | + gcov_dump("/data/app/el1/100/base/${bundleName}/cov/") | ||
| 241 | + | ||
| 242 | + abilityDelegator.finishTest("Test finished.", 0) | ||
| 243 | + } | ||
| 244 | + } | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +let _ = TestRunner.registerCreator("OpenHarmonyTestRunner") {OpenHarmonyTestRunner()} | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | +{ | ||
| 2 | + "module": { | ||
| 3 | + "name": "MMKV_test", | ||
| 4 | + "type": "feature", | ||
| 5 | + "description": "$string:module_desc", | ||
| 6 | + "mainElement": "EntryAbility", | ||
| 7 | + "deviceTypes": [ | ||
| 8 | + "default" | ||
| 9 | + ], | ||
| 10 | + "deliveryWithInstall": true, | ||
| 11 | + "installationFree": false, | ||
| 12 | + "srcEntry": "ohos_app_cangjie_MMKV_test.MyAbilityStage", | ||
| 13 | + "abilities": [ | ||
| 14 | + { | ||
| 15 | + "name": "EntryAbility", | ||
| 16 | + "srcEntry": "ohos_app_cangjie_MMKV_test.MainAbility", | ||
| 17 | + "description": "$string:EntryAbility_desc", | ||
| 18 | + "icon": "$media:layered_image", | ||
| 19 | + "label": "$string:EntryAbility_label", | ||
| 20 | + "startWindowIcon": "$media:startIcon", | ||
| 21 | + "startWindowBackground": "$color:start_window_background", | ||
| 22 | + "exported": true | ||
| 23 | + } | ||
| 24 | + ] | ||
| 25 | + } | ||
| 26 | +} | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +{ | ||
| 2 | + "color": [ | ||
| 3 | + { | ||
| 4 | + "name": "start_window_background", | ||
| 5 | + "value": "#FFFFFF" | ||
| 6 | + } | ||
| 7 | + ] | ||
| 8 | +} | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | +{ | ||
| 2 | + "string": [ | ||
| 3 | + { | ||
| 4 | + "name": "module_desc", | ||
| 5 | + "value": "module description" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "name": "EntryAbility_desc", | ||
| 9 | + "value": "description" | ||
| 10 | + }, | ||
| 11 | + { | ||
| 12 | + "name": "EntryAbility_label", | ||
| 13 | + "value": "label" | ||
| 14 | + } | ||
| 15 | + ] | ||
| 16 | +} | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | +{ | ||
| 2 | + "layered-image": | ||
| 3 | + { | ||
| 4 | + "background" : "$media:background", | ||
| 5 | + "foreground" : "$media:foreground" | ||
| 6 | + } | ||
| 7 | +} | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | +{ | ||
| 2 | +} | ||
| @@ -91,7 +91,8 @@ MMKV 是一个基于 mmap 的高性能 key-value 存储库,主要用于解决 | |||
| 91 | 91 | ||
| 92 | ### 接口说明 | 92 | ### 接口说明 |
| 93 | 93 | ||
| 94 | -主要类和函数接口说明详见 [API](./doc/feature_api.md) | 94 | +- 仓颉(Cangjie)主要类和函数接口说明详见 [API](./doc/feature_api.md) |
| 95 | +- HarmonyOS ArkTS 面向对象接口(基于本 HAR + 仓颉桥接封装,含集成步骤与可运行范例 `entry`)详见 [ArkTS API](./doc/arkts_api.md) | ||
| 95 | 96 | ||
| 96 | ## 使用说明 | 97 | ## 使用说明 |
| 97 | 98 | ||