add rootfs
This commit is contained in:
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[{*.java, *.kt,*.kts, *.cpp, *.c, *.cc, *.h}]
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
max_line_length = 120
|
||||
72
.gitignore
vendored
Normal file
72
.gitignore
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
# Built application files
|
||||
*.apk
|
||||
*.ap_
|
||||
app/build/
|
||||
app/src/main/gen/
|
||||
app/src/main/bin/
|
||||
cmake-build-*
|
||||
release/
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
app/.cxx/
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following line if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
app/src/main/res/drawable/icon.png
|
||||
|
||||
.settings
|
||||
.project
|
||||
.classpath
|
||||
app/signing.properties
|
||||
.vscode
|
||||
203
app/build.gradle.kts
Normal file
203
app/build.gradle.kts
Normal file
@@ -0,0 +1,203 @@
|
||||
import java.io.PrintStream
|
||||
import java.nio.file.Paths
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("com.google.devtools.ksp") version "${Version.kotlin}-${Version.ksp}"
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 31
|
||||
buildToolsVersion = "31.0.0"
|
||||
ndkVersion = "21.4.7075529"
|
||||
defaultConfig {
|
||||
applicationId = "io.github.qauxv"
|
||||
minSdk = 21
|
||||
targetSdk = 32
|
||||
versionCode = Common.getTimeStamp()
|
||||
// versionName = major.minor.bugfix.rev.commit
|
||||
versionName = "0.1.0" + (Common.getGitHeadRefsSuffix(rootProject))
|
||||
multiDexEnabled = false
|
||||
ndk {
|
||||
abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments("-DQAUXV_VERSION=$versionName")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (System.getenv("KEYSTORE_PATH") != null) {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
storeFile = file(System.getenv("KEYSTORE_PATH"))
|
||||
storePassword = System.getenv("KEYSTORE_PASSWORD")
|
||||
keyAlias = System.getenv("KEY_ALIAS")
|
||||
keyPassword = System.getenv("KEY_PASSWORD")
|
||||
enableV1Signing = true
|
||||
enableV2Signing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
isShrinkResources = true
|
||||
isMinifyEnabled = true
|
||||
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
|
||||
if (System.getenv("KEYSTORE_PATH") != null) {
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
tasks.forEach {
|
||||
if (it.name.contains("lint")) {
|
||||
it.enabled = false
|
||||
}
|
||||
}
|
||||
kotlinOptions.suppressWarnings = true
|
||||
}
|
||||
getByName("debug") {
|
||||
isShrinkResources = true
|
||||
isMinifyEnabled = true
|
||||
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
|
||||
}
|
||||
create("CI") {
|
||||
initWith(getByName("debug"))
|
||||
isShrinkResources = false
|
||||
isMinifyEnabled = false
|
||||
signingConfig = null
|
||||
ndk {
|
||||
abiFilters.clear()
|
||||
abiFilters.add("arm64-v8a")
|
||||
}
|
||||
matchingFallbacks += listOf("debug")
|
||||
tasks.forEach {
|
||||
if (it.name.contains("lint")) {
|
||||
it.enabled = false
|
||||
}
|
||||
}
|
||||
kotlinOptions.suppressWarnings = true
|
||||
}
|
||||
}
|
||||
androidResources {
|
||||
additionalParameters("--allow-reserved-package-id", "--package-id", "0x39")
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = Version.java
|
||||
targetCompatibility = Version.java
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = Version.java.toString()
|
||||
compileOptions {
|
||||
kotlinOptions.freeCompilerArgs += "-Xmulti-platform"
|
||||
}
|
||||
}
|
||||
// Encapsulates your external native build configurations.
|
||||
externalNativeBuild {
|
||||
// Encapsulates your CMake build configurations.
|
||||
cmake {
|
||||
// Provides a relative path to your CMake build script.
|
||||
path = File(projectDir, "src/main/cpp/CMakeLists.txt")
|
||||
version = "3.10.2"
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets.debug {
|
||||
kotlin.srcDir("build/generated/ksp/debug/kotlin")
|
||||
}
|
||||
sourceSets.release {
|
||||
kotlin.srcDir("build/generated/ksp/release/kotlin")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(fileTree(mapOf("dir" to "lib", "include" to listOf("*.jar"))))
|
||||
compileOnly(project(":stub"))
|
||||
implementation(project(":mmkv"))
|
||||
//add("kspAndroid", project(":compiler"))
|
||||
ksp(project(":ksp"))
|
||||
compileOnly("de.robv.android.xposed:api:82")
|
||||
implementation("com.jaredrummler:colorpicker:1.1.0")
|
||||
implementation("de.psdev.licensesdialog:licensesdialog:2.2.0")
|
||||
implementation("io.noties.markwon:core:4.6.2")
|
||||
implementation(kotlin("stdlib", Version.kotlin))
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
|
||||
// 脚本解析
|
||||
implementation("org.apache-extras.beanshell:bsh:2.0b6")
|
||||
// androidx
|
||||
implementation("androidx.preference:preference-ktx:1.1.1")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
|
||||
implementation("androidx.browser:browser:1.4.0")
|
||||
implementation("com.google.android.material:material:1.5.0")
|
||||
implementation("com.google.code.gson:gson:2.8.9")
|
||||
implementation("com.afollestad.material-dialogs:core:3.3.0")
|
||||
implementation("com.afollestad.material-dialogs:input:3.3.0")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val appCenterSdkVersion = "4.4.2"
|
||||
implementation("com.microsoft.appcenter:appcenter-analytics:${appCenterSdkVersion}")
|
||||
implementation("com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val lifecycleVersion = "2.4.0"
|
||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion")
|
||||
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion")
|
||||
}
|
||||
|
||||
tasks.register("checkTargetNativeLibsDebug") {
|
||||
dependsOn(":app:externalNativeBuildDebug")
|
||||
doLast {
|
||||
val targetAbi = listOf("arm64-v8a", "armeabi-v7a")
|
||||
val soName = "libqauxv.so"
|
||||
val libPath = "app/build/intermediates/cmake/debug/obj"
|
||||
for (abi in targetAbi) {
|
||||
var tmpPath = "$libPath/$abi/$soName"
|
||||
if ("/" != File.separator) {
|
||||
tmpPath = tmpPath.replace('/', File.separatorChar)
|
||||
}
|
||||
val f = File(rootProject.projectDir, tmpPath)
|
||||
if (!f.exists()) {
|
||||
throw IllegalStateException(" Native library missing for the target abi: $abi. Please run gradle task ':app:externalNativeBuildDebug' manually to force android gradle plugin to satisfy all required ABIs.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.register("checkTargetNativeLibsRelease") {
|
||||
dependsOn(":app:externalNativeBuildRelease")
|
||||
doLast {
|
||||
val targetAbi = listOf("arm64-v8a", "armeabi-v7a")
|
||||
val soName = "libqauxv.so"
|
||||
val libPath = "app/build/intermediates/cmake/release/obj"
|
||||
for (abi in targetAbi) {
|
||||
var tmpPath = "$libPath/$abi/$soName"
|
||||
if ("/" != File.separator) {
|
||||
tmpPath = tmpPath.replace('/', File.separatorChar)
|
||||
}
|
||||
val f = File(rootProject.projectDir, tmpPath)
|
||||
if (!f.exists()) {
|
||||
throw IllegalStateException("Native library missing for the target abi: $abi.\nPlease run gradle task ':app:externalNativeBuildRelease' manually to force android gradle plugin to satisfy all required ABIs.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<ReplaceIcon>("replaceIcon")
|
||||
tasks.getByName("preBuild").dependsOn(tasks.getByName("replaceIcon"))
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
|
||||
if (name.contains("release", true)) {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = freeCompilerArgs + listOf(
|
||||
"-Xno-call-assertions",
|
||||
"-Xno-receiver-assertions",
|
||||
"-Xno-param-assertions",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
10
app/lint.xml
Normal file
10
app/lint.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<issue id="InvalidPackage">
|
||||
<ignore regexp='^.*java.applet..*$' />
|
||||
<ignore regexp='^.*java.awt..*$' />
|
||||
<ignore regexp='^.*javax.script..*$' />
|
||||
<ignore regexp='^.*javax.servlet..*$' />
|
||||
<ignore regexp='^.*javax.swing..*$' />
|
||||
</issue>
|
||||
</lint>
|
||||
57
app/proguard-rules.pro
vendored
Normal file
57
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
-keep class nil.** { *; }
|
||||
-keep class me.** { *; }
|
||||
-keep class bsh.** { *; }
|
||||
-keep class de.** { *; }
|
||||
-keep class cc.** { *; }
|
||||
-keep class io.** { *; }
|
||||
-keep class org.** { *; }
|
||||
-keep class com.microsoft.** { *; }
|
||||
-keep class com.rymmmmm.** { *; }
|
||||
-keep class cn.lliiooll.** { *; }
|
||||
-keep class xyz.nextalone.** { *; }
|
||||
-keep class cc.ioctl.** { *; }
|
||||
-keep class com.tencent.mmkv.** { *; }
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keepclassmembers class * extends android.app.Activity {
|
||||
public void *(android.view.View);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
|
||||
-dontobfuscate
|
||||
-dontoptimize
|
||||
|
||||
-dontwarn javax.**
|
||||
-dontwarn java.awt.**
|
||||
-dontwarn java.lang.instrument.ClassFileTransformer
|
||||
-dontwarn sun.misc.SignalHandler
|
||||
-dontwarn org.apache.bsf.util.BSFEngineImpl
|
||||
-dontwarn java.applet.Applet
|
||||
-dontwarn org.apache.bsf.*
|
||||
20
build.gradle.kts
Normal file
20
build.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
extra["kotlin_version"] = Version.kotlin
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
//noinspection AndroidGradlePluginVersion,GradleDependency
|
||||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
classpath(kotlin("gradle-plugin", version = Version.kotlin))
|
||||
classpath("org.jetbrains.compose:compose-gradle-plugin:1.0.0")
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module settings.gradle.kts files
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Delete>("clean").configure {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
||||
13
buildSrc/build.gradle.kts
Normal file
13
buildSrc/build.gradle.kts
Normal file
@@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
|
||||
dependencies {
|
||||
implementation("org.eclipse.jgit:org.eclipse.jgit:5.10.0.202012080955-r")
|
||||
}
|
||||
}
|
||||
57
buildSrc/src/main/kotlin/Common.kt
Normal file
57
buildSrc/src/main/kotlin/Common.kt
Normal file
@@ -0,0 +1,57 @@
|
||||
import java.io.File
|
||||
import org.eclipse.jgit.internal.storage.file.FileRepository
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.gradle.api.Project
|
||||
|
||||
object Common {
|
||||
|
||||
@JvmStatic
|
||||
fun getGitHeadRefsSuffix(project: Project): String {
|
||||
// .git/HEAD描述当前目录所指向的分支信息,内容示例:"ref: refs/heads/master\n"
|
||||
val headFile = File(project.rootProject.projectDir, ".git" + File.separator + "HEAD")
|
||||
if (headFile.exists()) {
|
||||
var commitHash: String
|
||||
val strings = headFile.readText(Charsets.UTF_8).split(" ")
|
||||
if (strings.size > 1) {
|
||||
val refFilePath = ".git" + File.separator + strings[1];
|
||||
// 根据HEAD读取当前指向的hash值,路径示例为:".git/refs/heads/master"
|
||||
val refFile = File(project.rootProject.projectDir, refFilePath.replace("\n", "").replace("\r", ""));
|
||||
// 索引文件内容为hash值+"\n",
|
||||
commitHash = refFile.readText(Charsets.UTF_8)
|
||||
} else {
|
||||
commitHash = strings[0]
|
||||
}
|
||||
commitHash = commitHash.trim()
|
||||
val repo = FileRepository(project.rootProject.file(".git"))
|
||||
val refId = repo.resolve(commitHash)
|
||||
val iterator = Git(repo).log().add(refId).call().iterator()
|
||||
var commitCount = 0
|
||||
while (iterator.hasNext()) {
|
||||
commitCount++
|
||||
iterator.next()
|
||||
}
|
||||
repo.close()
|
||||
return ".r" + commitCount + "." + commitHash.substring(0, 7)
|
||||
} else {
|
||||
println("WARN: .git/HEAD does NOT exist")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBuildIdSuffix(): String {
|
||||
return try {
|
||||
val ciBuildId = System.getenv()["APPCENTER_BUILD_ID"]
|
||||
if (ciBuildId != null) ".$ciBuildId"
|
||||
else ""
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getTimeStamp(): Int {
|
||||
return (System.currentTimeMillis() / 1000L).toInt()
|
||||
}
|
||||
}
|
||||
34
buildSrc/src/main/kotlin/ReplaceIcon.kt
Normal file
34
buildSrc/src/main/kotlin/ReplaceIcon.kt
Normal file
@@ -0,0 +1,34 @@
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
abstract class ReplaceIcon : DefaultTask() {
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val iconsDir = File(project.projectDir, "icons")
|
||||
val iconFileDirs = listOf(
|
||||
File(iconsDir, "MiStyleIcons"),
|
||||
File(iconsDir, "classic"),
|
||||
//File(projectDir ,"ChineseNewYearIcons")
|
||||
)
|
||||
val fileCount = iconFileDirs.fold(0) { i: Int, file: File ->
|
||||
i + file.listFiles()!!.size
|
||||
}
|
||||
var number = Random().nextInt(fileCount)
|
||||
|
||||
//for (aNumber in 0..fileCount) {
|
||||
//var number = aNumber
|
||||
var iconFile: File? = null
|
||||
for (iconFileDir in iconFileDirs) {
|
||||
if (number < iconFileDir.listFiles()!!.size) {
|
||||
iconFile = iconFileDir.listFiles()!![number]
|
||||
break
|
||||
}
|
||||
number -= iconFileDir.listFiles()!!.size
|
||||
}
|
||||
println("Select Icon: $iconFile")
|
||||
iconFile!!.copyTo(File(project.projectDir, "src/main/res/drawable/icon.png"), true)
|
||||
//}
|
||||
}
|
||||
}
|
||||
7
buildSrc/src/main/kotlin/Version.kt
Normal file
7
buildSrc/src/main/kotlin/Version.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
import org.gradle.api.JavaVersion
|
||||
|
||||
object Version {
|
||||
const val kotlin = "1.5.31"
|
||||
const val ksp = "1.0.1"
|
||||
val java = JavaVersion.VERSION_11
|
||||
}
|
||||
20
gradle.properties
Normal file
20
gradle.properties
Normal file
@@ -0,0 +1,20 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
--warning-mode=all
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Sun Nov 07 00:06:24 CST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
185
gradlew
vendored
Executable file
185
gradlew
vendored
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
104
gradlew.bat
vendored
Normal file
104
gradlew.bat
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
20
libs/ksp/build.gradle.kts
Normal file
20
libs/ksp/build.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.google.devtools.ksp:symbol-processing-api:${Version.kotlin}-${Version.ksp}")
|
||||
// Note that this API is currently in preview and subject to API changes.
|
||||
implementation("com.squareup:kotlinpoet-ksp:1.10.2")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = Version.java.toString()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
sourceCompatibility = Version.java.toString()
|
||||
targetCompatibility = Version.java.toString()
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package cn.lliiooll.processors
|
||||
|
||||
import com.google.devtools.ksp.processing.*
|
||||
import com.google.devtools.ksp.symbol.KSAnnotated
|
||||
import com.google.devtools.ksp.symbol.KSClassDeclaration
|
||||
import com.squareup.kotlinpoet.AnnotationSpec
|
||||
import com.squareup.kotlinpoet.CodeBlock
|
||||
import com.squareup.kotlinpoet.FileSpec
|
||||
import com.squareup.kotlinpoet.FunSpec
|
||||
import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview
|
||||
import com.squareup.kotlinpoet.ksp.toTypeName
|
||||
import com.squareup.kotlinpoet.ksp.writeTo
|
||||
|
||||
@KotlinPoetKspPreview
|
||||
class FunctionItemProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) :
|
||||
SymbolProcessor {
|
||||
|
||||
override fun process(resolver: Resolver): List<KSAnnotated> {
|
||||
val symbols =
|
||||
resolver.getSymbolsWithAnnotation("io.github.qauxv.base.annotation.FunctionEntry")
|
||||
.filter { it is KSClassDeclaration }
|
||||
.map { it as KSClassDeclaration }
|
||||
.toList()
|
||||
if (symbols.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
logger.info("FunctionItemProcessor start.")
|
||||
val simpleNameMap = HashMap<String, String>(symbols.size)
|
||||
val mGetApi = FunSpec.builder("getAnnotatedFunctionItemClassList").run {
|
||||
addCode(CodeBlock.Builder().run {
|
||||
add("return arrayOf(«")
|
||||
symbols.forEachIndexed { index, ksClassDeclaration ->
|
||||
if (simpleNameMap.contains(ksClassDeclaration.simpleName.asString())) {
|
||||
logger.error("Duplicate name in FunctionEntry's simpleName: ${ksClassDeclaration.qualifiedName?.asString() ?: "null"}, ${simpleNameMap[ksClassDeclaration.simpleName.asString()]}")
|
||||
} else {
|
||||
simpleNameMap[ksClassDeclaration.simpleName.asString()] =
|
||||
ksClassDeclaration.qualifiedName?.asString()
|
||||
?: "null"
|
||||
}
|
||||
val isJava = ksClassDeclaration.containingFile?.filePath?.endsWith(".java") == true
|
||||
// logger.warn("Processing >>> $ksClassDeclaration,isJava = $isJava")
|
||||
val typeName = ksClassDeclaration.asStarProjectedType().toTypeName()
|
||||
val format = StringBuilder("\n%T").run {
|
||||
if (isJava) append(".INSTANCE")
|
||||
if (index == symbols.lastIndex) append("\n") else append(",")
|
||||
toString()
|
||||
}
|
||||
add(format, typeName)
|
||||
}
|
||||
add("»)")
|
||||
build()
|
||||
})
|
||||
build()
|
||||
}
|
||||
logger.info("FunctionItemProcessor count = " + symbols.size + ".")
|
||||
// @file:JvmName("AnnotatedFunctionItemList")
|
||||
val annotationSpec = AnnotationSpec.builder(JvmName::class).run {
|
||||
addMember("%S", "AnnotatedFunctionItemList")
|
||||
build()
|
||||
}
|
||||
val dependencies = Dependencies(true, *(symbols.map {
|
||||
it.containingFile!!
|
||||
}.toTypedArray()))
|
||||
FileSpec.builder("io.github.qauxv.gen", "AnnotatedFunctionItemList")
|
||||
.addAnnotation(annotationSpec)
|
||||
.addFunction(mGetApi)
|
||||
.build()
|
||||
.writeTo(codeGenerator, dependencies)
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
@KotlinPoetKspPreview
|
||||
class FunctionItemProvider : SymbolProcessorProvider {
|
||||
override fun create(
|
||||
environment: SymbolProcessorEnvironment
|
||||
): SymbolProcessor {
|
||||
return FunctionItemProcessor(environment.codeGenerator, environment.logger)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cn.lliiooll.processors.FunctionItemProvider
|
||||
55
libs/mmkv/Android/CMakeLists.txt
Normal file
55
libs/mmkv/Android/CMakeLists.txt
Normal file
@@ -0,0 +1,55 @@
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.0)
|
||||
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# You can define multiple libraries, and CMake builds them for you.
|
||||
# Gradle automatically packages shared libraries with your APK.
|
||||
|
||||
add_subdirectory(../Core Core)
|
||||
|
||||
add_library(mmkv
|
||||
|
||||
# Sets the library as a static library.
|
||||
STATIC
|
||||
|
||||
# Provides a relative path to your source file(s).
|
||||
src/main/cpp/native-bridge.cpp
|
||||
src/main/cpp/flutter-bridge.cpp
|
||||
)
|
||||
|
||||
set_target_properties(mmkv PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_EXTENSIONS OFF
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
# Searches for a specified prebuilt library and stores the path as a
|
||||
# variable. Because CMake includes system libraries in the search path by
|
||||
# default, you only need to specify the name of the public NDK library
|
||||
# you want to add. CMake verifies that the library exists before
|
||||
# completing its build.
|
||||
|
||||
find_library( # Sets the name of the path variable.
|
||||
log-lib
|
||||
|
||||
# Specifies the name of the NDK library that
|
||||
# you want CMake to locate.
|
||||
log)
|
||||
|
||||
# Specifies libraries CMake should link to your target library. You
|
||||
# can link multiple libraries, such as libraries you define in this
|
||||
# build script, prebuilt third-party libraries, or system libraries.
|
||||
|
||||
target_link_libraries(mmkv
|
||||
|
||||
# Links the target library to the log library
|
||||
# included in the NDK.
|
||||
${log-lib}
|
||||
core
|
||||
# aes
|
||||
)
|
||||
57
libs/mmkv/Android/build.gradle
Normal file
57
libs/mmkv/Android/build.gradle
Normal file
@@ -0,0 +1,57 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
|
||||
compileSdkVersion 31
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
}
|
||||
defaultPublishConfig "StaticCppRelease"
|
||||
|
||||
defaultConfig {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-fvisibility=hidden", "-funwind-tables", "-fasynchronous-unwind-tables"
|
||||
}
|
||||
}
|
||||
// debuggable true
|
||||
// jniDebuggable true
|
||||
}
|
||||
debug {
|
||||
jniDebuggable true
|
||||
}
|
||||
}
|
||||
// externalNativeBuild {
|
||||
// cmake {
|
||||
// path "CMakeLists.txt"
|
||||
// version "3.8.0+"
|
||||
// }
|
||||
// }
|
||||
|
||||
flavorDimensions "stl_mode"
|
||||
productFlavors {
|
||||
StaticCpp {
|
||||
dimension "stl_mode"
|
||||
ext.artifactIdSuffix = 'static'
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments = ["-DANDROID_STL=c++_static"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
}
|
||||
9
libs/mmkv/Android/proguard-rules.pro
vendored
Normal file
9
libs/mmkv/Android/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# Keep all native methods, their classes and any classes in their descriptors
|
||||
-keepclasseswithmembers,includedescriptorclasses class com.tencent.mmkv.** {
|
||||
native <methods>;
|
||||
long nativeHandle;
|
||||
private static *** onMMKVCRCCheckFail(***);
|
||||
private static *** onMMKVFileLengthError(***);
|
||||
private static *** mmkvLogImp(...);
|
||||
private static *** onContentChangedByOuterProcess(***);
|
||||
}
|
||||
3
libs/mmkv/Android/src/main/AndroidManifest.xml
Normal file
3
libs/mmkv/Android/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.tencent.mmkv"></manifest>
|
||||
@@ -0,0 +1,4 @@
|
||||
// MMKV.aidl
|
||||
package com.tencent.mmkv;
|
||||
|
||||
parcelable ParcelableMMKV;
|
||||
409
libs/mmkv/Android/src/main/cpp/flutter-bridge.cpp
Normal file
409
libs/mmkv/Android/src/main/cpp/flutter-bridge.cpp
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#ifndef MMKV_DISABLE_FLUTTER
|
||||
|
||||
# include "MMKV.h"
|
||||
# include <stdint.h>
|
||||
# include <string>
|
||||
|
||||
using namespace mmkv;
|
||||
using namespace std;
|
||||
|
||||
# define MMKV_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used))
|
||||
|
||||
MMKV_EXPORT void mmkvInitialize(const char *rootDir, int32_t logLevel) {
|
||||
if (!rootDir) {
|
||||
return;
|
||||
}
|
||||
MMKV::initializeMMKV(rootDir, (MMKVLogLevel) logLevel);
|
||||
}
|
||||
|
||||
MMKV_EXPORT void onExit() {
|
||||
MMKV::onExit();
|
||||
}
|
||||
|
||||
MMKV_EXPORT void *getMMKVWithID(const char *mmapID, int32_t mode, const char *cryptKey, const char *rootPath) {
|
||||
MMKV *kv = nullptr;
|
||||
if (!mmapID) {
|
||||
return kv;
|
||||
}
|
||||
string str = mmapID;
|
||||
|
||||
bool done = false;
|
||||
if (cryptKey) {
|
||||
string crypt = cryptKey;
|
||||
if (crypt.length() > 0) {
|
||||
if (rootPath) {
|
||||
string path = rootPath;
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, &crypt, &path);
|
||||
} else {
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, &crypt, nullptr);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
if (rootPath) {
|
||||
string path = rootPath;
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, nullptr, &path);
|
||||
} else {
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return kv;
|
||||
}
|
||||
|
||||
MMKV_EXPORT void *getDefaultMMKV(int32_t mode, const char *cryptKey) {
|
||||
MMKV *kv = nullptr;
|
||||
|
||||
if (cryptKey) {
|
||||
string crypt = cryptKey;
|
||||
if (crypt.length() > 0) {
|
||||
kv = MMKV::defaultMMKV((MMKVMode) mode, &crypt);
|
||||
}
|
||||
}
|
||||
if (!kv) {
|
||||
kv = MMKV::defaultMMKV((MMKVMode) mode, nullptr);
|
||||
}
|
||||
|
||||
return kv;
|
||||
}
|
||||
|
||||
MMKV_EXPORT const char *mmapID(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
return kv->mmapID().c_str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKV_EXPORT bool encodeBool(void *handle, const char *oKey, bool value) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->set((bool) value, key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_EXPORT bool decodeBool(void *handle, const char *oKey, bool defaultValue) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->getBool(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_EXPORT bool encodeInt32(void *handle, const char *oKey, int32_t value) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->set((int32_t) value, key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_EXPORT int32_t decodeInt32(void *handle, const char *oKey, int32_t defaultValue) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->getInt32(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_EXPORT bool encodeInt64(void *handle, const char *oKey, int64_t value) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->set((int64_t) value, key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_EXPORT int64_t decodeInt64(void *handle, const char *oKey, int64_t defaultValue) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->getInt64(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_EXPORT bool encodeDouble(void *handle, const char *oKey, double value) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->set((double) value, key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_EXPORT double decodeDouble(void *handle, const char *oKey, double defaultValue) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
return kv->getDouble(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_EXPORT bool encodeBytes(void *handle, const char *oKey, void *oValue, uint64_t length) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
if (oValue) {
|
||||
auto value = MMBuffer(oValue, static_cast<size_t>(length), MMBufferNoCopy);
|
||||
return kv->set(value, key);
|
||||
} else {
|
||||
kv->removeValueForKey(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_EXPORT void *decodeBytes(void *handle, const char *oKey, uint64_t *lengthPtr) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
auto key = string(oKey);
|
||||
auto value = kv->getBytes(key);
|
||||
if (value.length() > 0) {
|
||||
if (value.isStoredOnStack()) {
|
||||
auto result = malloc(value.length());
|
||||
if (result) {
|
||||
memcpy(result, value.getPtr(), value.length());
|
||||
*lengthPtr = value.length();
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
void *result = value.getPtr();
|
||||
*lengthPtr = value.length();
|
||||
value.detach();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
MMKV_EXPORT bool reKey(void *handle, char *oKey, uint64_t length) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
if (oKey && length > 0) {
|
||||
string key(oKey, length);
|
||||
return kv->reKey(key);
|
||||
} else {
|
||||
return kv->reKey(string());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_EXPORT void *cryptKey(void *handle, uint64_t *lengthPtr) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && lengthPtr) {
|
||||
auto cryptKey = kv->cryptKey();
|
||||
if (cryptKey.length() > 0) {
|
||||
auto ptr = malloc(cryptKey.length());
|
||||
if (ptr) {
|
||||
memcpy(ptr, cryptKey.data(), cryptKey.length());
|
||||
*lengthPtr = cryptKey.length();
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKV_EXPORT void checkReSetCryptKey(void *handle, char *oKey, uint64_t length) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
if (oKey && length > 0) {
|
||||
string key(oKey, length);
|
||||
kv->checkReSetCryptKey(&key);
|
||||
} else {
|
||||
kv->checkReSetCryptKey(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
MMKV_EXPORT uint32_t valueSize(void *handle, char *oKey, bool actualSize) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key(oKey);
|
||||
auto ret = kv->getValueSize(key, actualSize);
|
||||
return static_cast<uint32_t>(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_EXPORT int32_t writeValueToNB(void *handle, char *oKey, void *pointer, uint32_t size) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key(oKey);
|
||||
return kv->writeValueToBuffer(key, pointer, size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MMKV_EXPORT uint64_t allKeys(void *handle, char ***keyArrayPtr, uint32_t **sizeArrayPtr) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
auto keys = kv->allKeys();
|
||||
if (!keys.empty()) {
|
||||
auto keyArray = (char **) malloc(keys.size() * sizeof(void *));
|
||||
auto sizeArray = (uint32_t *) malloc(keys.size() * sizeof(uint32_t *));
|
||||
if (!keyArray || !sizeArray) {
|
||||
free(keyArray);
|
||||
free(sizeArray);
|
||||
return 0;
|
||||
}
|
||||
*keyArrayPtr = keyArray;
|
||||
*sizeArrayPtr = sizeArray;
|
||||
|
||||
for (size_t index = 0; index < keys.size(); index++) {
|
||||
auto &key = keys[index];
|
||||
sizeArray[index] = static_cast<uint32_t>(key.length());
|
||||
keyArray[index] = (char *) malloc(key.length());
|
||||
if (keyArray[index]) {
|
||||
memcpy(keyArray[index], key.data(), key.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_EXPORT bool containsKey(void *handle, char *oKey) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key(oKey);
|
||||
return kv->containsKey(key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_EXPORT uint64_t count(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
return kv->count();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_EXPORT uint64_t totalSize(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
return kv->totalSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_EXPORT uint64_t actualSize(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
return kv->actualSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_EXPORT void removeValueForKey(void *handle, char *oKey) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key(oKey);
|
||||
kv->removeValueForKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_EXPORT void removeValuesForKeys(void *handle, char **keyArray, uint32_t *sizeArray, uint64_t count) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv && keyArray && sizeArray && count > 0) {
|
||||
vector<string> arrKeys;
|
||||
arrKeys.reserve(count);
|
||||
for (uint64_t index = 0; index < count; index++) {
|
||||
if (sizeArray[index] > 0 && keyArray[index]) {
|
||||
arrKeys.emplace_back(keyArray[index], sizeArray[index]);
|
||||
}
|
||||
}
|
||||
if (!arrKeys.empty()) {
|
||||
kv->removeValuesForKeys(arrKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_EXPORT void clearAll(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
kv->clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_EXPORT void mmkvSync(void *handle, bool sync) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
kv->sync((SyncFlag) sync);
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_EXPORT void clearMemoryCache(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
kv->clearMemoryCache();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_EXPORT int32_t pageSize() {
|
||||
return static_cast<int32_t>(DEFAULT_MMAP_SIZE);
|
||||
}
|
||||
|
||||
MMKV_EXPORT const char *version() {
|
||||
return MMKV_VERSION;
|
||||
}
|
||||
|
||||
MMKV_EXPORT void trim(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
kv->trim();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_EXPORT void mmkvClose(void *handle) {
|
||||
MMKV *kv = static_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
kv->close();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_EXPORT void mmkvMemcpy(void *dst, const void *src, uint64_t size) {
|
||||
memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
#endif // MMKV_DISABLE_FLUTTER
|
||||
844
libs/mmkv/Android/src/main/cpp/native-bridge.cpp
Normal file
844
libs/mmkv/Android/src/main/cpp/native-bridge.cpp
Normal file
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#ifdef MMKV_ANDROID
|
||||
|
||||
# include "MMBuffer.h"
|
||||
# include "MMKV.h"
|
||||
# include "MMKVLog.h"
|
||||
# include "MemoryFile.h"
|
||||
# include <cstdint>
|
||||
# include <jni.h>
|
||||
# include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace mmkv;
|
||||
|
||||
static jclass g_cls = nullptr;
|
||||
static jfieldID g_fileID = nullptr;
|
||||
static jmethodID g_callbackOnCRCFailID = nullptr;
|
||||
static jmethodID g_callbackOnFileLengthErrorID = nullptr;
|
||||
static jmethodID g_mmkvLogID = nullptr;
|
||||
static jmethodID g_callbackOnContentChange = nullptr;
|
||||
static JavaVM *g_currentJVM = nullptr;
|
||||
|
||||
static int registerNativeMethods(JNIEnv *env, jclass cls);
|
||||
|
||||
extern "C" jint MMKV_JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
g_currentJVM = vm;
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g_cls) {
|
||||
env->DeleteGlobalRef(g_cls);
|
||||
}
|
||||
static const char *clsName = "com/tencent/mmkv/MMKV";
|
||||
jclass instance = env->FindClass(clsName);
|
||||
if (!instance) {
|
||||
MMKVError("fail to locate class: %s", clsName);
|
||||
return -2;
|
||||
}
|
||||
g_cls = reinterpret_cast<jclass>(env->NewGlobalRef(instance));
|
||||
if (!g_cls) {
|
||||
MMKVError("fail to create global reference for %s", clsName);
|
||||
return -3;
|
||||
}
|
||||
int ret = registerNativeMethods(env, g_cls);
|
||||
if (ret != 0) {
|
||||
MMKVError("fail to register native methods for class %s, ret = %d", clsName, ret);
|
||||
return -4;
|
||||
}
|
||||
g_fileID = env->GetFieldID(g_cls, "nativeHandle", "J");
|
||||
if (!g_fileID) {
|
||||
MMKVError("fail to locate fileID");
|
||||
return -5;
|
||||
}
|
||||
|
||||
g_callbackOnCRCFailID = env->GetStaticMethodID(g_cls, "onMMKVCRCCheckFail", "(Ljava/lang/String;)I");
|
||||
if (!g_callbackOnCRCFailID) {
|
||||
MMKVError("fail to get method id for onMMKVCRCCheckFail");
|
||||
}
|
||||
g_callbackOnFileLengthErrorID = env->GetStaticMethodID(g_cls, "onMMKVFileLengthError", "(Ljava/lang/String;)I");
|
||||
if (!g_callbackOnFileLengthErrorID) {
|
||||
MMKVError("fail to get method id for onMMKVFileLengthError");
|
||||
}
|
||||
g_mmkvLogID =
|
||||
env->GetStaticMethodID(g_cls, "mmkvLogImp", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;)V");
|
||||
if (!g_mmkvLogID) {
|
||||
MMKVError("fail to get method id for mmkvLogImp");
|
||||
}
|
||||
g_callbackOnContentChange =
|
||||
env->GetStaticMethodID(g_cls, "onContentChangedByOuterProcess", "(Ljava/lang/String;)V");
|
||||
if (!g_callbackOnContentChange) {
|
||||
MMKVError("fail to get method id for onContentChangedByOuterProcess()");
|
||||
}
|
||||
|
||||
// get current API level by accessing android.os.Build.VERSION.SDK_INT
|
||||
jclass versionClass = env->FindClass("android/os/Build$VERSION");
|
||||
if (versionClass) {
|
||||
jfieldID sdkIntFieldID = env->GetStaticFieldID(versionClass, "SDK_INT", "I");
|
||||
if (sdkIntFieldID) {
|
||||
g_android_api = env->GetStaticIntField(versionClass, sdkIntFieldID);
|
||||
MMKVInfo("current API level = %d", g_android_api);
|
||||
} else {
|
||||
MMKVError("fail to get field id android.os.Build.VERSION.SDK_INT");
|
||||
}
|
||||
} else {
|
||||
MMKVError("fail to get class android.os.Build.VERSION");
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
//#define MMKV_JNI extern "C" JNIEXPORT JNICALL
|
||||
# define MMKV_JNI static
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
MMKV_JNI void jniInitialize(JNIEnv *env, jobject obj, jstring rootDir, jint logLevel) {
|
||||
if (!rootDir) {
|
||||
return;
|
||||
}
|
||||
const char *kstr = env->GetStringUTFChars(rootDir, nullptr);
|
||||
if (kstr) {
|
||||
MMKV::initializeMMKV(kstr, (MMKVLogLevel) logLevel);
|
||||
env->ReleaseStringUTFChars(rootDir, kstr);
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void onExit(JNIEnv *env, jobject obj) {
|
||||
MMKV::onExit();
|
||||
}
|
||||
|
||||
static MMKV *getMMKV(JNIEnv *env, jobject obj) {
|
||||
jlong handle = env->GetLongField(obj, g_fileID);
|
||||
return reinterpret_cast<MMKV *>(handle);
|
||||
}
|
||||
|
||||
static string jstring2string(JNIEnv *env, jstring str) {
|
||||
if (str) {
|
||||
const char *kstr = env->GetStringUTFChars(str, nullptr);
|
||||
if (kstr) {
|
||||
string result(kstr);
|
||||
env->ReleaseStringUTFChars(str, kstr);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static jstring string2jstring(JNIEnv *env, const string &str) {
|
||||
return env->NewStringUTF(str.c_str());
|
||||
}
|
||||
|
||||
static vector<string> jarray2vector(JNIEnv *env, jobjectArray array) {
|
||||
vector<string> keys;
|
||||
if (array) {
|
||||
jsize size = env->GetArrayLength(array);
|
||||
keys.reserve(size);
|
||||
for (jsize i = 0; i < size; i++) {
|
||||
jstring str = (jstring) env->GetObjectArrayElement(array, i);
|
||||
if (str) {
|
||||
keys.push_back(jstring2string(env, str));
|
||||
env->DeleteLocalRef(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
static jobjectArray vector2jarray(JNIEnv *env, const vector<string> &arr) {
|
||||
if (!arr.empty()) {
|
||||
jobjectArray result = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), nullptr);
|
||||
if (result) {
|
||||
for (size_t index = 0; index < arr.size(); index++) {
|
||||
jstring value = string2jstring(env, arr[index]);
|
||||
env->SetObjectArrayElement(result, index, value);
|
||||
env->DeleteLocalRef(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static JNIEnv *getCurrentEnv() {
|
||||
if (g_currentJVM) {
|
||||
JNIEnv *currentEnv = nullptr;
|
||||
auto ret = g_currentJVM->GetEnv(reinterpret_cast<void **>(¤tEnv), JNI_VERSION_1_6);
|
||||
if (ret == JNI_OK) {
|
||||
return currentEnv;
|
||||
} else {
|
||||
MMKVError("fail to get current JNIEnv: %d", ret);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKVRecoverStrategic onMMKVError(const std::string &mmapID, MMKVErrorType errorType) {
|
||||
jmethodID methodID = nullptr;
|
||||
if (errorType == MMKVCRCCheckFail) {
|
||||
methodID = g_callbackOnCRCFailID;
|
||||
} else if (errorType == MMKVFileLength) {
|
||||
methodID = g_callbackOnFileLengthErrorID;
|
||||
}
|
||||
|
||||
auto currentEnv = getCurrentEnv();
|
||||
if (currentEnv && methodID) {
|
||||
jstring str = string2jstring(currentEnv, mmapID);
|
||||
auto strategic = currentEnv->CallStaticIntMethod(g_cls, methodID, str);
|
||||
return static_cast<MMKVRecoverStrategic>(strategic);
|
||||
}
|
||||
return OnErrorDiscard;
|
||||
}
|
||||
|
||||
static void mmkvLog(MMKVLogLevel level, const char *file, int line, const char *function, const std::string &message) {
|
||||
auto currentEnv = getCurrentEnv();
|
||||
if (currentEnv && g_mmkvLogID) {
|
||||
jstring oFile = string2jstring(currentEnv, string(file));
|
||||
jstring oFunction = string2jstring(currentEnv, string(function));
|
||||
jstring oMessage = string2jstring(currentEnv, message);
|
||||
int readLevel = level;
|
||||
currentEnv->CallStaticVoidMethod(g_cls, g_mmkvLogID, readLevel, oFile, line, oFunction, oMessage);
|
||||
}
|
||||
}
|
||||
|
||||
static void onContentChangedByOuterProcess(const std::string &mmapID) {
|
||||
auto currentEnv = getCurrentEnv();
|
||||
if (currentEnv && g_callbackOnContentChange) {
|
||||
jstring str = string2jstring(currentEnv, mmapID);
|
||||
currentEnv->CallStaticVoidMethod(g_cls, g_callbackOnContentChange, str);
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI jlong getMMKVWithID(JNIEnv *env, jobject, jstring mmapID, jint mode, jstring cryptKey, jstring rootPath) {
|
||||
MMKV *kv = nullptr;
|
||||
if (!mmapID) {
|
||||
return (jlong) kv;
|
||||
}
|
||||
string str = jstring2string(env, mmapID);
|
||||
|
||||
bool done = false;
|
||||
if (cryptKey) {
|
||||
string crypt = jstring2string(env, cryptKey);
|
||||
if (crypt.length() > 0) {
|
||||
if (rootPath) {
|
||||
string path = jstring2string(env, rootPath);
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, &crypt, &path);
|
||||
} else {
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, &crypt, nullptr);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
if (rootPath) {
|
||||
string path = jstring2string(env, rootPath);
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, nullptr, &path);
|
||||
} else {
|
||||
kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return (jlong) kv;
|
||||
}
|
||||
|
||||
MMKV_JNI jlong getMMKVWithIDAndSize(JNIEnv *env, jobject obj, jstring mmapID, jint size, jint mode, jstring cryptKey) {
|
||||
MMKV *kv = nullptr;
|
||||
if (!mmapID || size < 0) {
|
||||
return (jlong) kv;
|
||||
}
|
||||
string str = jstring2string(env, mmapID);
|
||||
|
||||
if (cryptKey) {
|
||||
string crypt = jstring2string(env, cryptKey);
|
||||
if (crypt.length() > 0) {
|
||||
kv = MMKV::mmkvWithID(str, size, (MMKVMode) mode, &crypt);
|
||||
}
|
||||
}
|
||||
if (!kv) {
|
||||
kv = MMKV::mmkvWithID(str, size, (MMKVMode) mode, nullptr);
|
||||
}
|
||||
return (jlong) kv;
|
||||
}
|
||||
|
||||
MMKV_JNI jlong getDefaultMMKV(JNIEnv *env, jobject obj, jint mode, jstring cryptKey) {
|
||||
MMKV *kv = nullptr;
|
||||
|
||||
if (cryptKey) {
|
||||
string crypt = jstring2string(env, cryptKey);
|
||||
if (crypt.length() > 0) {
|
||||
kv = MMKV::defaultMMKV((MMKVMode) mode, &crypt);
|
||||
}
|
||||
}
|
||||
if (!kv) {
|
||||
kv = MMKV::defaultMMKV((MMKVMode) mode, nullptr);
|
||||
}
|
||||
|
||||
return (jlong) kv;
|
||||
}
|
||||
|
||||
MMKV_JNI jlong getMMKVWithAshmemFD(JNIEnv *env, jobject obj, jstring mmapID, jint fd, jint metaFD, jstring cryptKey) {
|
||||
MMKV *kv = nullptr;
|
||||
if (!mmapID || fd < 0 || metaFD < 0) {
|
||||
return (jlong) kv;
|
||||
}
|
||||
string id = jstring2string(env, mmapID);
|
||||
|
||||
if (cryptKey) {
|
||||
string crypt = jstring2string(env, cryptKey);
|
||||
if (crypt.length() > 0) {
|
||||
kv = MMKV::mmkvWithAshmemFD(id, fd, metaFD, &crypt);
|
||||
}
|
||||
}
|
||||
if (!kv) {
|
||||
kv = MMKV::mmkvWithAshmemFD(id, fd, metaFD, nullptr);
|
||||
}
|
||||
|
||||
return (jlong) kv;
|
||||
}
|
||||
|
||||
MMKV_JNI jstring mmapID(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
return string2jstring(env, kv->mmapID());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKV_JNI jint ashmemFD(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
return kv->ashmemFD();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MMKV_JNI jint ashmemMetaFD(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
return kv->ashmemMetaFD();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean checkProcessMode(JNIEnv *env, jobject, jlong handle) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
return kv->checkProcessMode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeBool(JNIEnv *env, jobject, jlong handle, jstring oKey, jboolean value) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jboolean) kv->set((bool) value, key);
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean decodeBool(JNIEnv *env, jobject, jlong handle, jstring oKey, jboolean defaultValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jboolean) kv->getBool(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeInt(JNIEnv *env, jobject obj, jlong handle, jstring oKey, jint value) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jboolean) kv->set((int32_t) value, key);
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jint decodeInt(JNIEnv *env, jobject obj, jlong handle, jstring oKey, jint defaultValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jint) kv->getInt32(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeLong(JNIEnv *env, jobject obj, jlong handle, jstring oKey, jlong value) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jboolean) kv->set((int64_t) value, key);
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jlong decodeLong(JNIEnv *env, jobject obj, jlong handle, jstring oKey, jlong defaultValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jlong) kv->getInt64(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeFloat(JNIEnv *env, jobject obj, jlong handle, jstring oKey, jfloat value) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jboolean) kv->set((float) value, key);
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jfloat decodeFloat(JNIEnv *env, jobject, jlong handle, jstring oKey, jfloat defaultValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jfloat) kv->getFloat(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeDouble(JNIEnv *env, jobject obj, jlong handle, jstring oKey, jdouble value) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jboolean) kv->set((double) value, key);
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jdouble decodeDouble(JNIEnv *env, jobject, jlong handle, jstring oKey, jdouble defaultValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jdouble) kv->getDouble(key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeString(JNIEnv *env, jobject, jlong handle, jstring oKey, jstring oValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
if (oValue) {
|
||||
string value = jstring2string(env, oValue);
|
||||
return (jboolean) kv->set(value, key);
|
||||
} else {
|
||||
kv->removeValueForKey(key);
|
||||
return (jboolean) true;
|
||||
}
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jstring decodeString(JNIEnv *env, jobject obj, jlong handle, jstring oKey, jstring oDefaultValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
string value;
|
||||
bool hasValue = kv->getString(key, value);
|
||||
if (hasValue) {
|
||||
return string2jstring(env, value);
|
||||
}
|
||||
}
|
||||
return oDefaultValue;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeBytes(JNIEnv *env, jobject, jlong handle, jstring oKey, jbyteArray oValue) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
if (oValue) {
|
||||
MMBuffer value(0);
|
||||
{
|
||||
jsize len = env->GetArrayLength(oValue);
|
||||
void *bufferPtr = env->GetPrimitiveArrayCritical(oValue, nullptr);
|
||||
if (bufferPtr) {
|
||||
value = MMBuffer(bufferPtr, len);
|
||||
env->ReleasePrimitiveArrayCritical(oValue, bufferPtr, JNI_ABORT);
|
||||
} else {
|
||||
MMKVError("fail to get array: %s=%p", key.c_str(), oValue);
|
||||
}
|
||||
}
|
||||
return (jboolean) kv->set(value, key);
|
||||
} else {
|
||||
kv->removeValueForKey(key);
|
||||
return (jboolean) true;
|
||||
}
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jbyteArray decodeBytes(JNIEnv *env, jobject obj, jlong handle, jstring oKey) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
MMBuffer value = kv->getBytes(key);
|
||||
if (value.length() > 0) {
|
||||
jbyteArray result = env->NewByteArray(value.length());
|
||||
env->SetByteArrayRegion(result, 0, value.length(), (const jbyte *) value.getPtr());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKV_JNI jobjectArray allKeys(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
vector<string> keys = kv->allKeys();
|
||||
return vector2jarray(env, keys);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean containsKey(JNIEnv *env, jobject instance, jlong handle, jstring oKey) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return (jboolean) kv->containsKey(key);
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jlong count(JNIEnv *env, jobject instance, jlong handle) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
jlong size = kv->count();
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_JNI jlong totalSize(JNIEnv *env, jobject instance, jlong handle) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv) {
|
||||
jlong size = kv->totalSize();
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_JNI void removeValueForKey(JNIEnv *env, jobject instance, jlong handle, jstring oKey) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
kv->removeValueForKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void removeValuesForKeys(JNIEnv *env, jobject instance, jobjectArray arrKeys) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv && arrKeys) {
|
||||
vector<string> keys = jarray2vector(env, arrKeys);
|
||||
if (!keys.empty()) {
|
||||
kv->removeValuesForKeys(keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void clearAll(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void sync(JNIEnv *env, jobject instance, jboolean sync) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->sync((SyncFlag) sync);
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean isFileValid(JNIEnv *env, jclass type, jstring oMmapID, jstring rootPath) {
|
||||
if (oMmapID) {
|
||||
string mmapID = jstring2string(env, oMmapID);
|
||||
if (!rootPath) {
|
||||
return (jboolean) MMKV::isFileValid(mmapID, nullptr);
|
||||
} else {
|
||||
auto root = jstring2string(env, rootPath);
|
||||
return (jboolean) MMKV::isFileValid(mmapID, &root);
|
||||
}
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean encodeSet(JNIEnv *env, jobject, jlong handle, jstring oKey, jobjectArray arrStr) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
if (arrStr) {
|
||||
vector<string> value = jarray2vector(env, arrStr);
|
||||
return (jboolean) kv->set(value, key);
|
||||
} else {
|
||||
kv->removeValueForKey(key);
|
||||
return (jboolean) true;
|
||||
}
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI jobjectArray decodeStringSet(JNIEnv *env, jobject, jlong handle, jstring oKey) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
vector<string> value;
|
||||
bool hasValue = kv->getVector(key, value);
|
||||
if (hasValue) {
|
||||
return vector2jarray(env, value);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKV_JNI void clearMemoryCache(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->clearMemoryCache();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void lock(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->lock();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void unlock(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean tryLock(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
return (jboolean) kv->try_lock();
|
||||
}
|
||||
return jboolean(false);
|
||||
}
|
||||
|
||||
MMKV_JNI jint pageSize(JNIEnv *env, jclass type) {
|
||||
return DEFAULT_MMAP_SIZE;
|
||||
}
|
||||
|
||||
MMKV_JNI jstring version(JNIEnv *env, jclass type) {
|
||||
return string2jstring(env, MMKV_VERSION);
|
||||
}
|
||||
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
MMKV_JNI jstring cryptKey(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
string cryptKey = kv->cryptKey();
|
||||
if (cryptKey.length() > 0) {
|
||||
return string2jstring(env, cryptKey);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MMKV_JNI jboolean reKey(JNIEnv *env, jobject instance, jstring cryptKey) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
string newKey;
|
||||
if (cryptKey) {
|
||||
newKey = jstring2string(env, cryptKey);
|
||||
}
|
||||
return (jboolean) kv->reKey(newKey);
|
||||
}
|
||||
return (jboolean) false;
|
||||
}
|
||||
|
||||
MMKV_JNI void checkReSetCryptKey(JNIEnv *env, jobject instance, jstring cryptKey) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
string newKey;
|
||||
if (cryptKey) {
|
||||
newKey = jstring2string(env, cryptKey);
|
||||
}
|
||||
|
||||
if (!cryptKey || newKey.empty()) {
|
||||
kv->checkReSetCryptKey(nullptr);
|
||||
} else {
|
||||
kv->checkReSetCryptKey(&newKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
MMKV_JNI void trim(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->trim();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void close(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->close();
|
||||
env->SetLongField(instance, g_fileID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI jint valueSize(JNIEnv *env, jobject, jlong handle, jstring oKey, jboolean actualSize) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return static_cast<jint>(kv->getValueSize(key, (bool) actualSize));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMKV_JNI void setLogLevel(JNIEnv *env, jclass type, jint level) {
|
||||
MMKV::setLogLevel((MMKVLogLevel) level);
|
||||
}
|
||||
|
||||
MMKV_JNI void setCallbackHandler(JNIEnv *env, jclass type, jboolean logReDirecting, jboolean hasCallback) {
|
||||
if (logReDirecting == JNI_TRUE) {
|
||||
MMKV::registerLogHandler(mmkvLog);
|
||||
} else {
|
||||
MMKV::unRegisterLogHandler();
|
||||
}
|
||||
|
||||
if (hasCallback == JNI_TRUE) {
|
||||
MMKV::registerErrorHandler(onMMKVError);
|
||||
} else {
|
||||
MMKV::unRegisterErrorHandler();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI jlong createNB(JNIEnv *env, jobject instance, jint size) {
|
||||
auto ptr = malloc(static_cast<size_t>(size));
|
||||
if (!ptr) {
|
||||
MMKVError("fail to create NativeBuffer:%s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return reinterpret_cast<jlong>(ptr);
|
||||
}
|
||||
|
||||
MMKV_JNI void destroyNB(JNIEnv *env, jobject instance, jlong pointer, jint size) {
|
||||
free(reinterpret_cast<void *>(pointer));
|
||||
}
|
||||
|
||||
MMKV_JNI jint writeValueToNB(JNIEnv *env, jobject instance, jlong handle, jstring oKey, jlong pointer, jint size) {
|
||||
MMKV *kv = reinterpret_cast<MMKV *>(handle);
|
||||
if (kv && oKey) {
|
||||
string key = jstring2string(env, oKey);
|
||||
return kv->writeValueToBuffer(key, reinterpret_cast<void *>(pointer), size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MMKV_JNI void setWantsContentChangeNotify(JNIEnv *env, jclass type, jboolean notify) {
|
||||
if (notify == JNI_TRUE) {
|
||||
MMKV::registerContentChangeHandler(onContentChangedByOuterProcess);
|
||||
} else {
|
||||
MMKV::unRegisterContentChangeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV_JNI void checkContentChanged(JNIEnv *env, jobject instance) {
|
||||
MMKV *kv = getMMKV(env, instance);
|
||||
if (kv) {
|
||||
kv->checkContentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
static JNINativeMethod g_methods[] = {
|
||||
{"onExit", "()V", (void *) mmkv::onExit},
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
{"cryptKey", "()Ljava/lang/String;", (void *) mmkv::cryptKey},
|
||||
{"reKey", "(Ljava/lang/String;)Z", (void *) mmkv::reKey},
|
||||
{"checkReSetCryptKey", "(Ljava/lang/String;)V", (void *) mmkv::checkReSetCryptKey},
|
||||
# endif
|
||||
{"pageSize", "()I", (void *) mmkv::pageSize},
|
||||
{"mmapID", "()Ljava/lang/String;", (void *) mmkv::mmapID},
|
||||
{"version", "()Ljava/lang/String;", (void *) mmkv::version},
|
||||
{"lock", "()V", (void *) mmkv::lock},
|
||||
{"unlock", "()V", (void *) mmkv::unlock},
|
||||
{"tryLock", "()Z", (void *) mmkv::tryLock},
|
||||
{"allKeys", "()[Ljava/lang/String;", (void *) mmkv::allKeys},
|
||||
{"removeValuesForKeys", "([Ljava/lang/String;)V", (void *) mmkv::removeValuesForKeys},
|
||||
{"clearAll", "()V", (void *) mmkv::clearAll},
|
||||
{"trim", "()V", (void *) mmkv::trim},
|
||||
{"close", "()V", (void *) mmkv::close},
|
||||
{"clearMemoryCache", "()V", (void *) mmkv::clearMemoryCache},
|
||||
{"sync", "(Z)V", (void *) mmkv::sync},
|
||||
{"isFileValid", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *) mmkv::isFileValid},
|
||||
{"ashmemFD", "()I", (void *) mmkv::ashmemFD},
|
||||
{"ashmemMetaFD", "()I", (void *) mmkv::ashmemMetaFD},
|
||||
{"jniInitialize", "(Ljava/lang/String;I)V", (void *) mmkv::jniInitialize},
|
||||
{"getMMKVWithID", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)J", (void *) mmkv::getMMKVWithID},
|
||||
{"getMMKVWithIDAndSize", "(Ljava/lang/String;IILjava/lang/String;)J", (void *) mmkv::getMMKVWithIDAndSize},
|
||||
{"getDefaultMMKV", "(ILjava/lang/String;)J", (void *) mmkv::getDefaultMMKV},
|
||||
{"getMMKVWithAshmemFD", "(Ljava/lang/String;IILjava/lang/String;)J", (void *) mmkv::getMMKVWithAshmemFD},
|
||||
{"encodeBool", "(JLjava/lang/String;Z)Z", (void *) mmkv::encodeBool},
|
||||
{"decodeBool", "(JLjava/lang/String;Z)Z", (void *) mmkv::decodeBool},
|
||||
{"encodeInt", "(JLjava/lang/String;I)Z", (void *) mmkv::encodeInt},
|
||||
{"decodeInt", "(JLjava/lang/String;I)I", (void *) mmkv::decodeInt},
|
||||
{"encodeLong", "(JLjava/lang/String;J)Z", (void *) mmkv::encodeLong},
|
||||
{"decodeLong", "(JLjava/lang/String;J)J", (void *) mmkv::decodeLong},
|
||||
{"encodeFloat", "(JLjava/lang/String;F)Z", (void *) mmkv::encodeFloat},
|
||||
{"decodeFloat", "(JLjava/lang/String;F)F", (void *) mmkv::decodeFloat},
|
||||
{"encodeDouble", "(JLjava/lang/String;D)Z", (void *) mmkv::encodeDouble},
|
||||
{"decodeDouble", "(JLjava/lang/String;D)D", (void *) mmkv::decodeDouble},
|
||||
{"encodeString", "(JLjava/lang/String;Ljava/lang/String;)Z", (void *) mmkv::encodeString},
|
||||
{"decodeString", "(JLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;", (void *) mmkv::decodeString},
|
||||
{"encodeSet", "(JLjava/lang/String;[Ljava/lang/String;)Z", (void *) mmkv::encodeSet},
|
||||
{"decodeStringSet", "(JLjava/lang/String;)[Ljava/lang/String;", (void *) mmkv::decodeStringSet},
|
||||
{"encodeBytes", "(JLjava/lang/String;[B)Z", (void *) mmkv::encodeBytes},
|
||||
{"decodeBytes", "(JLjava/lang/String;)[B", (void *) mmkv::decodeBytes},
|
||||
{"containsKey", "(JLjava/lang/String;)Z", (void *) mmkv::containsKey},
|
||||
{"count", "(J)J", (void *) mmkv::count},
|
||||
{"totalSize", "(J)J", (void *) mmkv::totalSize},
|
||||
{"removeValueForKey", "(JLjava/lang/String;)V", (void *) mmkv::removeValueForKey},
|
||||
{"valueSize", "(JLjava/lang/String;Z)I", (void *) mmkv::valueSize},
|
||||
{"setLogLevel", "(I)V", (void *) mmkv::setLogLevel},
|
||||
{"setCallbackHandler", "(ZZ)V", (void *) mmkv::setCallbackHandler},
|
||||
{"createNB", "(I)J", (void *) mmkv::createNB},
|
||||
{"destroyNB", "(JI)V", (void *) mmkv::destroyNB},
|
||||
{"writeValueToNB", "(JLjava/lang/String;JI)I", (void *) mmkv::writeValueToNB},
|
||||
{"setWantsContentChangeNotify", "(Z)V", (void *) mmkv::setWantsContentChangeNotify},
|
||||
{"checkContentChangedByOuterProcess", "()V", (void *) mmkv::checkContentChanged},
|
||||
{"checkProcessMode", "(J)Z", (void *) mmkv::checkProcessMode},
|
||||
};
|
||||
|
||||
static int registerNativeMethods(JNIEnv *env, jclass cls) {
|
||||
return env->RegisterNatives(cls, g_methods, sizeof(g_methods) / sizeof(g_methods[0]));
|
||||
}
|
||||
|
||||
#endif // MMKV_ANDROID
|
||||
1000
libs/mmkv/Android/src/main/java/com/tencent/mmkv/MMKV.java
Normal file
1000
libs/mmkv/Android/src/main/java/com/tencent/mmkv/MMKV.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
package com.tencent.mmkv;
|
||||
|
||||
public interface MMKVContentChangeNotification {
|
||||
|
||||
// content change notification of other process
|
||||
// trigger by getXXX() or setXXX() or checkContentChangedByOuterProcess()
|
||||
void onContentChangedByOuterProcess(String mmapID);
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.mmkv;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class MMKVContentProvider extends ContentProvider {
|
||||
|
||||
static protected final String KEY = "KEY";
|
||||
static protected final String KEY_SIZE = "KEY_SIZE";
|
||||
static protected final String KEY_MODE = "KEY_MODE";
|
||||
static protected final String KEY_CRYPT = "KEY_CRYPT";
|
||||
static protected final String FUNCTION_NAME = "mmkvFromAshmemID";
|
||||
|
||||
static private Uri gUri;
|
||||
|
||||
@Nullable
|
||||
static protected Uri contentUri(Context context) {
|
||||
if (MMKVContentProvider.gUri != null) {
|
||||
return MMKVContentProvider.gUri;
|
||||
}
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
String authority = queryAuthority(context);
|
||||
if (authority == null) {
|
||||
return null;
|
||||
}
|
||||
MMKVContentProvider.gUri = Uri.parse(ContentResolver.SCHEME_CONTENT + "://" + authority);
|
||||
return MMKVContentProvider.gUri;
|
||||
}
|
||||
|
||||
private Bundle mmkvFromAshmemID(String ashmemID, int size, int mode, String cryptKey) {
|
||||
MMKV mmkv = MMKV.mmkvWithAshmemID(getContext(), ashmemID, size, mode, cryptKey);
|
||||
if (mmkv != null) {
|
||||
ParcelableMMKV parcelableMMKV = new ParcelableMMKV(mmkv);
|
||||
Log.i("MMKV",
|
||||
ashmemID + " fd = " + mmkv.ashmemFD() + ", meta fd = " + mmkv.ashmemMetaFD());
|
||||
Bundle result = new Bundle();
|
||||
result.putParcelable(MMKVContentProvider.KEY, parcelableMMKV);
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String queryAuthority(Context context) {
|
||||
try {
|
||||
ComponentName componentName = new ComponentName(context,
|
||||
MMKVContentProvider.class.getName());
|
||||
PackageManager mgr = context.getPackageManager();
|
||||
if (mgr != null) {
|
||||
ProviderInfo providerInfo = mgr.getProviderInfo(componentName, 0);
|
||||
if (providerInfo != null) {
|
||||
return providerInfo.authority;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
Context context = getContext();
|
||||
if (context == null) {
|
||||
return false;
|
||||
}
|
||||
String authority = queryAuthority(context);
|
||||
if (authority == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MMKVContentProvider.gUri == null) {
|
||||
MMKVContentProvider.gUri = Uri
|
||||
.parse(ContentResolver.SCHEME_CONTENT + "://" + authority);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static String getProcessNameByPID(Context context, int pid) {
|
||||
ActivityManager manager = (ActivityManager) context
|
||||
.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (manager != null) {
|
||||
// clang-format off
|
||||
for (ActivityManager.RunningAppProcessInfo processInfo
|
||||
: manager.getRunningAppProcesses()) {
|
||||
if (processInfo.pid == pid) {
|
||||
return processInfo.processName;
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Bundle call(@NonNull String method, @Nullable String mmapID, @Nullable Bundle extras) {
|
||||
if (method.equals(MMKVContentProvider.FUNCTION_NAME)) {
|
||||
if (extras != null) {
|
||||
int size = extras.getInt(MMKVContentProvider.KEY_SIZE);
|
||||
int mode = extras.getInt(MMKVContentProvider.KEY_MODE);
|
||||
String cryptKey = extras.getString(MMKVContentProvider.KEY_CRYPT);
|
||||
return mmkvFromAshmemID(mmapID, size, mode, cryptKey);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getType(@NonNull Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri,
|
||||
@Nullable String[] projection,
|
||||
@Nullable String selection,
|
||||
@Nullable String[] selectionArgs,
|
||||
@Nullable String sortOrder) {
|
||||
throw new java.lang.UnsupportedOperationException("Not implement in MMKV");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri,
|
||||
@Nullable ContentValues values,
|
||||
@Nullable String selection,
|
||||
@Nullable String[] selectionArgs) {
|
||||
throw new java.lang.UnsupportedOperationException("Not implement in MMKV");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, @Nullable String selection,
|
||||
@Nullable String[] selectionArgs) {
|
||||
throw new java.lang.UnsupportedOperationException("Not implement in MMKV");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
|
||||
throw new java.lang.UnsupportedOperationException("Not implement in MMKV");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.mmkv;
|
||||
|
||||
// callback is called on the operating thread of the MMKV instance
|
||||
public interface MMKVHandler {
|
||||
|
||||
// by default MMKV will discard all data on crc32-check failure
|
||||
// return `OnErrorRecover` to recover any data on the file
|
||||
MMKVRecoverStrategic onMMKVCRCCheckFail(String mmapID);
|
||||
|
||||
// by default MMKV will discard all data on file length mismatch
|
||||
// return `OnErrorRecover` to recover any data on the file
|
||||
MMKVRecoverStrategic onMMKVFileLengthError(String mmapID);
|
||||
|
||||
// return false if you don't want log redirecting
|
||||
boolean wantLogRedirecting();
|
||||
|
||||
// log redirecting
|
||||
void mmkvLog(MMKVLogLevel level, String file, int line, String function, String message);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.tencent.mmkv;
|
||||
|
||||
public enum MMKVLogLevel {
|
||||
LevelDebug, // not available for release/production build
|
||||
LevelInfo, // default level
|
||||
LevelWarning,
|
||||
LevelError,
|
||||
LevelNone // special level used to disable all log messages
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.mmkv;
|
||||
|
||||
public enum MMKVRecoverStrategic {
|
||||
OnErrorDiscard,
|
||||
OnErrorRecover,
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tencent.mmkv;
|
||||
|
||||
public final class NativeBuffer {
|
||||
|
||||
public long pointer;
|
||||
public int size;
|
||||
|
||||
public NativeBuffer(long ptr, int length) {
|
||||
pointer = ptr;
|
||||
size = length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.tencent.mmkv;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class ParcelableMMKV implements Parcelable {
|
||||
|
||||
private final String mmapID;
|
||||
private int ashmemFD = -1;
|
||||
private int ashmemMetaFD = -1;
|
||||
private String cryptKey = null;
|
||||
|
||||
public ParcelableMMKV(MMKV mmkv) {
|
||||
mmapID = mmkv.mmapID();
|
||||
ashmemFD = mmkv.ashmemFD();
|
||||
ashmemMetaFD = mmkv.ashmemMetaFD();
|
||||
cryptKey = mmkv.cryptKey();
|
||||
}
|
||||
|
||||
private ParcelableMMKV(String id, int fd, int metaFD, String key) {
|
||||
mmapID = id;
|
||||
ashmemFD = fd;
|
||||
ashmemMetaFD = metaFD;
|
||||
cryptKey = key;
|
||||
}
|
||||
|
||||
public MMKV toMMKV() {
|
||||
if (ashmemFD >= 0 && ashmemMetaFD >= 0) {
|
||||
return MMKV.mmkvWithAshmemFD(mmapID, ashmemFD, ashmemMetaFD, cryptKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return CONTENTS_FILE_DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
try {
|
||||
dest.writeString(mmapID);
|
||||
ParcelFileDescriptor fd = ParcelFileDescriptor.fromFd(ashmemFD);
|
||||
ParcelFileDescriptor metaFD = ParcelFileDescriptor.fromFd(ashmemMetaFD);
|
||||
flags = flags | Parcelable.PARCELABLE_WRITE_RETURN_VALUE;
|
||||
fd.writeToParcel(dest, flags);
|
||||
metaFD.writeToParcel(dest, flags);
|
||||
if (cryptKey != null) {
|
||||
dest.writeString(cryptKey);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ParcelableMMKV> CREATOR = new Parcelable.Creator<ParcelableMMKV>() {
|
||||
@Override
|
||||
public ParcelableMMKV createFromParcel(Parcel source) {
|
||||
String mmapID = source.readString();
|
||||
ParcelFileDescriptor fd = ParcelFileDescriptor.CREATOR.createFromParcel(source);
|
||||
ParcelFileDescriptor metaFD = ParcelFileDescriptor.CREATOR.createFromParcel(source);
|
||||
String cryptKey = source.readString();
|
||||
if (fd != null && metaFD != null) {
|
||||
return new ParcelableMMKV(mmapID, fd.detachFd(), metaFD.detachFd(), cryptKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelableMMKV[] newArray(int size) {
|
||||
return new ParcelableMMKV[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
144
libs/mmkv/Core/CMakeLists.txt
Normal file
144
libs/mmkv/Core/CMakeLists.txt
Normal file
@@ -0,0 +1,144 @@
|
||||
#
|
||||
# Tencent is pleased to support the open source community by making
|
||||
# MMKV available.
|
||||
#
|
||||
# Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
# this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# https://opensource.org/licenses/BSD-3-Clause
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.0)
|
||||
|
||||
IF (APPLE)
|
||||
# tell ranlib to ignore empty compilation units
|
||||
SET(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
SET(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
# prevents ar from invoking ranlib, let CMake do it
|
||||
SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qc -S <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
SET(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qc -S <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
|
||||
add_compile_definitions(FORCE_POSIX)
|
||||
ENDIF ()
|
||||
|
||||
set(can_use_assembler TRUE)
|
||||
enable_language(ASM)
|
||||
IF ("${ANDROID_ABI}" STREQUAL "arm64-v8a")
|
||||
SET(ASM_OPTIONS "-x assembler-with-cpp")
|
||||
SET(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS} -march=armv8+crypto -D__ANDROID__")
|
||||
ELSEIF ("${ANDROID_ABI}" STREQUAL "armeabi-v7a")
|
||||
SET(ASM_OPTIONS "-x assembler-with-cpp")
|
||||
SET(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS} -march=armv7a -D__ANDROID__")
|
||||
ELSEIF ("${ANDROID_ABI}" STREQUAL "armeabi")
|
||||
SET(ASM_OPTIONS "-x assembler-with-cpp")
|
||||
SET(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS} -march=armv5 -D__ANDROID__")
|
||||
ENDIF ()
|
||||
|
||||
#include(CMakePrintHelpers)
|
||||
#cmake_print_variables(CMAKE_SYSTEM_PROCESSOR)
|
||||
IF (UNIX AND (NOT APPLE))
|
||||
IF ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64")
|
||||
SET(ASM_OPTIONS "-x assembler-with-cpp")
|
||||
SET(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS} -march=armv8-a+crypto")
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
|
||||
project(core)
|
||||
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# You can define multiple libraries, and CMake builds them for you.
|
||||
# Gradle automatically packages shared libraries with your APK.
|
||||
|
||||
add_library(core
|
||||
|
||||
# Sets the library as a shared library.
|
||||
STATIC
|
||||
|
||||
# Provides a relative path to your source file(s).
|
||||
MMKV.h
|
||||
MMKV.cpp
|
||||
MMKV_Android.cpp
|
||||
MMKV_IO.h
|
||||
MMKV_IO.cpp
|
||||
MMKVLog.h
|
||||
MMKVLog.cpp
|
||||
MMKVLog_Android.cpp
|
||||
CodedInputData.h
|
||||
CodedInputData.cpp
|
||||
CodedInputDataCrypt.h
|
||||
CodedInputDataCrypt.cpp
|
||||
CodedOutputData.h
|
||||
CodedOutputData.cpp
|
||||
KeyValueHolder.h
|
||||
KeyValueHolder.cpp
|
||||
PBUtility.h
|
||||
PBUtility.cpp
|
||||
MiniPBCoder.h
|
||||
MiniPBCoder.cpp
|
||||
MMBuffer.h
|
||||
MMBuffer.cpp
|
||||
InterProcessLock.h
|
||||
InterProcessLock.cpp
|
||||
InterProcessLock_Android.cpp
|
||||
MemoryFile.h
|
||||
MemoryFile.cpp
|
||||
MemoryFile_Android.cpp
|
||||
ThreadLock.h
|
||||
ThreadLock.cpp
|
||||
MMKVMetaInfo.hpp
|
||||
aes/AESCrypt.h
|
||||
aes/AESCrypt.cpp
|
||||
aes/openssl/openssl_aes.h
|
||||
aes/openssl/openssl_aes_core.cpp
|
||||
aes/openssl/openssl_aes_locl.h
|
||||
aes/openssl/openssl_cfb128.cpp
|
||||
aes/openssl/openssl_opensslconf.h
|
||||
aes/openssl/openssl_md5_dgst.cpp
|
||||
aes/openssl/openssl_md5_locl.h
|
||||
aes/openssl/openssl_md5_one.cpp
|
||||
aes/openssl/openssl_md5.h
|
||||
aes/openssl/openssl_md32_common.h
|
||||
aes/openssl/openssl_aesv8-armx.S
|
||||
aes/openssl/openssl_aes-armv4.S
|
||||
aes/openssl/openssl_arm_arch.h
|
||||
crc32/Checksum.h
|
||||
crc32/crc32_armv8.cpp
|
||||
crc32/zlib/zconf.h
|
||||
crc32/zlib/zutil.h
|
||||
crc32/zlib/crc32.h
|
||||
crc32/zlib/crc32.cpp
|
||||
MMKVPredef.h
|
||||
)
|
||||
|
||||
target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
set_target_properties(core PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_EXTENSIONS OFF
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
find_library(zlib
|
||||
z
|
||||
)
|
||||
|
||||
IF (NOT zlib)
|
||||
target_compile_definitions(core PUBLIC MMKV_EMBED_ZLIB=1)
|
||||
ELSE ()
|
||||
target_link_libraries(core ${zlib})
|
||||
ENDIF ()
|
||||
|
||||
228
libs/mmkv/Core/CodedInputData.cpp
Normal file
228
libs/mmkv/Core/CodedInputData.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CodedInputData.h"
|
||||
#include "PBUtility.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
# if __has_feature(objc_arc)
|
||||
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
||||
# endif
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
CodedInputData::CodedInputData(const void *oData, size_t length)
|
||||
: m_ptr((uint8_t *) oData), m_size(length), m_position(0) {
|
||||
MMKV_ASSERT(m_ptr);
|
||||
}
|
||||
|
||||
void CodedInputData::seek(size_t addedSize) {
|
||||
if (m_position + addedSize > m_size) {
|
||||
throw out_of_range("OutOfSpace");
|
||||
}
|
||||
m_position += addedSize;
|
||||
}
|
||||
|
||||
double CodedInputData::readDouble() {
|
||||
return Int64ToFloat64(this->readRawLittleEndian64());
|
||||
}
|
||||
|
||||
float CodedInputData::readFloat() {
|
||||
return Int32ToFloat32(this->readRawLittleEndian32());
|
||||
}
|
||||
|
||||
int64_t CodedInputData::readInt64() {
|
||||
int32_t shift = 0;
|
||||
int64_t result = 0;
|
||||
while (shift < 64) {
|
||||
int8_t b = this->readRawByte();
|
||||
result |= (int64_t)(b & 0x7f) << shift;
|
||||
if ((b & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
shift += 7;
|
||||
}
|
||||
throw invalid_argument("InvalidProtocolBuffer malformedInt64");
|
||||
}
|
||||
|
||||
uint64_t CodedInputData::readUInt64() {
|
||||
return static_cast<uint64_t>(readInt64());
|
||||
}
|
||||
|
||||
int32_t CodedInputData::readInt32() {
|
||||
return this->readRawVarint32();
|
||||
}
|
||||
|
||||
uint32_t CodedInputData::readUInt32() {
|
||||
return static_cast<uint32_t>(readRawVarint32());
|
||||
}
|
||||
|
||||
bool CodedInputData::readBool() {
|
||||
return this->readRawVarint32() != 0;
|
||||
}
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
|
||||
string CodedInputData::readString() {
|
||||
int32_t size = readRawVarint32();
|
||||
if (size < 0) {
|
||||
throw length_error("InvalidProtocolBuffer negativeSize");
|
||||
}
|
||||
|
||||
auto s_size = static_cast<size_t>(size);
|
||||
if (s_size <= m_size - m_position) {
|
||||
string result((char *) (m_ptr + m_position), s_size);
|
||||
m_position += s_size;
|
||||
return result;
|
||||
} else {
|
||||
throw out_of_range("InvalidProtocolBuffer truncatedMessage");
|
||||
}
|
||||
}
|
||||
|
||||
string CodedInputData::readString(KeyValueHolder &kvHolder) {
|
||||
kvHolder.offset = static_cast<uint32_t>(m_position);
|
||||
|
||||
int32_t size = this->readRawVarint32();
|
||||
if (size < 0) {
|
||||
throw length_error("InvalidProtocolBuffer negativeSize");
|
||||
}
|
||||
|
||||
auto s_size = static_cast<size_t>(size);
|
||||
if (s_size <= m_size - m_position) {
|
||||
kvHolder.keySize = static_cast<uint16_t>(s_size);
|
||||
|
||||
auto ptr = m_ptr + m_position;
|
||||
string result((char *) (m_ptr + m_position), s_size);
|
||||
m_position += s_size;
|
||||
return result;
|
||||
} else {
|
||||
throw out_of_range("InvalidProtocolBuffer truncatedMessage");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
MMBuffer CodedInputData::readData() {
|
||||
int32_t size = this->readRawVarint32();
|
||||
if (size < 0) {
|
||||
throw length_error("InvalidProtocolBuffer negativeSize");
|
||||
}
|
||||
|
||||
auto s_size = static_cast<size_t>(size);
|
||||
if (s_size <= m_size - m_position) {
|
||||
MMBuffer data(((int8_t *) m_ptr) + m_position, s_size);
|
||||
m_position += s_size;
|
||||
return data;
|
||||
} else {
|
||||
throw out_of_range("InvalidProtocolBuffer truncatedMessage");
|
||||
}
|
||||
}
|
||||
|
||||
void CodedInputData::readData(KeyValueHolder &kvHolder) {
|
||||
int32_t size = this->readRawVarint32();
|
||||
if (size < 0) {
|
||||
throw length_error("InvalidProtocolBuffer negativeSize");
|
||||
}
|
||||
|
||||
auto s_size = static_cast<size_t>(size);
|
||||
if (s_size <= m_size - m_position) {
|
||||
kvHolder.computedKVSize = static_cast<uint16_t>(m_position - kvHolder.offset);
|
||||
kvHolder.valueSize = static_cast<uint32_t>(s_size);
|
||||
|
||||
m_position += s_size;
|
||||
} else {
|
||||
throw out_of_range("InvalidProtocolBuffer truncatedMessage");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t CodedInputData::readRawVarint32() {
|
||||
int8_t tmp = this->readRawByte();
|
||||
if (tmp >= 0) {
|
||||
return tmp;
|
||||
}
|
||||
int32_t result = tmp & 0x7f;
|
||||
if ((tmp = this->readRawByte()) >= 0) {
|
||||
result |= tmp << 7;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 7;
|
||||
if ((tmp = this->readRawByte()) >= 0) {
|
||||
result |= tmp << 14;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 14;
|
||||
if ((tmp = this->readRawByte()) >= 0) {
|
||||
result |= tmp << 21;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 21;
|
||||
result |= (tmp = this->readRawByte()) << 28;
|
||||
if (tmp < 0) {
|
||||
// discard upper 32 bits
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (this->readRawByte() >= 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw invalid_argument("InvalidProtocolBuffer malformed varint32");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t CodedInputData::readRawLittleEndian32() {
|
||||
int8_t b1 = this->readRawByte();
|
||||
int8_t b2 = this->readRawByte();
|
||||
int8_t b3 = this->readRawByte();
|
||||
int8_t b4 = this->readRawByte();
|
||||
return (((int32_t) b1 & 0xff)) | (((int32_t) b2 & 0xff) << 8) | (((int32_t) b3 & 0xff) << 16) |
|
||||
(((int32_t) b4 & 0xff) << 24);
|
||||
}
|
||||
|
||||
int64_t CodedInputData::readRawLittleEndian64() {
|
||||
int8_t b1 = this->readRawByte();
|
||||
int8_t b2 = this->readRawByte();
|
||||
int8_t b3 = this->readRawByte();
|
||||
int8_t b4 = this->readRawByte();
|
||||
int8_t b5 = this->readRawByte();
|
||||
int8_t b6 = this->readRawByte();
|
||||
int8_t b7 = this->readRawByte();
|
||||
int8_t b8 = this->readRawByte();
|
||||
return (((int64_t) b1 & 0xff)) | (((int64_t) b2 & 0xff) << 8) | (((int64_t) b3 & 0xff) << 16) |
|
||||
(((int64_t) b4 & 0xff) << 24) | (((int64_t) b5 & 0xff) << 32) | (((int64_t) b6 & 0xff) << 40) |
|
||||
(((int64_t) b7 & 0xff) << 48) | (((int64_t) b8 & 0xff) << 56);
|
||||
}
|
||||
|
||||
int8_t CodedInputData::readRawByte() {
|
||||
if (m_position == m_size) {
|
||||
auto msg = "reach end, m_position: " + to_string(m_position) + ", m_size: " + to_string(m_size);
|
||||
throw out_of_range(msg);
|
||||
}
|
||||
auto *bytes = (int8_t *) m_ptr;
|
||||
return bytes[m_position++];
|
||||
}
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
} // namespace mmkv
|
||||
83
libs/mmkv/Core/CodedInputData.h
Normal file
83
libs/mmkv/Core/CodedInputData.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_CODEDINPUTDATA_H
|
||||
#define MMKV_CODEDINPUTDATA_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include "KeyValueHolder.h"
|
||||
#include "MMBuffer.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
class CodedInputData {
|
||||
uint8_t *const m_ptr;
|
||||
size_t m_size;
|
||||
size_t m_position;
|
||||
|
||||
int8_t readRawByte();
|
||||
|
||||
int32_t readRawVarint32();
|
||||
|
||||
int32_t readRawLittleEndian32();
|
||||
|
||||
int64_t readRawLittleEndian64();
|
||||
|
||||
public:
|
||||
CodedInputData(const void *oData, size_t length);
|
||||
|
||||
bool isAtEnd() const { return m_position == m_size; };
|
||||
|
||||
void seek(size_t addedSize);
|
||||
|
||||
bool readBool();
|
||||
|
||||
double readDouble();
|
||||
|
||||
float readFloat();
|
||||
|
||||
int64_t readInt64();
|
||||
|
||||
uint64_t readUInt64();
|
||||
|
||||
int32_t readInt32();
|
||||
|
||||
uint32_t readUInt32();
|
||||
|
||||
MMBuffer readData();
|
||||
void readData(KeyValueHolder &kvHolder);
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
std::string readString();
|
||||
std::string readString(KeyValueHolder &kvHolder);
|
||||
#else
|
||||
NSString *readString();
|
||||
NSString *readString(KeyValueHolder &kvHolder);
|
||||
NSData *readNSData();
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_CODEDINPUTDATA_H
|
||||
280
libs/mmkv/Core/CodedInputDataCrypt.cpp
Normal file
280
libs/mmkv/Core/CodedInputDataCrypt.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CodedInputDataCrypt.h"
|
||||
#include "MMKVLog.h"
|
||||
#include "PBUtility.h"
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
# if __has_feature(objc_arc)
|
||||
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
||||
# endif
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
CodedInputDataCrypt::CodedInputDataCrypt(const void *oData, size_t length, AESCrypt &crypt)
|
||||
: m_ptr((uint8_t *) oData), m_size(length), m_position(0), m_decryptPosition(0), m_decrypter(crypt) {
|
||||
m_decryptBufferSize = AES_KEY_LEN * 2;
|
||||
m_decryptBufferPosition = static_cast<size_t>(crypt.m_number);
|
||||
m_decryptBufferDiscardPosition = m_decryptBufferPosition;
|
||||
m_decryptBufferDecryptLength = m_decryptBufferPosition;
|
||||
|
||||
m_decryptBuffer = (uint8_t *) malloc(m_decryptBufferSize);
|
||||
if (!m_decryptBuffer) {
|
||||
throw runtime_error(strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
CodedInputDataCrypt::~CodedInputDataCrypt() {
|
||||
if (m_decryptBuffer) {
|
||||
free(m_decryptBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CodedInputDataCrypt::seek(size_t addedSize) {
|
||||
m_position += addedSize;
|
||||
m_decryptPosition += addedSize;
|
||||
|
||||
if (m_position > m_size) {
|
||||
throw out_of_range("OutOfSpace");
|
||||
}
|
||||
assert(m_position % AES_KEY_LEN == m_decrypter.m_number);
|
||||
}
|
||||
|
||||
void CodedInputDataCrypt::consumeBytes(size_t length, bool discardPreData) {
|
||||
if (discardPreData) {
|
||||
m_decryptBufferDiscardPosition = m_decryptBufferPosition;
|
||||
}
|
||||
auto decryptedBytesLeft = m_decryptBufferDecryptLength - m_decryptBufferPosition;
|
||||
if (decryptedBytesLeft >= length) {
|
||||
return;
|
||||
}
|
||||
length -= decryptedBytesLeft;
|
||||
|
||||
// if there's some data left inside m_decrypter.m_vector, use them first
|
||||
// it will be faster when always decrypt with (n * AES_KEY_LEN) bytes
|
||||
if (m_decrypter.m_number != 0) {
|
||||
auto alignDecrypter = AES_KEY_LEN - m_decrypter.m_number;
|
||||
// make sure no data left inside m_decrypter.m_vector after decrypt
|
||||
if (length < alignDecrypter) {
|
||||
length = alignDecrypter;
|
||||
} else {
|
||||
length -= alignDecrypter;
|
||||
length = ((length + AES_KEY_LEN - 1) / AES_KEY_LEN) * AES_KEY_LEN;
|
||||
length += alignDecrypter;
|
||||
}
|
||||
} else {
|
||||
length = ((length + AES_KEY_LEN - 1) / AES_KEY_LEN) * AES_KEY_LEN;
|
||||
}
|
||||
auto bytesLeftInSrc = m_size - m_decryptPosition;
|
||||
length = min(bytesLeftInSrc, length);
|
||||
|
||||
auto bytesLeftInBuffer = m_decryptBufferSize - m_decryptBufferDecryptLength;
|
||||
// try move some space
|
||||
if (bytesLeftInBuffer < length && m_decryptBufferDiscardPosition > 0) {
|
||||
auto posToMove = (m_decryptBufferDiscardPosition / AES_KEY_LEN) * AES_KEY_LEN;
|
||||
if (posToMove) {
|
||||
auto sizeToMove = m_decryptBufferDecryptLength - posToMove;
|
||||
memmove(m_decryptBuffer, m_decryptBuffer + posToMove, sizeToMove);
|
||||
m_decryptBufferPosition -= posToMove;
|
||||
m_decryptBufferDecryptLength -= posToMove;
|
||||
m_decryptBufferDiscardPosition = 0;
|
||||
bytesLeftInBuffer = m_decryptBufferSize - m_decryptBufferDecryptLength;
|
||||
}
|
||||
}
|
||||
// still no enough sapce, try realloc()
|
||||
if (bytesLeftInBuffer < length) {
|
||||
auto newSize = m_decryptBufferSize + length;
|
||||
auto newBuffer = realloc(m_decryptBuffer, newSize);
|
||||
if (!newBuffer) {
|
||||
throw runtime_error(strerror(errno));
|
||||
}
|
||||
m_decryptBuffer = (uint8_t *) newBuffer;
|
||||
m_decryptBufferSize = newSize;
|
||||
}
|
||||
m_decrypter.decrypt(m_ptr + m_decryptPosition, m_decryptBuffer + m_decryptBufferDecryptLength, length);
|
||||
m_decryptPosition += length;
|
||||
m_decryptBufferDecryptLength += length;
|
||||
assert(m_decryptPosition == m_size || m_decrypter.m_number == 0);
|
||||
}
|
||||
|
||||
void CodedInputDataCrypt::skipBytes(size_t length) {
|
||||
m_position += length;
|
||||
|
||||
auto decryptedBytesLeft = m_decryptBufferDecryptLength - m_decryptBufferPosition;
|
||||
if (decryptedBytesLeft >= length) {
|
||||
m_decryptBufferPosition += length;
|
||||
return;
|
||||
}
|
||||
length -= decryptedBytesLeft;
|
||||
// if this happens, we need optimization like the alignDecrypter above
|
||||
assert(m_decrypter.m_number == 0);
|
||||
|
||||
size_t alignSize = ((length + AES_KEY_LEN - 1) / AES_KEY_LEN) * AES_KEY_LEN;
|
||||
auto bytesLeftInSrc = m_size - m_decryptPosition;
|
||||
auto size = min(alignSize, bytesLeftInSrc);
|
||||
decryptedBytesLeft = size - length;
|
||||
for (size_t index = 0, round = size / AES_KEY_LEN; index < round; index++) {
|
||||
m_decrypter.decrypt(m_ptr + m_decryptPosition, m_decryptBuffer, AES_KEY_LEN);
|
||||
m_decryptPosition += AES_KEY_LEN;
|
||||
size -= AES_KEY_LEN;
|
||||
}
|
||||
if (size) {
|
||||
m_decrypter.decrypt(m_ptr + m_decryptPosition, m_decryptBuffer, size);
|
||||
m_decryptPosition += size;
|
||||
m_decryptBufferPosition = size - decryptedBytesLeft;
|
||||
m_decryptBufferDecryptLength = size;
|
||||
} else {
|
||||
m_decryptBufferPosition = AES_KEY_LEN - decryptedBytesLeft;
|
||||
m_decryptBufferDecryptLength = AES_KEY_LEN;
|
||||
}
|
||||
assert(m_decryptBufferPosition <= m_decryptBufferDecryptLength);
|
||||
assert(m_decryptPosition - m_decryptBufferDecryptLength + m_decryptBufferPosition == m_position);
|
||||
}
|
||||
|
||||
inline void CodedInputDataCrypt::statusBeforeDecrypt(size_t rollbackSize, AESCryptStatus &status) {
|
||||
rollbackSize += m_decryptBufferDecryptLength - m_decryptBufferPosition;
|
||||
m_decrypter.statusBeforeDecrypt(m_ptr + m_decryptPosition, m_decryptBuffer + m_decryptBufferDecryptLength,
|
||||
rollbackSize, status);
|
||||
}
|
||||
|
||||
int8_t CodedInputDataCrypt::readRawByte() {
|
||||
assert(m_position <= m_decryptPosition);
|
||||
if (m_position == m_size) {
|
||||
auto msg = "reach end, m_position: " + to_string(m_position) + ", m_size: " + to_string(m_size);
|
||||
throw out_of_range(msg);
|
||||
}
|
||||
m_position++;
|
||||
|
||||
assert(m_decryptBufferPosition < m_decryptBufferSize);
|
||||
auto *bytes = (int8_t *) m_decryptBuffer;
|
||||
return bytes[m_decryptBufferPosition++];
|
||||
}
|
||||
|
||||
int32_t CodedInputDataCrypt::readRawVarint32(bool discardPreData) {
|
||||
consumeBytes(10, discardPreData);
|
||||
|
||||
int8_t tmp = this->readRawByte();
|
||||
if (tmp >= 0) {
|
||||
return tmp;
|
||||
}
|
||||
int32_t result = tmp & 0x7f;
|
||||
if ((tmp = this->readRawByte()) >= 0) {
|
||||
result |= tmp << 7;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 7;
|
||||
if ((tmp = this->readRawByte()) >= 0) {
|
||||
result |= tmp << 14;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 14;
|
||||
if ((tmp = this->readRawByte()) >= 0) {
|
||||
result |= tmp << 21;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 21;
|
||||
result |= (tmp = this->readRawByte()) << 28;
|
||||
if (tmp < 0) {
|
||||
// discard upper 32 bits
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (this->readRawByte() >= 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw invalid_argument("InvalidProtocolBuffer malformed varint32");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t CodedInputDataCrypt::readInt32() {
|
||||
return this->readRawVarint32();
|
||||
}
|
||||
|
||||
# ifndef MMKV_APPLE
|
||||
|
||||
string CodedInputDataCrypt::readString(KeyValueHolderCrypt &kvHolder) {
|
||||
kvHolder.offset = static_cast<uint32_t>(m_position);
|
||||
|
||||
int32_t size = this->readRawVarint32(true);
|
||||
if (size < 0) {
|
||||
throw length_error("InvalidProtocolBuffer negativeSize");
|
||||
}
|
||||
|
||||
auto s_size = static_cast<size_t>(size);
|
||||
if (s_size <= m_size - m_position) {
|
||||
consumeBytes(s_size);
|
||||
|
||||
kvHolder.keySize = static_cast<uint16_t>(s_size);
|
||||
|
||||
string result((char *) (m_decryptBuffer + m_decryptBufferPosition), s_size);
|
||||
m_position += s_size;
|
||||
m_decryptBufferPosition += s_size;
|
||||
return result;
|
||||
} else {
|
||||
throw out_of_range("InvalidProtocolBuffer truncatedMessage");
|
||||
}
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
void CodedInputDataCrypt::readData(KeyValueHolderCrypt &kvHolder) {
|
||||
int32_t size = this->readRawVarint32();
|
||||
if (size < 0) {
|
||||
throw length_error("InvalidProtocolBuffer negativeSize");
|
||||
}
|
||||
|
||||
auto s_size = static_cast<size_t>(size);
|
||||
if (s_size <= m_size - m_position) {
|
||||
if (KeyValueHolderCrypt::isValueStoredAsOffset(s_size)) {
|
||||
kvHolder.type = KeyValueHolderType_Offset;
|
||||
kvHolder.valueSize = static_cast<uint32_t>(s_size);
|
||||
kvHolder.pbKeyValueSize =
|
||||
static_cast<uint8_t>(pbRawVarint32Size(kvHolder.valueSize) + pbRawVarint32Size(kvHolder.keySize));
|
||||
|
||||
size_t rollbackSize = kvHolder.pbKeyValueSize + kvHolder.keySize;
|
||||
statusBeforeDecrypt(rollbackSize, kvHolder.cryptStatus);
|
||||
|
||||
skipBytes(s_size);
|
||||
} else {
|
||||
consumeBytes(s_size);
|
||||
|
||||
kvHolder.type = KeyValueHolderType_Direct;
|
||||
kvHolder = KeyValueHolderCrypt(m_decryptBuffer + m_decryptBufferPosition, s_size);
|
||||
m_decryptBufferPosition += s_size;
|
||||
m_position += s_size;
|
||||
}
|
||||
} else {
|
||||
throw out_of_range("InvalidProtocolBuffer truncatedMessage");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
87
libs/mmkv/Core/CodedInputDataCrypt.h
Normal file
87
libs/mmkv/Core/CodedInputDataCrypt.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CodedInputDataCrypt_h
|
||||
#define CodedInputDataCrypt_h
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include "KeyValueHolder.h"
|
||||
#include "MMBuffer.h"
|
||||
#include "aes/AESCrypt.h"
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef MMKV_DISABLE_CRYPT
|
||||
|
||||
namespace mmkv {
|
||||
class CodedInputDataCrypt;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
class CodedInputDataCrypt {
|
||||
uint8_t *const m_ptr;
|
||||
size_t m_size;
|
||||
size_t m_position;
|
||||
size_t m_decryptPosition; // position of text that has beed decrypted
|
||||
|
||||
AESCrypt &m_decrypter;
|
||||
uint8_t *m_decryptBuffer; // internal decrypt buffer, grows by (n * AES_KEY_LEN) bytes
|
||||
size_t m_decryptBufferSize;
|
||||
size_t m_decryptBufferPosition; // reader position in the buffer, synced with m_position
|
||||
size_t m_decryptBufferDecryptLength; // length of the buffer that has been used
|
||||
size_t m_decryptBufferDiscardPosition; // recycle position, any data before that can be discarded
|
||||
|
||||
void consumeBytes(size_t length, bool discardPreData = false);
|
||||
void skipBytes(size_t length);
|
||||
void statusBeforeDecrypt(size_t rollbackSize, AESCryptStatus &status);
|
||||
|
||||
int8_t readRawByte();
|
||||
|
||||
int32_t readRawVarint32(bool discardPreData = false);
|
||||
|
||||
public:
|
||||
CodedInputDataCrypt(const void *oData, size_t length, AESCrypt &crypt);
|
||||
|
||||
~CodedInputDataCrypt();
|
||||
|
||||
bool isAtEnd() { return m_position == m_size; };
|
||||
|
||||
void seek(size_t addedSize);
|
||||
|
||||
int32_t readInt32();
|
||||
|
||||
void readData(KeyValueHolderCrypt &kvHolder);
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
std::string readString(KeyValueHolderCrypt &kvHolder);
|
||||
#else
|
||||
NSString *readString(KeyValueHolderCrypt &kvHolder);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
#endif // __cplusplus
|
||||
#endif /* CodedInputDataCrypt_h */
|
||||
174
libs/mmkv/Core/CodedOutputData.cpp
Normal file
174
libs/mmkv/Core/CodedOutputData.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CodedOutputData.h"
|
||||
#include "PBUtility.h"
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
# if __has_feature(objc_arc)
|
||||
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
||||
# endif
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
CodedOutputData::CodedOutputData(void *ptr, size_t len) : m_ptr((uint8_t *) ptr), m_size(len), m_position(0) {
|
||||
MMKV_ASSERT(m_ptr);
|
||||
}
|
||||
|
||||
uint8_t *CodedOutputData::curWritePointer() {
|
||||
return m_ptr + m_position;
|
||||
}
|
||||
|
||||
void CodedOutputData::writeDouble(double value) {
|
||||
this->writeRawLittleEndian64(Float64ToInt64(value));
|
||||
}
|
||||
|
||||
void CodedOutputData::writeFloat(float value) {
|
||||
this->writeRawLittleEndian32(Float32ToInt32(value));
|
||||
}
|
||||
|
||||
void CodedOutputData::writeInt64(int64_t value) {
|
||||
this->writeRawVarint64(value);
|
||||
}
|
||||
|
||||
void CodedOutputData::writeUInt64(uint64_t value) {
|
||||
writeRawVarint64(static_cast<int64_t>(value));
|
||||
}
|
||||
|
||||
void CodedOutputData::writeInt32(int32_t value) {
|
||||
if (value >= 0) {
|
||||
this->writeRawVarint32(value);
|
||||
} else {
|
||||
this->writeRawVarint64(value);
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputData::writeUInt32(uint32_t value) {
|
||||
writeRawVarint32(static_cast<int32_t>(value));
|
||||
}
|
||||
|
||||
void CodedOutputData::writeBool(bool value) {
|
||||
this->writeRawByte(static_cast<uint8_t>(value ? 1 : 0));
|
||||
}
|
||||
|
||||
void CodedOutputData::writeData(const MMBuffer &value) {
|
||||
this->writeRawVarint32((int32_t) value.length());
|
||||
this->writeRawData(value);
|
||||
}
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
|
||||
void CodedOutputData::writeString(const string &value) {
|
||||
size_t numberOfBytes = value.size();
|
||||
this->writeRawVarint32((int32_t) numberOfBytes);
|
||||
if (m_position + numberOfBytes > m_size) {
|
||||
auto msg = "m_position: " + to_string(m_position) + ", numberOfBytes: " + to_string(numberOfBytes) +
|
||||
", m_size: " + to_string(m_size);
|
||||
throw out_of_range(msg);
|
||||
}
|
||||
memcpy(m_ptr + m_position, ((uint8_t *) value.data()), numberOfBytes);
|
||||
m_position += numberOfBytes;
|
||||
}
|
||||
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
size_t CodedOutputData::spaceLeft() {
|
||||
if (m_size <= m_position) {
|
||||
return 0;
|
||||
}
|
||||
return m_size - m_position;
|
||||
}
|
||||
|
||||
void CodedOutputData::seek(size_t addedSize) {
|
||||
m_position += addedSize;
|
||||
|
||||
if (m_position > m_size) {
|
||||
throw out_of_range("OutOfSpace");
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputData::writeRawByte(uint8_t value) {
|
||||
if (m_position == m_size) {
|
||||
throw out_of_range("m_position: " + to_string(m_position) + " m_size: " + to_string(m_size));
|
||||
return;
|
||||
}
|
||||
|
||||
m_ptr[m_position++] = value;
|
||||
}
|
||||
|
||||
void CodedOutputData::writeRawData(const MMBuffer &data) {
|
||||
size_t numberOfBytes = data.length();
|
||||
if (m_position + numberOfBytes > m_size) {
|
||||
auto msg = "m_position: " + to_string(m_position) + ", numberOfBytes: " + to_string(numberOfBytes) +
|
||||
", m_size: " + to_string(m_size);
|
||||
throw out_of_range(msg);
|
||||
}
|
||||
memcpy(m_ptr + m_position, data.getPtr(), numberOfBytes);
|
||||
m_position += numberOfBytes;
|
||||
}
|
||||
|
||||
void CodedOutputData::writeRawVarint32(int32_t value) {
|
||||
while (true) {
|
||||
if ((value & ~0x7f) == 0) {
|
||||
this->writeRawByte(static_cast<uint8_t>(value));
|
||||
return;
|
||||
} else {
|
||||
this->writeRawByte(static_cast<uint8_t>((value & 0x7F) | 0x80));
|
||||
value = logicalRightShift32(value, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputData::writeRawVarint64(int64_t value) {
|
||||
while (true) {
|
||||
if ((value & ~0x7f) == 0) {
|
||||
this->writeRawByte(static_cast<uint8_t>(value));
|
||||
return;
|
||||
} else {
|
||||
this->writeRawByte(static_cast<uint8_t>((value & 0x7f) | 0x80));
|
||||
value = logicalRightShift64(value, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputData::writeRawLittleEndian32(int32_t value) {
|
||||
this->writeRawByte(static_cast<uint8_t>((value) &0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 8) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 16) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 24) & 0xff));
|
||||
}
|
||||
|
||||
void CodedOutputData::writeRawLittleEndian64(int64_t value) {
|
||||
this->writeRawByte(static_cast<uint8_t>((value) &0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 8) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 16) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 24) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 32) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 40) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 48) & 0xff));
|
||||
this->writeRawByte(static_cast<uint8_t>((value >> 56) & 0xff));
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
82
libs/mmkv/Core/CodedOutputData.h
Normal file
82
libs/mmkv/Core/CodedOutputData.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_CODEDOUTPUTDATA_H
|
||||
#define MMKV_CODEDOUTPUTDATA_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include "MMBuffer.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
class CodedOutputData {
|
||||
uint8_t *const m_ptr;
|
||||
size_t m_size;
|
||||
size_t m_position;
|
||||
|
||||
public:
|
||||
CodedOutputData(void *ptr, size_t len);
|
||||
|
||||
size_t spaceLeft();
|
||||
|
||||
uint8_t *curWritePointer();
|
||||
|
||||
void seek(size_t addedSize);
|
||||
|
||||
void writeRawByte(uint8_t value);
|
||||
|
||||
void writeRawLittleEndian32(int32_t value);
|
||||
|
||||
void writeRawLittleEndian64(int64_t value);
|
||||
|
||||
void writeRawVarint32(int32_t value);
|
||||
|
||||
void writeRawVarint64(int64_t value);
|
||||
|
||||
void writeRawData(const MMBuffer &data);
|
||||
|
||||
void writeDouble(double value);
|
||||
|
||||
void writeFloat(float value);
|
||||
|
||||
void writeInt64(int64_t value);
|
||||
|
||||
void writeUInt64(uint64_t value);
|
||||
|
||||
void writeInt32(int32_t value);
|
||||
|
||||
void writeUInt32(uint32_t value);
|
||||
|
||||
void writeBool(bool value);
|
||||
|
||||
void writeData(const MMBuffer &value);
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
void writeString(const std::string &value);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_CODEDOUTPUTDATA_H
|
||||
186
libs/mmkv/Core/InterProcessLock.cpp
Normal file
186
libs/mmkv/Core/InterProcessLock.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "InterProcessLock.h"
|
||||
#include "MMKVLog.h"
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
bool FileLock::lock(LockType lockType) {
|
||||
return doLock(lockType, true);
|
||||
}
|
||||
|
||||
bool FileLock::try_lock(LockType lockType, bool *tryAgain) {
|
||||
return doLock(lockType, false, tryAgain);
|
||||
}
|
||||
|
||||
bool FileLock::doLock(LockType lockType, bool wait, bool *tryAgain) {
|
||||
if (!isFileLockValid()) {
|
||||
return false;
|
||||
}
|
||||
bool unLockFirstIfNeeded = false;
|
||||
|
||||
if (lockType == SharedLockType) {
|
||||
// don't want shared-lock to break any existing locks
|
||||
if (m_sharedLockCount > 0 || m_exclusiveLockCount > 0) {
|
||||
m_sharedLockCount++;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// don't want exclusive-lock to break existing exclusive-locks
|
||||
if (m_exclusiveLockCount > 0) {
|
||||
m_exclusiveLockCount++;
|
||||
return true;
|
||||
}
|
||||
// prevent deadlock
|
||||
if (m_sharedLockCount > 0) {
|
||||
unLockFirstIfNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = platformLock(lockType, wait, unLockFirstIfNeeded, tryAgain);
|
||||
if (ret) {
|
||||
if (lockType == SharedLockType) {
|
||||
m_sharedLockCount++;
|
||||
} else {
|
||||
m_exclusiveLockCount++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
|
||||
static int32_t LockType2FlockType(LockType lockType) {
|
||||
switch (lockType) {
|
||||
case SharedLockType:
|
||||
return LOCK_SH;
|
||||
case ExclusiveLockType:
|
||||
return LOCK_EX;
|
||||
}
|
||||
return LOCK_EX;
|
||||
}
|
||||
|
||||
bool FileLock::platformLock(LockType lockType, bool wait, bool unLockFirstIfNeeded, bool *tryAgain) {
|
||||
# ifdef MMKV_ANDROID
|
||||
if (m_isAshmem) {
|
||||
return ashmemLock(lockType, wait, unLockFirstIfNeeded, tryAgain);
|
||||
}
|
||||
# endif
|
||||
auto realLockType = LockType2FlockType(lockType);
|
||||
auto cmd = wait ? realLockType : (realLockType | LOCK_NB);
|
||||
if (unLockFirstIfNeeded) {
|
||||
// try lock
|
||||
auto ret = flock(m_fd, realLockType | LOCK_NB);
|
||||
if (ret == 0) {
|
||||
return true;
|
||||
}
|
||||
// let's be gentleman: unlock my shared-lock to prevent deadlock
|
||||
ret = flock(m_fd, LOCK_UN);
|
||||
if (ret != 0) {
|
||||
MMKVError("fail to try unlock first fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = flock(m_fd, cmd);
|
||||
if (ret != 0) {
|
||||
if (tryAgain) {
|
||||
*tryAgain = (errno == EWOULDBLOCK);
|
||||
}
|
||||
if (wait) {
|
||||
MMKVError("fail to lock fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
}
|
||||
// try recover my shared-lock
|
||||
if (unLockFirstIfNeeded) {
|
||||
ret = flock(m_fd, LockType2FlockType(SharedLockType));
|
||||
if (ret != 0) {
|
||||
// let's hope this never happen
|
||||
MMKVError("fail to recover shared-lock fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileLock::platformUnLock(bool unlockToSharedLock) {
|
||||
# ifdef MMKV_ANDROID
|
||||
if (m_isAshmem) {
|
||||
return ashmemUnLock(unlockToSharedLock);
|
||||
}
|
||||
# endif
|
||||
int cmd = unlockToSharedLock ? LOCK_SH : LOCK_UN;
|
||||
auto ret = flock(m_fd, cmd);
|
||||
if (ret != 0) {
|
||||
MMKVError("fail to unlock fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MMKV_WIN32
|
||||
|
||||
bool FileLock::unlock(LockType lockType) {
|
||||
if (!isFileLockValid()) {
|
||||
return false;
|
||||
}
|
||||
bool unlockToSharedLock = false;
|
||||
|
||||
if (lockType == SharedLockType) {
|
||||
if (m_sharedLockCount == 0) {
|
||||
return false;
|
||||
}
|
||||
// don't want shared-lock to break any existing locks
|
||||
if (m_sharedLockCount > 1 || m_exclusiveLockCount > 0) {
|
||||
m_sharedLockCount--;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (m_exclusiveLockCount == 0) {
|
||||
return false;
|
||||
}
|
||||
if (m_exclusiveLockCount > 1) {
|
||||
m_exclusiveLockCount--;
|
||||
return true;
|
||||
}
|
||||
// restore shared-lock when all exclusive-locks are done
|
||||
if (m_sharedLockCount > 0) {
|
||||
unlockToSharedLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = platformUnLock(unlockToSharedLock);
|
||||
if (ret) {
|
||||
if (lockType == SharedLockType) {
|
||||
m_sharedLockCount--;
|
||||
} else {
|
||||
m_exclusiveLockCount--;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
119
libs/mmkv/Core/InterProcessLock.h
Normal file
119
libs/mmkv/Core/InterProcessLock.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_INTERPROCESSLOCK_H
|
||||
#define MMKV_INTERPROCESSLOCK_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
# include "MMKVPredef.h"
|
||||
|
||||
# include <fcntl.h>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
enum LockType {
|
||||
SharedLockType,
|
||||
ExclusiveLockType,
|
||||
};
|
||||
|
||||
// a recursive POSIX file-lock wrapper
|
||||
// handles lock upgrade & downgrade correctly
|
||||
class FileLock {
|
||||
MMKVFileHandle_t m_fd;
|
||||
size_t m_sharedLockCount;
|
||||
size_t m_exclusiveLockCount;
|
||||
|
||||
bool doLock(LockType lockType, bool wait, bool *tryAgain = nullptr);
|
||||
bool platformLock(LockType lockType, bool wait, bool unLockFirstIfNeeded, bool *tryAgain);
|
||||
bool platformUnLock(bool unLockFirstIfNeeded);
|
||||
|
||||
# ifndef MMKV_WIN32
|
||||
bool isFileLockValid() { return m_fd >= 0; }
|
||||
# ifdef MMKV_ANDROID
|
||||
const bool m_isAshmem;
|
||||
struct flock m_lockInfo;
|
||||
bool ashmemLock(LockType lockType, bool wait, bool unLockFirstIfNeeded, bool *tryAgain);
|
||||
bool ashmemUnLock(bool unLockFirstIfNeeded);
|
||||
# endif
|
||||
|
||||
# else // defined(MMKV_WIN32)
|
||||
OVERLAPPED m_overLapped;
|
||||
|
||||
bool isFileLockValid() { return m_fd != INVALID_HANDLE_VALUE; }
|
||||
# endif // MMKV_WIN32
|
||||
|
||||
public:
|
||||
# ifndef MMKV_WIN32
|
||||
# ifndef MMKV_ANDROID
|
||||
explicit FileLock(MMKVFileHandle_t fd) : m_fd(fd), m_sharedLockCount(0), m_exclusiveLockCount(0) {}
|
||||
# else
|
||||
explicit FileLock(MMKVFileHandle_t fd, bool isAshmem = false);
|
||||
# endif // MMKV_ANDROID
|
||||
# else // defined(MMKV_WIN32)
|
||||
explicit FileLock(MMKVFileHandle_t fd) : m_fd(fd), m_overLapped{}, m_sharedLockCount(0), m_exclusiveLockCount(0) {}
|
||||
# endif // MMKV_WIN32
|
||||
|
||||
bool lock(LockType lockType);
|
||||
|
||||
bool try_lock(LockType lockType, bool *tryAgain);
|
||||
|
||||
bool unlock(LockType lockType);
|
||||
|
||||
// just forbid it for possibly misuse
|
||||
explicit FileLock(const FileLock &other) = delete;
|
||||
FileLock &operator=(const FileLock &other) = delete;
|
||||
};
|
||||
|
||||
class InterProcessLock {
|
||||
FileLock *m_fileLock;
|
||||
LockType m_lockType;
|
||||
|
||||
public:
|
||||
InterProcessLock(FileLock *fileLock, LockType lockType)
|
||||
: m_fileLock(fileLock), m_lockType(lockType), m_enable(true) {
|
||||
MMKV_ASSERT(m_fileLock);
|
||||
}
|
||||
|
||||
bool m_enable;
|
||||
|
||||
void lock() {
|
||||
if (m_enable) {
|
||||
m_fileLock->lock(m_lockType);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock(bool *tryAgain = nullptr) {
|
||||
if (m_enable) {
|
||||
return m_fileLock->try_lock(m_lockType, tryAgain);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
if (m_enable) {
|
||||
m_fileLock->unlock(m_lockType);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // MMKV_INTERPROCESSLOCK_H
|
||||
103
libs/mmkv/Core/InterProcessLock_Android.cpp
Normal file
103
libs/mmkv/Core/InterProcessLock_Android.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "InterProcessLock.h"
|
||||
|
||||
#ifdef MMKV_ANDROID
|
||||
# include "MMKVLog.h"
|
||||
# include <sys/file.h>
|
||||
# include <unistd.h>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
FileLock::FileLock(MMKVFileHandle_t fd, bool isAshmem)
|
||||
: m_fd(fd), m_sharedLockCount(0), m_exclusiveLockCount(0), m_isAshmem(isAshmem) {
|
||||
m_lockInfo.l_type = F_WRLCK;
|
||||
m_lockInfo.l_start = 0;
|
||||
m_lockInfo.l_whence = SEEK_SET;
|
||||
m_lockInfo.l_len = 0;
|
||||
m_lockInfo.l_pid = 0;
|
||||
}
|
||||
|
||||
static short LockType2FlockType(LockType lockType) {
|
||||
switch (lockType) {
|
||||
case SharedLockType:
|
||||
return F_RDLCK;
|
||||
case ExclusiveLockType:
|
||||
return F_WRLCK;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileLock::ashmemLock(LockType lockType, bool wait, bool unLockFirstIfNeeded, bool *tryAgain) {
|
||||
m_lockInfo.l_type = LockType2FlockType(lockType);
|
||||
if (unLockFirstIfNeeded) {
|
||||
// try lock
|
||||
auto ret = fcntl(m_fd, F_SETLK, &m_lockInfo);
|
||||
if (ret == 0) {
|
||||
return true;
|
||||
}
|
||||
// lets be gentleman: unlock my shared-lock to prevent deadlock
|
||||
auto type = m_lockInfo.l_type;
|
||||
m_lockInfo.l_type = F_UNLCK;
|
||||
ret = fcntl(m_fd, F_SETLK, &m_lockInfo);
|
||||
if (ret != 0) {
|
||||
MMKVError("fail to try unlock first fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
}
|
||||
m_lockInfo.l_type = type;
|
||||
}
|
||||
|
||||
int cmd = wait ? F_SETLKW : F_SETLK;
|
||||
auto ret = fcntl(m_fd, cmd, &m_lockInfo);
|
||||
if (ret != 0) {
|
||||
if (tryAgain) {
|
||||
*tryAgain = (errno == EAGAIN);
|
||||
}
|
||||
if (wait) {
|
||||
MMKVError("fail to lock fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
}
|
||||
// try recover my shared-lock
|
||||
if (unLockFirstIfNeeded) {
|
||||
m_lockInfo.l_type = LockType2FlockType(SharedLockType);
|
||||
ret = fcntl(m_fd, cmd, &m_lockInfo);
|
||||
if (ret != 0) {
|
||||
// let's hope this never happen
|
||||
MMKVError("fail to recover shared-lock fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileLock::ashmemUnLock(bool unlockToSharedLock) {
|
||||
m_lockInfo.l_type = static_cast<short>(unlockToSharedLock ? F_RDLCK : F_UNLCK);
|
||||
auto ret = fcntl(m_fd, F_SETLK, &m_lockInfo);
|
||||
if (ret != 0) {
|
||||
MMKVError("fail to unlock fd=%d, ret=%d, error:%s", m_fd, ret, strerror(errno));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // MMKV_ANDROID
|
||||
236
libs/mmkv/Core/KeyValueHolder.cpp
Normal file
236
libs/mmkv/Core/KeyValueHolder.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "KeyValueHolder.h"
|
||||
#include "PBUtility.h"
|
||||
#include "aes/AESCrypt.h"
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
KeyValueHolder::KeyValueHolder(uint32_t keyLength, uint32_t valueLength, uint32_t off)
|
||||
: keySize(static_cast<uint16_t>(keyLength)), valueSize(valueLength), offset(off) {
|
||||
computedKVSize = keySize + static_cast<uint16_t>(pbRawVarint32Size(keySize));
|
||||
computedKVSize += static_cast<uint16_t>(pbRawVarint32Size(valueSize));
|
||||
}
|
||||
|
||||
MMBuffer KeyValueHolder::toMMBuffer(const void *basePtr) const {
|
||||
auto realPtr = (uint8_t *) basePtr + offset;
|
||||
realPtr += computedKVSize;
|
||||
return MMBuffer(realPtr, valueSize, MMBufferNoCopy);
|
||||
}
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
KeyValueHolderCrypt::KeyValueHolderCrypt(const void *src, size_t length) {
|
||||
if (length <= SmallBufferSize()) {
|
||||
type = KeyValueHolderType_Direct;
|
||||
paddedSize = static_cast<uint8_t>(length);
|
||||
memcpy(paddedValue, src, length);
|
||||
} else {
|
||||
type = KeyValueHolderType_Memory;
|
||||
memSize = static_cast<uint32_t>(length);
|
||||
memPtr = malloc(length);
|
||||
if (!memPtr) {
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
memcpy(memPtr, src, memSize);
|
||||
}
|
||||
}
|
||||
|
||||
KeyValueHolderCrypt::KeyValueHolderCrypt(MMBuffer &&data) {
|
||||
if (data.type == MMBuffer::MMBufferType_Small) {
|
||||
static_assert(SmallBufferSize() >= MMBuffer::SmallBufferSize(), "KeyValueHolderCrypt can't hold MMBuffer");
|
||||
|
||||
type = KeyValueHolderType_Direct;
|
||||
paddedSize = static_cast<uint8_t>(data.length());
|
||||
memcpy(paddedValue, data.getPtr(), data.length());
|
||||
} else {
|
||||
type = KeyValueHolderType_Memory;
|
||||
memSize = static_cast<uint32_t>(data.length());
|
||||
# ifdef MMKV_APPLE
|
||||
if (data.m_data != nil) {
|
||||
memPtr = malloc(memSize);
|
||||
if (!memPtr) {
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
memcpy(memPtr, data.getPtr(), memSize);
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
memPtr = data.getPtr();
|
||||
data.detach();
|
||||
}
|
||||
}
|
||||
|
||||
KeyValueHolderCrypt::KeyValueHolderCrypt(uint32_t keyLength, uint32_t valueLength, uint32_t off)
|
||||
: type(KeyValueHolderType_Offset), keySize(static_cast<uint16_t>(keyLength)), valueSize(valueLength), offset(off) {
|
||||
|
||||
pbKeyValueSize = static_cast<uint8_t>(pbRawVarint32Size(keySize) + pbRawVarint32Size(valueSize));
|
||||
}
|
||||
|
||||
KeyValueHolderCrypt::KeyValueHolderCrypt(KeyValueHolderCrypt &&other) noexcept {
|
||||
this->move(std::move(other));
|
||||
}
|
||||
|
||||
KeyValueHolderCrypt &KeyValueHolderCrypt::operator=(KeyValueHolderCrypt &&other) noexcept {
|
||||
if (type == KeyValueHolderType_Memory && memPtr) {
|
||||
free(memPtr);
|
||||
}
|
||||
this->move(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void KeyValueHolderCrypt::move(KeyValueHolderCrypt &&other) noexcept {
|
||||
if (other.type == KeyValueHolderType_Direct || other.type == KeyValueHolderType_Offset) {
|
||||
memcpy(this, &other, sizeof(other));
|
||||
} else if (other.type == KeyValueHolderType_Memory) {
|
||||
type = KeyValueHolderType_Memory;
|
||||
memSize = other.memSize;
|
||||
memPtr = other.memPtr;
|
||||
other.memPtr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
KeyValueHolderCrypt::~KeyValueHolderCrypt() {
|
||||
if (type == KeyValueHolderType_Memory && memPtr) {
|
||||
free(memPtr);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t KeyValueHolderCrypt::realValueSize() const {
|
||||
switch (type) {
|
||||
case KeyValueHolderType_Direct:
|
||||
return paddedSize;
|
||||
case KeyValueHolderType_Offset:
|
||||
return valueSize;
|
||||
case KeyValueHolderType_Memory:
|
||||
return memSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get decrypt data with [position, -1)
|
||||
static MMBuffer decryptBuffer(AESCrypt &crypter, const MMBuffer &inputBuffer, size_t position) {
|
||||
static size_t smallBuffer[16 / sizeof(size_t)];
|
||||
auto basePtr = (uint8_t *) inputBuffer.getPtr();
|
||||
auto ptr = basePtr;
|
||||
for (size_t index = sizeof(smallBuffer); index < position; index += sizeof(smallBuffer)) {
|
||||
crypter.decrypt(ptr, smallBuffer, sizeof(smallBuffer));
|
||||
ptr += sizeof(smallBuffer);
|
||||
}
|
||||
if (ptr < basePtr + position) {
|
||||
crypter.decrypt(ptr, smallBuffer, static_cast<size_t>(basePtr + position - ptr));
|
||||
ptr = basePtr + position;
|
||||
}
|
||||
size_t length = inputBuffer.length() - position;
|
||||
MMBuffer tmp(length);
|
||||
|
||||
auto input = ptr;
|
||||
auto output = tmp.getPtr();
|
||||
crypter.decrypt(input, output, length);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
MMBuffer KeyValueHolderCrypt::toMMBuffer(const void *basePtr, const AESCrypt *crypter) const {
|
||||
if (type == KeyValueHolderType_Direct) {
|
||||
return MMBuffer((void *) paddedValue, paddedSize, MMBufferNoCopy);
|
||||
} else if (type == KeyValueHolderType_Memory) {
|
||||
return MMBuffer(memPtr, memSize, MMBufferNoCopy);
|
||||
} else {
|
||||
auto realPtr = (uint8_t *) basePtr + offset;
|
||||
auto position = static_cast<uint32_t>(pbKeyValueSize + keySize);
|
||||
auto realSize = position + valueSize;
|
||||
auto kvBuffer = MMBuffer(realPtr, realSize, MMBufferNoCopy);
|
||||
auto decrypter = crypter->cloneWithStatus(cryptStatus);
|
||||
return decryptBuffer(decrypter, kvBuffer, position);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#if !defined(MMKV_DISABLE_CRYPT) && defined(MMKV_DEBUG)
|
||||
# include "CodedInputData.h"
|
||||
# include "CodedOutputData.h"
|
||||
# include "MMKVLog.h"
|
||||
# include <ctime>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
void KeyValueHolderCrypt::testAESToMMBuffer() {
|
||||
const uint8_t plainText[] = "Hello, OpenSSL-mmkv::KeyValueHolderCrypt::testAESToMMBuffer() with AES CFB 128.";
|
||||
constexpr size_t textLength = sizeof(plainText) - 1;
|
||||
|
||||
const uint8_t key[] = "TheAESKey";
|
||||
constexpr size_t keyLength = sizeof(key) - 1;
|
||||
|
||||
uint8_t iv[AES_KEY_LEN];
|
||||
srand((unsigned) time(nullptr));
|
||||
for (uint32_t i = 0; i < AES_KEY_LEN; i++) {
|
||||
iv[i] = (uint8_t) rand();
|
||||
}
|
||||
AESCrypt crypt1(key, keyLength, iv, sizeof(iv));
|
||||
|
||||
auto encryptText = new uint8_t[DEFAULT_MMAP_SIZE];
|
||||
memset(encryptText, 0, DEFAULT_MMAP_SIZE);
|
||||
CodedOutputData output(encryptText, DEFAULT_MMAP_SIZE);
|
||||
output.writeData(MMBuffer((void *) key, keyLength, MMBufferNoCopy));
|
||||
auto lengthOfValue = textLength + pbRawVarint32Size((uint32_t) textLength);
|
||||
output.writeRawVarint32((int32_t) lengthOfValue);
|
||||
output.writeData(MMBuffer((void *) plainText, textLength, MMBufferNoCopy));
|
||||
crypt1.encrypt(encryptText, encryptText, (size_t)(output.curWritePointer() - encryptText));
|
||||
|
||||
AESCrypt decrypt(key, keyLength, iv, sizeof(iv));
|
||||
uint8_t smallBuffer[32];
|
||||
decrypt.decrypt(encryptText, smallBuffer, 5);
|
||||
auto keySize = CodedInputData(smallBuffer, 5).readUInt32();
|
||||
auto sizeOfKeySize = pbRawVarint32Size(keySize);
|
||||
auto position = sizeOfKeySize;
|
||||
decrypt.decrypt(encryptText + 5, smallBuffer + 5, static_cast<size_t>(sizeOfKeySize + keySize - 5));
|
||||
position += keySize;
|
||||
decrypt.decrypt(encryptText + position, smallBuffer + position, 5);
|
||||
auto valueSize = CodedInputData(smallBuffer + position, 5).readUInt32();
|
||||
// auto sizeOfValueSize = pbRawVarint32Size(valueSize);
|
||||
KeyValueHolderCrypt kvHolder(keySize, valueSize, 0);
|
||||
auto rollbackSize = position + 5;
|
||||
decrypt.statusBeforeDecrypt(encryptText + rollbackSize, smallBuffer + rollbackSize, rollbackSize,
|
||||
kvHolder.cryptStatus);
|
||||
auto value = kvHolder.toMMBuffer(encryptText, &decrypt);
|
||||
# ifdef MMKV_APPLE
|
||||
MMKVInfo("testAESToMMBuffer: %@", CodedInputData((char *) value.getPtr(), value.length()).readString());
|
||||
# else
|
||||
MMKVInfo("testAESToMMBuffer: %s", CodedInputData((char *) value.getPtr(), value.length()).readString().c_str());
|
||||
# endif
|
||||
MMKVInfo("MMBuffer::SmallBufferSize() = %u, KeyValueHolderCrypt::SmallBufferSize() = %u",
|
||||
MMBuffer::SmallBufferSize(), KeyValueHolderCrypt::SmallBufferSize());
|
||||
|
||||
delete[] encryptText;
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
118
libs/mmkv/Core/KeyValueHolder.h
Normal file
118
libs/mmkv/Core/KeyValueHolder.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef KeyValueHolder_hpp
|
||||
#define KeyValueHolder_hpp
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMBuffer.h"
|
||||
#include "aes/AESCrypt.h"
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct KeyValueHolder {
|
||||
uint16_t computedKVSize; // internal use only
|
||||
uint16_t keySize;
|
||||
uint32_t valueSize;
|
||||
uint32_t offset;
|
||||
|
||||
KeyValueHolder() = default;
|
||||
KeyValueHolder(uint32_t keyLength, uint32_t valueLength, uint32_t offset);
|
||||
|
||||
MMBuffer toMMBuffer(const void *basePtr) const;
|
||||
};
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
enum KeyValueHolderType : uint8_t {
|
||||
KeyValueHolderType_Direct, // store value directly
|
||||
KeyValueHolderType_Memory, // store value in the heap memory
|
||||
KeyValueHolderType_Offset, // store value by offset
|
||||
};
|
||||
|
||||
// kv holder for encrypted mmkv
|
||||
struct KeyValueHolderCrypt {
|
||||
KeyValueHolderType type = KeyValueHolderType_Direct;
|
||||
|
||||
union {
|
||||
// store value by offset
|
||||
struct {
|
||||
uint8_t pbKeyValueSize; // size needed to encode keySize & valueSize
|
||||
uint16_t keySize;
|
||||
uint32_t valueSize;
|
||||
uint32_t offset;
|
||||
AESCryptStatus cryptStatus;
|
||||
};
|
||||
// store value directly
|
||||
struct {
|
||||
uint8_t paddedSize;
|
||||
uint8_t paddedValue[1];
|
||||
};
|
||||
// store value in the heap memory
|
||||
struct {
|
||||
uint32_t memSize;
|
||||
void *memPtr;
|
||||
};
|
||||
};
|
||||
|
||||
static constexpr size_t SmallBufferSize() {
|
||||
return sizeof(KeyValueHolderCrypt) - offsetof(KeyValueHolderCrypt, paddedValue);
|
||||
}
|
||||
|
||||
static bool isValueStoredAsOffset(size_t valueSize) { return valueSize >= 256; }
|
||||
|
||||
KeyValueHolderCrypt() = default;
|
||||
KeyValueHolderCrypt(const void *valuePtr, size_t valueLength);
|
||||
explicit KeyValueHolderCrypt(MMBuffer &&data);
|
||||
KeyValueHolderCrypt(uint32_t keyLength, uint32_t valueLength, uint32_t offset);
|
||||
|
||||
KeyValueHolderCrypt(KeyValueHolderCrypt &&other) noexcept;
|
||||
KeyValueHolderCrypt &operator=(KeyValueHolderCrypt &&other) noexcept;
|
||||
void move(KeyValueHolderCrypt &&other) noexcept;
|
||||
|
||||
~KeyValueHolderCrypt();
|
||||
|
||||
uint32_t realValueSize() const;
|
||||
|
||||
MMBuffer toMMBuffer(const void *basePtr, const AESCrypt *crypter) const;
|
||||
|
||||
std::tuple<uint32_t, uint32_t, AESCryptStatus *> toTuple() {
|
||||
return std::make_tuple(offset, pbKeyValueSize + keySize + valueSize, &cryptStatus);
|
||||
}
|
||||
|
||||
// those are expensive, just forbid it for possibly misuse
|
||||
explicit KeyValueHolderCrypt(const KeyValueHolderCrypt &other) = delete;
|
||||
KeyValueHolderCrypt &operator=(const KeyValueHolderCrypt &other) = delete;
|
||||
|
||||
#ifdef MMKV_DEBUG
|
||||
static void testAESToMMBuffer();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif /* KeyValueHolder_hpp */
|
||||
185
libs/mmkv/Core/MMBuffer.cpp
Normal file
185
libs/mmkv/Core/MMBuffer.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MMBuffer.h"
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
# if __has_feature(objc_arc)
|
||||
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
||||
# endif
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
MMBuffer::MMBuffer(size_t length) {
|
||||
if (length > SmallBufferSize()) {
|
||||
type = MMBufferType_Normal;
|
||||
isNoCopy = MMBufferCopy;
|
||||
size = length;
|
||||
ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
#ifdef MMKV_APPLE
|
||||
m_data = nil;
|
||||
#endif
|
||||
} else {
|
||||
type = MMBufferType_Small;
|
||||
paddedSize = static_cast<uint8_t>(length);
|
||||
}
|
||||
}
|
||||
|
||||
MMBuffer::MMBuffer(void *source, size_t length, MMBufferCopyFlag flag) : isNoCopy(flag) {
|
||||
if (isNoCopy == MMBufferCopy) {
|
||||
if (length > SmallBufferSize()) {
|
||||
type = MMBufferType_Normal;
|
||||
size = length;
|
||||
ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
memcpy(ptr, source, size);
|
||||
#ifdef MMKV_APPLE
|
||||
m_data = nil;
|
||||
#endif
|
||||
} else {
|
||||
type = MMBufferType_Small;
|
||||
paddedSize = static_cast<uint8_t>(length);
|
||||
memcpy(paddedBuffer, source, length);
|
||||
}
|
||||
} else {
|
||||
type = MMBufferType_Normal;
|
||||
size = length;
|
||||
ptr = source;
|
||||
#ifdef MMKV_APPLE
|
||||
m_data = nil;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
MMBuffer::MMBuffer(NSData *data, MMBufferCopyFlag flag)
|
||||
: type(MMBufferType_Normal), ptr((void *) data.bytes), size(data.length), isNoCopy(flag) {
|
||||
if (isNoCopy == MMBufferCopy) {
|
||||
m_data = [data retain];
|
||||
} else {
|
||||
m_data = data;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MMBuffer::MMBuffer(MMBuffer &&other) noexcept : type(other.type) {
|
||||
if (type == MMBufferType_Normal) {
|
||||
size = other.size;
|
||||
ptr = other.ptr;
|
||||
isNoCopy = other.isNoCopy;
|
||||
#ifdef MMKV_APPLE
|
||||
m_data = other.m_data;
|
||||
#endif
|
||||
other.detach();
|
||||
} else {
|
||||
paddedSize = other.paddedSize;
|
||||
memcpy(paddedBuffer, other.paddedBuffer, paddedSize);
|
||||
}
|
||||
}
|
||||
|
||||
MMBuffer &MMBuffer::operator=(MMBuffer &&other) noexcept {
|
||||
if (type == MMBufferType_Normal) {
|
||||
if (other.type == MMBufferType_Normal) {
|
||||
std::swap(isNoCopy, other.isNoCopy);
|
||||
std::swap(size, other.size);
|
||||
std::swap(ptr, other.ptr);
|
||||
#ifdef MMKV_APPLE
|
||||
std::swap(m_data, other.m_data);
|
||||
#endif
|
||||
} else {
|
||||
type = MMBufferType_Small;
|
||||
if (isNoCopy == MMBufferCopy) {
|
||||
#ifdef MMKV_APPLE
|
||||
if (m_data) {
|
||||
[m_data release];
|
||||
} else if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
#else
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
paddedSize = other.paddedSize;
|
||||
memcpy(paddedBuffer, other.paddedBuffer, paddedSize);
|
||||
}
|
||||
} else {
|
||||
if (other.type == MMBufferType_Normal) {
|
||||
type = MMBufferType_Normal;
|
||||
isNoCopy = other.isNoCopy;
|
||||
size = other.size;
|
||||
ptr = other.ptr;
|
||||
#ifdef MMKV_APPLE
|
||||
m_data = other.m_data;
|
||||
#endif
|
||||
other.detach();
|
||||
} else {
|
||||
uint8_t tmp[SmallBufferSize()];
|
||||
memcpy(tmp, other.paddedBuffer, other.paddedSize);
|
||||
memcpy(other.paddedBuffer, paddedBuffer, paddedSize);
|
||||
memcpy(paddedBuffer, tmp, other.paddedSize);
|
||||
std::swap(paddedSize, other.paddedSize);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
MMBuffer::~MMBuffer() {
|
||||
if (isStoredOnStack()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
if (m_data) {
|
||||
if (isNoCopy == MMBufferCopy) {
|
||||
[m_data release];
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isNoCopy == MMBufferCopy && ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void MMBuffer::detach() {
|
||||
// type = MMBufferType_Small;
|
||||
// paddedSize = 0;
|
||||
auto memsetPtr = (size_t *) &type;
|
||||
*memsetPtr = 0;
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
106
libs/mmkv/Core/MMBuffer.h
Normal file
106
libs/mmkv/Core/MMBuffer.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_MMBUFFER_H
|
||||
#define MMKV_MMBUFFER_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
enum MMBufferCopyFlag : bool {
|
||||
MMBufferCopy = false,
|
||||
MMBufferNoCopy = true,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
struct KeyValueHolderCrypt;
|
||||
#endif
|
||||
|
||||
class MMBuffer {
|
||||
enum MMBufferType : uint8_t {
|
||||
MMBufferType_Small, // store small buffer in stack memory
|
||||
MMBufferType_Normal, // store in heap memory
|
||||
};
|
||||
MMBufferType type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
MMBufferCopyFlag isNoCopy;
|
||||
size_t size;
|
||||
void *ptr;
|
||||
#ifdef MMKV_APPLE
|
||||
NSData *m_data;
|
||||
#endif
|
||||
};
|
||||
struct {
|
||||
uint8_t paddedSize;
|
||||
// make at least 10 bytes to hold all primitive types (negative int32, int64, double etc) on 32 bit device
|
||||
// on 64 bit device it's guaranteed larger than 10 bytes
|
||||
uint8_t paddedBuffer[10];
|
||||
};
|
||||
};
|
||||
|
||||
static constexpr size_t SmallBufferSize() {
|
||||
return sizeof(MMBuffer) - offsetof(MMBuffer, paddedBuffer);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit MMBuffer(size_t length = 0);
|
||||
MMBuffer(void *source, size_t length, MMBufferCopyFlag flag = MMBufferCopy);
|
||||
#ifdef MMKV_APPLE
|
||||
explicit MMBuffer(NSData *data, MMBufferCopyFlag flag = MMBufferCopy);
|
||||
#endif
|
||||
|
||||
MMBuffer(MMBuffer &&other) noexcept;
|
||||
MMBuffer &operator=(MMBuffer &&other) noexcept;
|
||||
|
||||
~MMBuffer();
|
||||
|
||||
bool isStoredOnStack() const { return (type == MMBufferType_Small); }
|
||||
|
||||
void *getPtr() const { return isStoredOnStack() ? (void *) paddedBuffer : ptr; }
|
||||
|
||||
size_t length() const { return isStoredOnStack() ? paddedSize : size; }
|
||||
|
||||
// transfer ownership to others
|
||||
void detach();
|
||||
|
||||
// those are expensive, just forbid it for possibly misuse
|
||||
explicit MMBuffer(const MMBuffer &other) = delete;
|
||||
MMBuffer &operator=(const MMBuffer &other) = delete;
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
friend KeyValueHolderCrypt;
|
||||
#endif
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_MMBUFFER_H
|
||||
995
libs/mmkv/Core/MMKV.cpp
Normal file
995
libs/mmkv/Core/MMKV.cpp
Normal file
@@ -0,0 +1,995 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CodedInputData.h"
|
||||
#include "CodedOutputData.h"
|
||||
#include "InterProcessLock.h"
|
||||
#include "KeyValueHolder.h"
|
||||
#include "MMBuffer.h"
|
||||
#include "MMKVLog.h"
|
||||
#include "MMKVMetaInfo.hpp"
|
||||
#include "MMKV_IO.h"
|
||||
#include "MemoryFile.h"
|
||||
#include "MiniPBCoder.h"
|
||||
#include "PBUtility.h"
|
||||
#include "ScopedLock.hpp"
|
||||
#include "ThreadLock.h"
|
||||
#include "aes/AESCrypt.h"
|
||||
#include "aes/openssl/openssl_aes.h"
|
||||
#include "aes/openssl/openssl_md5.h"
|
||||
#include "crc32/Checksum.h"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(__aarch64__) && defined(__linux)
|
||||
# include <asm/hwcap.h>
|
||||
# include <sys/auxv.h>
|
||||
#endif
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
# if __has_feature(objc_arc)
|
||||
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
||||
# endif
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
using namespace std;
|
||||
using namespace mmkv;
|
||||
|
||||
unordered_map<std::string, MMKV *> *g_instanceDic;
|
||||
ThreadLock *g_instanceLock;
|
||||
MMKVPath_t g_rootDir;
|
||||
static mmkv::ErrorHandler g_errorHandler;
|
||||
size_t mmkv::DEFAULT_MMAP_SIZE;
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = "specialCharacter";
|
||||
#else
|
||||
constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = L"specialCharacter";
|
||||
#endif
|
||||
constexpr uint32_t Fixed32Size = pbFixed32Size();
|
||||
|
||||
MMKV_NAMESPACE_BEGIN
|
||||
|
||||
#ifndef MMKV_ANDROID
|
||||
MMKV::MMKV(const std::string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath)
|
||||
: m_mmapID(mmapID)
|
||||
, m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
|
||||
, m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
|
||||
, m_dic(nullptr)
|
||||
, m_dicCrypt(nullptr)
|
||||
, m_file(new MemoryFile(m_path))
|
||||
, m_metaFile(new MemoryFile(m_crcPath))
|
||||
, m_metaInfo(new MMKVMetaInfo())
|
||||
, m_crypter(nullptr)
|
||||
, m_lock(new ThreadLock())
|
||||
, m_fileLock(new FileLock(m_metaFile->getFd()))
|
||||
, m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
|
||||
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
|
||||
, m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0) {
|
||||
m_actualSize = 0;
|
||||
m_output = nullptr;
|
||||
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
if (cryptKey && cryptKey->length() > 0) {
|
||||
m_dicCrypt = new MMKVMapCrypt();
|
||||
m_crypter = new AESCrypt(cryptKey->data(), cryptKey->length());
|
||||
} else {
|
||||
m_dic = new MMKVMap();
|
||||
}
|
||||
# else
|
||||
m_dic = new MMKVMap();
|
||||
# endif
|
||||
|
||||
m_needLoadFromFile = true;
|
||||
m_hasFullWriteback = false;
|
||||
|
||||
m_crcDigest = 0;
|
||||
|
||||
m_lock->initialize();
|
||||
m_sharedProcessLock->m_enable = m_isInterProcess;
|
||||
m_exclusiveProcessLock->m_enable = m_isInterProcess;
|
||||
|
||||
// sensitive zone
|
||||
{
|
||||
SCOPED_LOCK(m_sharedProcessLock);
|
||||
loadFromFile();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MMKV::~MMKV() {
|
||||
clearMemoryCache();
|
||||
|
||||
delete m_dic;
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
delete m_dicCrypt;
|
||||
delete m_crypter;
|
||||
#endif
|
||||
delete m_file;
|
||||
delete m_metaFile;
|
||||
delete m_metaInfo;
|
||||
delete m_lock;
|
||||
delete m_fileLock;
|
||||
delete m_sharedProcessLock;
|
||||
delete m_exclusiveProcessLock;
|
||||
#ifdef MMKV_ANDROID
|
||||
delete m_fileModeLock;
|
||||
delete m_sharedProcessModeLock;
|
||||
delete m_exclusiveProcessModeLock;
|
||||
#endif
|
||||
|
||||
MMKVInfo("destruct [%s]", m_mmapID.c_str());
|
||||
}
|
||||
|
||||
MMKV *MMKV::defaultMMKV(MMKVMode mode, string *cryptKey) {
|
||||
#ifndef MMKV_ANDROID
|
||||
return mmkvWithID(DEFAULT_MMAP_ID, mode, cryptKey);
|
||||
#else
|
||||
return mmkvWithID(DEFAULT_MMAP_ID, DEFAULT_MMAP_SIZE, mode, cryptKey);
|
||||
#endif
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
g_instanceDic = new unordered_map<string, MMKV *>;
|
||||
g_instanceLock = new ThreadLock();
|
||||
g_instanceLock->initialize();
|
||||
|
||||
mmkv::DEFAULT_MMAP_SIZE = mmkv::getPageSize();
|
||||
MMKVInfo("version %s page size:%d", MMKV_VERSION, DEFAULT_MMAP_SIZE);
|
||||
|
||||
// get CPU status of ARMv8 extensions (CRC32, AES)
|
||||
#if defined(__aarch64__) && defined(__linux__)
|
||||
auto hwcaps = getauxval(AT_HWCAP);
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
if (hwcaps & HWCAP_AES) {
|
||||
AES_set_encrypt_key = openssl_aes_armv8_set_encrypt_key;
|
||||
AES_set_decrypt_key = openssl_aes_armv8_set_decrypt_key;
|
||||
AES_encrypt = openssl_aes_armv8_encrypt;
|
||||
AES_decrypt = openssl_aes_armv8_decrypt;
|
||||
MMKVInfo("armv8 AES instructions is supported");
|
||||
} else {
|
||||
MMKVInfo("armv8 AES instructions is not supported");
|
||||
}
|
||||
# endif // MMKV_DISABLE_CRYPT
|
||||
# ifdef MMKV_USE_ARMV8_CRC32
|
||||
if (hwcaps & HWCAP_CRC32) {
|
||||
CRC32 = mmkv::armv8_crc32;
|
||||
MMKVInfo("armv8 CRC32 instructions is supported");
|
||||
} else {
|
||||
MMKVInfo("armv8 CRC32 instructions is not supported");
|
||||
}
|
||||
# endif // MMKV_USE_ARMV8_CRC32
|
||||
#endif // __aarch64__ && defined(__linux__)
|
||||
|
||||
#if defined(MMKV_DEBUG) && !defined(MMKV_DISABLE_CRYPT)
|
||||
AESCrypt::testAESCrypt();
|
||||
KeyValueHolderCrypt::testAESToMMBuffer();
|
||||
#endif
|
||||
}
|
||||
|
||||
ThreadOnceToken_t once_control = ThreadOnceUninitialized;
|
||||
|
||||
void MMKV::initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel) {
|
||||
g_currentLogLevel = logLevel;
|
||||
|
||||
ThreadLock::ThreadOnce(&once_control, initialize);
|
||||
|
||||
g_rootDir = rootDir;
|
||||
mkPath(g_rootDir);
|
||||
|
||||
MMKVInfo("root dir: " MMKV_PATH_FORMAT, g_rootDir.c_str());
|
||||
}
|
||||
|
||||
#ifndef MMKV_ANDROID
|
||||
MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath) {
|
||||
|
||||
if (mmapID.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
|
||||
auto mmapKey = mmapedKVKey(mmapID, rootPath);
|
||||
auto itr = g_instanceDic->find(mmapKey);
|
||||
if (itr != g_instanceDic->end()) {
|
||||
MMKV *kv = itr->second;
|
||||
return kv;
|
||||
}
|
||||
|
||||
if (rootPath) {
|
||||
MMKVPath_t specialPath = (*rootPath) + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
||||
if (!isFileExist(specialPath)) {
|
||||
mkPath(specialPath);
|
||||
}
|
||||
MMKVInfo("prepare to load %s (id %s) from rootPath %s", mmapID.c_str(), mmapKey.c_str(), rootPath->c_str());
|
||||
}
|
||||
|
||||
auto kv = new MMKV(mmapID, mode, cryptKey, rootPath);
|
||||
kv->m_mmapKey = mmapKey;
|
||||
(*g_instanceDic)[mmapKey] = kv;
|
||||
return kv;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MMKV::onExit() {
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
|
||||
for (auto &pair : *g_instanceDic) {
|
||||
MMKV *kv = pair.second;
|
||||
kv->sync();
|
||||
kv->clearMemoryCache();
|
||||
delete kv;
|
||||
pair.second = nullptr;
|
||||
}
|
||||
|
||||
delete g_instanceDic;
|
||||
g_instanceDic = nullptr;
|
||||
}
|
||||
|
||||
const string &MMKV::mmapID() const {
|
||||
return m_mmapID;
|
||||
}
|
||||
|
||||
mmkv::ContentChangeHandler g_contentChangeHandler = nullptr;
|
||||
|
||||
void MMKV::notifyContentChanged() {
|
||||
if (g_contentChangeHandler) {
|
||||
g_contentChangeHandler(m_mmapID);
|
||||
}
|
||||
}
|
||||
|
||||
void MMKV::checkContentChanged() {
|
||||
SCOPED_LOCK(m_lock);
|
||||
checkLoadData();
|
||||
}
|
||||
|
||||
void MMKV::registerContentChangeHandler(mmkv::ContentChangeHandler handler) {
|
||||
g_contentChangeHandler = handler;
|
||||
}
|
||||
|
||||
void MMKV::unRegisterContentChangeHandler() {
|
||||
g_contentChangeHandler = nullptr;
|
||||
}
|
||||
|
||||
void MMKV::clearMemoryCache() {
|
||||
SCOPED_LOCK(m_lock);
|
||||
if (m_needLoadFromFile) {
|
||||
return;
|
||||
}
|
||||
MMKVInfo("clearMemoryCache [%s]", m_mmapID.c_str());
|
||||
m_needLoadFromFile = true;
|
||||
m_hasFullWriteback = false;
|
||||
|
||||
clearDictionary(m_dic);
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
clearDictionary(m_dicCrypt);
|
||||
if (m_crypter) {
|
||||
if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
|
||||
m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
|
||||
} else {
|
||||
m_crypter->resetIV();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
delete m_output;
|
||||
m_output = nullptr;
|
||||
|
||||
m_file->clearMemoryCache();
|
||||
m_actualSize = 0;
|
||||
m_metaInfo->m_crcDigest = 0;
|
||||
}
|
||||
|
||||
void MMKV::close() {
|
||||
MMKVInfo("close [%s]", m_mmapID.c_str());
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
m_lock->lock();
|
||||
|
||||
#ifndef MMKV_ANDROID
|
||||
auto itr = g_instanceDic->find(m_mmapKey);
|
||||
#else
|
||||
auto itr = g_instanceDic->find(m_mmapID);
|
||||
#endif
|
||||
if (itr != g_instanceDic->end()) {
|
||||
g_instanceDic->erase(itr);
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
string MMKV::cryptKey() const {
|
||||
SCOPED_LOCK(m_lock);
|
||||
|
||||
if (m_crypter) {
|
||||
char key[AES_KEY_LEN];
|
||||
m_crypter->getKey(key);
|
||||
return string(key, strnlen(key, AES_KEY_LEN));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void MMKV::checkReSetCryptKey(const string *cryptKey) {
|
||||
SCOPED_LOCK(m_lock);
|
||||
|
||||
if (m_crypter) {
|
||||
if (cryptKey && cryptKey->length() > 0) {
|
||||
string oldKey = this->cryptKey();
|
||||
if (oldKey != *cryptKey) {
|
||||
MMKVInfo("setting new aes key");
|
||||
delete m_crypter;
|
||||
auto ptr = cryptKey->data();
|
||||
m_crypter = new AESCrypt(ptr, cryptKey->length());
|
||||
|
||||
checkLoadData();
|
||||
} else {
|
||||
// nothing to do
|
||||
}
|
||||
} else {
|
||||
MMKVInfo("reset aes key");
|
||||
delete m_crypter;
|
||||
m_crypter = nullptr;
|
||||
|
||||
checkLoadData();
|
||||
}
|
||||
} else {
|
||||
if (cryptKey && cryptKey->length() > 0) {
|
||||
MMKVInfo("setting new aes key");
|
||||
auto ptr = cryptKey->data();
|
||||
m_crypter = new AESCrypt(ptr, cryptKey->length());
|
||||
|
||||
checkLoadData();
|
||||
} else {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
bool MMKV::isFileValid() {
|
||||
return m_file->isFileValid();
|
||||
}
|
||||
|
||||
// crc
|
||||
|
||||
// assuming m_file is valid
|
||||
bool MMKV::checkFileCRCValid(size_t actualSize, uint32_t crcDigest) {
|
||||
auto ptr = (uint8_t *) m_file->getMemory();
|
||||
if (ptr) {
|
||||
m_crcDigest = (uint32_t) CRC32(0, (const uint8_t *) ptr + Fixed32Size, (uint32_t) actualSize);
|
||||
|
||||
if (m_crcDigest == crcDigest) {
|
||||
return true;
|
||||
}
|
||||
MMKVError("check crc [%s] fail, crc32:%u, m_crcDigest:%u", m_mmapID.c_str(), crcDigest, m_crcDigest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MMKV::recaculateCRCDigestWithIV(const void *iv) {
|
||||
auto ptr = (const uint8_t *) m_file->getMemory();
|
||||
if (ptr) {
|
||||
m_crcDigest = 0;
|
||||
m_crcDigest = (uint32_t) CRC32(0, ptr + Fixed32Size, (uint32_t) m_actualSize);
|
||||
writeActualSize(m_actualSize, m_crcDigest, iv, IncreaseSequence);
|
||||
}
|
||||
}
|
||||
|
||||
void MMKV::updateCRCDigest(const uint8_t *ptr, size_t length) {
|
||||
if (ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_crcDigest = (uint32_t) CRC32(m_crcDigest, ptr, (uint32_t) length);
|
||||
|
||||
writeActualSize(m_actualSize, m_crcDigest, nullptr, KeepSequence);
|
||||
}
|
||||
|
||||
// set & get
|
||||
|
||||
bool MMKV::set(bool value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
size_t size = pbBoolSize();
|
||||
MMBuffer data(size);
|
||||
CodedOutputData output(data.getPtr(), size);
|
||||
output.writeBool(value);
|
||||
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
bool MMKV::set(int32_t value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
size_t size = pbInt32Size(value);
|
||||
MMBuffer data(size);
|
||||
CodedOutputData output(data.getPtr(), size);
|
||||
output.writeInt32(value);
|
||||
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
bool MMKV::set(uint32_t value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
size_t size = pbUInt32Size(value);
|
||||
MMBuffer data(size);
|
||||
CodedOutputData output(data.getPtr(), size);
|
||||
output.writeUInt32(value);
|
||||
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
bool MMKV::set(int64_t value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
size_t size = pbInt64Size(value);
|
||||
MMBuffer data(size);
|
||||
CodedOutputData output(data.getPtr(), size);
|
||||
output.writeInt64(value);
|
||||
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
bool MMKV::set(uint64_t value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
size_t size = pbUInt64Size(value);
|
||||
MMBuffer data(size);
|
||||
CodedOutputData output(data.getPtr(), size);
|
||||
output.writeUInt64(value);
|
||||
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
bool MMKV::set(float value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
size_t size = pbFloatSize();
|
||||
MMBuffer data(size);
|
||||
CodedOutputData output(data.getPtr(), size);
|
||||
output.writeFloat(value);
|
||||
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
bool MMKV::set(double value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
size_t size = pbDoubleSize();
|
||||
MMBuffer data(size);
|
||||
CodedOutputData output(data.getPtr(), size);
|
||||
output.writeDouble(value);
|
||||
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
|
||||
bool MMKV::set(const char *value, MMKVKey_t key) {
|
||||
if (!value) {
|
||||
removeValueForKey(key);
|
||||
return true;
|
||||
}
|
||||
return setDataForKey(MMBuffer((void *) value, strlen(value), MMBufferNoCopy), key, true);
|
||||
}
|
||||
|
||||
bool MMKV::set(const string &value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
return setDataForKey(MMBuffer((void *) value.data(), value.length(), MMBufferNoCopy), key, true);
|
||||
}
|
||||
|
||||
bool MMKV::set(const MMBuffer &value, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
// delay write the size needed for encoding value
|
||||
// avoid memory copying
|
||||
return setDataForKey(MMBuffer(value.getPtr(), value.length(), MMBufferNoCopy), key, true);
|
||||
}
|
||||
|
||||
bool MMKV::set(const vector<string> &v, MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
auto data = MiniPBCoder::encodeDataWithObject(v);
|
||||
return setDataForKey(move(data), key);
|
||||
}
|
||||
|
||||
bool MMKV::getString(MMKVKey_t key, string &result) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
result = input.readString();
|
||||
return true;
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MMBuffer MMKV::getBytes(MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return MMBuffer();
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readData();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return MMBuffer();
|
||||
}
|
||||
|
||||
bool MMKV::getVector(MMKVKey_t key, vector<string> &result) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
result = MiniPBCoder::decodeVector(data);
|
||||
return true;
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
bool MMKV::getBool(MMKVKey_t key, bool defaultValue) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readBool();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int32_t MMKV::getInt32(MMKVKey_t key, int32_t defaultValue) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readInt32();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
uint32_t MMKV::getUInt32(MMKVKey_t key, uint32_t defaultValue) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readUInt32();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int64_t MMKV::getInt64(MMKVKey_t key, int64_t defaultValue) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readInt64();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
uint64_t MMKV::getUInt64(MMKVKey_t key, uint64_t defaultValue) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readUInt64();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
float MMKV::getFloat(MMKVKey_t key, float defaultValue) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readFloat();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
double MMKV::getDouble(MMKVKey_t key, double defaultValue) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (data.length() > 0) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
return input.readDouble();
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
size_t MMKV::getValueSize(MMKVKey_t key, bool actualSize) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return 0;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
if (actualSize) {
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
auto length = input.readInt32();
|
||||
if (length >= 0) {
|
||||
auto s_length = static_cast<size_t>(length);
|
||||
if (pbRawVarint32Size(length) + s_length == data.length()) {
|
||||
return s_length;
|
||||
}
|
||||
}
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
return data.length();
|
||||
}
|
||||
|
||||
int32_t MMKV::writeValueToBuffer(MMKVKey_t key, void *ptr, int32_t size) {
|
||||
if (isKeyEmpty(key) || size < 0) {
|
||||
return -1;
|
||||
}
|
||||
auto s_size = static_cast<size_t>(size);
|
||||
|
||||
SCOPED_LOCK(m_lock);
|
||||
auto data = getDataForKey(key);
|
||||
try {
|
||||
CodedInputData input(data.getPtr(), data.length());
|
||||
auto length = input.readInt32();
|
||||
auto offset = pbRawVarint32Size(length);
|
||||
if (length >= 0) {
|
||||
auto s_length = static_cast<size_t>(length);
|
||||
if (offset + s_length == data.length()) {
|
||||
if (s_length <= s_size) {
|
||||
memcpy(ptr, (uint8_t *) data.getPtr() + offset, s_length);
|
||||
return length;
|
||||
}
|
||||
} else {
|
||||
if (data.length() <= s_size) {
|
||||
memcpy(ptr, data.getPtr(), data.length());
|
||||
return static_cast<int32_t>(data.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// enumerate
|
||||
|
||||
bool MMKV::containsKey(MMKVKey_t key) {
|
||||
SCOPED_LOCK(m_lock);
|
||||
checkLoadData();
|
||||
|
||||
if (m_crypter) {
|
||||
return m_dicCrypt->find(key) != m_dicCrypt->end();
|
||||
} else {
|
||||
return m_dic->find(key) != m_dic->end();
|
||||
}
|
||||
}
|
||||
|
||||
size_t MMKV::count() {
|
||||
SCOPED_LOCK(m_lock);
|
||||
checkLoadData();
|
||||
if (m_crypter) {
|
||||
return m_dicCrypt->size();
|
||||
} else {
|
||||
return m_dic->size();
|
||||
}
|
||||
}
|
||||
|
||||
size_t MMKV::totalSize() {
|
||||
SCOPED_LOCK(m_lock);
|
||||
checkLoadData();
|
||||
return m_file->getFileSize();
|
||||
}
|
||||
|
||||
size_t MMKV::actualSize() {
|
||||
SCOPED_LOCK(m_lock);
|
||||
checkLoadData();
|
||||
return m_actualSize;
|
||||
}
|
||||
|
||||
void MMKV::removeValueForKey(MMKVKey_t key) {
|
||||
if (isKeyEmpty(key)) {
|
||||
return;
|
||||
}
|
||||
SCOPED_LOCK(m_lock);
|
||||
SCOPED_LOCK(m_exclusiveProcessLock);
|
||||
checkLoadData();
|
||||
|
||||
removeDataForKey(key);
|
||||
}
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
|
||||
vector<string> MMKV::allKeys() {
|
||||
SCOPED_LOCK(m_lock);
|
||||
checkLoadData();
|
||||
|
||||
vector<string> keys;
|
||||
if (m_crypter) {
|
||||
for (const auto &itr : *m_dicCrypt) {
|
||||
keys.push_back(itr.first);
|
||||
}
|
||||
} else {
|
||||
for (const auto &itr : *m_dic) {
|
||||
keys.push_back(itr.first);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
void MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
|
||||
if (arrKeys.empty()) {
|
||||
return;
|
||||
}
|
||||
if (arrKeys.size() == 1) {
|
||||
return removeValueForKey(arrKeys[0]);
|
||||
}
|
||||
|
||||
SCOPED_LOCK(m_lock);
|
||||
SCOPED_LOCK(m_exclusiveProcessLock);
|
||||
checkLoadData();
|
||||
|
||||
size_t deleteCount = 0;
|
||||
if (m_crypter) {
|
||||
for (const auto &key : arrKeys) {
|
||||
auto itr = m_dicCrypt->find(key);
|
||||
if (itr != m_dicCrypt->end()) {
|
||||
m_dicCrypt->erase(itr);
|
||||
deleteCount++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &key : arrKeys) {
|
||||
auto itr = m_dic->find(key);
|
||||
if (itr != m_dic->end()) {
|
||||
m_dic->erase(itr);
|
||||
deleteCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deleteCount > 0) {
|
||||
m_hasFullWriteback = false;
|
||||
|
||||
fullWriteback();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
// file
|
||||
|
||||
void MMKV::sync(SyncFlag flag) {
|
||||
SCOPED_LOCK(m_lock);
|
||||
if (m_needLoadFromFile || !isFileValid()) {
|
||||
return;
|
||||
}
|
||||
SCOPED_LOCK(m_exclusiveProcessLock);
|
||||
|
||||
m_file->msync(flag);
|
||||
m_metaFile->msync(flag);
|
||||
}
|
||||
|
||||
void MMKV::lock() {
|
||||
m_exclusiveProcessLock->lock();
|
||||
}
|
||||
void MMKV::unlock() {
|
||||
m_exclusiveProcessLock->unlock();
|
||||
}
|
||||
bool MMKV::try_lock() {
|
||||
return m_exclusiveProcessLock->try_lock();
|
||||
}
|
||||
|
||||
void MMKV::registerErrorHandler(ErrorHandler handler) {
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
g_errorHandler = handler;
|
||||
}
|
||||
|
||||
void MMKV::unRegisterErrorHandler() {
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
g_errorHandler = nullptr;
|
||||
}
|
||||
|
||||
void MMKV::registerLogHandler(LogHandler handler) {
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
g_logHandler = handler;
|
||||
}
|
||||
|
||||
void MMKV::unRegisterLogHandler() {
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
g_logHandler = nullptr;
|
||||
}
|
||||
|
||||
void MMKV::setLogLevel(MMKVLogLevel level) {
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
g_currentLogLevel = level;
|
||||
}
|
||||
|
||||
static void mkSpecialCharacterFileDirectory() {
|
||||
MMKVPath_t path = g_rootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
||||
mkPath(path);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static string md5(const basic_string<T> &value) {
|
||||
uint8_t md[MD5_DIGEST_LENGTH] = {};
|
||||
char tmp[3] = {}, buf[33] = {};
|
||||
openssl::MD5((const uint8_t *) value.c_str(), value.size() * (sizeof(T) / sizeof(uint8_t)), md);
|
||||
for (auto ch : md) {
|
||||
snprintf(tmp, sizeof(tmp), "%2.2x", ch);
|
||||
strcat(buf, tmp);
|
||||
}
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
static MMKVPath_t encodeFilePath(const string &mmapID) {
|
||||
const char *specialCharacters = "\\/:*?\"<>|";
|
||||
string encodedID;
|
||||
bool hasSpecialCharacter = false;
|
||||
for (auto ch : mmapID) {
|
||||
if (strchr(specialCharacters, ch) != nullptr) {
|
||||
encodedID = md5(mmapID);
|
||||
hasSpecialCharacter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasSpecialCharacter) {
|
||||
static ThreadOnceToken_t once_control = ThreadOnceUninitialized;
|
||||
ThreadLock::ThreadOnce(&once_control, mkSpecialCharacterFileDirectory);
|
||||
return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
|
||||
} else {
|
||||
return string2MMKVPath_t(mmapID);
|
||||
}
|
||||
}
|
||||
|
||||
string mmapedKVKey(const string &mmapID, MMKVPath_t *rootPath) {
|
||||
if (rootPath && g_rootDir != (*rootPath)) {
|
||||
return md5(*rootPath + MMKV_PATH_SLASH + string2MMKVPath_t(mmapID));
|
||||
}
|
||||
return mmapID;
|
||||
}
|
||||
|
||||
MMKVPath_t mappedKVPathWithID(const string &mmapID, MMKVMode mode, MMKVPath_t *rootPath) {
|
||||
#ifndef MMKV_ANDROID
|
||||
if (rootPath) {
|
||||
#else
|
||||
if (mode & MMKV_ASHMEM) {
|
||||
return ashmemMMKVPathWithID(encodeFilePath(mmapID));
|
||||
} else if (rootPath) {
|
||||
#endif
|
||||
return *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID);
|
||||
}
|
||||
return g_rootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID);
|
||||
}
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
constexpr auto CRC_SUFFIX = ".crc";
|
||||
#else
|
||||
constexpr auto CRC_SUFFIX = L".crc";
|
||||
#endif
|
||||
|
||||
MMKVPath_t crcPathWithID(const string &mmapID, MMKVMode mode, MMKVPath_t *rootPath) {
|
||||
#ifndef MMKV_ANDROID
|
||||
if (rootPath) {
|
||||
#else
|
||||
if (mode & MMKV_ASHMEM) {
|
||||
return ashmemMMKVPathWithID(encodeFilePath(mmapID)) + CRC_SUFFIX;
|
||||
} else if (rootPath) {
|
||||
#endif
|
||||
return *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID) + CRC_SUFFIX;
|
||||
}
|
||||
return g_rootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID) + CRC_SUFFIX;
|
||||
}
|
||||
|
||||
MMKVRecoverStrategic onMMKVCRCCheckFail(const string &mmapID) {
|
||||
if (g_errorHandler) {
|
||||
return g_errorHandler(mmapID, MMKVErrorType::MMKVCRCCheckFail);
|
||||
}
|
||||
return OnErrorDiscard;
|
||||
}
|
||||
|
||||
MMKVRecoverStrategic onMMKVFileLengthError(const string &mmapID) {
|
||||
if (g_errorHandler) {
|
||||
return g_errorHandler(mmapID, MMKVErrorType::MMKVFileLength);
|
||||
}
|
||||
return OnErrorDiscard;
|
||||
}
|
||||
|
||||
MMKV_NAMESPACE_END
|
||||
357
libs/mmkv/Core/MMKV.h
Normal file
357
libs/mmkv/Core/MMKV.h
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_MMKV_H
|
||||
#define MMKV_MMKV_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMBuffer.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace mmkv {
|
||||
class CodedOutputData;
|
||||
class MemoryFile;
|
||||
class AESCrypt;
|
||||
struct MMKVMetaInfo;
|
||||
class FileLock;
|
||||
class InterProcessLock;
|
||||
class ThreadLock;
|
||||
} // namespace mmkv
|
||||
|
||||
MMKV_NAMESPACE_BEGIN
|
||||
|
||||
enum MMKVMode : uint32_t {
|
||||
MMKV_SINGLE_PROCESS = 0x1,
|
||||
MMKV_MULTI_PROCESS = 0x2,
|
||||
#ifdef MMKV_ANDROID
|
||||
CONTEXT_MODE_MULTI_PROCESS = 0x4, // in case someone mistakenly pass Context.MODE_MULTI_PROCESS
|
||||
MMKV_ASHMEM = 0x8,
|
||||
#endif
|
||||
};
|
||||
|
||||
class MMKV {
|
||||
#ifndef MMKV_ANDROID
|
||||
std::string m_mmapKey;
|
||||
MMKV(const std::string &mmapID, MMKVMode mode, std::string *cryptKey, MMKVPath_t *rootPath);
|
||||
#else // defined(MMKV_ANDROID)
|
||||
mmkv::FileLock *m_fileModeLock;
|
||||
mmkv::InterProcessLock *m_sharedProcessModeLock;
|
||||
mmkv::InterProcessLock *m_exclusiveProcessModeLock;
|
||||
|
||||
MMKV(const std::string &mmapID, int size, MMKVMode mode, std::string *cryptKey, MMKVPath_t *rootPath);
|
||||
|
||||
MMKV(const std::string &mmapID, int ashmemFD, int ashmemMetaFd, std::string *cryptKey = nullptr);
|
||||
#endif
|
||||
|
||||
~MMKV();
|
||||
|
||||
std::string m_mmapID;
|
||||
MMKVPath_t m_path;
|
||||
MMKVPath_t m_crcPath;
|
||||
mmkv::MMKVMap *m_dic;
|
||||
mmkv::MMKVMapCrypt *m_dicCrypt;
|
||||
|
||||
mmkv::MemoryFile *m_file;
|
||||
size_t m_actualSize;
|
||||
mmkv::CodedOutputData *m_output;
|
||||
|
||||
bool m_needLoadFromFile;
|
||||
bool m_hasFullWriteback;
|
||||
|
||||
uint32_t m_crcDigest;
|
||||
mmkv::MemoryFile *m_metaFile;
|
||||
mmkv::MMKVMetaInfo *m_metaInfo;
|
||||
|
||||
mmkv::AESCrypt *m_crypter;
|
||||
|
||||
mmkv::ThreadLock *m_lock;
|
||||
mmkv::FileLock *m_fileLock;
|
||||
mmkv::InterProcessLock *m_sharedProcessLock;
|
||||
mmkv::InterProcessLock *m_exclusiveProcessLock;
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
using MMKVKey_t = NSString *__unsafe_unretained;
|
||||
static bool isKeyEmpty(MMKVKey_t key) { return key.length <= 0; }
|
||||
#else
|
||||
using MMKVKey_t = const std::string &;
|
||||
static bool isKeyEmpty(MMKVKey_t key) { return key.empty(); }
|
||||
#endif
|
||||
|
||||
void loadFromFile();
|
||||
|
||||
void partialLoadFromFile();
|
||||
|
||||
void checkDataValid(bool &loadFromFile, bool &needFullWriteback);
|
||||
|
||||
void checkLoadData();
|
||||
|
||||
bool isFileValid();
|
||||
|
||||
bool checkFileCRCValid(size_t actualSize, uint32_t crcDigest);
|
||||
|
||||
void recaculateCRCDigestWithIV(const void *iv);
|
||||
|
||||
void updateCRCDigest(const uint8_t *ptr, size_t length);
|
||||
|
||||
size_t readActualSize();
|
||||
|
||||
void oldStyleWriteActualSize(size_t actualSize);
|
||||
|
||||
bool writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool increaseSequence);
|
||||
|
||||
bool ensureMemorySize(size_t newSize);
|
||||
|
||||
bool fullWriteback(mmkv::AESCrypt *newCrypter = nullptr);
|
||||
|
||||
bool doFullWriteBack(std::pair<mmkv::MMBuffer, size_t> preparedData, mmkv::AESCrypt *newCrypter);
|
||||
|
||||
mmkv::MMBuffer getDataForKey(MMKVKey_t key);
|
||||
|
||||
// isDataHolder: avoid memory copying
|
||||
bool setDataForKey(mmkv::MMBuffer &&data, MMKVKey_t key, bool isDataHolder = false);
|
||||
|
||||
bool removeDataForKey(MMKVKey_t key);
|
||||
|
||||
using KVHolderRet_t = std::pair<bool, mmkv::KeyValueHolder>;
|
||||
// isDataHolder: avoid memory copying
|
||||
KVHolderRet_t doAppendDataWithKey(const mmkv::MMBuffer &data, const mmkv::MMBuffer &key, bool isDataHolder, uint32_t keyLength);
|
||||
KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data, MMKVKey_t key, bool isDataHolder = false);
|
||||
KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data, const mmkv::KeyValueHolder &kvHolder, bool isDataHolder = false);
|
||||
#ifdef MMKV_APPLE
|
||||
KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data,
|
||||
MMKVKey_t key,
|
||||
const mmkv::KeyValueHolderCrypt &kvHolder,
|
||||
bool isDataHolder = false);
|
||||
#endif
|
||||
|
||||
void notifyContentChanged();
|
||||
|
||||
#if defined(MMKV_ANDROID) && !defined(MMKV_DISABLE_CRYPT)
|
||||
void checkReSetCryptKey(int fd, int metaFD, std::string *cryptKey);
|
||||
#endif
|
||||
|
||||
public:
|
||||
// call this before getting any MMKV instance
|
||||
static void initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel = MMKVLogInfo);
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
// protect from some old code that don't call initializeMMKV()
|
||||
static void minimalInit(MMKVPath_t defaultRootDir);
|
||||
#endif
|
||||
|
||||
// a generic purpose instance
|
||||
static MMKV *defaultMMKV(MMKVMode mode = MMKV_SINGLE_PROCESS, std::string *cryptKey = nullptr);
|
||||
|
||||
#ifndef MMKV_ANDROID
|
||||
|
||||
// mmapID: any unique ID (com.tencent.xin.pay, etc)
|
||||
// if you want a per-user mmkv, you could merge user-id within mmapID
|
||||
// cryptKey: 16 bytes at most
|
||||
static MMKV *mmkvWithID(const std::string &mmapID,
|
||||
MMKVMode mode = MMKV_SINGLE_PROCESS,
|
||||
std::string *cryptKey = nullptr,
|
||||
MMKVPath_t *rootPath = nullptr);
|
||||
|
||||
#else // defined(MMKV_ANDROID)
|
||||
|
||||
// mmapID: any unique ID (com.tencent.xin.pay, etc)
|
||||
// if you want a per-user mmkv, you could merge user-id within mmapID
|
||||
// cryptKey: 16 bytes at most
|
||||
static MMKV *mmkvWithID(const std::string &mmapID,
|
||||
int size = mmkv::DEFAULT_MMAP_SIZE,
|
||||
MMKVMode mode = MMKV_SINGLE_PROCESS,
|
||||
std::string *cryptKey = nullptr,
|
||||
MMKVPath_t *rootPath = nullptr);
|
||||
|
||||
static MMKV *mmkvWithAshmemFD(const std::string &mmapID, int fd, int metaFD, std::string *cryptKey = nullptr);
|
||||
|
||||
int ashmemFD();
|
||||
|
||||
int ashmemMetaFD();
|
||||
|
||||
bool checkProcessMode();
|
||||
#endif // MMKV_ANDROID
|
||||
|
||||
// you can call this on application termination, it's totally fine if you don't call
|
||||
static void onExit();
|
||||
|
||||
const std::string &mmapID() const;
|
||||
|
||||
const bool m_isInterProcess;
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
std::string cryptKey() const;
|
||||
|
||||
// transform plain text into encrypted text, or vice versa with empty cryptKey
|
||||
// you can change existing crypt key with different cryptKey
|
||||
bool reKey(const std::string &cryptKey);
|
||||
|
||||
// just reset cryptKey (will not encrypt or decrypt anything)
|
||||
// usually you should call this method after other process reKey() the multi-process mmkv
|
||||
void checkReSetCryptKey(const std::string *cryptKey);
|
||||
#endif
|
||||
|
||||
bool set(bool value, MMKVKey_t key);
|
||||
|
||||
bool set(int32_t value, MMKVKey_t key);
|
||||
|
||||
bool set(uint32_t value, MMKVKey_t key);
|
||||
|
||||
bool set(int64_t value, MMKVKey_t key);
|
||||
|
||||
bool set(uint64_t value, MMKVKey_t key);
|
||||
|
||||
bool set(float value, MMKVKey_t key);
|
||||
|
||||
bool set(double value, MMKVKey_t key);
|
||||
|
||||
// avoid unexpected type conversion (pointer to bool, etc)
|
||||
template <typename T>
|
||||
bool set(T value, MMKVKey_t key) = delete;
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
bool set(NSObject<NSCoding> *__unsafe_unretained obj, MMKVKey_t key);
|
||||
|
||||
NSObject *getObject(MMKVKey_t key, Class cls);
|
||||
#else // !defined(MMKV_APPLE)
|
||||
bool set(const char *value, MMKVKey_t key);
|
||||
|
||||
bool set(const std::string &value, MMKVKey_t key);
|
||||
|
||||
bool set(const mmkv::MMBuffer &value, MMKVKey_t key);
|
||||
|
||||
bool set(const std::vector<std::string> &vector, MMKVKey_t key);
|
||||
|
||||
bool getString(MMKVKey_t key, std::string &result);
|
||||
|
||||
mmkv::MMBuffer getBytes(MMKVKey_t key);
|
||||
|
||||
bool getVector(MMKVKey_t key, std::vector<std::string> &result);
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
bool getBool(MMKVKey_t key, bool defaultValue = false);
|
||||
|
||||
int32_t getInt32(MMKVKey_t key, int32_t defaultValue = 0);
|
||||
|
||||
uint32_t getUInt32(MMKVKey_t key, uint32_t defaultValue = 0);
|
||||
|
||||
int64_t getInt64(MMKVKey_t key, int64_t defaultValue = 0);
|
||||
|
||||
uint64_t getUInt64(MMKVKey_t key, uint64_t defaultValue = 0);
|
||||
|
||||
float getFloat(MMKVKey_t key, float defaultValue = 0);
|
||||
|
||||
double getDouble(MMKVKey_t key, double defaultValue = 0);
|
||||
|
||||
// return the actual size consumption of the key's value
|
||||
// pass actualSize = true to get value's length
|
||||
size_t getValueSize(MMKVKey_t key, bool actualSize);
|
||||
|
||||
// return size written into buffer
|
||||
// return -1 on any error
|
||||
int32_t writeValueToBuffer(MMKVKey_t key, void *ptr, int32_t size);
|
||||
|
||||
bool containsKey(MMKVKey_t key);
|
||||
|
||||
size_t count();
|
||||
|
||||
size_t totalSize();
|
||||
|
||||
size_t actualSize();
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
NSArray *allKeys();
|
||||
|
||||
void removeValuesForKeys(NSArray *arrKeys);
|
||||
|
||||
typedef void (^EnumerateBlock)(NSString *key, BOOL *stop);
|
||||
void enumerateKeys(EnumerateBlock block);
|
||||
|
||||
# ifdef MMKV_IOS
|
||||
static void setIsInBackground(bool isInBackground);
|
||||
static bool isInBackground();
|
||||
# endif
|
||||
#else // !defined(MMKV_APPLE)
|
||||
std::vector<std::string> allKeys();
|
||||
|
||||
void removeValuesForKeys(const std::vector<std::string> &arrKeys);
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
void removeValueForKey(MMKVKey_t key);
|
||||
|
||||
void clearAll();
|
||||
|
||||
// MMKV's size won't reduce after deleting key-values
|
||||
// call this method after lots of deleting if you care about disk usage
|
||||
// note that `clearAll` has the similar effect of `trim`
|
||||
void trim();
|
||||
|
||||
// call this method if the instance is no longer needed in the near future
|
||||
// any subsequent call to the instance is undefined behavior
|
||||
void close();
|
||||
|
||||
// call this method if you are facing memory-warning
|
||||
// any subsequent call to the instance will load all key-values from file again
|
||||
void clearMemoryCache();
|
||||
|
||||
// you don't need to call this, really, I mean it
|
||||
// unless you worry about running out of battery
|
||||
void sync(SyncFlag flag = MMKV_SYNC);
|
||||
|
||||
// get exclusive access
|
||||
void lock();
|
||||
void unlock();
|
||||
bool try_lock();
|
||||
|
||||
// check if content been changed by other process
|
||||
void checkContentChanged();
|
||||
|
||||
// called when content is changed by other process
|
||||
// doesn't guarantee real-time notification
|
||||
static void registerContentChangeHandler(mmkv::ContentChangeHandler handler);
|
||||
static void unRegisterContentChangeHandler();
|
||||
|
||||
// by default MMKV will discard all datas on failure
|
||||
// return `OnErrorRecover` to recover any data from file
|
||||
static void registerErrorHandler(mmkv::ErrorHandler handler);
|
||||
static void unRegisterErrorHandler();
|
||||
|
||||
// MMKVLogInfo by default
|
||||
// pass MMKVLogNone to disable all logging
|
||||
static void setLogLevel(MMKVLogLevel level);
|
||||
|
||||
// by default MMKV will print log to the console
|
||||
// implement this method to redirect MMKV's log
|
||||
static void registerLogHandler(mmkv::LogHandler handler);
|
||||
static void unRegisterLogHandler();
|
||||
|
||||
// detect if the MMKV file is valid or not
|
||||
// Note: Don't use this to check the existence of the instance, the return value is undefined if the file was never created.
|
||||
static bool isFileValid(const std::string &mmapID, MMKVPath_t *relatePath = nullptr);
|
||||
|
||||
// just forbid it for possibly misuse
|
||||
explicit MMKV(const MMKV &other) = delete;
|
||||
MMKV &operator=(const MMKV &other) = delete;
|
||||
};
|
||||
|
||||
MMKV_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
#endif // MMKV_MMKV_H
|
||||
126
libs/mmkv/Core/MMKVLog.cpp
Normal file
126
libs/mmkv/Core/MMKVLog.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MMKVLog.h"
|
||||
|
||||
MMKV_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef MMKV_DEBUG
|
||||
MMKVLogLevel g_currentLogLevel = MMKVLogDebug;
|
||||
#else
|
||||
MMKVLogLevel g_currentLogLevel = MMKVLogInfo;
|
||||
#endif
|
||||
|
||||
mmkv::LogHandler g_logHandler;
|
||||
|
||||
MMKV_NAMESPACE_END
|
||||
|
||||
#ifdef ENABLE_MMKV_LOG
|
||||
# include <cstdarg>
|
||||
# include <string>
|
||||
|
||||
using namespace mmkv;
|
||||
|
||||
# ifndef __FILE_NAME__
|
||||
const char *_getFileName(const char *path) {
|
||||
const char *ptr = strrchr(path, '/');
|
||||
if (!ptr) {
|
||||
ptr = strrchr(path, '\\');
|
||||
}
|
||||
if (ptr) {
|
||||
return ptr + 1;
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifndef MMKV_ANDROID
|
||||
|
||||
static const char *MMKVLogLevelDesc(MMKVLogLevel level) {
|
||||
switch (level) {
|
||||
case MMKVLogDebug:
|
||||
return "D";
|
||||
case MMKVLogInfo:
|
||||
return "I";
|
||||
case MMKVLogWarning:
|
||||
return "W";
|
||||
case MMKVLogError:
|
||||
return "E";
|
||||
default:
|
||||
return "N";
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef MMKV_APPLE
|
||||
|
||||
void _MMKVLogWithLevel(MMKVLogLevel level, const char *filename, const char *func, int line, const char *format, ...) {
|
||||
if (level >= g_currentLogLevel) {
|
||||
NSString *nsFormat = [NSString stringWithUTF8String:format];
|
||||
va_list argList;
|
||||
va_start(argList, format);
|
||||
NSString *message = [[NSString alloc] initWithFormat:nsFormat arguments:argList];
|
||||
va_end(argList);
|
||||
|
||||
if (g_logHandler) {
|
||||
g_logHandler(level, filename, line, func, message);
|
||||
} else {
|
||||
NSLog(@"[%s] <%s:%d::%s> %@", MMKVLogLevelDesc(level), filename, line, func, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
void _MMKVLogWithLevel(MMKVLogLevel level, const char *filename, const char *func, int line, const char *format, ...) {
|
||||
if (level >= g_currentLogLevel) {
|
||||
std::string message;
|
||||
char buffer[16];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
auto length = std::vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
if (length < 0) { // something wrong
|
||||
message = {};
|
||||
} else if (length < sizeof(buffer)) {
|
||||
message = std::string(buffer, static_cast<unsigned long>(length));
|
||||
} else {
|
||||
message.resize(static_cast<unsigned long>(length), '\0');
|
||||
va_start(args, format);
|
||||
std::vsnprintf(const_cast<char *>(message.data()), static_cast<size_t>(length) + 1, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (g_logHandler) {
|
||||
g_logHandler(level, filename, line, func, message);
|
||||
} else {
|
||||
printf("[%s] <%s:%d::%s> %s\n", MMKVLogLevelDesc(level), filename, line, func, message.c_str());
|
||||
//fflush(stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# endif // MMKV_APPLE
|
||||
|
||||
# endif // MMKV_ANDROID
|
||||
|
||||
#endif // ENABLE_MMKV_LOG
|
||||
86
libs/mmkv/Core/MMKVLog.h
Normal file
86
libs/mmkv/Core/MMKVLog.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_MMKVLOG_H
|
||||
#define MMKV_MMKVLOG_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
void _MMKVLogWithLevel(
|
||||
MMKV_NAMESPACE_PREFIX::MMKVLogLevel level, const char *filename, const char *func, int line, const char *format, ...);
|
||||
|
||||
MMKV_NAMESPACE_BEGIN
|
||||
|
||||
extern MMKVLogLevel g_currentLogLevel;
|
||||
extern mmkv::LogHandler g_logHandler;
|
||||
|
||||
// enable logging
|
||||
#define ENABLE_MMKV_LOG
|
||||
|
||||
#ifdef ENABLE_MMKV_LOG
|
||||
|
||||
# ifdef __FILE_NAME__
|
||||
# define __MMKV_FILE_NAME__ __FILE_NAME__
|
||||
# else
|
||||
const char *_getFileName(const char *path);
|
||||
# define __MMKV_FILE_NAME__ _getFileName(__FILE__)
|
||||
# endif
|
||||
|
||||
# define MMKVError(format, ...) \
|
||||
_MMKVLogWithLevel(MMKV_NAMESPACE_PREFIX::MMKVLogError, __MMKV_FILE_NAME__, __func__, __LINE__, format, \
|
||||
##__VA_ARGS__)
|
||||
# define MMKVWarning(format, ...) \
|
||||
_MMKVLogWithLevel(MMKV_NAMESPACE_PREFIX::MMKVLogWarning, __MMKV_FILE_NAME__, __func__, __LINE__, format, \
|
||||
##__VA_ARGS__)
|
||||
# define MMKVInfo(format, ...) \
|
||||
_MMKVLogWithLevel(MMKV_NAMESPACE_PREFIX::MMKVLogInfo, __MMKV_FILE_NAME__, __func__, __LINE__, format, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
# ifdef MMKV_DEBUG
|
||||
# define MMKVDebug(format, ...) \
|
||||
_MMKVLogWithLevel(MMKV_NAMESPACE_PREFIX::MMKVLogDebug, __MMKV_FILE_NAME__, __func__, __LINE__, format, \
|
||||
##__VA_ARGS__)
|
||||
# else
|
||||
# define MMKVDebug(format, ...) \
|
||||
{}
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# define MMKVError(format, ...) \
|
||||
{}
|
||||
# define MMKVWarning(format, ...) \
|
||||
{}
|
||||
# define MMKVInfo(format, ...) \
|
||||
{}
|
||||
# define MMKVDebug(format, ...) \
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
MMKV_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
#endif //MMKV_MMKVLOG_H
|
||||
79
libs/mmkv/Core/MMKVLog_Android.cpp
Normal file
79
libs/mmkv/Core/MMKVLog_Android.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MMKVLog.h"
|
||||
|
||||
#ifdef ENABLE_MMKV_LOG
|
||||
# ifdef MMKV_ANDROID
|
||||
# include <android/log.h>
|
||||
# include <cstdarg>
|
||||
# include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
constexpr auto APP_NAME = "MMKV";
|
||||
|
||||
static android_LogPriority MMKVLogLevelDesc(MMKVLogLevel level) {
|
||||
switch (level) {
|
||||
case MMKVLogDebug:
|
||||
return ANDROID_LOG_DEBUG;
|
||||
case MMKVLogInfo:
|
||||
return ANDROID_LOG_INFO;
|
||||
case MMKVLogWarning:
|
||||
return ANDROID_LOG_WARN;
|
||||
case MMKVLogError:
|
||||
return ANDROID_LOG_ERROR;
|
||||
default:
|
||||
return ANDROID_LOG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void _MMKVLogWithLevel(MMKVLogLevel level, const char *filename, const char *func, int line, const char *format, ...) {
|
||||
if (level >= g_currentLogLevel) {
|
||||
string message;
|
||||
char buffer[16];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
auto length = std::vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
if (length < 0) { // something wrong
|
||||
message = {};
|
||||
} else if (length < sizeof(buffer)) {
|
||||
message = string(buffer, static_cast<unsigned long>(length));
|
||||
} else {
|
||||
message.resize(static_cast<unsigned long>(length), '\0');
|
||||
va_start(args, format);
|
||||
std::vsnprintf(const_cast<char *>(message.data()), static_cast<size_t>(length) + 1, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (g_logHandler) {
|
||||
g_logHandler(level, filename, line, func, message);
|
||||
} else {
|
||||
auto desc = MMKVLogLevelDesc(level);
|
||||
__android_log_print(desc, APP_NAME, "<%s:%d::%s> %s", filename, line, func, message.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif // MMKV_ANDROID
|
||||
|
||||
#endif // ENABLE_MMKV_LOG
|
||||
81
libs/mmkv/Core/MMKVMetaInfo.hpp
Normal file
81
libs/mmkv/Core/MMKVMetaInfo.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_MMKVMETAINFO_H
|
||||
#define MMKV_MMKVMETAINFO_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "aes/AESCrypt.h"
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
enum MMKVVersion : uint32_t {
|
||||
MMKVVersionDefault = 0,
|
||||
|
||||
// record full write back count
|
||||
MMKVVersionSequence = 1,
|
||||
|
||||
// store random iv for encryption
|
||||
MMKVVersionRandomIV = 2,
|
||||
|
||||
// store actual size together with crc checksum, try to reduce file corruption
|
||||
MMKVVersionActualSize = 3,
|
||||
};
|
||||
|
||||
struct MMKVMetaInfo {
|
||||
uint32_t m_crcDigest = 0;
|
||||
uint32_t m_version = MMKVVersionSequence;
|
||||
uint32_t m_sequence = 0; // full write-back count
|
||||
uint8_t m_vector[AES_KEY_LEN] = {};
|
||||
uint32_t m_actualSize = 0;
|
||||
|
||||
// confirmed info: it's been synced to file
|
||||
struct {
|
||||
uint32_t lastActualSize = 0;
|
||||
uint32_t lastCRCDigest = 0;
|
||||
uint32_t _reserved[16] = {};
|
||||
} m_lastConfirmedMetaInfo;
|
||||
|
||||
void write(void *ptr) const {
|
||||
MMKV_ASSERT(ptr);
|
||||
memcpy(ptr, this, sizeof(MMKVMetaInfo));
|
||||
}
|
||||
|
||||
void writeCRCAndActualSizeOnly(void *ptr) const {
|
||||
MMKV_ASSERT(ptr);
|
||||
auto other = (MMKVMetaInfo *) ptr;
|
||||
other->m_crcDigest = m_crcDigest;
|
||||
other->m_actualSize = m_actualSize;
|
||||
}
|
||||
|
||||
void read(const void *ptr) {
|
||||
MMKV_ASSERT(ptr);
|
||||
memcpy(this, ptr, sizeof(MMKVMetaInfo));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(MMKVMetaInfo) <= (4 * 1024), "MMKVMetaInfo lager than one pagesize");
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_MMKVMETAINFO_H
|
||||
211
libs/mmkv/Core/MMKVPredef.h
Executable file
211
libs/mmkv/Core/MMKVPredef.h
Executable file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_SRC_MMKVPREDEF_H
|
||||
#define MMKV_SRC_MMKVPREDEF_H
|
||||
|
||||
// disable encryption & decryption to reduce some code
|
||||
//#define MMKV_DISABLE_CRYPT
|
||||
//#define MMKV_DISABLE_FLUTTER
|
||||
|
||||
// using POSIX implementation
|
||||
//#define FORCE_POSIX
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
constexpr auto MMKV_VERSION = "v1.2.8";
|
||||
|
||||
#ifdef DEBUG
|
||||
# define MMKV_DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
# undef MMKV_DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# ifdef FORCE_POSIX
|
||||
# define MMKV_POSIX
|
||||
# else
|
||||
# define MMKV_ANDROID
|
||||
# endif
|
||||
#elif __APPLE__
|
||||
# ifdef FORCE_POSIX
|
||||
# define MMKV_POSIX
|
||||
# else
|
||||
# define MMKV_APPLE
|
||||
# ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
|
||||
# define MMKV_IOS
|
||||
# elif __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__
|
||||
# define MMKV_WATCH
|
||||
# else
|
||||
# define MMKV_MAC
|
||||
# endif
|
||||
# endif // FORCE_POSIX
|
||||
#elif __linux__ || __unix__
|
||||
# define MMKV_POSIX
|
||||
# if __linux__
|
||||
# define MMKV_LINUX
|
||||
# endif
|
||||
#elif _WIN32
|
||||
# define MMKV_WIN32
|
||||
#endif
|
||||
|
||||
#ifdef MMKV_WIN32
|
||||
# if !defined(_WIN32_WINNT)
|
||||
# define _WIN32_WINNT _WIN32_WINNT_WINXP
|
||||
# endif
|
||||
|
||||
# include <SDKDDKVer.h>
|
||||
// Exclude rarely-used stuff from Windows headers
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
// Windows Header Files
|
||||
# include <windows.h>
|
||||
|
||||
constexpr auto MMKV_PATH_SLASH = L"\\";
|
||||
# define MMKV_PATH_FORMAT "%ws"
|
||||
using MMKVFileHandle_t = HANDLE;
|
||||
using MMKVPath_t = std::wstring;
|
||||
extern MMKVPath_t string2MMKVPath_t(const std::string &str);
|
||||
|
||||
# ifndef MMKV_EMBED_ZLIB
|
||||
# define MMKV_EMBED_ZLIB 1
|
||||
# endif
|
||||
|
||||
#else // MMKV_WIN32
|
||||
|
||||
constexpr auto MMKV_PATH_SLASH = "/";
|
||||
# define MMKV_PATH_FORMAT "%s"
|
||||
using MMKVFileHandle_t = int;
|
||||
using MMKVPath_t = std::string;
|
||||
# define string2MMKVPath_t(str) (str)
|
||||
|
||||
# ifndef MMKV_EMBED_ZLIB
|
||||
# define MMKV_EMBED_ZLIB 0
|
||||
# endif
|
||||
|
||||
#endif // MMKV_WIN32
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
# import <Foundation/Foundation.h>
|
||||
# define MMKV_NAMESPACE_BEGIN namespace mmkv {
|
||||
# define MMKV_NAMESPACE_END }
|
||||
# define MMKV_NAMESPACE_PREFIX mmkv
|
||||
using MMKVLog_t = NSString *;
|
||||
#else
|
||||
# define MMKV_NAMESPACE_BEGIN
|
||||
# define MMKV_NAMESPACE_END
|
||||
# define MMKV_NAMESPACE_PREFIX
|
||||
using MMKVLog_t = const std::string &;
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
MMKV_NAMESPACE_BEGIN
|
||||
|
||||
enum MMKVLogLevel : int {
|
||||
MMKVLogDebug = 0, // not available for release/product build
|
||||
MMKVLogInfo = 1, // default level
|
||||
MMKVLogWarning,
|
||||
MMKVLogError,
|
||||
MMKVLogNone, // special level used to disable all log messages
|
||||
};
|
||||
|
||||
enum MMKVRecoverStrategic : int {
|
||||
OnErrorDiscard = 0,
|
||||
OnErrorRecover,
|
||||
};
|
||||
|
||||
enum MMKVErrorType : int {
|
||||
MMKVCRCCheckFail = 0,
|
||||
MMKVFileLength,
|
||||
};
|
||||
|
||||
enum SyncFlag : bool { MMKV_SYNC = true, MMKV_ASYNC = false };
|
||||
|
||||
MMKV_NAMESPACE_END
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
typedef void (*LogHandler)(MMKVLogLevel level, const char *file, int line, const char *function, MMKVLog_t message);
|
||||
|
||||
// by default MMKV will discard all datas on failure
|
||||
// return `OnErrorRecover` to recover any data from file
|
||||
typedef MMKVRecoverStrategic (*ErrorHandler)(const std::string &mmapID, MMKVErrorType errorType);
|
||||
|
||||
// called when content is changed by other process
|
||||
// doesn't guarantee real-time notification
|
||||
typedef void (*ContentChangeHandler)(const std::string &mmapID);
|
||||
|
||||
extern size_t DEFAULT_MMAP_SIZE;
|
||||
#define DEFAULT_MMAP_ID "mmkv.default"
|
||||
|
||||
class MMBuffer;
|
||||
struct KeyValueHolder;
|
||||
|
||||
#ifdef MMKV_DISABLE_CRYPT
|
||||
using KeyValueHolderCrypt = KeyValueHolder;
|
||||
#else
|
||||
struct KeyValueHolderCrypt;
|
||||
#endif
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
struct KeyHasher {
|
||||
size_t operator()(NSString *key) const { return key.hash; }
|
||||
};
|
||||
|
||||
struct KeyEqualer {
|
||||
bool operator()(NSString *left, NSString *right) const {
|
||||
if (left == right) {
|
||||
return true;
|
||||
}
|
||||
return ([left isEqualToString:right] == YES);
|
||||
}
|
||||
};
|
||||
|
||||
using MMKVVector = std::vector<std::pair<NSString *, mmkv::MMBuffer>>;
|
||||
using MMKVMap = std::unordered_map<NSString *, mmkv::KeyValueHolder, KeyHasher, KeyEqualer>;
|
||||
using MMKVMapCrypt = std::unordered_map<NSString *, mmkv::KeyValueHolderCrypt, KeyHasher, KeyEqualer>;
|
||||
#else
|
||||
using MMKVVector = std::vector<std::pair<std::string, mmkv::MMBuffer>>;
|
||||
using MMKVMap = std::unordered_map<std::string, mmkv::KeyValueHolder>;
|
||||
using MMKVMapCrypt = std::unordered_map<std::string, mmkv::KeyValueHolderCrypt>;
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
template <typename T>
|
||||
void unused(const T &) {}
|
||||
|
||||
constexpr size_t AES_KEY_LEN = 16;
|
||||
constexpr size_t AES_KEY_BITSET_LEN = 128;
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#ifdef MMKV_DEBUG
|
||||
# include <cassert>
|
||||
# define MMKV_ASSERT(var) assert(var)
|
||||
#else
|
||||
# define MMKV_ASSERT(var) mmkv::unused(var)
|
||||
#endif
|
||||
|
||||
#endif //cplus-plus
|
||||
|
||||
#endif //MMKV_SRC_MMKVPREDEF_H
|
||||
263
libs/mmkv/Core/MMKV_Android.cpp
Normal file
263
libs/mmkv/Core/MMKV_Android.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MMKV.h"
|
||||
|
||||
#ifdef MMKV_ANDROID
|
||||
|
||||
# include "InterProcessLock.h"
|
||||
# include "KeyValueHolder.h"
|
||||
# include "MMKVLog.h"
|
||||
# include "MMKVMetaInfo.hpp"
|
||||
# include "MemoryFile.h"
|
||||
# include "ScopedLock.hpp"
|
||||
# include "ThreadLock.h"
|
||||
# include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace mmkv;
|
||||
|
||||
extern unordered_map<string, MMKV *> *g_instanceDic;
|
||||
extern ThreadLock *g_instanceLock;
|
||||
|
||||
extern string mmapedKVKey(const string &mmapID, string *rootPath);
|
||||
extern string mappedKVPathWithID(const string &mmapID, MMKVMode mode, string *rootPath);
|
||||
extern string crcPathWithID(const string &mmapID, MMKVMode mode, string *rootPath);
|
||||
|
||||
MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath)
|
||||
: m_mmapID(mmapedKVKey(mmapID, rootPath)) // historically Android mistakenly use mmapKey as mmapID
|
||||
, m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
|
||||
, m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
|
||||
, m_dic(nullptr)
|
||||
, m_dicCrypt(nullptr)
|
||||
, m_file(new MemoryFile(m_path, size, (mode & MMKV_ASHMEM) ? MMFILE_TYPE_ASHMEM : MMFILE_TYPE_FILE))
|
||||
, m_metaFile(new MemoryFile(m_crcPath, DEFAULT_MMAP_SIZE, m_file->m_fileType))
|
||||
, m_metaInfo(new MMKVMetaInfo())
|
||||
, m_crypter(nullptr)
|
||||
, m_lock(new ThreadLock())
|
||||
, m_fileLock(new FileLock(m_metaFile->getFd(), (mode & MMKV_ASHMEM)))
|
||||
, m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
|
||||
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
|
||||
, m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0 || (mode & CONTEXT_MODE_MULTI_PROCESS) != 0) {
|
||||
m_actualSize = 0;
|
||||
m_output = nullptr;
|
||||
|
||||
// force use fcntl(), otherwise will conflict with MemoryFile::reloadFromFile()
|
||||
m_fileModeLock = new FileLock(m_file->getFd(), true);
|
||||
m_sharedProcessModeLock = new InterProcessLock(m_fileModeLock, SharedLockType);
|
||||
m_exclusiveProcessModeLock = nullptr;
|
||||
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
if (cryptKey && cryptKey->length() > 0) {
|
||||
m_dicCrypt = new MMKVMapCrypt();
|
||||
m_crypter = new AESCrypt(cryptKey->data(), cryptKey->length());
|
||||
} else
|
||||
# endif
|
||||
{
|
||||
m_dic = new MMKVMap();
|
||||
}
|
||||
|
||||
m_needLoadFromFile = true;
|
||||
m_hasFullWriteback = false;
|
||||
|
||||
m_crcDigest = 0;
|
||||
|
||||
m_sharedProcessLock->m_enable = m_isInterProcess;
|
||||
m_exclusiveProcessLock->m_enable = m_isInterProcess;
|
||||
|
||||
// sensitive zone
|
||||
{
|
||||
SCOPED_LOCK(m_sharedProcessLock);
|
||||
loadFromFile();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKey)
|
||||
: m_mmapID(mmapID)
|
||||
, m_path(mappedKVPathWithID(m_mmapID, MMKV_ASHMEM, nullptr))
|
||||
, m_crcPath(crcPathWithID(m_mmapID, MMKV_ASHMEM, nullptr))
|
||||
, m_dic(nullptr)
|
||||
, m_dicCrypt(nullptr)
|
||||
, m_file(new MemoryFile(ashmemFD))
|
||||
, m_metaFile(new MemoryFile(ashmemMetaFD))
|
||||
, m_metaInfo(new MMKVMetaInfo())
|
||||
, m_crypter(nullptr)
|
||||
, m_lock(new ThreadLock())
|
||||
, m_fileLock(new FileLock(m_metaFile->getFd(), true))
|
||||
, m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
|
||||
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
|
||||
, m_isInterProcess(true) {
|
||||
|
||||
m_actualSize = 0;
|
||||
m_output = nullptr;
|
||||
|
||||
// force use fcntl(), otherwise will conflict with MemoryFile::reloadFromFile()
|
||||
m_fileModeLock = new FileLock(m_file->getFd(), true);
|
||||
m_sharedProcessModeLock = new InterProcessLock(m_fileModeLock, SharedLockType);
|
||||
m_exclusiveProcessModeLock = nullptr;
|
||||
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
if (cryptKey && cryptKey->length() > 0) {
|
||||
m_dicCrypt = new MMKVMapCrypt();
|
||||
m_crypter = new AESCrypt(cryptKey->data(), cryptKey->length());
|
||||
} else
|
||||
# endif
|
||||
{
|
||||
m_dic = new MMKVMap();
|
||||
}
|
||||
|
||||
m_needLoadFromFile = true;
|
||||
m_hasFullWriteback = false;
|
||||
|
||||
m_crcDigest = 0;
|
||||
|
||||
m_sharedProcessLock->m_enable = m_isInterProcess;
|
||||
m_exclusiveProcessLock->m_enable = m_isInterProcess;
|
||||
|
||||
// sensitive zone
|
||||
{
|
||||
SCOPED_LOCK(m_sharedProcessLock);
|
||||
loadFromFile();
|
||||
}
|
||||
}
|
||||
|
||||
MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath) {
|
||||
|
||||
if (mmapID.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
|
||||
auto mmapKey = mmapedKVKey(mmapID, rootPath);
|
||||
auto itr = g_instanceDic->find(mmapKey);
|
||||
if (itr != g_instanceDic->end()) {
|
||||
MMKV *kv = itr->second;
|
||||
return kv;
|
||||
}
|
||||
if (rootPath) {
|
||||
if (!isFileExist(*rootPath)) {
|
||||
if (!mkPath(*rootPath)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
MMKVInfo("prepare to load %s (id %s) from rootPath %s", mmapID.c_str(), mmapKey.c_str(), rootPath->c_str());
|
||||
}
|
||||
auto kv = new MMKV(mmapID, size, mode, cryptKey, rootPath);
|
||||
(*g_instanceDic)[mmapKey] = kv;
|
||||
return kv;
|
||||
}
|
||||
|
||||
MMKV *MMKV::mmkvWithAshmemFD(const string &mmapID, int fd, int metaFD, string *cryptKey) {
|
||||
|
||||
if (fd < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
SCOPED_LOCK(g_instanceLock);
|
||||
|
||||
auto itr = g_instanceDic->find(mmapID);
|
||||
if (itr != g_instanceDic->end()) {
|
||||
MMKV *kv = itr->second;
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
kv->checkReSetCryptKey(fd, metaFD, cryptKey);
|
||||
# endif
|
||||
return kv;
|
||||
}
|
||||
auto kv = new MMKV(mmapID, fd, metaFD, cryptKey);
|
||||
(*g_instanceDic)[mmapID] = kv;
|
||||
return kv;
|
||||
}
|
||||
|
||||
int MMKV::ashmemFD() {
|
||||
return (m_file->m_fileType & mmkv::MMFILE_TYPE_ASHMEM) ? m_file->getFd() : -1;
|
||||
}
|
||||
|
||||
int MMKV::ashmemMetaFD() {
|
||||
return (m_file->m_fileType & mmkv::MMFILE_TYPE_ASHMEM) ? m_metaFile->getFd() : -1;
|
||||
}
|
||||
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
void MMKV::checkReSetCryptKey(int fd, int metaFD, string *cryptKey) {
|
||||
SCOPED_LOCK(m_lock);
|
||||
|
||||
checkReSetCryptKey(cryptKey);
|
||||
|
||||
if (m_file->m_fileType & MMFILE_TYPE_ASHMEM) {
|
||||
if (m_file->getFd() != fd) {
|
||||
::close(fd);
|
||||
}
|
||||
if (m_metaFile->getFd() != metaFD) {
|
||||
::close(metaFD);
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
bool MMKV::checkProcessMode() {
|
||||
// avoid exception on open() error
|
||||
if (!m_file->isFileValid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_isInterProcess) {
|
||||
if (!m_exclusiveProcessModeLock) {
|
||||
m_exclusiveProcessModeLock = new InterProcessLock(m_fileModeLock, ExclusiveLockType);
|
||||
}
|
||||
// avoid multiple processes get shared lock at the same time, https://github.com/Tencent/MMKV/issues/523
|
||||
auto tryAgain = false;
|
||||
auto exclusiveLocked = m_exclusiveProcessModeLock->try_lock(&tryAgain);
|
||||
if (exclusiveLocked) {
|
||||
return true;
|
||||
}
|
||||
auto shareLocked = m_sharedProcessModeLock->try_lock();
|
||||
if (!shareLocked) {
|
||||
// this call will fail on most case, just do it to make sure
|
||||
m_exclusiveProcessModeLock->try_lock();
|
||||
return true;
|
||||
} else {
|
||||
if (!tryAgain) {
|
||||
// something wrong with the OS/filesystem, let's try again
|
||||
exclusiveLocked = m_exclusiveProcessModeLock->try_lock(&tryAgain);
|
||||
if (!exclusiveLocked && !tryAgain) {
|
||||
// still something wrong, we have to give up and assume it passed the test
|
||||
MMKVWarning("Got a shared lock, but fail to exclusive lock [%s], assume it's ok", m_mmapID.c_str());
|
||||
exclusiveLocked = true;
|
||||
}
|
||||
}
|
||||
if (!exclusiveLocked) {
|
||||
MMKVError("Got a shared lock, but fail to exclusive lock [%s]", m_mmapID.c_str());
|
||||
}
|
||||
return exclusiveLocked;
|
||||
}
|
||||
} else {
|
||||
auto tryAgain = false;
|
||||
auto shareLocked = m_sharedProcessModeLock->try_lock(&tryAgain);
|
||||
if (!shareLocked && !tryAgain) {
|
||||
// something wrong with the OS/filesystem, we have to give up and assume it passed the test
|
||||
MMKVWarning("Fail to shared lock [%s], assume it's ok", m_mmapID.c_str());
|
||||
shareLocked = true;
|
||||
}
|
||||
if (!shareLocked) {
|
||||
MMKVError("Fail to share lock [%s]", m_mmapID.c_str());
|
||||
}
|
||||
return shareLocked;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MMKV_ANDROID
|
||||
1121
libs/mmkv/Core/MMKV_IO.cpp
Normal file
1121
libs/mmkv/Core/MMKV_IO.cpp
Normal file
File diff suppressed because it is too large
Load Diff
57
libs/mmkv/Core/MMKV_IO.h
Normal file
57
libs/mmkv/Core/MMKV_IO.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_IO_h
|
||||
#define MMKV_IO_h
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKV.h"
|
||||
|
||||
MMKV_NAMESPACE_BEGIN
|
||||
|
||||
std::string mmapedKVKey(const std::string &mmapID, MMKVPath_t *rootPath = nullptr);
|
||||
MMKVPath_t mappedKVPathWithID(const std::string &mmapID, MMKVMode mode, MMKVPath_t *rootPath);
|
||||
MMKVPath_t crcPathWithID(const std::string &mmapID, MMKVMode mode, MMKVPath_t *rootPath);
|
||||
|
||||
MMKVRecoverStrategic onMMKVCRCCheckFail(const std::string &mmapID);
|
||||
MMKVRecoverStrategic onMMKVFileLengthError(const std::string &mmapID);
|
||||
|
||||
template <typename T>
|
||||
void clearDictionary(T *dic) {
|
||||
if (!dic) {
|
||||
return;
|
||||
}
|
||||
#ifdef MMKV_APPLE
|
||||
for (auto &pair : *dic) {
|
||||
[pair.first release];
|
||||
}
|
||||
#endif
|
||||
dic->clear();
|
||||
}
|
||||
|
||||
enum : bool {
|
||||
KeepSequence = false,
|
||||
IncreaseSequence = true,
|
||||
};
|
||||
|
||||
MMKV_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
#endif /* MMKV_IO_h */
|
||||
304
libs/mmkv/Core/MemoryFile.cpp
Normal file
304
libs/mmkv/Core/MemoryFile.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MemoryFile.h"
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
|
||||
# include "InterProcessLock.h"
|
||||
# include "MMBuffer.h"
|
||||
# include "MMKVLog.h"
|
||||
# include "ScopedLock.hpp"
|
||||
# include <cerrno>
|
||||
# include <fcntl.h>
|
||||
# include <sys/mman.h>
|
||||
# include <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
static bool getFileSize(int fd, size_t &size);
|
||||
|
||||
# ifdef MMKV_ANDROID
|
||||
extern size_t ASharedMemory_getSize(int fd);
|
||||
# else
|
||||
MemoryFile::MemoryFile(const MMKVPath_t &path) : m_name(path), m_fd(-1), m_ptr(nullptr), m_size(0) {
|
||||
reloadFromFile();
|
||||
}
|
||||
# endif // MMKV_ANDROID
|
||||
|
||||
# ifdef MMKV_IOS
|
||||
void tryResetFileProtection(const string &path);
|
||||
# endif
|
||||
|
||||
bool MemoryFile::truncate(size_t size) {
|
||||
if (m_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
if (size == m_size) {
|
||||
return true;
|
||||
}
|
||||
# ifdef MMKV_ANDROID
|
||||
if (m_fileType == MMFILE_TYPE_ASHMEM) {
|
||||
if (size > m_size) {
|
||||
MMKVError("ashmem %s reach size limit:%zu, consider configure with larger size", m_name.c_str(), m_size);
|
||||
} else {
|
||||
MMKVInfo("no way to trim ashmem %s from %zu to smaller size %zu", m_name.c_str(), m_size, size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
# endif // MMKV_ANDROID
|
||||
|
||||
auto oldSize = m_size;
|
||||
m_size = size;
|
||||
// round up to (n * pagesize)
|
||||
if (m_size < DEFAULT_MMAP_SIZE || (m_size % DEFAULT_MMAP_SIZE != 0)) {
|
||||
m_size = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
|
||||
}
|
||||
|
||||
if (::ftruncate(m_fd, static_cast<off_t>(m_size)) != 0) {
|
||||
MMKVError("fail to truncate [%s] to size %zu, %s", m_name.c_str(), m_size, strerror(errno));
|
||||
m_size = oldSize;
|
||||
return false;
|
||||
}
|
||||
if (m_size > oldSize) {
|
||||
if (!zeroFillFile(m_fd, oldSize, m_size - oldSize)) {
|
||||
MMKVError("fail to zeroFile [%s] to size %zu, %s", m_name.c_str(), m_size, strerror(errno));
|
||||
m_size = oldSize;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ptr) {
|
||||
if (munmap(m_ptr, oldSize) != 0) {
|
||||
MMKVError("fail to munmap [%s], %s", m_name.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
auto ret = mmap();
|
||||
if (!ret) {
|
||||
doCleanMemoryCache(true);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MemoryFile::msync(SyncFlag syncFlag) {
|
||||
if (m_ptr) {
|
||||
auto ret = ::msync(m_ptr, m_size, syncFlag ? MS_SYNC : MS_ASYNC);
|
||||
if (ret == 0) {
|
||||
return true;
|
||||
}
|
||||
MMKVError("fail to msync [%s], %s", m_name.c_str(), strerror(errno));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemoryFile::mmap() {
|
||||
m_ptr = (char *) ::mmap(m_ptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);
|
||||
if (m_ptr == MAP_FAILED) {
|
||||
MMKVError("fail to mmap [%s], %s", m_name.c_str(), strerror(errno));
|
||||
m_ptr = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryFile::reloadFromFile() {
|
||||
# ifdef MMKV_ANDROID
|
||||
if (m_fileType == MMFILE_TYPE_ASHMEM) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
if (isFileValid()) {
|
||||
MMKVWarning("calling reloadFromFile while the cache [%s] is still valid", m_name.c_str());
|
||||
MMKV_ASSERT(0);
|
||||
clearMemoryCache();
|
||||
}
|
||||
|
||||
m_fd = open(m_name.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, S_IRWXU);
|
||||
if (m_fd < 0) {
|
||||
MMKVError("fail to open:%s, %s", m_name.c_str(), strerror(errno));
|
||||
} else {
|
||||
FileLock fileLock(m_fd);
|
||||
InterProcessLock lock(&fileLock, ExclusiveLockType);
|
||||
SCOPED_LOCK(&lock);
|
||||
|
||||
mmkv::getFileSize(m_fd, m_size);
|
||||
// round up to (n * pagesize)
|
||||
if (m_size < DEFAULT_MMAP_SIZE || (m_size % DEFAULT_MMAP_SIZE != 0)) {
|
||||
size_t roundSize = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
|
||||
truncate(roundSize);
|
||||
} else {
|
||||
auto ret = mmap();
|
||||
if (!ret) {
|
||||
doCleanMemoryCache(true);
|
||||
}
|
||||
}
|
||||
# ifdef MMKV_IOS
|
||||
tryResetFileProtection(m_name);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryFile::doCleanMemoryCache(bool forceClean) {
|
||||
# ifdef MMKV_ANDROID
|
||||
if (m_fileType == MMFILE_TYPE_ASHMEM && !forceClean) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
if (m_ptr && m_ptr != MAP_FAILED) {
|
||||
if (munmap(m_ptr, m_size) != 0) {
|
||||
MMKVError("fail to munmap [%s], %s", m_name.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
m_ptr = nullptr;
|
||||
|
||||
if (m_fd >= 0) {
|
||||
if (::close(m_fd) != 0) {
|
||||
MMKVError("fail to close [%s], %s", m_name.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
m_fd = -1;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
size_t MemoryFile::getActualFileSize() {
|
||||
# ifdef MMKV_ANDROID
|
||||
if (m_fileType == MMFILE_TYPE_ASHMEM) {
|
||||
return ASharedMemory_getSize(m_fd);
|
||||
}
|
||||
# endif
|
||||
size_t size = 0;
|
||||
mmkv::getFileSize(m_fd, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
bool isFileExist(const string &nsFilePath) {
|
||||
if (nsFilePath.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat temp = {};
|
||||
return lstat(nsFilePath.c_str(), &temp) == 0;
|
||||
}
|
||||
|
||||
extern bool mkPath(const MMKVPath_t &str) {
|
||||
char *path = strdup(str.c_str());
|
||||
|
||||
struct stat sb = {};
|
||||
bool done = false;
|
||||
char *slash = path;
|
||||
|
||||
while (!done) {
|
||||
slash += strspn(slash, "/");
|
||||
slash += strcspn(slash, "/");
|
||||
|
||||
done = (*slash == '\0');
|
||||
*slash = '\0';
|
||||
|
||||
if (stat(path, &sb) != 0) {
|
||||
if (errno != ENOENT || mkdir(path, 0777) != 0) {
|
||||
MMKVWarning("%s : %s", path, strerror(errno));
|
||||
free(path);
|
||||
return false;
|
||||
}
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
MMKVWarning("%s: %s", path, strerror(ENOTDIR));
|
||||
free(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
*slash = '/';
|
||||
}
|
||||
free(path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MMBuffer *readWholeFile(const MMKVPath_t &path) {
|
||||
MMBuffer *buffer = nullptr;
|
||||
int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
auto fileLength = lseek(fd, 0, SEEK_END);
|
||||
if (fileLength > 0) {
|
||||
buffer = new MMBuffer(static_cast<size_t>(fileLength));
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
auto readSize = read(fd, buffer->getPtr(), static_cast<size_t>(fileLength));
|
||||
if (readSize != -1) {
|
||||
//fileSize = readSize;
|
||||
} else {
|
||||
MMKVWarning("fail to read %s: %s", path.c_str(), strerror(errno));
|
||||
|
||||
delete buffer;
|
||||
buffer = nullptr;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
MMKVWarning("fail to open %s: %s", path.c_str(), strerror(errno));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool zeroFillFile(int fd, size_t startPos, size_t size) {
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lseek(fd, static_cast<off_t>(startPos), SEEK_SET) < 0) {
|
||||
MMKVError("fail to lseek fd[%d], error:%s", fd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char zeros[4096] = {};
|
||||
while (size >= sizeof(zeros)) {
|
||||
if (write(fd, zeros, sizeof(zeros)) < 0) {
|
||||
MMKVError("fail to write fd[%d], error:%s", fd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
size -= sizeof(zeros);
|
||||
}
|
||||
if (size > 0) {
|
||||
if (write(fd, zeros, size) < 0) {
|
||||
MMKVError("fail to write fd[%d], error:%s", fd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getFileSize(int fd, size_t &size) {
|
||||
struct stat st = {};
|
||||
if (fstat(fd, &st) != -1) {
|
||||
size = (size_t) st.st_size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t getPageSize() {
|
||||
return static_cast<size_t>(getpagesize());
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // MMKV_WIN32
|
||||
106
libs/mmkv/Core/MemoryFile.h
Normal file
106
libs/mmkv/Core/MemoryFile.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_MAMERYFILE_H
|
||||
#define MMKV_MAMERYFILE_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#ifdef MMKV_ANDROID
|
||||
MMKVPath_t ashmemMMKVPathWithID(const MMKVPath_t &mmapID);
|
||||
|
||||
namespace mmkv {
|
||||
extern int g_android_api;
|
||||
|
||||
enum FileType : bool { MMFILE_TYPE_FILE = false, MMFILE_TYPE_ASHMEM = true };
|
||||
} // namespace mmkv
|
||||
#endif // MMKV_ANDROID
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
class MemoryFile {
|
||||
MMKVPath_t m_name;
|
||||
MMKVFileHandle_t m_fd;
|
||||
#ifdef MMKV_WIN32
|
||||
HANDLE m_fileMapping;
|
||||
#endif
|
||||
void *m_ptr;
|
||||
size_t m_size;
|
||||
|
||||
bool mmap();
|
||||
|
||||
void doCleanMemoryCache(bool forceClean);
|
||||
|
||||
public:
|
||||
#ifndef MMKV_ANDROID
|
||||
explicit MemoryFile(const MMKVPath_t &path);
|
||||
#else
|
||||
MemoryFile(const MMKVPath_t &path, size_t size, FileType fileType);
|
||||
explicit MemoryFile(MMKVFileHandle_t ashmemFD);
|
||||
|
||||
const FileType m_fileType;
|
||||
#endif // MMKV_ANDROID
|
||||
|
||||
~MemoryFile() { doCleanMemoryCache(true); }
|
||||
|
||||
size_t getFileSize() const { return m_size; }
|
||||
|
||||
// get the actual file size on disk
|
||||
size_t getActualFileSize();
|
||||
|
||||
void *getMemory() { return m_ptr; }
|
||||
|
||||
const MMKVPath_t &getName() { return m_name; }
|
||||
|
||||
MMKVFileHandle_t getFd() { return m_fd; }
|
||||
|
||||
// the newly expanded file content will be zeroed
|
||||
bool truncate(size_t size);
|
||||
|
||||
bool msync(SyncFlag syncFlag);
|
||||
|
||||
// call this if clearMemoryCache() has been called
|
||||
void reloadFromFile();
|
||||
|
||||
void clearMemoryCache() { doCleanMemoryCache(false); }
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
bool isFileValid() { return m_fd >= 0 && m_size > 0 && m_ptr; }
|
||||
#else
|
||||
bool isFileValid() { return m_fd != INVALID_HANDLE_VALUE && m_size > 0 && m_fileMapping && m_ptr; }
|
||||
#endif
|
||||
|
||||
// just forbid it for possibly misuse
|
||||
explicit MemoryFile(const MemoryFile &other) = delete;
|
||||
MemoryFile &operator=(const MemoryFile &other) = delete;
|
||||
};
|
||||
|
||||
class MMBuffer;
|
||||
|
||||
extern bool mkPath(const MMKVPath_t &path);
|
||||
extern bool isFileExist(const MMKVPath_t &nsFilePath);
|
||||
extern MMBuffer *readWholeFile(const MMKVPath_t &path);
|
||||
extern bool zeroFillFile(MMKVFileHandle_t fd, size_t startPos, size_t size);
|
||||
extern size_t getPageSize();
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_MAMERYFILE_H
|
||||
192
libs/mmkv/Core/MemoryFile_Android.cpp
Normal file
192
libs/mmkv/Core/MemoryFile_Android.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MemoryFile.h"
|
||||
|
||||
#ifdef MMKV_ANDROID
|
||||
|
||||
# include "MMBuffer.h"
|
||||
# include "MMKVLog.h"
|
||||
# include <cerrno>
|
||||
# include <fcntl.h>
|
||||
# include <sys/mman.h>
|
||||
# include <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
constexpr char ASHMEM_NAME_DEF[] = "/dev/ashmem";
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
// for Android Q limiting ashmem access
|
||||
extern int ASharedMemory_create(const char *name, size_t size);
|
||||
extern size_t ASharedMemory_getSize(int fd);
|
||||
extern string ASharedMemory_getName(int fd);
|
||||
|
||||
MemoryFile::MemoryFile(const string &path, size_t size, FileType fileType)
|
||||
: m_name(path), m_fd(-1), m_ptr(nullptr), m_size(0), m_fileType(fileType) {
|
||||
if (m_fileType == MMFILE_TYPE_FILE) {
|
||||
reloadFromFile();
|
||||
} else {
|
||||
// round up to (n * pagesize)
|
||||
if (size < DEFAULT_MMAP_SIZE || (size % DEFAULT_MMAP_SIZE != 0)) {
|
||||
size = ((size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
|
||||
}
|
||||
auto filename = m_name.c_str();
|
||||
auto ptr = strstr(filename, ASHMEM_NAME_DEF);
|
||||
if (ptr && ptr[sizeof(ASHMEM_NAME_DEF) - 1] == '/') {
|
||||
filename = ptr + sizeof(ASHMEM_NAME_DEF);
|
||||
}
|
||||
m_fd = ASharedMemory_create(filename, size);
|
||||
if (m_fd >= 0) {
|
||||
m_size = size;
|
||||
auto ret = mmap();
|
||||
if (!ret) {
|
||||
doCleanMemoryCache(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryFile::MemoryFile(int ashmemFD)
|
||||
: m_name(""), m_fd(ashmemFD), m_ptr(nullptr), m_size(0), m_fileType(MMFILE_TYPE_ASHMEM) {
|
||||
if (m_fd < 0) {
|
||||
MMKVError("fd %d invalid", m_fd);
|
||||
} else {
|
||||
m_name = ASharedMemory_getName(m_fd);
|
||||
m_size = ASharedMemory_getSize(m_fd);
|
||||
MMKVInfo("ashmem name:%s, size:%zu", m_name.c_str(), m_size);
|
||||
auto ret = mmap();
|
||||
if (!ret) {
|
||||
doCleanMemoryCache(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
# pragma mark - ashmem
|
||||
# include <dlfcn.h>
|
||||
# include <sys/ioctl.h>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
constexpr auto ASHMEM_NAME_LEN = 256;
|
||||
constexpr auto __ASHMEMIOC = 0x77;
|
||||
# define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
|
||||
# define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
|
||||
# define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
|
||||
# define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
|
||||
|
||||
int g_android_api = __ANDROID_API_L__;
|
||||
|
||||
void *loadLibrary() {
|
||||
auto name = "libandroid.so";
|
||||
static auto handle = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (handle == RTLD_DEFAULT) {
|
||||
MMKVError("unable to load library %s", name);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
typedef int (*AShmem_create_t)(const char *name, size_t size);
|
||||
|
||||
int ASharedMemory_create(const char *name, size_t size) {
|
||||
int fd = -1;
|
||||
if (g_android_api >= __ANDROID_API_O__) {
|
||||
static auto handle = loadLibrary();
|
||||
static AShmem_create_t funcPtr =
|
||||
(handle != nullptr) ? reinterpret_cast<AShmem_create_t>(dlsym(handle, "ASharedMemory_create")) : nullptr;
|
||||
if (funcPtr) {
|
||||
fd = funcPtr(name, size);
|
||||
if (fd < 0) {
|
||||
MMKVError("fail to ASharedMemory_create %s with size %zu, errno:%s", name, size, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
MMKVWarning("fail to locate ASharedMemory_create() from loading libandroid.so");
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
fd = open(ASHMEM_NAME_DEF, O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
MMKVError("fail to open ashmem:%s, %s", name, strerror(errno));
|
||||
} else {
|
||||
if (ioctl(fd, ASHMEM_SET_NAME, name) != 0) {
|
||||
MMKVError("fail to set ashmem name:%s, %s", name, strerror(errno));
|
||||
} else if (ioctl(fd, ASHMEM_SET_SIZE, size) != 0) {
|
||||
MMKVError("fail to set ashmem:%s, size %zu, %s", name, size, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
typedef size_t (*AShmem_getSize_t)(int fd);
|
||||
|
||||
size_t ASharedMemory_getSize(int fd) {
|
||||
size_t size = 0;
|
||||
if (g_android_api >= __ANDROID_API_O__) {
|
||||
static auto handle = loadLibrary();
|
||||
static AShmem_getSize_t funcPtr =
|
||||
(handle != nullptr) ? reinterpret_cast<AShmem_getSize_t>(dlsym(handle, "ASharedMemory_getSize")) : nullptr;
|
||||
if (funcPtr) {
|
||||
size = funcPtr(fd);
|
||||
if (size == 0) {
|
||||
MMKVError("fail to ASharedMemory_getSize:%d, %s", fd, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
MMKVWarning("fail to locate ASharedMemory_create() from loading libandroid.so");
|
||||
}
|
||||
}
|
||||
if (size == 0) {
|
||||
int tmp = ioctl(fd, ASHMEM_GET_SIZE, nullptr);
|
||||
if (tmp < 0) {
|
||||
MMKVError("fail to get ashmem size:%d, %s", fd, strerror(errno));
|
||||
} else {
|
||||
size = static_cast<size_t>(tmp);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
string ASharedMemory_getName(int fd) {
|
||||
// Android Q doesn't have ASharedMemory_getName()
|
||||
// I've make a request to Google, https://issuetracker.google.com/issues/130741665
|
||||
// There's nothing we can do before it's supported officially by Google
|
||||
if (g_android_api >= 29) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char name[ASHMEM_NAME_LEN] = {0};
|
||||
if (ioctl(fd, ASHMEM_GET_NAME, name) != 0) {
|
||||
MMKVError("fail to get ashmem name:%d, %s", fd, strerror(errno));
|
||||
return "";
|
||||
}
|
||||
return string(name);
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
MMKVPath_t ashmemMMKVPathWithID(const MMKVPath_t &mmapID) {
|
||||
return MMKVPath_t(ASHMEM_NAME_DEF) + MMKV_PATH_SLASH + mmapID;
|
||||
}
|
||||
|
||||
#endif // MMKV_ANDROID
|
||||
366
libs/mmkv/Core/MiniPBCoder.cpp
Normal file
366
libs/mmkv/Core/MiniPBCoder.cpp
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MiniPBCoder.h"
|
||||
#include "CodedInputData.h"
|
||||
#include "CodedInputDataCrypt.h"
|
||||
#include "CodedOutputData.h"
|
||||
#include "PBEncodeItem.hpp"
|
||||
|
||||
#ifdef MMKV_APPLE
|
||||
# if __has_feature(objc_arc)
|
||||
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
||||
# endif
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
MiniPBCoder::MiniPBCoder() : m_encodeItems(new std::vector<PBEncodeItem>()) {
|
||||
}
|
||||
|
||||
MiniPBCoder::MiniPBCoder(const MMBuffer *inputBuffer, AESCrypt *crypter) : MiniPBCoder() {
|
||||
m_inputBuffer = inputBuffer;
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
if (crypter) {
|
||||
m_inputDataDecrpt = new CodedInputDataCrypt(m_inputBuffer->getPtr(), m_inputBuffer->length(), *crypter);
|
||||
} else {
|
||||
m_inputData = new CodedInputData(m_inputBuffer->getPtr(), m_inputBuffer->length());
|
||||
}
|
||||
#else
|
||||
m_inputData = new CodedInputData(m_inputBuffer->getPtr(), m_inputBuffer->length());
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
}
|
||||
|
||||
MiniPBCoder::~MiniPBCoder() {
|
||||
delete m_inputData;
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
delete m_inputDataDecrpt;
|
||||
#endif
|
||||
delete m_outputBuffer;
|
||||
delete m_outputData;
|
||||
delete m_encodeItems;
|
||||
}
|
||||
|
||||
// encode
|
||||
|
||||
// write object using prepared m_encodeItems[]
|
||||
void MiniPBCoder::writeRootObject() {
|
||||
for (size_t index = 0, total = m_encodeItems->size(); index < total; index++) {
|
||||
PBEncodeItem *encodeItem = &(*m_encodeItems)[index];
|
||||
switch (encodeItem->type) {
|
||||
case PBEncodeItemType_Data: {
|
||||
m_outputData->writeData(*(encodeItem->value.bufferValue));
|
||||
break;
|
||||
}
|
||||
case PBEncodeItemType_Container: {
|
||||
m_outputData->writeUInt32(encodeItem->valueSize);
|
||||
break;
|
||||
}
|
||||
#ifndef MMKV_APPLE
|
||||
case PBEncodeItemType_String: {
|
||||
m_outputData->writeString(*(encodeItem->value.strValue));
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case PBEncodeItemType_NSString: {
|
||||
m_outputData->writeUInt32(encodeItem->valueSize);
|
||||
if (encodeItem->valueSize > 0 && encodeItem->value.tmpObjectValue != nullptr) {
|
||||
auto obj = (__bridge NSData *) encodeItem->value.tmpObjectValue;
|
||||
MMBuffer buffer(obj, MMBufferNoCopy);
|
||||
m_outputData->writeRawData(buffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBEncodeItemType_NSData: {
|
||||
m_outputData->writeUInt32(encodeItem->valueSize);
|
||||
if (encodeItem->valueSize > 0 && encodeItem->value.objectValue != nullptr) {
|
||||
auto obj = (__bridge NSData *) encodeItem->value.objectValue;
|
||||
MMBuffer buffer(obj, MMBufferNoCopy);
|
||||
m_outputData->writeRawData(buffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBEncodeItemType_NSDate: {
|
||||
NSDate *oDate = (__bridge NSDate *) encodeItem->value.objectValue;
|
||||
m_outputData->writeDouble(oDate.timeIntervalSince1970);
|
||||
break;
|
||||
}
|
||||
#endif // MMKV_APPLE
|
||||
case PBEncodeItemType_None: {
|
||||
MMKVError("%d", encodeItem->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t MiniPBCoder::prepareObjectForEncode(const MMBuffer &buffer) {
|
||||
m_encodeItems->push_back(PBEncodeItem());
|
||||
PBEncodeItem *encodeItem = &(m_encodeItems->back());
|
||||
size_t index = m_encodeItems->size() - 1;
|
||||
{
|
||||
encodeItem->type = PBEncodeItemType_Data;
|
||||
encodeItem->value.bufferValue = &buffer;
|
||||
encodeItem->valueSize = static_cast<uint32_t>(buffer.length());
|
||||
}
|
||||
encodeItem->compiledSize = pbRawVarint32Size(encodeItem->valueSize) + encodeItem->valueSize;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
size_t MiniPBCoder::prepareObjectForEncode(const MMKVVector &vec) {
|
||||
m_encodeItems->push_back(PBEncodeItem());
|
||||
PBEncodeItem *encodeItem = &(m_encodeItems->back());
|
||||
size_t index = m_encodeItems->size() - 1;
|
||||
{
|
||||
encodeItem->type = PBEncodeItemType_Container;
|
||||
encodeItem->value.bufferValue = nullptr;
|
||||
|
||||
for (const auto &itr : vec) {
|
||||
const auto &key = itr.first;
|
||||
const auto &value = itr.second;
|
||||
# ifdef MMKV_APPLE
|
||||
if (key.length <= 0) {
|
||||
# else
|
||||
if (key.length() <= 0) {
|
||||
# endif
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t keyIndex = prepareObjectForEncode(key);
|
||||
if (keyIndex < m_encodeItems->size()) {
|
||||
size_t valueIndex = prepareObjectForEncode(value);
|
||||
if (valueIndex < m_encodeItems->size()) {
|
||||
(*m_encodeItems)[index].valueSize += (*m_encodeItems)[keyIndex].compiledSize;
|
||||
(*m_encodeItems)[index].valueSize += (*m_encodeItems)[valueIndex].compiledSize;
|
||||
} else {
|
||||
m_encodeItems->pop_back(); // pop key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
encodeItem = &(*m_encodeItems)[index];
|
||||
}
|
||||
encodeItem->compiledSize = pbRawVarint32Size(encodeItem->valueSize) + encodeItem->valueSize;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
MMBuffer MiniPBCoder::writePreparedItems(size_t index) {
|
||||
PBEncodeItem *oItem = (index < m_encodeItems->size()) ? &(*m_encodeItems)[index] : nullptr;
|
||||
if (oItem && oItem->compiledSize > 0) {
|
||||
m_outputBuffer = new MMBuffer(oItem->compiledSize);
|
||||
m_outputData = new CodedOutputData(m_outputBuffer->getPtr(), m_outputBuffer->length());
|
||||
|
||||
writeRootObject();
|
||||
}
|
||||
|
||||
return std::move(*m_outputBuffer);
|
||||
}
|
||||
|
||||
MMBuffer MiniPBCoder::encodeDataWithObject(const MMBuffer &obj) {
|
||||
try {
|
||||
auto valueSize = static_cast<uint32_t>(obj.length());
|
||||
auto compiledSize = pbRawVarint32Size(valueSize) + valueSize;
|
||||
MMBuffer result(compiledSize);
|
||||
CodedOutputData output(result.getPtr(), result.length());
|
||||
output.writeData(obj);
|
||||
return result;
|
||||
} catch (const std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
return MMBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
|
||||
size_t MiniPBCoder::prepareObjectForEncode(const string &str) {
|
||||
m_encodeItems->push_back(PBEncodeItem());
|
||||
PBEncodeItem *encodeItem = &(m_encodeItems->back());
|
||||
size_t index = m_encodeItems->size() - 1;
|
||||
{
|
||||
encodeItem->type = PBEncodeItemType_String;
|
||||
encodeItem->value.strValue = &str;
|
||||
encodeItem->valueSize = static_cast<int32_t>(str.size());
|
||||
}
|
||||
encodeItem->compiledSize = pbRawVarint32Size(encodeItem->valueSize) + encodeItem->valueSize;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
size_t MiniPBCoder::prepareObjectForEncode(const vector<string> &v) {
|
||||
m_encodeItems->push_back(PBEncodeItem());
|
||||
PBEncodeItem *encodeItem = &(m_encodeItems->back());
|
||||
size_t index = m_encodeItems->size() - 1;
|
||||
{
|
||||
encodeItem->type = PBEncodeItemType_Container;
|
||||
encodeItem->value.bufferValue = nullptr;
|
||||
|
||||
for (const auto &str : v) {
|
||||
size_t itemIndex = prepareObjectForEncode(str);
|
||||
if (itemIndex < m_encodeItems->size()) {
|
||||
(*m_encodeItems)[index].valueSize += (*m_encodeItems)[itemIndex].compiledSize;
|
||||
}
|
||||
}
|
||||
|
||||
encodeItem = &(*m_encodeItems)[index];
|
||||
}
|
||||
encodeItem->compiledSize = pbRawVarint32Size(encodeItem->valueSize) + encodeItem->valueSize;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
vector<string> MiniPBCoder::decodeOneVector() {
|
||||
vector<string> v;
|
||||
|
||||
m_inputData->readInt32();
|
||||
|
||||
while (!m_inputData->isAtEnd()) {
|
||||
auto value = m_inputData->readString();
|
||||
v.push_back(move(value));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void MiniPBCoder::decodeOneMap(MMKVMap &dic, size_t position, bool greedy) {
|
||||
auto block = [position, this](MMKVMap &dictionary) {
|
||||
if (position) {
|
||||
m_inputData->seek(position);
|
||||
} else {
|
||||
m_inputData->readInt32();
|
||||
}
|
||||
while (!m_inputData->isAtEnd()) {
|
||||
KeyValueHolder kvHolder;
|
||||
const auto &key = m_inputData->readString(kvHolder);
|
||||
if (key.length() > 0) {
|
||||
m_inputData->readData(kvHolder);
|
||||
if (kvHolder.valueSize > 0) {
|
||||
dictionary[key] = move(kvHolder);
|
||||
} else {
|
||||
auto itr = dictionary.find(key);
|
||||
if (itr != dictionary.end()) {
|
||||
dictionary.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (greedy) {
|
||||
try {
|
||||
block(dic);
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
MMKVMap tmpDic;
|
||||
block(tmpDic);
|
||||
dic.swap(tmpDic);
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
void MiniPBCoder::decodeOneMap(MMKVMapCrypt &dic, size_t position, bool greedy) {
|
||||
auto block = [position, this](MMKVMapCrypt &dictionary) {
|
||||
if (position) {
|
||||
m_inputDataDecrpt->seek(position);
|
||||
} else {
|
||||
m_inputDataDecrpt->readInt32();
|
||||
}
|
||||
while (!m_inputDataDecrpt->isAtEnd()) {
|
||||
KeyValueHolderCrypt kvHolder;
|
||||
const auto &key = m_inputDataDecrpt->readString(kvHolder);
|
||||
if (key.length() > 0) {
|
||||
m_inputDataDecrpt->readData(kvHolder);
|
||||
if (kvHolder.realValueSize() > 0) {
|
||||
dictionary[key] = move(kvHolder);
|
||||
} else {
|
||||
auto itr = dictionary.find(key);
|
||||
if (itr != dictionary.end()) {
|
||||
dictionary.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (greedy) {
|
||||
try {
|
||||
block(dic);
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
MMKVMapCrypt tmpDic;
|
||||
block(tmpDic);
|
||||
dic.swap(tmpDic);
|
||||
} catch (std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
vector<string> MiniPBCoder::decodeVector(const MMBuffer &oData) {
|
||||
MiniPBCoder oCoder(&oData);
|
||||
return oCoder.decodeOneVector();
|
||||
}
|
||||
|
||||
#endif // MMKV_APPLE
|
||||
|
||||
void MiniPBCoder::decodeMap(MMKVMap &dic, const MMBuffer &oData, size_t position) {
|
||||
MiniPBCoder oCoder(&oData);
|
||||
oCoder.decodeOneMap(dic, position, false);
|
||||
}
|
||||
|
||||
void MiniPBCoder::greedyDecodeMap(MMKVMap &dic, const MMBuffer &oData, size_t position) {
|
||||
MiniPBCoder oCoder(&oData);
|
||||
oCoder.decodeOneMap(dic, position, true);
|
||||
}
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
void MiniPBCoder::decodeMap(MMKVMapCrypt &dic, const MMBuffer &oData, AESCrypt *crypter, size_t position) {
|
||||
MiniPBCoder oCoder(&oData, crypter);
|
||||
oCoder.decodeOneMap(dic, position, false);
|
||||
}
|
||||
|
||||
void MiniPBCoder::greedyDecodeMap(MMKVMapCrypt &dic, const MMBuffer &oData, AESCrypt *crypter, size_t position) {
|
||||
MiniPBCoder oCoder(&oData, crypter);
|
||||
oCoder.decodeOneMap(dic, position, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mmkv
|
||||
129
libs/mmkv/Core/MiniPBCoder.h
Normal file
129
libs/mmkv/Core/MiniPBCoder.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_MINIPBCODER_H
|
||||
#define MMKV_MINIPBCODER_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include "KeyValueHolder.h"
|
||||
#include "MMBuffer.h"
|
||||
#include "MMBuffer.h"
|
||||
#include "MMKVLog.h"
|
||||
#include "PBUtility.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
class CodedInputData;
|
||||
class CodedOutputData;
|
||||
class AESCrypt;
|
||||
class CodedInputDataCrypt;
|
||||
struct PBEncodeItem;
|
||||
|
||||
class MiniPBCoder {
|
||||
const MMBuffer *m_inputBuffer = nullptr;
|
||||
CodedInputData *m_inputData = nullptr;
|
||||
CodedInputDataCrypt *m_inputDataDecrpt = nullptr;
|
||||
|
||||
MMBuffer *m_outputBuffer = nullptr;
|
||||
CodedOutputData *m_outputData = nullptr;
|
||||
std::vector<PBEncodeItem> *m_encodeItems = nullptr;
|
||||
|
||||
MiniPBCoder();
|
||||
explicit MiniPBCoder(const MMBuffer *inputBuffer, AESCrypt *crypter = nullptr);
|
||||
~MiniPBCoder();
|
||||
|
||||
void writeRootObject();
|
||||
|
||||
size_t prepareObjectForEncode(const MMKVVector &vec);
|
||||
size_t prepareObjectForEncode(const MMBuffer &buffer);
|
||||
|
||||
template <typename T>
|
||||
MMBuffer getEncodeData(const T &obj) {
|
||||
size_t index = prepareObjectForEncode(obj);
|
||||
return writePreparedItems(index);
|
||||
}
|
||||
|
||||
MMBuffer writePreparedItems(size_t index);
|
||||
|
||||
void decodeOneMap(MMKVMap &dic, size_t position, bool greedy);
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
void decodeOneMap(MMKVMapCrypt &dic, size_t position, bool greedy);
|
||||
#endif
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
size_t prepareObjectForEncode(const std::string &str);
|
||||
size_t prepareObjectForEncode(const std::vector<std::string> &vector);
|
||||
|
||||
std::vector<std::string> decodeOneVector();
|
||||
#else
|
||||
// NSString, NSData, NSDate
|
||||
size_t prepareObjectForEncode(__unsafe_unretained NSObject *obj);
|
||||
#endif
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
static MMBuffer encodeDataWithObject(const T &obj) {
|
||||
try {
|
||||
MiniPBCoder pbcoder;
|
||||
return pbcoder.getEncodeData(obj);
|
||||
} catch (const std::exception &exception) {
|
||||
MMKVError("%s", exception.what());
|
||||
return MMBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
// opt encoding a single MMBuffer
|
||||
static MMBuffer encodeDataWithObject(const MMBuffer &obj);
|
||||
|
||||
// return empty result if there's any error
|
||||
static void decodeMap(MMKVMap &dic, const MMBuffer &oData, size_t position = 0);
|
||||
|
||||
// decode as much data as possible before any error happens
|
||||
static void greedyDecodeMap(MMKVMap &dic, const MMBuffer &oData, size_t position = 0);
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
// return empty result if there's any error
|
||||
static void decodeMap(MMKVMapCrypt &dic, const MMBuffer &oData, AESCrypt *crypter, size_t position = 0);
|
||||
|
||||
// decode as much data as possible before any error happens
|
||||
static void greedyDecodeMap(MMKVMapCrypt &dic, const MMBuffer &oData, AESCrypt *crypter, size_t position = 0);
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
static std::vector<std::string> decodeVector(const MMBuffer &oData);
|
||||
#else
|
||||
// NSString, NSData, NSDate
|
||||
static NSObject *decodeObject(const MMBuffer &oData, Class cls);
|
||||
|
||||
static bool isCompatibleClass(Class cls);
|
||||
#endif
|
||||
|
||||
// just forbid it for possibly misuse
|
||||
explicit MiniPBCoder(const MiniPBCoder &other) = delete;
|
||||
MiniPBCoder &operator=(const MiniPBCoder &other) = delete;
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_MINIPBCODER_H
|
||||
86
libs/mmkv/Core/PBEncodeItem.hpp
Normal file
86
libs/mmkv/Core/PBEncodeItem.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_PBENCODEITEM_HPP
|
||||
#define MMKV_PBENCODEITEM_HPP
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include "MMBuffer.h"
|
||||
#include <cstdint>
|
||||
#include <memory.h>
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
enum PBEncodeItemType {
|
||||
PBEncodeItemType_None,
|
||||
PBEncodeItemType_Data,
|
||||
PBEncodeItemType_Container,
|
||||
#ifndef MMKV_APPLE
|
||||
PBEncodeItemType_String,
|
||||
#else
|
||||
PBEncodeItemType_NSString,
|
||||
PBEncodeItemType_NSData,
|
||||
PBEncodeItemType_NSDate,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct PBEncodeItem {
|
||||
PBEncodeItemType type;
|
||||
uint32_t compiledSize;
|
||||
uint32_t valueSize;
|
||||
union {
|
||||
const MMBuffer *bufferValue;
|
||||
#ifndef MMKV_APPLE
|
||||
const std::string *strValue;
|
||||
#else
|
||||
void *objectValue;
|
||||
void *tmpObjectValue; // this object should be released on dealloc
|
||||
#endif
|
||||
} value;
|
||||
|
||||
PBEncodeItem() : type(PBEncodeItemType_None), compiledSize(0), valueSize(0) { memset(&value, 0, sizeof(value)); }
|
||||
|
||||
#ifndef MMKV_APPLE
|
||||
// opt std::vector.push_back() on slow_path
|
||||
PBEncodeItem(PBEncodeItem &&other) = default;
|
||||
#else
|
||||
// opt std::vector.push_back() on slow_path
|
||||
PBEncodeItem(PBEncodeItem &&other)
|
||||
: type(other.type), compiledSize(other.compiledSize), valueSize(other.valueSize), value(other.value) {
|
||||
// omit unnecessary CFRetain() & CFRelease()
|
||||
other.type = PBEncodeItemType_None;
|
||||
}
|
||||
|
||||
~PBEncodeItem() {
|
||||
if (type == PBEncodeItemType_NSString) {
|
||||
if (value.tmpObjectValue) {
|
||||
CFRelease(value.tmpObjectValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // MMKV_APPLE
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_PBENCODEITEM_HPP
|
||||
61
libs/mmkv/Core/PBUtility.cpp
Normal file
61
libs/mmkv/Core/PBUtility.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "PBUtility.h"
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
uint32_t pbRawVarint32Size(uint32_t value) {
|
||||
if ((value & (0xffffffff << 7)) == 0) {
|
||||
return 1;
|
||||
} else if ((value & (0xffffffff << 14)) == 0) {
|
||||
return 2;
|
||||
} else if ((value & (0xffffffff << 21)) == 0) {
|
||||
return 3;
|
||||
} else if ((value & (0xffffffff << 28)) == 0) {
|
||||
return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
uint32_t pbUInt64Size(uint64_t value) {
|
||||
if ((value & (0xffffffffffffffffL << 7)) == 0) {
|
||||
return 1;
|
||||
} else if ((value & (0xffffffffffffffffL << 14)) == 0) {
|
||||
return 2;
|
||||
} else if ((value & (0xffffffffffffffffL << 21)) == 0) {
|
||||
return 3;
|
||||
} else if ((value & (0xffffffffffffffffL << 28)) == 0) {
|
||||
return 4;
|
||||
} else if ((value & (0xffffffffffffffffL << 35)) == 0) {
|
||||
return 5;
|
||||
} else if ((value & (0xffffffffffffffffL << 42)) == 0) {
|
||||
return 6;
|
||||
} else if ((value & (0xffffffffffffffffL << 49)) == 0) {
|
||||
return 7;
|
||||
} else if ((value & (0xffffffffffffffffL << 56)) == 0) {
|
||||
return 8;
|
||||
} else if ((value & (0xffffffffffffffffL << 63)) == 0) {
|
||||
return 9;
|
||||
}
|
||||
return 10;
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
153
libs/mmkv/Core/PBUtility.h
Executable file
153
libs/mmkv/Core/PBUtility.h
Executable file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_PBUTILITY_H
|
||||
#define MMKV_PBUTILITY_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
# ifndef likely
|
||||
# define unlikely(x) (__builtin_expect(bool(x), 0))
|
||||
# define likely(x) (__builtin_expect(bool(x), 1))
|
||||
# endif
|
||||
#else
|
||||
# ifndef likely
|
||||
# define unlikely(x) (x)
|
||||
# define likely(x) (x)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
template <typename T, typename P>
|
||||
union Converter {
|
||||
static_assert(sizeof(T) == sizeof(P), "size not match");
|
||||
T first;
|
||||
P second;
|
||||
};
|
||||
|
||||
static inline int64_t Float64ToInt64(double v) {
|
||||
Converter<double, int64_t> converter;
|
||||
converter.first = v;
|
||||
return converter.second;
|
||||
}
|
||||
|
||||
static inline int32_t Float32ToInt32(float v) {
|
||||
Converter<float, int32_t> converter;
|
||||
converter.first = v;
|
||||
return converter.second;
|
||||
}
|
||||
|
||||
static inline double Int64ToFloat64(int64_t v) {
|
||||
Converter<double, int64_t> converter;
|
||||
converter.second = v;
|
||||
return converter.first;
|
||||
}
|
||||
|
||||
static inline float Int32ToFloat32(int32_t v) {
|
||||
Converter<float, int32_t> converter;
|
||||
converter.second = v;
|
||||
return converter.first;
|
||||
}
|
||||
|
||||
static inline uint64_t Int64ToUInt64(int64_t v) {
|
||||
Converter<int64_t, uint64_t> converter;
|
||||
converter.first = v;
|
||||
return converter.second;
|
||||
}
|
||||
|
||||
static inline int64_t UInt64ToInt64(uint64_t v) {
|
||||
Converter<int64_t, uint64_t> converter;
|
||||
converter.second = v;
|
||||
return converter.first;
|
||||
}
|
||||
|
||||
static inline uint32_t Int32ToUInt32(int32_t v) {
|
||||
Converter<int32_t, uint32_t> converter;
|
||||
converter.first = v;
|
||||
return converter.second;
|
||||
}
|
||||
|
||||
static inline int32_t UInt32ToInt32(uint32_t v) {
|
||||
Converter<int32_t, uint32_t> converter;
|
||||
converter.second = v;
|
||||
return converter.first;
|
||||
}
|
||||
|
||||
static inline int32_t logicalRightShift32(int32_t value, uint32_t spaces) {
|
||||
return UInt32ToInt32((Int32ToUInt32(value) >> spaces));
|
||||
}
|
||||
|
||||
static inline int64_t logicalRightShift64(int64_t value, uint32_t spaces) {
|
||||
return UInt64ToInt64((Int64ToUInt64(value) >> spaces));
|
||||
}
|
||||
|
||||
constexpr uint32_t LittleEdian32Size = 4;
|
||||
|
||||
constexpr uint32_t pbFloatSize() {
|
||||
return LittleEdian32Size;
|
||||
}
|
||||
|
||||
constexpr uint32_t pbFixed32Size() {
|
||||
return LittleEdian32Size;
|
||||
}
|
||||
|
||||
constexpr uint32_t LittleEdian64Size = 8;
|
||||
|
||||
constexpr uint32_t pbDoubleSize() {
|
||||
return LittleEdian64Size;
|
||||
}
|
||||
|
||||
constexpr uint32_t pbBoolSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern uint32_t pbRawVarint32Size(uint32_t value);
|
||||
|
||||
static inline uint32_t pbRawVarint32Size(int32_t value) {
|
||||
return pbRawVarint32Size(Int32ToUInt32(value));
|
||||
}
|
||||
|
||||
extern uint32_t pbUInt64Size(uint64_t value);
|
||||
|
||||
static inline uint32_t pbInt64Size(int64_t value) {
|
||||
return pbUInt64Size(Int64ToUInt64(value));
|
||||
}
|
||||
|
||||
static inline uint32_t pbInt32Size(int32_t value) {
|
||||
if (value >= 0) {
|
||||
return pbRawVarint32Size(value);
|
||||
} else {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t pbUInt32Size(uint32_t value) {
|
||||
return pbRawVarint32Size(value);
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_PBUTILITY_H
|
||||
69
libs/mmkv/Core/ScopedLock.hpp
Normal file
69
libs/mmkv/Core/ScopedLock.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_SCOPEDLOCK_HPP
|
||||
#define MMKV_SCOPEDLOCK_HPP
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
template <typename T>
|
||||
class ScopedLock {
|
||||
T *m_lock;
|
||||
|
||||
void lock() {
|
||||
if (m_lock) {
|
||||
m_lock->lock();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
if (m_lock) {
|
||||
m_lock->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ScopedLock(T *oLock) : m_lock(oLock) {
|
||||
MMKV_ASSERT(m_lock);
|
||||
lock();
|
||||
}
|
||||
|
||||
~ScopedLock() {
|
||||
unlock();
|
||||
m_lock = nullptr;
|
||||
}
|
||||
|
||||
// just forbid it for possibly misuse
|
||||
explicit ScopedLock(const ScopedLock<T> &other) = delete;
|
||||
ScopedLock &operator=(const ScopedLock<T> &other) = delete;
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#define SCOPED_LOCK(lock) _SCOPEDLOCK(lock, __COUNTER__)
|
||||
#define _SCOPEDLOCK(lock, counter) __SCOPEDLOCK(lock, counter)
|
||||
#define __SCOPEDLOCK(lock, counter) \
|
||||
mmkv::ScopedLock<std::remove_pointer<decltype(lock)>::type> __scopedLock##counter(lock)
|
||||
|
||||
#endif
|
||||
#endif //MMKV_SCOPEDLOCK_HPP
|
||||
68
libs/mmkv/Core/ThreadLock.cpp
Normal file
68
libs/mmkv/Core/ThreadLock.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ThreadLock.h"
|
||||
#include "MMKVLog.h"
|
||||
|
||||
#if MMKV_USING_PTHREAD
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
ThreadLock::ThreadLock() {
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
pthread_mutex_init(&m_lock, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
ThreadLock::~ThreadLock() {
|
||||
pthread_mutex_destroy(&m_lock);
|
||||
}
|
||||
|
||||
void ThreadLock::initialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
void ThreadLock::lock() {
|
||||
auto ret = pthread_mutex_lock(&m_lock);
|
||||
if (ret != 0) {
|
||||
MMKVError("fail to lock %p, ret=%d, errno=%s", &m_lock, ret, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadLock::unlock() {
|
||||
auto ret = pthread_mutex_unlock(&m_lock);
|
||||
if (ret != 0) {
|
||||
MMKVError("fail to unlock %p, ret=%d, errno=%s", &m_lock, ret, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadLock::ThreadOnce(ThreadOnceToken_t *onceToken, void (*callback)()) {
|
||||
pthread_once(onceToken, callback);
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // MMKV_USING_PTHREAD
|
||||
78
libs/mmkv/Core/ThreadLock.h
Normal file
78
libs/mmkv/Core/ThreadLock.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MMKV_THREADLOCK_H
|
||||
#define MMKV_THREADLOCK_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
|
||||
#ifndef MMKV_WIN32
|
||||
# include <pthread.h>
|
||||
# define MMKV_USING_PTHREAD 1
|
||||
#endif
|
||||
|
||||
#if MMKV_USING_PTHREAD
|
||||
#else
|
||||
# include <atomic>
|
||||
#endif
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
#if MMKV_USING_PTHREAD
|
||||
# define ThreadOnceToken_t pthread_once_t
|
||||
# define ThreadOnceUninitialized PTHREAD_ONCE_INIT
|
||||
#else
|
||||
enum ThreadOnceTokenEnum : int32_t { ThreadOnceUninitialized = 0, ThreadOnceInitializing, ThreadOnceInitialized };
|
||||
using ThreadOnceToken_t = std::atomic<ThreadOnceTokenEnum>;
|
||||
#endif
|
||||
|
||||
class ThreadLock {
|
||||
private:
|
||||
#if MMKV_USING_PTHREAD
|
||||
pthread_mutex_t m_lock;
|
||||
#else
|
||||
CRITICAL_SECTION m_lock;
|
||||
#endif
|
||||
|
||||
public:
|
||||
ThreadLock();
|
||||
~ThreadLock();
|
||||
|
||||
void initialize();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
static void ThreadOnce(ThreadOnceToken_t *onceToken, void (*callback)(void));
|
||||
|
||||
#ifdef MMKV_WIN32
|
||||
static void Sleep(int ms);
|
||||
#endif
|
||||
|
||||
// just forbid it for possibly misuse
|
||||
explicit ThreadLock(const ThreadLock &other) = delete;
|
||||
ThreadLock &operator=(const ThreadLock &other) = delete;
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif
|
||||
#endif //MMKV_THREADLOCK_H
|
||||
256
libs/mmkv/Core/aes/AESCrypt.cpp
Normal file
256
libs/mmkv/Core/aes/AESCrypt.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "AESCrypt.h"
|
||||
#include "openssl/openssl_aes.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
using namespace openssl;
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
AESCrypt::AESCrypt(const void *key, size_t keyLength, const void *iv, size_t ivLength) {
|
||||
if (key && keyLength > 0) {
|
||||
memcpy(m_key, key, (keyLength > AES_KEY_LEN) ? AES_KEY_LEN : keyLength);
|
||||
|
||||
resetIV(iv, ivLength);
|
||||
|
||||
m_aesKey = new AES_KEY;
|
||||
memset(m_aesKey, 0, sizeof(AES_KEY));
|
||||
int ret = AES_set_encrypt_key(m_key, AES_KEY_BITSET_LEN, m_aesKey);
|
||||
MMKV_ASSERT(ret == 0);
|
||||
}
|
||||
}
|
||||
|
||||
AESCrypt::AESCrypt(const AESCrypt &other, const AESCryptStatus &status) : m_isClone(true), m_number(status.m_number) {
|
||||
//memcpy(m_key, other.m_key, sizeof(m_key));
|
||||
memcpy(m_vector, status.m_vector, sizeof(m_vector));
|
||||
m_aesKey = other.m_aesKey;
|
||||
}
|
||||
|
||||
AESCrypt::~AESCrypt() {
|
||||
if (!m_isClone) {
|
||||
delete m_aesKey;
|
||||
delete m_aesRollbackKey;
|
||||
}
|
||||
}
|
||||
|
||||
void AESCrypt::resetIV(const void *iv, size_t ivLength) {
|
||||
m_number = 0;
|
||||
if (iv && ivLength > 0) {
|
||||
memcpy(m_vector, iv, (ivLength > AES_KEY_LEN) ? AES_KEY_LEN : ivLength);
|
||||
} else {
|
||||
memcpy(m_vector, m_key, AES_KEY_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
void AESCrypt::resetStatus(const AESCryptStatus &status) {
|
||||
m_number = status.m_number;
|
||||
memcpy(m_vector, status.m_vector, AES_KEY_LEN);
|
||||
}
|
||||
|
||||
void AESCrypt::getKey(void *output) const {
|
||||
if (output) {
|
||||
memcpy(output, m_key, AES_KEY_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
void AESCrypt::encrypt(const void *input, void *output, size_t length) {
|
||||
if (!input || !output || length == 0) {
|
||||
return;
|
||||
}
|
||||
AES_cfb128_encrypt((const uint8_t *) input, (uint8_t *) output, length, m_aesKey, m_vector, &m_number);
|
||||
}
|
||||
|
||||
void AESCrypt::decrypt(const void *input, void *output, size_t length) {
|
||||
if (!input || !output || length == 0) {
|
||||
return;
|
||||
}
|
||||
AES_cfb128_decrypt((const uint8_t *) input, (uint8_t *) output, length, m_aesKey, m_vector, &m_number);
|
||||
}
|
||||
|
||||
void AESCrypt::fillRandomIV(void *vector) {
|
||||
if (!vector) {
|
||||
return;
|
||||
}
|
||||
srand((unsigned) time(nullptr));
|
||||
int *ptr = (int *) vector;
|
||||
for (uint32_t i = 0; i < AES_KEY_LEN / sizeof(int); i++) {
|
||||
ptr[i] = rand();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
Rollback_cfb_decrypt(const uint8_t *input, const uint8_t *output, size_t len, AES_KEY *key, AESCryptStatus &status) {
|
||||
auto ivec = status.m_vector;
|
||||
auto n = status.m_number;
|
||||
|
||||
while (n && len) {
|
||||
auto c = *(--output);
|
||||
ivec[--n] = *(--input) ^ c;
|
||||
len--;
|
||||
}
|
||||
if (n == 0 && (status.m_number != 0)) {
|
||||
AES_decrypt(ivec, ivec, key);
|
||||
}
|
||||
while (len >= 16) {
|
||||
len -= 16;
|
||||
output -= 16;
|
||||
input -= 16;
|
||||
for (; n < 16; n += sizeof(size_t)) {
|
||||
size_t t = *(size_t *) (output + n);
|
||||
*(size_t *) (ivec + n) = *(size_t *) (input + n) ^ t;
|
||||
}
|
||||
n = 0;
|
||||
AES_decrypt(ivec, ivec, key);
|
||||
}
|
||||
if (len) {
|
||||
n = 16;
|
||||
do {
|
||||
auto c = *(--output);
|
||||
ivec[--n] = *(--input) ^ c;
|
||||
len--;
|
||||
} while (len);
|
||||
}
|
||||
|
||||
status.m_number = n;
|
||||
}
|
||||
|
||||
void AESCrypt::statusBeforeDecrypt(const void *input, const void *output, size_t length, AESCryptStatus &status) {
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
if (!m_aesRollbackKey) {
|
||||
m_aesRollbackKey = new AES_KEY;
|
||||
memset(m_aesRollbackKey, 0, sizeof(AES_KEY));
|
||||
int ret = AES_set_decrypt_key(m_key, AES_KEY_BITSET_LEN, m_aesRollbackKey);
|
||||
MMKV_ASSERT(ret == 0);
|
||||
}
|
||||
getCurStatus(status);
|
||||
Rollback_cfb_decrypt((const uint8_t *) input, (const uint8_t *) output, length, m_aesRollbackKey, status);
|
||||
}
|
||||
|
||||
void AESCrypt::getCurStatus(AESCryptStatus &status) {
|
||||
status.m_number = static_cast<uint8_t>(m_number);
|
||||
memcpy(status.m_vector, m_vector, sizeof(m_vector));
|
||||
}
|
||||
|
||||
AESCrypt AESCrypt::cloneWithStatus(const AESCryptStatus &status) const {
|
||||
return AESCrypt(*this, status);
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
# ifdef MMKV_DEBUG
|
||||
|
||||
# include "../MMKVLog.h"
|
||||
# include "../MemoryFile.h"
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
// check if AESCrypt is encrypt-decrypt full-duplex
|
||||
void AESCrypt::testAESCrypt() {
|
||||
const uint8_t plainText[] = "Hello, OpenSSL-mmkv::AESCrypt::testAESCrypt() with AES CFB 128.";
|
||||
constexpr size_t textLength = sizeof(plainText) - 1;
|
||||
|
||||
const uint8_t key[] = "TheAESKey";
|
||||
constexpr size_t keyLength = sizeof(key) - 1;
|
||||
|
||||
uint8_t iv[AES_KEY_LEN];
|
||||
srand((unsigned) time(nullptr));
|
||||
for (uint32_t i = 0; i < AES_KEY_LEN; i++) {
|
||||
iv[i] = (uint8_t) rand();
|
||||
}
|
||||
AESCrypt crypt1(key, keyLength, iv, sizeof(iv));
|
||||
AESCrypt crypt2(key, keyLength, iv, sizeof(iv));
|
||||
|
||||
auto encryptText = new uint8_t[DEFAULT_MMAP_SIZE];
|
||||
auto decryptText = new uint8_t[DEFAULT_MMAP_SIZE];
|
||||
memset(encryptText, 0, DEFAULT_MMAP_SIZE);
|
||||
memset(decryptText, 0, DEFAULT_MMAP_SIZE);
|
||||
|
||||
/* in-place encryption & decryption
|
||||
memcpy(encryptText, plainText, textLength);
|
||||
crypt1.encrypt(encryptText, encryptText, textLength);
|
||||
crypt2.decrypt(encryptText, encryptText, textLength);
|
||||
return;
|
||||
*/
|
||||
AES_KEY decryptKey;
|
||||
AES_set_decrypt_key(crypt1.m_key, AES_KEY_BITSET_LEN, &decryptKey);
|
||||
|
||||
size_t actualSize = 0;
|
||||
bool flip = false;
|
||||
for (const uint8_t *ptr = plainText; ptr < plainText + textLength;) {
|
||||
auto tokenPtr = (const uint8_t *) strchr((const char *) ptr, ' ');
|
||||
size_t size = 0;
|
||||
if (!tokenPtr) {
|
||||
size = static_cast<size_t>(plainText + textLength - ptr);
|
||||
} else {
|
||||
size = static_cast<size_t>(tokenPtr - ptr + 1);
|
||||
}
|
||||
|
||||
AESCrypt *decrypter;
|
||||
uint32_t oldNum;
|
||||
uint8_t oldVector[sizeof(crypt1.m_vector)];
|
||||
|
||||
flip = !flip;
|
||||
if (flip) {
|
||||
crypt1.encrypt(plainText + actualSize, encryptText + actualSize, size);
|
||||
|
||||
decrypter = &crypt2;
|
||||
oldNum = decrypter->m_number;
|
||||
memcpy(oldVector, decrypter->m_vector, sizeof(oldVector));
|
||||
crypt2.decrypt(encryptText + actualSize, decryptText + actualSize, size);
|
||||
} else {
|
||||
crypt2.encrypt(plainText + actualSize, encryptText + actualSize, size);
|
||||
|
||||
decrypter = &crypt1;
|
||||
oldNum = decrypter->m_number;
|
||||
memcpy(oldVector, decrypter->m_vector, sizeof(oldVector));
|
||||
crypt1.decrypt(encryptText + actualSize, decryptText + actualSize, size);
|
||||
}
|
||||
// that's why AESCrypt can be full-duplex
|
||||
assert(crypt1.m_number == crypt2.m_number);
|
||||
assert(0 == memcmp(crypt1.m_vector, crypt2.m_vector, sizeof(crypt1.m_vector)));
|
||||
|
||||
// how rollback works
|
||||
AESCryptStatus status;
|
||||
decrypter->statusBeforeDecrypt(encryptText + actualSize + size, decryptText + actualSize + size, size, status);
|
||||
assert(oldNum == status.m_number);
|
||||
assert(0 == memcmp(oldVector, status.m_vector, sizeof(oldVector)));
|
||||
|
||||
actualSize += size;
|
||||
ptr += size;
|
||||
}
|
||||
MMKVInfo("AES CFB decode: %s", decryptText);
|
||||
|
||||
delete[] encryptText;
|
||||
delete[] decryptText;
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
# endif // MMKV_DEBUG
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
107
libs/mmkv/Core/aes/AESCrypt.h
Normal file
107
libs/mmkv/Core/aes/AESCrypt.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef AES_CRYPT_H_
|
||||
#define AES_CRYPT_H_
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "MMKVPredef.h"
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef MMKV_DISABLE_CRYPT
|
||||
|
||||
namespace mmkv {
|
||||
class AESCrypt;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace openssl {
|
||||
struct AES_KEY;
|
||||
}
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct AESCryptStatus {
|
||||
uint8_t m_number;
|
||||
uint8_t m_vector[AES_KEY_LEN];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
class CodedInputDataCrypt;
|
||||
|
||||
// a AES CFB-128 encrypt-decrypt full-duplex wrapper
|
||||
class AESCrypt {
|
||||
bool m_isClone = false;
|
||||
uint32_t m_number = 0;
|
||||
openssl::AES_KEY *m_aesKey = nullptr;
|
||||
openssl::AES_KEY *m_aesRollbackKey = nullptr;
|
||||
uint8_t m_key[AES_KEY_LEN] = {};
|
||||
|
||||
public:
|
||||
uint8_t m_vector[AES_KEY_LEN] = {};
|
||||
|
||||
private:
|
||||
// for cloneWithStatus()
|
||||
AESCrypt(const AESCrypt &other, const AESCryptStatus &status);
|
||||
|
||||
public:
|
||||
AESCrypt(const void *key, size_t keyLength, const void *iv = nullptr, size_t ivLength = 0);
|
||||
AESCrypt(AESCrypt &&other) = default;
|
||||
|
||||
~AESCrypt();
|
||||
|
||||
void encrypt(const void *input, void *output, size_t length);
|
||||
|
||||
void decrypt(const void *input, void *output, size_t length);
|
||||
|
||||
void getCurStatus(AESCryptStatus &status);
|
||||
void statusBeforeDecrypt(const void *input, const void *output, size_t length, AESCryptStatus &status);
|
||||
|
||||
AESCrypt cloneWithStatus(const AESCryptStatus &status) const;
|
||||
|
||||
void resetIV(const void *iv = nullptr, size_t ivLength = 0);
|
||||
void resetStatus(const AESCryptStatus &status);
|
||||
|
||||
// output must have [AES_KEY_LEN] space
|
||||
void getKey(void *output) const;
|
||||
|
||||
static void fillRandomIV(void *vector);
|
||||
|
||||
// just forbid it for possibly misuse
|
||||
explicit AESCrypt(const AESCrypt &other) = delete;
|
||||
AESCrypt &operator=(const AESCrypt &other) = delete;
|
||||
|
||||
friend CodedInputDataCrypt;
|
||||
|
||||
#ifdef MMKV_DEBUG
|
||||
// check if AESCrypt is encrypt-decrypt full-duplex
|
||||
static void testAESCrypt();
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
#endif // __cplusplus
|
||||
#endif /* AES_CRYPT_H_ */
|
||||
1231
libs/mmkv/Core/aes/openssl/openssl_aes-armv4.S
Normal file
1231
libs/mmkv/Core/aes/openssl/openssl_aes-armv4.S
Normal file
File diff suppressed because it is too large
Load Diff
118
libs/mmkv/Core/aes/openssl/openssl_aes.h
Normal file
118
libs/mmkv/Core/aes/openssl/openssl_aes.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef HEADER_AES_H
|
||||
# define HEADER_AES_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "openssl_opensslconf.h"
|
||||
#include "openssl_arm_arch.h"
|
||||
#include <stddef.h>
|
||||
#include "../../MMKVPredef.h"
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
namespace openssl {
|
||||
|
||||
/*
|
||||
* Because array size can't be a const in C, the following two are macros.
|
||||
* Both sizes are in bytes.
|
||||
*/
|
||||
# define AES_MAXNR 14
|
||||
# define AES_BLOCK_SIZE 16
|
||||
|
||||
/* This should be a hidden type, but EVP requires that the size be known */
|
||||
struct AES_KEY {
|
||||
# ifdef AES_LONG
|
||||
unsigned long rd_key[4 * (AES_MAXNR + 1)];
|
||||
# else
|
||||
unsigned int rd_key[4 * (AES_MAXNR + 1)];
|
||||
# endif
|
||||
int rounds;
|
||||
};
|
||||
|
||||
void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, uint32_t *num);
|
||||
void AES_cfb128_decrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, uint32_t *num);
|
||||
|
||||
} // namespace openssl
|
||||
|
||||
#if __ARM_MAX_ARCH__ > 0
|
||||
|
||||
#ifndef __linux__
|
||||
|
||||
extern "C" int openssl_aes_arm_set_encrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
extern "C" int openssl_aes_arm_set_decrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
extern "C" void openssl_aes_arm_encrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
extern "C" void openssl_aes_arm_decrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
|
||||
#define AES_set_encrypt_key(userKey, bits, key) openssl_aes_arm_set_encrypt_key(userKey, bits, key)
|
||||
#define AES_set_decrypt_key(userKey, bits, key) openssl_aes_arm_set_decrypt_key(userKey, bits, key)
|
||||
#define AES_encrypt(in, out, key) openssl_aes_arm_encrypt(in, out, key)
|
||||
#define AES_decrypt(in, out, key) openssl_aes_arm_decrypt(in, out, key)
|
||||
|
||||
#else // __linux__
|
||||
|
||||
#if __ARM_MAX_ARCH__ <= 7
|
||||
|
||||
extern "C" int openssl_aes_arm_set_encrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
extern "C" int openssl_aes_arm_set_decrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
extern "C" void openssl_aes_arm_encrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
extern "C" void openssl_aes_arm_decrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
|
||||
#define AES_set_encrypt_key(userKey, bits, key) openssl_aes_arm_set_encrypt_key(userKey, bits, key)
|
||||
#define AES_set_decrypt_key(userKey, bits, key) openssl_aes_arm_set_decrypt_key(userKey, bits, key)
|
||||
#define AES_encrypt(in, out, key) openssl_aes_arm_encrypt(in, out, key)
|
||||
#define AES_decrypt(in, out, key) openssl_aes_arm_decrypt(in, out, key)
|
||||
|
||||
#else // __ARM_MAX_ARCH__ > 7
|
||||
|
||||
extern "C" int openssl_aes_armv8_set_encrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
extern "C" int openssl_aes_armv8_set_decrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
extern "C" void openssl_aes_armv8_encrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
extern "C" void openssl_aes_armv8_decrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
|
||||
typedef int (*aes_set_encrypt_t)(const uint8_t *userKey, const int bits, void *key);
|
||||
typedef int (*aes_set_decrypt_t)(const uint8_t *userKey, const int bits, void *key);
|
||||
typedef void (*aes_encrypt_t)(const uint8_t *in, uint8_t *out, const void *key);
|
||||
typedef void (*aes_decrypt_t)(const uint8_t *in, uint8_t *out, const void *key);
|
||||
|
||||
namespace openssl {
|
||||
|
||||
int AES_C_set_encrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
int AES_C_set_decrypt_key(const uint8_t *userKey, const int bits, void *key);
|
||||
void AES_C_encrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
void AES_C_decrypt(const uint8_t *in, uint8_t *out, const void *key);
|
||||
|
||||
} // namespace openssl
|
||||
|
||||
extern aes_set_encrypt_t AES_set_encrypt_key;
|
||||
extern aes_set_decrypt_t AES_set_decrypt_key;
|
||||
extern aes_encrypt_t AES_encrypt;
|
||||
extern aes_decrypt_t AES_decrypt;
|
||||
|
||||
#endif // __ARM_MAX_ARCH__ <= 7
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
#else // __ARM_MAX_ARCH__ <= 0
|
||||
|
||||
namespace openssl {
|
||||
|
||||
int AES_set_encrypt_key(const uint8_t *userKey, const int bits, AES_KEY *key);
|
||||
int AES_set_decrypt_key(const uint8_t *userKey, const int bits, AES_KEY *key);
|
||||
void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
|
||||
void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
|
||||
|
||||
} // namespace openssl
|
||||
|
||||
#endif // __ARM_MAX_ARCH__ > 0
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
#endif // __cplusplus
|
||||
#endif // HEADER_AES_H
|
||||
1044
libs/mmkv/Core/aes/openssl/openssl_aes_core.cpp
Executable file
1044
libs/mmkv/Core/aes/openssl/openssl_aes_core.cpp
Executable file
File diff suppressed because it is too large
Load Diff
38
libs/mmkv/Core/aes/openssl/openssl_aes_locl.h
Normal file
38
libs/mmkv/Core/aes/openssl/openssl_aes_locl.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef HEADER_AES_LOCL_H
|
||||
# define HEADER_AES_LOCL_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
# include "openssl_opensslconf.h"
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <stdint.h>
|
||||
|
||||
# if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
|
||||
# define GETU32(p) SWAP(*((u32 *)(p)))
|
||||
# define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
|
||||
# else
|
||||
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
|
||||
# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
|
||||
# endif
|
||||
|
||||
# ifdef AES_LONG
|
||||
typedef unsigned long u32;
|
||||
# else
|
||||
typedef unsigned int u32;
|
||||
# endif
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
|
||||
#endif
|
||||
#endif /* !HEADER_AES_LOCL_H */
|
||||
308
libs/mmkv/Core/aes/openssl/openssl_aesv8-armx.S
Normal file
308
libs/mmkv/Core/aes/openssl/openssl_aesv8-armx.S
Normal file
@@ -0,0 +1,308 @@
|
||||
#include "openssl_arm_arch.h"
|
||||
#include "../../MMKVPredef.h"
|
||||
|
||||
#if (__ARM_MAX_ARCH__ > 7) && !defined(MMKV_DISABLE_CRYPT)
|
||||
|
||||
.text
|
||||
|
||||
.align 5
|
||||
Lrcon:
|
||||
.long 0x01,0x01,0x01,0x01
|
||||
.long 0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d // rotate-n-splat
|
||||
.long 0x1b,0x1b,0x1b,0x1b
|
||||
|
||||
#ifndef __linux__
|
||||
.globl _openssl_aes_arm_set_encrypt_key
|
||||
|
||||
.align 5
|
||||
_openssl_aes_arm_set_encrypt_key:
|
||||
#else // __linux__
|
||||
.globl openssl_aes_armv8_set_encrypt_key
|
||||
|
||||
.align 5
|
||||
openssl_aes_armv8_set_encrypt_key:
|
||||
#endif // __linux__
|
||||
|
||||
Lenc_key:
|
||||
stp x29,x30,[sp,#-16]!
|
||||
add x29,sp,#0
|
||||
mov x3,#-1
|
||||
cmp x0,#0
|
||||
b.eq Lenc_key_abort
|
||||
cmp x2,#0
|
||||
b.eq Lenc_key_abort
|
||||
mov x3,#-2
|
||||
cmp w1,#128
|
||||
b.lt Lenc_key_abort
|
||||
cmp w1,#256
|
||||
b.gt Lenc_key_abort
|
||||
tst w1,#0x3f
|
||||
b.ne Lenc_key_abort
|
||||
|
||||
adr x3,Lrcon
|
||||
cmp w1,#192
|
||||
|
||||
eor v0.16b,v0.16b,v0.16b
|
||||
ld1 {v3.16b},[x0],#16
|
||||
mov w1,#8 // reuse w1
|
||||
ld1 {v1.4s,v2.4s},[x3],#32
|
||||
|
||||
b.lt Loop128
|
||||
b.eq L192
|
||||
b L256
|
||||
|
||||
.align 4
|
||||
Loop128:
|
||||
tbl v6.16b,{v3.16b},v2.16b
|
||||
ext v5.16b,v0.16b,v3.16b,#12
|
||||
st1 {v3.4s},[x2],#16
|
||||
aese v6.16b,v0.16b
|
||||
subs w1,w1,#1
|
||||
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v6.16b,v6.16b,v1.16b
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
shl v1.16b,v1.16b,#1
|
||||
eor v3.16b,v3.16b,v6.16b
|
||||
b.ne Loop128
|
||||
|
||||
ld1 {v1.4s},[x3]
|
||||
|
||||
tbl v6.16b,{v3.16b},v2.16b
|
||||
ext v5.16b,v0.16b,v3.16b,#12
|
||||
st1 {v3.4s},[x2],#16
|
||||
aese v6.16b,v0.16b
|
||||
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v6.16b,v6.16b,v1.16b
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
shl v1.16b,v1.16b,#1
|
||||
eor v3.16b,v3.16b,v6.16b
|
||||
|
||||
tbl v6.16b,{v3.16b},v2.16b
|
||||
ext v5.16b,v0.16b,v3.16b,#12
|
||||
st1 {v3.4s},[x2],#16
|
||||
aese v6.16b,v0.16b
|
||||
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v6.16b,v6.16b,v1.16b
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
eor v3.16b,v3.16b,v6.16b
|
||||
st1 {v3.4s},[x2]
|
||||
add x2,x2,#0x50
|
||||
|
||||
mov w12,#10
|
||||
b Ldone
|
||||
|
||||
.align 4
|
||||
L192:
|
||||
ld1 {v4.8b},[x0],#8
|
||||
movi v6.16b,#8 // borrow v6.16b
|
||||
st1 {v3.4s},[x2],#16
|
||||
sub v2.16b,v2.16b,v6.16b // adjust the mask
|
||||
|
||||
Loop192:
|
||||
tbl v6.16b,{v4.16b},v2.16b
|
||||
ext v5.16b,v0.16b,v3.16b,#12
|
||||
st1 {v4.8b},[x2],#8
|
||||
aese v6.16b,v0.16b
|
||||
subs w1,w1,#1
|
||||
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
|
||||
dup v5.4s,v3.s[3]
|
||||
eor v5.16b,v5.16b,v4.16b
|
||||
eor v6.16b,v6.16b,v1.16b
|
||||
ext v4.16b,v0.16b,v4.16b,#12
|
||||
shl v1.16b,v1.16b,#1
|
||||
eor v4.16b,v4.16b,v5.16b
|
||||
eor v3.16b,v3.16b,v6.16b
|
||||
eor v4.16b,v4.16b,v6.16b
|
||||
st1 {v3.4s},[x2],#16
|
||||
b.ne Loop192
|
||||
|
||||
mov w12,#12
|
||||
add x2,x2,#0x20
|
||||
b Ldone
|
||||
|
||||
.align 4
|
||||
L256:
|
||||
ld1 {v4.16b},[x0]
|
||||
mov w1,#7
|
||||
mov w12,#14
|
||||
st1 {v3.4s},[x2],#16
|
||||
|
||||
Loop256:
|
||||
tbl v6.16b,{v4.16b},v2.16b
|
||||
ext v5.16b,v0.16b,v3.16b,#12
|
||||
st1 {v4.4s},[x2],#16
|
||||
aese v6.16b,v0.16b
|
||||
subs w1,w1,#1
|
||||
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v6.16b,v6.16b,v1.16b
|
||||
eor v3.16b,v3.16b,v5.16b
|
||||
shl v1.16b,v1.16b,#1
|
||||
eor v3.16b,v3.16b,v6.16b
|
||||
st1 {v3.4s},[x2],#16
|
||||
b.eq Ldone
|
||||
|
||||
dup v6.4s,v3.s[3] // just splat
|
||||
ext v5.16b,v0.16b,v4.16b,#12
|
||||
aese v6.16b,v0.16b
|
||||
|
||||
eor v4.16b,v4.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v4.16b,v4.16b,v5.16b
|
||||
ext v5.16b,v0.16b,v5.16b,#12
|
||||
eor v4.16b,v4.16b,v5.16b
|
||||
|
||||
eor v4.16b,v4.16b,v6.16b
|
||||
b Loop256
|
||||
|
||||
Ldone:
|
||||
str w12,[x2]
|
||||
mov x3,#0
|
||||
|
||||
Lenc_key_abort:
|
||||
mov x0,x3 // return value
|
||||
ldr x29,[sp],#16
|
||||
ret
|
||||
|
||||
#ifndef __linux__
|
||||
.globl _openssl_aes_arm_set_decrypt_key
|
||||
|
||||
.align 5
|
||||
_openssl_aes_arm_set_decrypt_key:
|
||||
#else // __linux__
|
||||
.globl openssl_aes_armv8_set_decrypt_key
|
||||
|
||||
.align 5
|
||||
openssl_aes_armv8_set_decrypt_key:
|
||||
#endif // __linux__
|
||||
stp x29,x30,[sp,#-16]!
|
||||
add x29,sp,#0
|
||||
bl Lenc_key
|
||||
|
||||
cmp x0,#0
|
||||
b.ne Ldec_key_abort
|
||||
|
||||
sub x2,x2,#240 // restore original x2
|
||||
mov x4,#-16
|
||||
add x0,x2,x12,lsl#4 // end of key schedule
|
||||
|
||||
ld1 {v0.4s},[x2]
|
||||
ld1 {v1.4s},[x0]
|
||||
st1 {v0.4s},[x0],x4
|
||||
st1 {v1.4s},[x2],#16
|
||||
|
||||
Loop_imc:
|
||||
ld1 {v0.4s},[x2]
|
||||
ld1 {v1.4s},[x0]
|
||||
aesimc v0.16b,v0.16b
|
||||
aesimc v1.16b,v1.16b
|
||||
st1 {v0.4s},[x0],x4
|
||||
st1 {v1.4s},[x2],#16
|
||||
cmp x0,x2
|
||||
b.hi Loop_imc
|
||||
|
||||
ld1 {v0.4s},[x2]
|
||||
aesimc v0.16b,v0.16b
|
||||
st1 {v0.4s},[x0]
|
||||
|
||||
eor x0,x0,x0 // return value
|
||||
Ldec_key_abort:
|
||||
ldp x29,x30,[sp],#16
|
||||
ret
|
||||
|
||||
#ifndef __linux__
|
||||
.globl _openssl_aes_arm_encrypt
|
||||
|
||||
.align 5
|
||||
_openssl_aes_arm_encrypt:
|
||||
#else // __linux__
|
||||
.globl openssl_aes_armv8_encrypt
|
||||
|
||||
.align 5
|
||||
openssl_aes_armv8_encrypt:
|
||||
#endif // __linux__
|
||||
|
||||
ldr w3,[x2,#240]
|
||||
ld1 {v0.4s},[x2],#16
|
||||
ld1 {v2.16b},[x0]
|
||||
sub w3,w3,#2
|
||||
ld1 {v1.4s},[x2],#16
|
||||
|
||||
Loop_enc:
|
||||
aese v2.16b,v0.16b
|
||||
aesmc v2.16b,v2.16b
|
||||
ld1 {v0.4s},[x2],#16
|
||||
subs w3,w3,#2
|
||||
aese v2.16b,v1.16b
|
||||
aesmc v2.16b,v2.16b
|
||||
ld1 {v1.4s},[x2],#16
|
||||
b.gt Loop_enc
|
||||
|
||||
aese v2.16b,v0.16b
|
||||
aesmc v2.16b,v2.16b
|
||||
ld1 {v0.4s},[x2]
|
||||
aese v2.16b,v1.16b
|
||||
eor v2.16b,v2.16b,v0.16b
|
||||
|
||||
st1 {v2.16b},[x1]
|
||||
ret
|
||||
|
||||
#ifndef __linux__
|
||||
.globl _openssl_aes_arm_decrypt
|
||||
|
||||
.align 5
|
||||
_openssl_aes_arm_decrypt:
|
||||
#else // __linux__
|
||||
.globl openssl_aes_armv8_decrypt
|
||||
|
||||
.align 5
|
||||
openssl_aes_armv8_decrypt:
|
||||
#endif // __linux__
|
||||
|
||||
ldr w3,[x2,#240]
|
||||
ld1 {v0.4s},[x2],#16
|
||||
ld1 {v2.16b},[x0]
|
||||
sub w3,w3,#2
|
||||
ld1 {v1.4s},[x2],#16
|
||||
|
||||
Loop_dec:
|
||||
aesd v2.16b,v0.16b
|
||||
aesimc v2.16b,v2.16b
|
||||
ld1 {v0.4s},[x2],#16
|
||||
subs w3,w3,#2
|
||||
aesd v2.16b,v1.16b
|
||||
aesimc v2.16b,v2.16b
|
||||
ld1 {v1.4s},[x2],#16
|
||||
b.gt Loop_dec
|
||||
|
||||
aesd v2.16b,v0.16b
|
||||
aesimc v2.16b,v2.16b
|
||||
ld1 {v0.4s},[x2]
|
||||
aesd v2.16b,v1.16b
|
||||
eor v2.16b,v2.16b,v0.16b
|
||||
|
||||
st1 {v2.16b},[x1]
|
||||
ret
|
||||
|
||||
#endif
|
||||
84
libs/mmkv/Core/aes/openssl/openssl_arm_arch.h
Normal file
84
libs/mmkv/Core/aes/openssl/openssl_arm_arch.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2011-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef __ARM_ARCH_H__
|
||||
# define __ARM_ARCH_H__
|
||||
|
||||
# if !defined(__ARM_ARCH__)
|
||||
# if defined(__CC_ARM)
|
||||
# define __ARM_ARCH__ __TARGET_ARCH_ARM
|
||||
# if defined(__BIG_ENDIAN)
|
||||
# define __ARMEB__
|
||||
# else
|
||||
# define __ARMEL__
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# if defined(__aarch64__)
|
||||
# define __ARM_ARCH__ 8
|
||||
# if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
# define __ARMEB__
|
||||
# else
|
||||
# define __ARMEL__
|
||||
# endif
|
||||
/*
|
||||
* Why doesn't gcc define __ARM_ARCH__? Instead it defines
|
||||
* bunch of below macros. See all_architectires[] table in
|
||||
* gcc/config/arm/arm.c. On a side note it defines
|
||||
* __ARMEL__/__ARMEB__ for little-/big-endian.
|
||||
*/
|
||||
# elif defined(__ARM_ARCH)
|
||||
# define __ARM_ARCH__ __ARM_ARCH
|
||||
# elif defined(__ARM_ARCH_8A__)
|
||||
# define __ARM_ARCH__ 8
|
||||
# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
|
||||
defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \
|
||||
defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7K__)
|
||||
# define __ARM_ARCH__ 7
|
||||
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||
defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \
|
||||
defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \
|
||||
defined(__ARM_ARCH_6T2__)
|
||||
# define __ARM_ARCH__ 6
|
||||
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
|
||||
defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \
|
||||
defined(__ARM_ARCH_5TEJ__)
|
||||
# define __ARM_ARCH__ 5
|
||||
# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||
# define __ARM_ARCH__ 4
|
||||
# else
|
||||
//# error "unsupported ARM architecture"
|
||||
# define __ARM_ARCH__ 0
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(__ARM_MAX_ARCH__)
|
||||
# define __ARM_MAX_ARCH__ __ARM_ARCH__
|
||||
# endif
|
||||
|
||||
# if __ARM_MAX_ARCH__<__ARM_ARCH__
|
||||
# error "__ARM_MAX_ARCH__ can't be less than __ARM_ARCH__"
|
||||
# elif __ARM_MAX_ARCH__!=__ARM_ARCH__
|
||||
# if __ARM_ARCH__<7 && __ARM_MAX_ARCH__>=7 && defined(__ARMEB__)
|
||||
# error "can't build universal big-endian binary"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __ASSEMBLER__
|
||||
extern unsigned int OPENSSL_armcap_P;
|
||||
# endif
|
||||
|
||||
# define ARMV7_NEON (1<<0)
|
||||
# define ARMV7_TICK (1<<1)
|
||||
# define ARMV8_AES (1<<2)
|
||||
# define ARMV8_SHA1 (1<<3)
|
||||
# define ARMV8_SHA256 (1<<4)
|
||||
# define ARMV8_PMULL (1<<5)
|
||||
|
||||
#endif
|
||||
97
libs/mmkv/Core/aes/openssl/openssl_cfb128.cpp
Normal file
97
libs/mmkv/Core/aes/openssl/openssl_cfb128.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "openssl_aes.h"
|
||||
#include "../../MMKVPredef.h"
|
||||
#include <cstring>
|
||||
|
||||
#ifndef MMKV_DISABLE_CRYPT
|
||||
|
||||
namespace openssl {
|
||||
|
||||
/*
|
||||
* The input and output encrypted as though 128bit cfb mode is being used.
|
||||
* The extra state information to record how much of the 128bit block we have
|
||||
* used is contained in *num;
|
||||
*/
|
||||
void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, const AES_KEY *key, uint8_t ivec[16], uint32_t *num)
|
||||
{
|
||||
auto n = *num;
|
||||
|
||||
while (n && len) {
|
||||
*(out++) = ivec[n] ^= *(in++);
|
||||
--len;
|
||||
n = (n + 1) % 16;
|
||||
}
|
||||
while (len >= 16) {
|
||||
AES_encrypt(ivec, ivec, key);
|
||||
for (; n < 16; n += sizeof(size_t)) {
|
||||
*(size_t *)(out + n) =
|
||||
*(size_t *)(ivec + n) ^= *(size_t *)(in + n);
|
||||
}
|
||||
len -= 16;
|
||||
out += 16;
|
||||
in += 16;
|
||||
n = 0;
|
||||
}
|
||||
if (len) {
|
||||
AES_encrypt(ivec, ivec, key);
|
||||
while (len--) {
|
||||
out[n] = ivec[n] ^= in[n];
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
*num = n;
|
||||
}
|
||||
|
||||
/*
|
||||
* The input and output encrypted as though 128bit cfb mode is being used.
|
||||
* The extra state information to record how much of the 128bit block we have
|
||||
* used is contained in *num;
|
||||
*/
|
||||
void AES_cfb128_decrypt(const uint8_t *in, uint8_t *out, size_t len, const AES_KEY *key, uint8_t ivec[16], uint32_t *num)
|
||||
{
|
||||
auto n = *num;
|
||||
|
||||
while (n && len) {
|
||||
uint8_t c = *(in++);
|
||||
*(out++) = ivec[n] ^ c;
|
||||
ivec[n] = c;
|
||||
--len;
|
||||
n = (n + 1) % 16;
|
||||
}
|
||||
while (len >= 16) {
|
||||
AES_encrypt(ivec, ivec, key);
|
||||
for (; n < 16; n += sizeof(size_t)) {
|
||||
size_t t = *(size_t *)(in + n);
|
||||
*(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t;
|
||||
*(size_t *)(ivec + n) = t;
|
||||
}
|
||||
len -= 16;
|
||||
out += 16;
|
||||
in += 16;
|
||||
n = 0;
|
||||
}
|
||||
if (len) {
|
||||
AES_encrypt(ivec, ivec, key);
|
||||
while (len--) {
|
||||
uint8_t c = in[n];
|
||||
out[n] = ivec[n] ^ c;
|
||||
ivec[n] = c;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
*num = n;
|
||||
}
|
||||
|
||||
} // namespace openssl
|
||||
|
||||
#endif // MMKV_DISABLE_CRYPT
|
||||
254
libs/mmkv/Core/aes/openssl/openssl_md32_common.h
Executable file
254
libs/mmkv/Core/aes/openssl/openssl_md32_common.h
Executable file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*-
|
||||
* This is a generic 32 bit "collector" for message digest algorithms.
|
||||
* Whenever needed it collects input character stream into chunks of
|
||||
* 32 bit values and invokes a block function that performs actual hash
|
||||
* calculations.
|
||||
*
|
||||
* Porting guide.
|
||||
*
|
||||
* Obligatory macros:
|
||||
*
|
||||
* DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN
|
||||
* this macro defines byte order of input stream.
|
||||
* HASH_CBLOCK
|
||||
* size of a unit chunk HASH_BLOCK operates on.
|
||||
* HASH_LONG
|
||||
* has to be at least 32 bit wide.
|
||||
* HASH_CTX
|
||||
* context structure that at least contains following
|
||||
* members:
|
||||
* typedef struct {
|
||||
* ...
|
||||
* HASH_LONG Nl,Nh;
|
||||
* either {
|
||||
* HASH_LONG data[HASH_LBLOCK];
|
||||
* unsigned char data[HASH_CBLOCK];
|
||||
* };
|
||||
* unsigned int num;
|
||||
* ...
|
||||
* } HASH_CTX;
|
||||
* data[] vector is expected to be zeroed upon first call to
|
||||
* HASH_UPDATE.
|
||||
* HASH_UPDATE
|
||||
* name of "Update" function, implemented here.
|
||||
* HASH_TRANSFORM
|
||||
* name of "Transform" function, implemented here.
|
||||
* HASH_FINAL
|
||||
* name of "Final" function, implemented here.
|
||||
* HASH_BLOCK_DATA_ORDER
|
||||
* name of "block" function capable of treating *unaligned* input
|
||||
* message in original (data) byte order, implemented externally.
|
||||
* HASH_MAKE_STRING
|
||||
* macro converting context variables to an ASCII hash string.
|
||||
*
|
||||
* MD5 example:
|
||||
*
|
||||
* #define DATA_ORDER_IS_LITTLE_ENDIAN
|
||||
*
|
||||
* #define HASH_LONG MD5_LONG
|
||||
* #define HASH_CTX MD5_CTX
|
||||
* #define HASH_CBLOCK MD5_CBLOCK
|
||||
* #define HASH_UPDATE MD5_Update
|
||||
* #define HASH_TRANSFORM MD5_Transform
|
||||
* #define HASH_FINAL MD5_Final
|
||||
* #define HASH_BLOCK_DATA_ORDER md5_block_data_order
|
||||
*/
|
||||
|
||||
|
||||
#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
|
||||
# error "DATA_ORDER must be defined!"
|
||||
#endif
|
||||
|
||||
#ifndef HASH_CBLOCK
|
||||
# error "HASH_CBLOCK must be defined!"
|
||||
#endif
|
||||
#ifndef HASH_LONG
|
||||
# error "HASH_LONG must be defined!"
|
||||
#endif
|
||||
#ifndef HASH_CTX
|
||||
# error "HASH_CTX must be defined!"
|
||||
#endif
|
||||
|
||||
#ifndef HASH_UPDATE
|
||||
# error "HASH_UPDATE must be defined!"
|
||||
#endif
|
||||
//#ifndef HASH_TRANSFORM
|
||||
//# error "HASH_TRANSFORM must be defined!"
|
||||
//#endif
|
||||
#ifndef HASH_FINAL
|
||||
# error "HASH_FINAL must be defined!"
|
||||
#endif
|
||||
|
||||
#ifndef HASH_BLOCK_DATA_ORDER
|
||||
# error "HASH_BLOCK_DATA_ORDER must be defined!"
|
||||
#endif
|
||||
|
||||
#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
|
||||
|
||||
#if defined(DATA_ORDER_IS_BIG_ENDIAN)
|
||||
|
||||
# define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
|
||||
l|=(((unsigned long)(*((c)++)))<<16), \
|
||||
l|=(((unsigned long)(*((c)++)))<< 8), \
|
||||
l|=(((unsigned long)(*((c)++))) ) )
|
||||
# define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
|
||||
*((c)++)=(unsigned char)(((l)>>16)&0xff), \
|
||||
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
|
||||
*((c)++)=(unsigned char)(((l) )&0xff), \
|
||||
l)
|
||||
|
||||
#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
|
||||
|
||||
# define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
|
||||
l|=(((unsigned long)(*((c)++)))<< 8), \
|
||||
l|=(((unsigned long)(*((c)++)))<<16), \
|
||||
l|=(((unsigned long)(*((c)++)))<<24) )
|
||||
# define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
|
||||
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
|
||||
*((c)++)=(unsigned char)(((l)>>16)&0xff), \
|
||||
*((c)++)=(unsigned char)(((l)>>24)&0xff), \
|
||||
l)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Time for some action :-)
|
||||
*/
|
||||
|
||||
int HASH_UPDATE(HASH_CTX *c, const void *data_, size_t len)
|
||||
{
|
||||
auto data = (const unsigned char *) data_;
|
||||
unsigned char *p;
|
||||
HASH_LONG l;
|
||||
size_t n;
|
||||
|
||||
if (len == 0)
|
||||
return 1;
|
||||
|
||||
l = (c->Nl + (((HASH_LONG) len) << 3)) & 0xffffffffUL;
|
||||
if (l < c->Nl) /* overflow */
|
||||
c->Nh++;
|
||||
c->Nh += (HASH_LONG) (len >> 29); /* might cause compiler warning on
|
||||
* 16-bit */
|
||||
c->Nl = l;
|
||||
|
||||
n = c->num;
|
||||
if (n != 0) {
|
||||
p = (unsigned char *)c->data;
|
||||
|
||||
if (len >= HASH_CBLOCK || len + n >= HASH_CBLOCK) {
|
||||
memcpy(p + n, data, HASH_CBLOCK - n);
|
||||
HASH_BLOCK_DATA_ORDER(c, p, 1);
|
||||
n = HASH_CBLOCK - n;
|
||||
data += n;
|
||||
len -= n;
|
||||
c->num = 0;
|
||||
/*
|
||||
* We use memset rather than OPENSSL_cleanse() here deliberately.
|
||||
* Using OPENSSL_cleanse() here could be a performance issue. It
|
||||
* will get properly cleansed on finalisation so this isn't a
|
||||
* security problem.
|
||||
*/
|
||||
memset(p, 0, HASH_CBLOCK); /* keep it zeroed */
|
||||
} else {
|
||||
memcpy(p + n, data, len);
|
||||
c->num += (unsigned int)len;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
n = len / HASH_CBLOCK;
|
||||
if (n > 0) {
|
||||
HASH_BLOCK_DATA_ORDER(c, data, n);
|
||||
n *= HASH_CBLOCK;
|
||||
data += n;
|
||||
len -= n;
|
||||
}
|
||||
|
||||
if (len != 0) {
|
||||
p = (unsigned char *)c->data;
|
||||
c->num = (unsigned int)len;
|
||||
memcpy(p, data, len);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//void HASH_TRANSFORM(HASH_CTX *c, const unsigned char *data)
|
||||
//{
|
||||
// HASH_BLOCK_DATA_ORDER(c, data, 1);
|
||||
//}
|
||||
|
||||
int HASH_FINAL(unsigned char *md, HASH_CTX *c)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)c->data;
|
||||
size_t n = c->num;
|
||||
|
||||
p[n] = 0x80; /* there is always room for one */
|
||||
n++;
|
||||
|
||||
if (n > (HASH_CBLOCK - 8)) {
|
||||
memset(p + n, 0, HASH_CBLOCK - n);
|
||||
n = 0;
|
||||
HASH_BLOCK_DATA_ORDER(c, p, 1);
|
||||
}
|
||||
memset(p + n, 0, HASH_CBLOCK - 8 - n);
|
||||
|
||||
p += HASH_CBLOCK - 8;
|
||||
#if defined(DATA_ORDER_IS_BIG_ENDIAN)
|
||||
(void)HOST_l2c(c->Nh, p);
|
||||
(void)HOST_l2c(c->Nl, p);
|
||||
#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
|
||||
(void)HOST_l2c(c->Nl, p);
|
||||
(void)HOST_l2c(c->Nh, p);
|
||||
#endif
|
||||
p -= HASH_CBLOCK;
|
||||
HASH_BLOCK_DATA_ORDER(c, p, 1);
|
||||
c->num = 0;
|
||||
|
||||
#ifndef HASH_MAKE_STRING
|
||||
# error "HASH_MAKE_STRING must be defined!"
|
||||
#else
|
||||
HASH_MAKE_STRING(c, md);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef MD32_REG_T
|
||||
# if (defined(_LP64) && _LP64)
|
||||
# define MD32_REG_T long
|
||||
/*
|
||||
* This comment was originally written for MD5, which is why it
|
||||
* discusses A-D. But it basically applies to all 32-bit digests,
|
||||
* which is why it was moved to common header file.
|
||||
*
|
||||
* In case you wonder why A-D are declared as long and not
|
||||
* as MD5_LONG. Doing so results in slight performance
|
||||
* boost on LP64 architectures. The catch is we don't
|
||||
* really care if 32 MSBs of a 64-bit register get polluted
|
||||
* with eventual overflows as we *save* only 32 LSBs in
|
||||
* *either* case. Now declaring 'em long excuses the compiler
|
||||
* from keeping 32 MSBs zeroed resulting in 13% performance
|
||||
* improvement under SPARC Solaris7/64 and 5% under AlphaLinux.
|
||||
* Well, to be honest it should say that this *prevents*
|
||||
* performance degradation.
|
||||
*/
|
||||
# else
|
||||
/*
|
||||
* Above is not absolute and there are LP64 compilers that
|
||||
* generate better code if MD32_REG_T is defined int. The above
|
||||
* pre-processor condition reflects the circumstances under which
|
||||
* the conclusion was made and is subject to further extension.
|
||||
*/
|
||||
# define MD32_REG_T int
|
||||
# endif
|
||||
#endif
|
||||
49
libs/mmkv/Core/aes/openssl/openssl_md5.h
Executable file
49
libs/mmkv/Core/aes/openssl/openssl_md5.h
Executable file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef HEADER_MD5_H
|
||||
# define HEADER_MD5_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
# include "openssl_opensslconf.h"
|
||||
|
||||
# ifndef OPENSSL_NO_MD5
|
||||
# include <stddef.h>
|
||||
|
||||
namespace openssl {
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* ! MD5_LONG has to be at least 32 bits wide. !
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*/
|
||||
# define MD5_LONG unsigned int
|
||||
|
||||
# define MD5_CBLOCK 64
|
||||
# define MD5_LBLOCK (MD5_CBLOCK/4)
|
||||
# define MD5_DIGEST_LENGTH 16
|
||||
|
||||
typedef struct MD5state_st {
|
||||
MD5_LONG A, B, C, D;
|
||||
MD5_LONG Nl, Nh;
|
||||
MD5_LONG data[MD5_LBLOCK];
|
||||
unsigned int num;
|
||||
} MD5_CTX;
|
||||
|
||||
int MD5_Init(MD5_CTX *c);
|
||||
int MD5_Update(MD5_CTX *c, const void *data, size_t len);
|
||||
int MD5_Final(unsigned char *md, MD5_CTX *c);
|
||||
unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
|
||||
//void MD5_Transform(MD5_CTX *c, const unsigned char *b);
|
||||
|
||||
} // namespace openssl
|
||||
# endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
166
libs/mmkv/Core/aes/openssl/openssl_md5_dgst.cpp
Executable file
166
libs/mmkv/Core/aes/openssl/openssl_md5_dgst.cpp
Executable file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "openssl_md5_locl.h"
|
||||
|
||||
namespace openssl {
|
||||
/*
|
||||
* Implemented from RFC1321 The MD5 Message-Digest Algorithm
|
||||
*/
|
||||
|
||||
#define INIT_DATA_A (unsigned long)0x67452301L
|
||||
#define INIT_DATA_B (unsigned long)0xefcdab89L
|
||||
#define INIT_DATA_C (unsigned long)0x98badcfeL
|
||||
#define INIT_DATA_D (unsigned long)0x10325476L
|
||||
|
||||
int MD5_Init(MD5_CTX *c)
|
||||
{
|
||||
memset(c, 0, sizeof(*c));
|
||||
c->A = INIT_DATA_A;
|
||||
c->B = INIT_DATA_B;
|
||||
c->C = INIT_DATA_C;
|
||||
c->D = INIT_DATA_D;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef md5_block_data_order
|
||||
# ifdef X
|
||||
# undef X
|
||||
# endif
|
||||
void md5_block_data_order(MD5_CTX *c, const void *data_, size_t num)
|
||||
{
|
||||
auto data = (const unsigned char *) data_;
|
||||
unsigned MD32_REG_T A, B, C, D, l;
|
||||
# ifndef MD32_XARRAY
|
||||
/* See comment in crypto/sha/sha_locl.h for details. */
|
||||
unsigned MD32_REG_T XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7,
|
||||
XX8, XX9, XX10, XX11, XX12, XX13, XX14, XX15;
|
||||
# define X(i) XX##i
|
||||
# else
|
||||
MD5_LONG XX[MD5_LBLOCK];
|
||||
# define X(i) XX[i]
|
||||
# endif
|
||||
|
||||
A = c->A;
|
||||
B = c->B;
|
||||
C = c->C;
|
||||
D = c->D;
|
||||
|
||||
for (; num--;) {
|
||||
(void)HOST_c2l(data, l);
|
||||
X(0) = l;
|
||||
(void)HOST_c2l(data, l);
|
||||
X(1) = l;
|
||||
/* Round 0 */
|
||||
R0(A, B, C, D, X(0), 7, 0xd76aa478L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(2) = l;
|
||||
R0(D, A, B, C, X(1), 12, 0xe8c7b756L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(3) = l;
|
||||
R0(C, D, A, B, X(2), 17, 0x242070dbL);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(4) = l;
|
||||
R0(B, C, D, A, X(3), 22, 0xc1bdceeeL);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(5) = l;
|
||||
R0(A, B, C, D, X(4), 7, 0xf57c0fafL);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(6) = l;
|
||||
R0(D, A, B, C, X(5), 12, 0x4787c62aL);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(7) = l;
|
||||
R0(C, D, A, B, X(6), 17, 0xa8304613L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(8) = l;
|
||||
R0(B, C, D, A, X(7), 22, 0xfd469501L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(9) = l;
|
||||
R0(A, B, C, D, X(8), 7, 0x698098d8L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(10) = l;
|
||||
R0(D, A, B, C, X(9), 12, 0x8b44f7afL);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(11) = l;
|
||||
R0(C, D, A, B, X(10), 17, 0xffff5bb1L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(12) = l;
|
||||
R0(B, C, D, A, X(11), 22, 0x895cd7beL);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(13) = l;
|
||||
R0(A, B, C, D, X(12), 7, 0x6b901122L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(14) = l;
|
||||
R0(D, A, B, C, X(13), 12, 0xfd987193L);
|
||||
(void)HOST_c2l(data, l);
|
||||
X(15) = l;
|
||||
R0(C, D, A, B, X(14), 17, 0xa679438eL);
|
||||
R0(B, C, D, A, X(15), 22, 0x49b40821L);
|
||||
/* Round 1 */
|
||||
R1(A, B, C, D, X(1), 5, 0xf61e2562L);
|
||||
R1(D, A, B, C, X(6), 9, 0xc040b340L);
|
||||
R1(C, D, A, B, X(11), 14, 0x265e5a51L);
|
||||
R1(B, C, D, A, X(0), 20, 0xe9b6c7aaL);
|
||||
R1(A, B, C, D, X(5), 5, 0xd62f105dL);
|
||||
R1(D, A, B, C, X(10), 9, 0x02441453L);
|
||||
R1(C, D, A, B, X(15), 14, 0xd8a1e681L);
|
||||
R1(B, C, D, A, X(4), 20, 0xe7d3fbc8L);
|
||||
R1(A, B, C, D, X(9), 5, 0x21e1cde6L);
|
||||
R1(D, A, B, C, X(14), 9, 0xc33707d6L);
|
||||
R1(C, D, A, B, X(3), 14, 0xf4d50d87L);
|
||||
R1(B, C, D, A, X(8), 20, 0x455a14edL);
|
||||
R1(A, B, C, D, X(13), 5, 0xa9e3e905L);
|
||||
R1(D, A, B, C, X(2), 9, 0xfcefa3f8L);
|
||||
R1(C, D, A, B, X(7), 14, 0x676f02d9L);
|
||||
R1(B, C, D, A, X(12), 20, 0x8d2a4c8aL);
|
||||
/* Round 2 */
|
||||
R2(A, B, C, D, X(5), 4, 0xfffa3942L);
|
||||
R2(D, A, B, C, X(8), 11, 0x8771f681L);
|
||||
R2(C, D, A, B, X(11), 16, 0x6d9d6122L);
|
||||
R2(B, C, D, A, X(14), 23, 0xfde5380cL);
|
||||
R2(A, B, C, D, X(1), 4, 0xa4beea44L);
|
||||
R2(D, A, B, C, X(4), 11, 0x4bdecfa9L);
|
||||
R2(C, D, A, B, X(7), 16, 0xf6bb4b60L);
|
||||
R2(B, C, D, A, X(10), 23, 0xbebfbc70L);
|
||||
R2(A, B, C, D, X(13), 4, 0x289b7ec6L);
|
||||
R2(D, A, B, C, X(0), 11, 0xeaa127faL);
|
||||
R2(C, D, A, B, X(3), 16, 0xd4ef3085L);
|
||||
R2(B, C, D, A, X(6), 23, 0x04881d05L);
|
||||
R2(A, B, C, D, X(9), 4, 0xd9d4d039L);
|
||||
R2(D, A, B, C, X(12), 11, 0xe6db99e5L);
|
||||
R2(C, D, A, B, X(15), 16, 0x1fa27cf8L);
|
||||
R2(B, C, D, A, X(2), 23, 0xc4ac5665L);
|
||||
/* Round 3 */
|
||||
R3(A, B, C, D, X(0), 6, 0xf4292244L);
|
||||
R3(D, A, B, C, X(7), 10, 0x432aff97L);
|
||||
R3(C, D, A, B, X(14), 15, 0xab9423a7L);
|
||||
R3(B, C, D, A, X(5), 21, 0xfc93a039L);
|
||||
R3(A, B, C, D, X(12), 6, 0x655b59c3L);
|
||||
R3(D, A, B, C, X(3), 10, 0x8f0ccc92L);
|
||||
R3(C, D, A, B, X(10), 15, 0xffeff47dL);
|
||||
R3(B, C, D, A, X(1), 21, 0x85845dd1L);
|
||||
R3(A, B, C, D, X(8), 6, 0x6fa87e4fL);
|
||||
R3(D, A, B, C, X(15), 10, 0xfe2ce6e0L);
|
||||
R3(C, D, A, B, X(6), 15, 0xa3014314L);
|
||||
R3(B, C, D, A, X(13), 21, 0x4e0811a1L);
|
||||
R3(A, B, C, D, X(4), 6, 0xf7537e82L);
|
||||
R3(D, A, B, C, X(11), 10, 0xbd3af235L);
|
||||
R3(C, D, A, B, X(2), 15, 0x2ad7d2bbL);
|
||||
R3(B, C, D, A, X(9), 21, 0xeb86d391L);
|
||||
|
||||
A = c->A += A;
|
||||
B = c->B += B;
|
||||
C = c->C += C;
|
||||
D = c->D += D;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace openssl
|
||||
75
libs/mmkv/Core/aes/openssl/openssl_md5_locl.h
Executable file
75
libs/mmkv/Core/aes/openssl/openssl_md5_locl.h
Executable file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "openssl_md5.h"
|
||||
|
||||
namespace openssl {
|
||||
|
||||
void md5_block_data_order(MD5_CTX *c, const void *p, size_t num);
|
||||
|
||||
#define DATA_ORDER_IS_LITTLE_ENDIAN
|
||||
|
||||
#define HASH_LONG MD5_LONG
|
||||
#define HASH_CTX MD5_CTX
|
||||
#define HASH_CBLOCK MD5_CBLOCK
|
||||
#define HASH_UPDATE MD5_Update
|
||||
//#define HASH_TRANSFORM MD5_Transform
|
||||
#define HASH_FINAL MD5_Final
|
||||
#define HASH_MAKE_STRING(c,s) do { \
|
||||
unsigned long ll; \
|
||||
ll=(c)->A; (void)HOST_l2c(ll,(s)); \
|
||||
ll=(c)->B; (void)HOST_l2c(ll,(s)); \
|
||||
ll=(c)->C; (void)HOST_l2c(ll,(s)); \
|
||||
ll=(c)->D; (void)HOST_l2c(ll,(s)); \
|
||||
} while (0)
|
||||
#define HASH_BLOCK_DATA_ORDER md5_block_data_order
|
||||
|
||||
#include "openssl_md32_common.h"
|
||||
|
||||
/*-
|
||||
#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z)))
|
||||
#define G(x,y,z) (((x) & (z)) | ((y) & (~(z))))
|
||||
*/
|
||||
|
||||
/*
|
||||
* As pointed out by Wei Dai, the above can be simplified to the code
|
||||
* below. Wei attributes these optimizations to Peter Gutmann's
|
||||
* SHS code, and he attributes it to Rich Schroeppel.
|
||||
*/
|
||||
#define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d))
|
||||
#define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c))
|
||||
#define H(b,c,d) ((b) ^ (c) ^ (d))
|
||||
#define I(b,c,d) (((~(d)) | (b)) ^ (c))
|
||||
|
||||
#define R0(a,b,c,d,k,s,t) { \
|
||||
a+=((k)+(t)+F((b),(c),(d))); \
|
||||
a=ROTATE(a,s); \
|
||||
a+=b; };\
|
||||
|
||||
#define R1(a,b,c,d,k,s,t) { \
|
||||
a+=((k)+(t)+G((b),(c),(d))); \
|
||||
a=ROTATE(a,s); \
|
||||
a+=b; };
|
||||
|
||||
#define R2(a,b,c,d,k,s,t) { \
|
||||
a+=((k)+(t)+H((b),(c),(d))); \
|
||||
a=ROTATE(a,s); \
|
||||
a+=b; };
|
||||
|
||||
#define R3(a,b,c,d,k,s,t) { \
|
||||
a+=((k)+(t)+I((b),(c),(d))); \
|
||||
a=ROTATE(a,s); \
|
||||
a+=b; };
|
||||
|
||||
} // namespace openssl
|
||||
|
||||
#endif
|
||||
30
libs/mmkv/Core/aes/openssl/openssl_md5_one.cpp
Executable file
30
libs/mmkv/Core/aes/openssl/openssl_md5_one.cpp
Executable file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "openssl_md5.h"
|
||||
|
||||
namespace openssl {
|
||||
|
||||
unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)
|
||||
{
|
||||
MD5_CTX c;
|
||||
static unsigned char m[MD5_DIGEST_LENGTH];
|
||||
|
||||
if (md == nullptr)
|
||||
md = m;
|
||||
if (!MD5_Init(&c))
|
||||
return nullptr;
|
||||
MD5_Update(&c, d, n);
|
||||
MD5_Final(md, &c);
|
||||
return md;
|
||||
}
|
||||
|
||||
} // namespace openssl
|
||||
271
libs/mmkv/Core/aes/openssl/openssl_opensslconf.h
Normal file
271
libs/mmkv/Core/aes/openssl/openssl_opensslconf.h
Normal file
@@ -0,0 +1,271 @@
|
||||
/* opensslconf.h */
|
||||
/* WARNING: Generated automatically from opensslconf.h.in by Configure. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* OpenSSL was configured with the following options: */
|
||||
#ifndef OPENSSL_SYSNAME_iOS
|
||||
# define OPENSSL_SYSNAME_iOS
|
||||
#endif
|
||||
#ifndef OPENSSL_DOING_MAKEDEPEND
|
||||
|
||||
|
||||
#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
|
||||
# define OPENSSL_NO_EC_NISTP_64_GCC_128
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_GMP
|
||||
# define OPENSSL_NO_GMP
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_JPAKE
|
||||
# define OPENSSL_NO_JPAKE
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_KRB5
|
||||
# define OPENSSL_NO_KRB5
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_LIBUNBOUND
|
||||
# define OPENSSL_NO_LIBUNBOUND
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_MD2
|
||||
# define OPENSSL_NO_MD2
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_RC5
|
||||
# define OPENSSL_NO_RC5
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_RFC3779
|
||||
# define OPENSSL_NO_RFC3779
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SCTP
|
||||
# define OPENSSL_NO_SCTP
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SSL_TRACE
|
||||
# define OPENSSL_NO_SSL_TRACE
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SSL2
|
||||
# define OPENSSL_NO_SSL2
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_STORE
|
||||
# define OPENSSL_NO_STORE
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_UNIT_TEST
|
||||
# define OPENSSL_NO_UNIT_TEST
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
|
||||
# define OPENSSL_NO_WEAK_SSL_CIPHERS
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_DOING_MAKEDEPEND */
|
||||
|
||||
#ifndef OPENSSL_THREADS
|
||||
# define OPENSSL_THREADS
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_DYNAMIC_ENGINE
|
||||
# define OPENSSL_NO_DYNAMIC_ENGINE
|
||||
#endif
|
||||
|
||||
/* The OPENSSL_NO_* macros are also defined as NO_* if the application
|
||||
asks for it. This is a transient feature that is provided for those
|
||||
who haven't had the time to do the appropriate changes in their
|
||||
applications. */
|
||||
#ifdef OPENSSL_ALGORITHM_DEFINES
|
||||
# if defined(OPENSSL_NO_EC_NISTP_64_GCC_128) && !defined(NO_EC_NISTP_64_GCC_128)
|
||||
# define NO_EC_NISTP_64_GCC_128
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_GMP) && !defined(NO_GMP)
|
||||
# define NO_GMP
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_JPAKE) && !defined(NO_JPAKE)
|
||||
# define NO_JPAKE
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_KRB5) && !defined(NO_KRB5)
|
||||
# define NO_KRB5
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_LIBUNBOUND) && !defined(NO_LIBUNBOUND)
|
||||
# define NO_LIBUNBOUND
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_MD2) && !defined(NO_MD2)
|
||||
# define NO_MD2
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_RC5) && !defined(NO_RC5)
|
||||
# define NO_RC5
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_RFC3779) && !defined(NO_RFC3779)
|
||||
# define NO_RFC3779
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_SCTP) && !defined(NO_SCTP)
|
||||
# define NO_SCTP
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_SSL_TRACE) && !defined(NO_SSL_TRACE)
|
||||
# define NO_SSL_TRACE
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_SSL2) && !defined(NO_SSL2)
|
||||
# define NO_SSL2
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_STORE) && !defined(NO_STORE)
|
||||
# define NO_STORE
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_UNIT_TEST) && !defined(NO_UNIT_TEST)
|
||||
# define NO_UNIT_TEST
|
||||
# endif
|
||||
# if defined(OPENSSL_NO_WEAK_SSL_CIPHERS) && !defined(NO_WEAK_SSL_CIPHERS)
|
||||
# define NO_WEAK_SSL_CIPHERS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* crypto/opensslconf.h.in */
|
||||
|
||||
/* Generate 80386 code? */
|
||||
#undef I386_ONLY
|
||||
|
||||
#if !(defined(VMS) || defined(__VMS)) /* VMS uses logical names instead */
|
||||
#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR)
|
||||
#define ENGINESDIR "/Users/elviswu/Desktop/compile/openssl-ios-build-shell-script-master/openssl-1.0.2k-build/armv7/lib/engines"
|
||||
#define OPENSSLDIR "/Users/elviswu/Desktop/compile/openssl-ios-build-shell-script-master/openssl-1.0.2k-build/armv7/ssl"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef OPENSSL_UNISTD
|
||||
#define OPENSSL_UNISTD <unistd.h>
|
||||
|
||||
#undef OPENSSL_EXPORT_VAR_AS_FUNCTION
|
||||
|
||||
#if defined(HEADER_IDEA_H) && !defined(IDEA_INT)
|
||||
#define IDEA_INT unsigned int
|
||||
#endif
|
||||
|
||||
#if defined(HEADER_MD2_H) && !defined(MD2_INT)
|
||||
#define MD2_INT unsigned int
|
||||
#endif
|
||||
|
||||
#if defined(HEADER_RC2_H) && !defined(RC2_INT)
|
||||
/* I need to put in a mod for the alpha - eay */
|
||||
#define RC2_INT unsigned int
|
||||
#endif
|
||||
|
||||
#if defined(HEADER_RC4_H)
|
||||
#if !defined(RC4_INT)
|
||||
/* using int types make the structure larger but make the code faster
|
||||
* on most boxes I have tested - up to %20 faster. */
|
||||
/*
|
||||
* I don't know what does "most" mean, but declaring "int" is a must on:
|
||||
* - Intel P6 because partial register stalls are very expensive;
|
||||
* - elder Alpha because it lacks byte load/store instructions;
|
||||
*/
|
||||
#define RC4_INT unsigned char
|
||||
#endif
|
||||
#if !defined(RC4_CHUNK)
|
||||
/*
|
||||
* This enables code handling data aligned at natural CPU word
|
||||
* boundary. See crypto/rc4/rc4_enc.c for further details.
|
||||
*/
|
||||
#define RC4_CHUNK unsigned long
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(HEADER_NEW_DES_H) || defined(HEADER_DES_H)) && !defined(DES_LONG)
|
||||
/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
|
||||
* %20 speed up (longs are 8 bytes, int's are 4). */
|
||||
#ifndef DES_LONG
|
||||
#define DES_LONG unsigned long
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H)
|
||||
#define CONFIG_HEADER_BN_H
|
||||
#define BN_LLONG
|
||||
|
||||
/* Should we define BN_DIV2W here? */
|
||||
|
||||
/* Only one for the following should be defined */
|
||||
#undef SIXTY_FOUR_BIT_LONG
|
||||
#undef SIXTY_FOUR_BIT
|
||||
#define THIRTY_TWO_BIT
|
||||
#endif
|
||||
|
||||
#if defined(HEADER_RC4_LOCL_H) && !defined(CONFIG_HEADER_RC4_LOCL_H)
|
||||
#define CONFIG_HEADER_RC4_LOCL_H
|
||||
/* if this is defined data[i] is used instead of *data, this is a %20
|
||||
* speedup on x86 */
|
||||
#undef RC4_INDEX
|
||||
#endif
|
||||
|
||||
#if defined(HEADER_BF_LOCL_H) && !defined(CONFIG_HEADER_BF_LOCL_H)
|
||||
#define CONFIG_HEADER_BF_LOCL_H
|
||||
#define BF_PTR
|
||||
#endif /* HEADER_BF_LOCL_H */
|
||||
|
||||
#if defined(HEADER_DES_LOCL_H) && !defined(CONFIG_HEADER_DES_LOCL_H)
|
||||
#define CONFIG_HEADER_DES_LOCL_H
|
||||
#ifndef DES_DEFAULT_OPTIONS
|
||||
/* the following is tweaked from a config script, that is why it is a
|
||||
* protected undef/define */
|
||||
#ifndef DES_PTR
|
||||
#undef DES_PTR
|
||||
#endif
|
||||
|
||||
/* This helps C compiler generate the correct code for multiple functional
|
||||
* units. It reduces register dependancies at the expense of 2 more
|
||||
* registers */
|
||||
#ifndef DES_RISC1
|
||||
#undef DES_RISC1
|
||||
#endif
|
||||
|
||||
#ifndef DES_RISC2
|
||||
#undef DES_RISC2
|
||||
#endif
|
||||
|
||||
#if defined(DES_RISC1) && defined(DES_RISC2)
|
||||
#error YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
|
||||
#endif
|
||||
|
||||
/* Unroll the inner loop, this sometimes helps, sometimes hinders.
|
||||
* Very mucy CPU dependant */
|
||||
#ifndef DES_UNROLL
|
||||
#define DES_UNROLL
|
||||
#endif
|
||||
|
||||
/* These default values were supplied by
|
||||
* Peter Gutman <pgut001@cs.auckland.ac.nz>
|
||||
* They are only used if nothing else has been defined */
|
||||
#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
|
||||
/* Special defines which change the way the code is built depending on the
|
||||
CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
|
||||
even newer MIPS CPU's, but at the moment one size fits all for
|
||||
optimization options. Older Sparc's work better with only UNROLL, but
|
||||
there's no way to tell at compile time what it is you're running on */
|
||||
|
||||
#if defined( __sun ) || defined ( sun ) /* Newer Sparc's */
|
||||
# define DES_PTR
|
||||
# define DES_RISC1
|
||||
# define DES_UNROLL
|
||||
#elif defined( __ultrix ) /* Older MIPS */
|
||||
# define DES_PTR
|
||||
# define DES_RISC2
|
||||
# define DES_UNROLL
|
||||
#elif defined( __osf1__ ) /* Alpha */
|
||||
# define DES_PTR
|
||||
# define DES_RISC2
|
||||
#elif defined ( _AIX ) /* RS6000 */
|
||||
/* Unknown */
|
||||
#elif defined( __hpux ) /* HP-PA */
|
||||
/* Unknown */
|
||||
#elif defined( __aux ) /* 68K */
|
||||
/* Unknown */
|
||||
#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */
|
||||
# define DES_UNROLL
|
||||
#elif defined( __sgi ) /* Newer MIPS */
|
||||
# define DES_PTR
|
||||
# define DES_RISC2
|
||||
# define DES_UNROLL
|
||||
#elif defined(i386) || defined(__i386__) /* x86 boxes, should be gcc */
|
||||
# define DES_PTR
|
||||
# define DES_RISC1
|
||||
# define DES_UNROLL
|
||||
#endif /* Systems-specific speed defines */
|
||||
#endif
|
||||
|
||||
#endif /* DES_DEFAULT_OPTIONS */
|
||||
#endif /* HEADER_DES_LOCL_H */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
67
libs/mmkv/Core/crc32/Checksum.h
Normal file
67
libs/mmkv/Core/crc32/Checksum.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2018 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CHECKSUM_H
|
||||
#define CHECKSUM_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "../MMKVPredef.h"
|
||||
|
||||
#if MMKV_EMBED_ZLIB
|
||||
|
||||
# include "zlib/zconf.h"
|
||||
|
||||
namespace zlib {
|
||||
|
||||
uLong crc32(uLong crc, const Bytef *buf, z_size_t len);
|
||||
|
||||
} // namespace zlib
|
||||
|
||||
# define ZLIB_CRC32(crc, buf, len) zlib::crc32(crc, buf, len)
|
||||
|
||||
#else // MMKV_EMBED_ZLIB
|
||||
|
||||
# include <zlib.h>
|
||||
|
||||
# define ZLIB_CRC32(crc, buf, len) ::crc32(crc, buf, static_cast<uInt>(len))
|
||||
|
||||
#endif // MMKV_EMBED_ZLIB
|
||||
|
||||
|
||||
#if defined(__aarch64__) && defined(__linux__)
|
||||
|
||||
# define MMKV_USE_ARMV8_CRC32
|
||||
|
||||
namespace mmkv {
|
||||
uint32_t armv8_crc32(uint32_t crc, const uint8_t *buf, size_t len);
|
||||
}
|
||||
|
||||
// have to check CPU's instruction set dynamically
|
||||
typedef uint32_t (*CRC32_Func_t)(uint32_t crc, const uint8_t *buf, size_t len);
|
||||
extern CRC32_Func_t CRC32;
|
||||
|
||||
#else // defined(__aarch64__) && defined(__linux__)
|
||||
|
||||
# define CRC32(crc, buf, len) ZLIB_CRC32(crc, buf, len)
|
||||
|
||||
#endif // defined(__aarch64__) && defined(__linux__)
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // CHECKSUM_H
|
||||
132
libs/mmkv/Core/crc32/crc32_armv8.cpp
Normal file
132
libs/mmkv/Core/crc32/crc32_armv8.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* MMKV available.
|
||||
*
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Checksum.h"
|
||||
|
||||
#ifdef MMKV_USE_ARMV8_CRC32
|
||||
|
||||
# if MMKV_EMBED_ZLIB
|
||||
|
||||
static inline uint32_t _crc32Wrap(uint32_t crc, const uint8_t *buf, size_t len) {
|
||||
return static_cast<uint32_t>(zlib::crc32(crc, buf, static_cast<uInt>(len)));
|
||||
}
|
||||
|
||||
CRC32_Func_t CRC32 = _crc32Wrap;
|
||||
|
||||
# else
|
||||
# include <zlib.h>
|
||||
|
||||
static inline uint32_t _crc32Wrap(uint32_t crc, const uint8_t *buf, size_t len) {
|
||||
return static_cast<uint32_t>(::crc32(crc, buf, static_cast<uInt>(len)));
|
||||
}
|
||||
|
||||
CRC32_Func_t CRC32 = _crc32Wrap;
|
||||
|
||||
# endif
|
||||
|
||||
// targeting armv8 with crc instruction extension
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# define TARGET_ARM_CRC __attribute__((target("+crc")))
|
||||
# define __builtin_arm_crc32b(a, b) __builtin_aarch64_crc32b(a, b)
|
||||
# define __builtin_arm_crc32h(a, b) __builtin_aarch64_crc32h(a, b)
|
||||
# define __builtin_arm_crc32w(a, b) __builtin_aarch64_crc32w(a, b)
|
||||
# define __builtin_arm_crc32d(a, b) __builtin_aarch64_crc32x(a, b)
|
||||
#else
|
||||
# define TARGET_ARM_CRC __attribute__((target("crc")))
|
||||
#endif
|
||||
|
||||
TARGET_ARM_CRC static inline uint32_t __crc32b(uint32_t a, uint8_t b) {
|
||||
return __builtin_arm_crc32b(a, b);
|
||||
}
|
||||
|
||||
TARGET_ARM_CRC static inline uint32_t __crc32h(uint32_t a, uint16_t b) {
|
||||
return __builtin_arm_crc32h(a, b);
|
||||
}
|
||||
|
||||
TARGET_ARM_CRC static inline uint32_t __crc32w(uint32_t a, uint32_t b) {
|
||||
return __builtin_arm_crc32w(a, b);
|
||||
}
|
||||
|
||||
TARGET_ARM_CRC static inline uint32_t __crc32d(uint32_t a, uint64_t b) {
|
||||
return __builtin_arm_crc32d(a, b);
|
||||
}
|
||||
|
||||
TARGET_ARM_CRC static inline uint32_t armv8_crc32_small(uint32_t crc, const uint8_t *buf, size_t len) {
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
crc = __crc32w(crc, *(const uint32_t *) buf);
|
||||
buf += sizeof(uint32_t);
|
||||
len -= sizeof(uint32_t);
|
||||
}
|
||||
if (len >= sizeof(uint16_t)) {
|
||||
crc = __crc32h(crc, *(const uint16_t *) buf);
|
||||
buf += sizeof(uint16_t);
|
||||
len -= sizeof(uint16_t);
|
||||
}
|
||||
if (len >= sizeof(uint8_t)) {
|
||||
crc = __crc32b(crc, *(const uint8_t *) buf);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
namespace mmkv {
|
||||
|
||||
TARGET_ARM_CRC uint32_t armv8_crc32(uint32_t crc, const uint8_t *buf, size_t len) {
|
||||
|
||||
crc = crc ^ 0xffffffffUL;
|
||||
|
||||
// roundup to 8 byte pointer
|
||||
auto offset = std::min(len, (uintptr_t) buf & 7);
|
||||
if (offset) {
|
||||
crc = armv8_crc32_small(crc, buf, offset);
|
||||
buf += offset;
|
||||
len -= offset;
|
||||
}
|
||||
if (!len) {
|
||||
return crc ^ 0xffffffffUL;
|
||||
}
|
||||
|
||||
// unroll to 8 * 8 byte per loop
|
||||
auto ptr64 = (const uint64_t *) buf;
|
||||
for (constexpr auto step = 8 * sizeof(uint64_t); len >= step; len -= step) {
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
}
|
||||
|
||||
for (constexpr auto step = sizeof(uint64_t); len >= step; len -= step) {
|
||||
crc = __crc32d(crc, *ptr64++);
|
||||
}
|
||||
|
||||
if (len) {
|
||||
crc = armv8_crc32_small(crc, (const uint8_t *) ptr64, len);
|
||||
}
|
||||
|
||||
return crc ^ 0xffffffffUL;
|
||||
}
|
||||
|
||||
} // namespace mmkv
|
||||
|
||||
#endif // MMKV_USE_ARMV8_CRC32
|
||||
55
libs/mmkv/Core/crc32/zlib/crc32.cpp
Normal file
55
libs/mmkv/Core/crc32/zlib/crc32.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* crc32.c -- compute the CRC-32 of a data stream
|
||||
* Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*
|
||||
* Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
|
||||
* CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
|
||||
* tables for updating the shift register in one step with three exclusive-ors
|
||||
* instead of four steps with four exclusive-ors. This results in about a
|
||||
* factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#include "../../MMKVPredef.h"
|
||||
|
||||
#if MMKV_EMBED_ZLIB
|
||||
|
||||
#include "zutil.h" /* for STDC and FAR definitions */
|
||||
|
||||
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
|
||||
# define TBLS 1
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
namespace zlib {
|
||||
|
||||
/* ========================================================================= */
|
||||
#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
|
||||
#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
|
||||
|
||||
/* ========================================================================= */
|
||||
unsigned long local crc32_z(unsigned long crc, const unsigned char FAR *buf, z_size_t len)
|
||||
{
|
||||
if (buf == Z_NULL) return 0UL;
|
||||
|
||||
crc = crc ^ 0xffffffffUL;
|
||||
while (len >= 8) {
|
||||
DO8;
|
||||
len -= 8;
|
||||
}
|
||||
if (len) do {
|
||||
DO1;
|
||||
} while (--len);
|
||||
return crc ^ 0xffffffffUL;
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, z_size_t len) {
|
||||
return crc32_z(crc, buf, len);
|
||||
}
|
||||
|
||||
} // namespace zlib
|
||||
|
||||
#endif // MMKV_EMBED_ZLIB
|
||||
48
libs/mmkv/Core/crc32/zlib/crc32.h
Normal file
48
libs/mmkv/Core/crc32/zlib/crc32.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* crc32.h -- tables for rapid CRC calculation
|
||||
* Generated automatically by crc32.c
|
||||
*/
|
||||
|
||||
local const z_crc_t FAR crc_table[TBLS][256] = {
|
||||
{0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL,
|
||||
0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL,
|
||||
0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL,
|
||||
0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL,
|
||||
0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
|
||||
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL,
|
||||
0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL,
|
||||
0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL,
|
||||
0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL,
|
||||
0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
|
||||
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL,
|
||||
0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL,
|
||||
0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL,
|
||||
0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL,
|
||||
0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
|
||||
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL,
|
||||
0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL,
|
||||
0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL,
|
||||
0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL,
|
||||
0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
|
||||
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL,
|
||||
0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL,
|
||||
0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL,
|
||||
0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL,
|
||||
0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
|
||||
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL,
|
||||
0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL,
|
||||
0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL,
|
||||
0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL,
|
||||
0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
|
||||
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL,
|
||||
0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL,
|
||||
0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL,
|
||||
0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL,
|
||||
0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
|
||||
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL,
|
||||
0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL,
|
||||
0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL,
|
||||
0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL,
|
||||
0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
|
||||
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL,
|
||||
0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL,
|
||||
0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL}};
|
||||
380
libs/mmkv/Core/crc32/zlib/zconf.h
Normal file
380
libs/mmkv/Core/crc32/zlib/zconf.h
Normal file
@@ -0,0 +1,380 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
#define Z_SOLO
|
||||
#define Z_NEED_DICT 2
|
||||
|
||||
#if defined(__MSDOS__) && !defined(MSDOS)
|
||||
#define MSDOS
|
||||
#endif
|
||||
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
|
||||
#define OS2
|
||||
#endif
|
||||
#if defined(_WINDOWS) && !defined(WINDOWS)
|
||||
#define WINDOWS
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
|
||||
#ifndef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
#endif
|
||||
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
|
||||
#if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
|
||||
#ifndef SYS16BIT
|
||||
#define SYS16BIT
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
#define MAXSEG_64K
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
#define UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_VERSION__
|
||||
#ifndef STDC
|
||||
#define STDC
|
||||
#endif
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
#ifndef STDC99
|
||||
#define STDC99
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
|
||||
#define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
|
||||
#define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
|
||||
#define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
|
||||
#define STDC
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
|
||||
#define STDC
|
||||
#endif
|
||||
|
||||
#ifndef STDC
|
||||
#ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
|
||||
#define const /* note: need a more gentle solution here */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ZLIB_CONST) && !defined(z_const)
|
||||
#define z_const const
|
||||
#else
|
||||
#define z_const
|
||||
#endif
|
||||
|
||||
#ifdef Z_SOLO
|
||||
typedef unsigned long z_size_t;
|
||||
#else
|
||||
#define z_longlong long long
|
||||
#if defined(NO_SIZE_T)
|
||||
typedef unsigned NO_SIZE_T z_size_t;
|
||||
#elif defined(STDC)
|
||||
#include <stddef.h>
|
||||
typedef size_t z_size_t;
|
||||
#else
|
||||
typedef unsigned long z_size_t;
|
||||
#endif
|
||||
#undef z_longlong
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#ifndef MAX_MEM_LEVEL
|
||||
#ifdef MAXSEG_64K
|
||||
#define MAX_MEM_LEVEL 8
|
||||
#else
|
||||
#define MAX_MEM_LEVEL 9
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#ifndef MAX_WBITS
|
||||
#define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
#endif
|
||||
|
||||
/* The memory requirements for deflate are (in bytes):
|
||||
(1 << (windowBits+2)) + (1 << (memLevel+9))
|
||||
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||
the default memory requirements from 256K to 128K, compile with
|
||||
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||
Of course this will generally degrade compression (there's no free lunch).
|
||||
|
||||
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
|
||||
for small objects.
|
||||
*/
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
#ifndef OF /* function prototypes */
|
||||
#ifdef STDC
|
||||
#define OF(args) args
|
||||
#else
|
||||
#define OF(args) ()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef Z_ARG /* function prototypes for stdarg */
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
#define Z_ARG(args) args
|
||||
#else
|
||||
#define Z_ARG(args) ()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The following definitions for FAR are needed only for MSDOS mixed
|
||||
* model programming (small or medium model with some far allocations).
|
||||
* This was tested only with MSC; for other MSDOS compilers you may have
|
||||
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
|
||||
* just define FAR to be empty.
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
#if defined(M_I86SM) || defined(M_I86MM)
|
||||
/* MSC small or medium model */
|
||||
#define SMALL_MEDIUM
|
||||
#ifdef _MSC_VER
|
||||
#define FAR _far
|
||||
#else
|
||||
#define FAR far
|
||||
#endif
|
||||
#endif
|
||||
#if (defined(__SMALL__) || defined(__MEDIUM__))
|
||||
/* Turbo C small or medium model */
|
||||
#define SMALL_MEDIUM
|
||||
#ifdef __BORLANDC__
|
||||
#define FAR _far
|
||||
#else
|
||||
#define FAR far
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(WINDOWS) || defined(WIN32)
|
||||
/* If building or using zlib as a DLL, define ZLIB_DLL.
|
||||
* This is not mandatory, but it offers a little performance increase.
|
||||
*/
|
||||
#ifdef ZLIB_DLL
|
||||
#if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
|
||||
#ifdef ZLIB_INTERNAL
|
||||
#define ZEXTERN extern __declspec(dllexport)
|
||||
#else
|
||||
#define ZEXTERN extern __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#endif /* ZLIB_DLL */
|
||||
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
|
||||
* define ZLIB_WINAPI.
|
||||
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
|
||||
*/
|
||||
#ifdef ZLIB_WINAPI
|
||||
#ifdef FAR
|
||||
#undef FAR
|
||||
#endif
|
||||
#include <windows.h>
|
||||
/* No need for _export, use ZLIB.DEF instead. */
|
||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||
#define ZEXPORT WINAPI
|
||||
#ifdef WIN32
|
||||
#define ZEXPORTVA WINAPIV
|
||||
#else
|
||||
#define ZEXPORTVA FAR CDECL
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__BEOS__)
|
||||
#ifdef ZLIB_DLL
|
||||
#ifdef ZLIB_INTERNAL
|
||||
#define ZEXPORT __declspec(dllexport)
|
||||
#define ZEXPORTVA __declspec(dllexport)
|
||||
#else
|
||||
#define ZEXPORT __declspec(dllimport)
|
||||
#define ZEXPORTVA __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ZEXTERN
|
||||
#define ZEXTERN extern
|
||||
#endif
|
||||
#ifndef ZEXPORT
|
||||
#define ZEXPORT
|
||||
#endif
|
||||
#ifndef ZEXPORTVA
|
||||
#define ZEXPORTVA
|
||||
#endif
|
||||
|
||||
#ifndef FAR
|
||||
#define FAR
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
#endif
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
#ifdef SMALL_MEDIUM
|
||||
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
|
||||
#define Bytef Byte FAR
|
||||
#else
|
||||
typedef Byte FAR Bytef;
|
||||
#endif
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
#ifdef STDC
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
#else
|
||||
typedef Byte const *voidpc;
|
||||
typedef Byte FAR *voidpf;
|
||||
typedef Byte *voidp;
|
||||
#endif
|
||||
|
||||
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
|
||||
#include <limits.h>
|
||||
#if (UINT_MAX == 0xffffffffUL)
|
||||
#define Z_U4 unsigned
|
||||
#elif (ULONG_MAX == 0xffffffffUL)
|
||||
#define Z_U4 unsigned long
|
||||
#elif (USHRT_MAX == 0xffffffffUL)
|
||||
#define Z_U4 unsigned short
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_U4
|
||||
typedef Z_U4 z_crc_t;
|
||||
#else
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
|
||||
#define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
|
||||
#define Z_HAVE_STDARG_H
|
||||
#endif
|
||||
|
||||
#ifdef STDC
|
||||
#ifndef Z_SOLO
|
||||
#include <sys/types.h> /* for off_t */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
#ifndef Z_SOLO
|
||||
#include <stdarg.h> /* for va_list */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef Z_SOLO
|
||||
#include <stddef.h> /* for wchar_t */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
|
||||
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
|
||||
* though the former does not conform to the LFS document), but considering
|
||||
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
|
||||
* equivalently requesting no 64-bit operations
|
||||
*/
|
||||
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
|
||||
#undef _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
|
||||
#define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
#ifndef Z_SOLO
|
||||
#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
|
||||
#include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
||||
#ifdef VMS
|
||||
#include <unixio.h> /* for off_t */
|
||||
#endif
|
||||
#ifndef z_off_t
|
||||
#define z_off_t off_t
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE - 0
|
||||
#define Z_LFS64
|
||||
#endif
|
||||
|
||||
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
|
||||
#define Z_LARGE64
|
||||
#endif
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS - 0 == 64 && defined(Z_LFS64)
|
||||
#define Z_WANT64
|
||||
#endif
|
||||
|
||||
#if !defined(SEEK_SET) && !defined(Z_SOLO)
|
||||
#define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
#define SEEK_CUR 1 /* Seek from current position. */
|
||||
#define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
|
||||
#endif
|
||||
|
||||
#ifndef z_off_t
|
||||
#define z_off_t long
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
#define z_off64_t off64_t
|
||||
#else
|
||||
#if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
|
||||
#define z_off64_t __int64
|
||||
#else
|
||||
#define z_off64_t z_off_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
#if defined(__MVS__)
|
||||
#pragma map(deflateInit_, "DEIN")
|
||||
#pragma map(deflateInit2_, "DEIN2")
|
||||
#pragma map(deflateEnd, "DEEND")
|
||||
#pragma map(deflateBound, "DEBND")
|
||||
#pragma map(inflateInit_, "ININ")
|
||||
#pragma map(inflateInit2_, "ININ2")
|
||||
#pragma map(inflateEnd, "INEND")
|
||||
#pragma map(inflateSync, "INSY")
|
||||
#pragma map(inflateSetDictionary, "INSEDI")
|
||||
#pragma map(compressBound, "CMBND")
|
||||
#pragma map(inflate_table, "INTABL")
|
||||
#pragma map(inflate_fast, "INFA")
|
||||
#pragma map(inflate_copyright, "INCOPY")
|
||||
#endif
|
||||
|
||||
#endif /* ZCONF_H */
|
||||
25
libs/mmkv/Core/crc32/zlib/zutil.h
Executable file
25
libs/mmkv/Core/crc32/zlib/zutil.h
Executable file
@@ -0,0 +1,25 @@
|
||||
/* zutil.h -- internal interface and configuration of the compression library
|
||||
* Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZUTIL_H
|
||||
#define ZUTIL_H
|
||||
|
||||
#include "zconf.h"
|
||||
|
||||
#ifndef local
|
||||
#define local static
|
||||
#endif
|
||||
/* since "static" is used to mean two completely different things in C, we
|
||||
define "local" for the non-static meaning of "static", for readability
|
||||
(compile with -Dlocal if your debugger can't find static symbols) */
|
||||
|
||||
#endif /* ZUTIL_H */
|
||||
193
libs/mmkv/LICENSE.TXT
Normal file
193
libs/mmkv/LICENSE.TXT
Normal file
@@ -0,0 +1,193 @@
|
||||
Tencent is pleased to support the open source community by making MMKV available.
|
||||
Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
If you have downloaded a copy of the MMKV binary from Tencent, please note that the MMKV binary is licensed under the BSD 3-Clause License.
|
||||
If you have downloaded a copy of the MMKV source code from Tencent, please note that MMKV source code is licensed under the BSD 3-Clause License, except for the third-party components listed below which are subject to different license terms. Your integration of MMKV into your own projects may require compliance with the BSD 3-Clause License, as well as the other licenses applicable to the third-party components included within MMKV.
|
||||
A copy of the BSD 3-Clause License is included in this file.
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
Open Source Software Licensed Under the OpenSSL License:
|
||||
----------------------------------------------------------------------------------------
|
||||
1. OpenSSL 1.1.0i
|
||||
Copyright (c) 1998-2018 The OpenSSL Project.
|
||||
All rights reserved.
|
||||
Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Terms of the OpenSSL License:
|
||||
---------------------------------------------------
|
||||
LICENSE ISSUES:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the OpenSSL License and the original SSLeay license apply to the toolkit.
|
||||
See below for the actual license texts.
|
||||
|
||||
OpenSSL License:
|
||||
--------------------------------------------------------------------
|
||||
Copyright (c) 1998-2018 The OpenSSL Project. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. All advertising materials mentioning features or use of this software must display the following acknowledgment:
|
||||
"This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
|
||||
4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact openssl-core@openssl.org.
|
||||
|
||||
5. Products derived from this software may not be called "OpenSSL" nor may "OpenSSL" appear in their names without prior written permission of the OpenSSL Project.
|
||||
|
||||
6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
====================================================================
|
||||
* This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). This product includes software written by Tim Hudson (tjh@cryptsoft.com).
|
||||
|
||||
|
||||
Original SSLeay License:
|
||||
--------------------------------------------------------------------
|
||||
Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
All rights reserved.
|
||||
|
||||
This package is an SSL implementation written by Eric Young (eay@cryptsoft.com).
|
||||
The implementation was written so as to conform with Netscapes SSL.
|
||||
|
||||
This library is free for commercial and non-commercial use as long as the following conditions are aheared to. The following conditions apply to all code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code; not just the SSL code. The SSL documentation included with this distribution is covered by the same copyright terms except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
|
||||
Copyright remains Eric Young's, and as such any Copyright notices in the code are not to be removed. If this package is used in a product, Eric Young should be given attribution as the author of the parts of the library used. This can be in the form of a textual message at program startup or in documentation (online or textual) provided with the package.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. All advertising materials mentioning features or use of this software must display the following acknowledgement:" This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)" The word 'cryptographic' can be left out if the rouines from the library being used are not cryptographic related :-).
|
||||
4. If you include any Windows specific code (or a derivative thereof) from the apps directory (application code) you must include an acknowledgement: "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The licence and distribution terms for any publically available version or derivative of this code cannot be changed. i.e. this code cannot simply be copied and put under another distribution licence [including the GNU Public Licence.]
|
||||
|
||||
|
||||
|
||||
Open Source Software Licensed Under the Apache License, Version 2.0:
|
||||
The below software in this distribution may have been modified by THL A29 Limited (“Tencent Modifications”). All Tencent Modifications are Copyright (C) 2018 THL A29 Limited.
|
||||
----------------------------------------------------------------------------------------
|
||||
1. MultiprocessSharedPreferences v1.0
|
||||
Copyright (C) 2014 seven456@gmail.com
|
||||
|
||||
|
||||
Terms of the Apache License, Version 2.0:
|
||||
--------------------------------------------------------------------
|
||||
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, “control” means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, “submitted” means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
d) If the Work includes a “NOTICE” text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
|
||||
Open Source Software Licensed Under the zlib License:
|
||||
The below software in this distribution may have been modified by THL A29 Limited (“Tencent Modifications”). All Tencent Modifications are Copyright (C) 2018 THL A29 Limited.
|
||||
----------------------------------------------------------------------------------------
|
||||
1. zlib v1.2.11
|
||||
Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
|
||||
|
||||
Terms of the zlib License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
|
||||
Open Source Software Licensed Under the BSD 3-Clause License:
|
||||
----------------------------------------------------------------------------------------
|
||||
1. pybind11 v2.5.0
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.
|
||||
|
||||
Terms of the BSD 3-Clause License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of [copyright holder] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
2
libs/stub/.gitignore
vendored
Normal file
2
libs/stub/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
/libs
|
||||
8
libs/stub/build.gradle
Normal file
8
libs/stub/build.gradle
Normal file
@@ -0,0 +1,8 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
}
|
||||
}
|
||||
2
libs/stub/src/main/AndroidManifest.xml
Normal file
2
libs/stub/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="io.github.qauxv.stub" />
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.tencent.common.app;
|
||||
|
||||
import android.os.Bundle;
|
||||
import mqq.app.AppRuntime;
|
||||
|
||||
public abstract class AppInterface extends AppRuntime {
|
||||
|
||||
public AppInterface(BaseApplicationImpl baseApplicationImpl, String str) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.tencent.common.app;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import mqq.app.AppActivity;
|
||||
import mqq.app.AppRuntime;
|
||||
import mqq.app.MobileQQ;
|
||||
|
||||
/* compiled from: ProGuard */
|
||||
public class BaseApplicationImpl extends MobileQQ {
|
||||
|
||||
// public static BaseApplicationImpl a() {
|
||||
// throw new RuntimeException("Stub!");
|
||||
// }
|
||||
|
||||
public AppRuntime a() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public AppRuntime createRuntime(String str) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public int getAppId(String str) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public String getBootBroadcastName(String str) {
|
||||
if (str.equals("com.tencent.mobileqq")) {
|
||||
return "com.tencent.mobileqq.broadcast.qq";
|
||||
}
|
||||
if (str.equals("com.tencent.mobileqq:video")) {
|
||||
return "com.tencent.av.ui.VChatActivity";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isNeedMSF(String str) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean onActivityCreate(AppActivity appActivity, Intent intent) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void onActivityFocusChanged(AppActivity appActivity, boolean z) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void onRecver(String str) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void startActivity(Intent intent) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void startActivity(Intent intent, Bundle bundle) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.tencent.mobileqq.app;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import mqq.app.AppActivity;
|
||||
import mqq.app.AppRuntime;
|
||||
|
||||
public class BaseActivity extends AppActivity {
|
||||
|
||||
public static boolean isUnLockSuccess = false;
|
||||
public static boolean mAppForground = true;
|
||||
public static BaseActivity sTopActivity;
|
||||
|
||||
public QQAppInterface app;
|
||||
|
||||
public static boolean isMoveTaskToBack(Context context, Intent intent) {
|
||||
return intent.getComponent() == null || !intent.getComponent().getPackageName()
|
||||
.equals(context.getPackageName());
|
||||
}
|
||||
|
||||
@SuppressLint({"SdCardPath"})
|
||||
public boolean doDispatchKeyEvent(KeyEvent keyEvent) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean doOnCreate(Bundle bundle) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void doOnStart() {
|
||||
super.doOnStart();
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void doOnConfigurationChanged(Configuration configuration) {
|
||||
super.doOnConfigurationChanged(configuration);
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void doOnStop() {
|
||||
super.doOnStop();
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void doOnResume() {
|
||||
super.doOnResume();
|
||||
sTopActivity = this;
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void doOnPause() {
|
||||
super.doOnPause();
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void doOnDestroy() {
|
||||
super.doOnDestroy();
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void doOnBackPressed() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Activity getActivity() {
|
||||
return this;
|
||||
}
|
||||
|
||||
// public void addObserver(BusinessObserver businessObserver) {
|
||||
// throw new RuntimeException("Stub!");
|
||||
// }
|
||||
//
|
||||
// public void removeObserver(BusinessObserver businessObserver) {
|
||||
// throw new RuntimeException("Stub!");
|
||||
// }
|
||||
|
||||
public void turnOnShake() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void turnOffShake() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void addTouchFeedback() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public int getTitleBarHeight() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void startActivity(Intent intent) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void onPreThemeChanged() {
|
||||
}
|
||||
|
||||
public void onPostThemeChanged() {
|
||||
}
|
||||
|
||||
public void onAccountChanged() {
|
||||
super.onAccountChanged();
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setCanLock(boolean z) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void startActivityForResult(Intent intent, int i) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void startActivityForResult(Intent intent, int i, int i2) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean preloadData(AppRuntime appRuntime, boolean z) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.tencent.mobileqq.app;
|
||||
|
||||
import static android.view.Window.FEATURE_CUSTOM_TITLE;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Paint;
|
||||
import android.view.View;
|
||||
|
||||
@Deprecated
|
||||
public class IphoneTitleBarActivity extends BaseActivity {
|
||||
|
||||
public static final int LAYER_TYPE_SOFTWARE = 1;
|
||||
|
||||
public static void setLayerType(View view) {
|
||||
if (view != null) {
|
||||
try {
|
||||
view.getClass().getMethod("setLayerType", Integer.TYPE, Paint.class)
|
||||
.invoke(view, 0, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void requestWindowFeature(Intent intent) {
|
||||
requestWindowFeature(FEATURE_CUSTOM_TITLE);
|
||||
}
|
||||
|
||||
public void setContentView(int i) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setContentView(View view) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence charSequence) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence charSequence, String str) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public String getTextTitle() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setLeftViewName(Intent intent) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setLeftViewName(int i) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setLeftButton(int i, View.OnClickListener onClickListener) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setRightButton(int i, View.OnClickListener onClickListener) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public View getRightTextView() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void removeWebViewLayerType() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.tencent.mobileqq.app;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.tencent.common.app.AppInterface;
|
||||
import com.tencent.common.app.BaseApplicationImpl;
|
||||
import mqq.manager.Manager;
|
||||
|
||||
public class QQAppInterface extends AppInterface {
|
||||
|
||||
public QQAppInterface(BaseApplicationImpl baseApplicationImpl, String str) {
|
||||
super(baseApplicationImpl, str);
|
||||
}
|
||||
|
||||
public void start(boolean z2) {
|
||||
|
||||
}
|
||||
|
||||
protected void addManager(int i2, Manager manager) {
|
||||
|
||||
}
|
||||
|
||||
public void onRunningBackground(Bundle bundle) {
|
||||
}
|
||||
|
||||
public Manager getManager(int i2) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void onRunningForeground() {
|
||||
|
||||
}
|
||||
|
||||
protected Class[] getMessagePushServlets() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
protected String[] getMessagePushSSOCommands() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
protected boolean canAutoLogin(String str) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setAutoLogin(boolean z2) {
|
||||
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
protected void userLogoutReleaseData() {
|
||||
}
|
||||
|
||||
public void logout(boolean z2) {
|
||||
}
|
||||
|
||||
public void onCreate(Bundle bundle) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.tencent.mobileqq.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import com.tencent.widget.ScrollView;
|
||||
|
||||
public class BounceScrollView extends ScrollView {
|
||||
|
||||
public BounceScrollView(Context context, AttributeSet attributeSet) {
|
||||
super(context, attributeSet);
|
||||
setOverScrollMode(0);
|
||||
setFadingEdgeLength(0);
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
protected void onScrollChanged(int i, int i2, int i3, int i4) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean dispatchTouchEvent(MotionEvent motionEvent) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.tencent.qphone.base.remote;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class SimpleAccount {
|
||||
|
||||
public static final String _ISLOGINED = "_isLogined";
|
||||
public static final String _LOGINPROCESS = "_loginedProcess";
|
||||
public static final String _LOGINTIME = "_loginTime";
|
||||
public static final String _UIN = "_uin";
|
||||
private static final String tag = "SimpleAccount";
|
||||
private HashMap attributes = new HashMap();
|
||||
|
||||
public static SimpleAccount parseSimpleAccount(String src) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public static boolean isSameAccount(SimpleAccount A, SimpleAccount B) {
|
||||
return A.getUin().equals(B.getUin()) && A.isLogined() == B.isLogined();
|
||||
}
|
||||
|
||||
public String getUin() {
|
||||
return getAttribute(_UIN, "");
|
||||
}
|
||||
|
||||
public void setUin(String uin) {
|
||||
setAttribute(_UIN, uin);
|
||||
}
|
||||
|
||||
public boolean isLogined() {
|
||||
return Boolean.parseBoolean(getAttribute(_ISLOGINED, String.valueOf(false)));
|
||||
}
|
||||
|
||||
public String getLoginProcess() {
|
||||
return getAttribute(_LOGINPROCESS, "");
|
||||
}
|
||||
|
||||
public void setLoginProcess(String loginProcess) {
|
||||
setAttribute(_LOGINPROCESS, loginProcess);
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return this.attributes.containsKey(key);
|
||||
}
|
||||
|
||||
public String getAttribute(String key, String defaultValue) {
|
||||
if (this.attributes.containsKey(key)) {
|
||||
return (String) this.attributes.get(key);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public String removeAttribute(String key) {
|
||||
return (String) this.attributes.remove(key);
|
||||
}
|
||||
|
||||
public void setAttribute(String key, String value) {
|
||||
if (key.indexOf(" ") > 0) {
|
||||
throw new RuntimeException("key found space ");
|
||||
}
|
||||
this.attributes.put(key, value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public String toStoreString() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public HashMap getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof SimpleAccount) {
|
||||
return isSameAccount(this, (SimpleAccount) o);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user