add rootfs

This commit is contained in:
ACh Sulfate
2022-01-29 20:55:15 +08:00
parent d3cabbf2b8
commit c5d877dccf
112 changed files with 17628 additions and 0 deletions

13
.editorconfig Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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")
}
}

View 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()
}
}

View 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)
//}
}
}

View 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
View 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

Binary file not shown.

View 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
View 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
View 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
View 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()
}

View File

@@ -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)
}
}

View File

@@ -0,0 +1 @@
cn.lliiooll.processors.FunctionItemProvider

View 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
)

View 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
View 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(***);
}

View 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>

View File

@@ -0,0 +1,4 @@
// MMKV.aidl
package com.tencent.mmkv;
parcelable ParcelableMMKV;

View 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

View 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 **>(&currentEnv), 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

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

View File

@@ -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");
}
}

View File

@@ -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);
}

View File

@@ -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
}

View File

@@ -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,
}

View File

@@ -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;
}
}

View File

@@ -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];
}
};
}

View 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 ()

View 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

View 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

View 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

View 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 */

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

View 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
View 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

View 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

File diff suppressed because it is too large Load Diff

57
libs/mmkv/Core/MMKV_IO.h Normal file
View 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 */

View 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
View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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

View 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

View 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

View 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

View 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_ */

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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 */

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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}};

View 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 */

View 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
View 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
View File

@@ -0,0 +1,2 @@
/build
/libs

8
libs/stub/build.gradle Normal file
View File

@@ -0,0 +1,8 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 31
defaultConfig {
minSdkVersion 21
}
}

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="io.github.qauxv.stub" />

View File

@@ -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();
}
}

View File

@@ -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!");
}
}

View File

@@ -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;
}
}

View File

@@ -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!");
}
}

View File

@@ -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) {
}
}

View File

@@ -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!");
}
}

View File

@@ -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