├── .gitignore
├── .gitmodules
├── CONTRIBUTING.md
├── CONTRIBUTORS.md
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── litl
│ │ └── leveldb
│ │ └── test
│ │ └── DBTests.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── litl
│ │ └── leveldb
│ │ ├── Chunk.java
│ │ ├── DB.java
│ │ ├── DatabaseCorruptException.java
│ │ ├── Iterator.java
│ │ ├── LevelDBException.java
│ │ ├── NativeObject.java
│ │ ├── NotFoundException.java
│ │ └── WriteBatch.java
│ └── jni
│ ├── Android.mk
│ ├── Application.mk
│ ├── Chunk.cc
│ ├── Chunk.h
│ ├── blocknames.cc
│ ├── blocknames.h
│ ├── com_litl_leveldb_Chunk.cc
│ ├── com_litl_leveldb_DB.cc
│ ├── com_litl_leveldb_Iterator.cc
│ ├── com_litl_leveldb_WriteBatch.cc
│ ├── debug_conf.h
│ ├── leveldbjni.cc
│ ├── leveldbjni.h
│ ├── mapkey.h
│ ├── qstr.h
│ ├── subchunk.cc
│ └── subchunk.h
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | gen
3 | obj
4 | libs
5 | local.properties
6 | .DS_Store
7 | .metadata
8 | .settings
9 | *~
10 |
11 |
12 | ### Gradle template
13 | .gradle
14 | build/
15 |
16 | # Ignore Gradle GUI config
17 | gradle-app.setting
18 |
19 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
20 | !gradle-wrapper.jar
21 |
22 | # Cache of project
23 | .gradletasknamecache
24 |
25 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
26 | # gradle/wrapper/gradle-wrapper.properties
27 |
28 |
29 | ### Android template
30 | # Built application files
31 | *.apk
32 | *.ap_
33 |
34 | # Files for the ART/Dalvik VM
35 | *.dex
36 |
37 | # Java class files
38 | *.class
39 |
40 | # Generated files
41 | bin/
42 | gen/
43 | out/
44 |
45 | # Gradle files
46 | .gradle/
47 |
48 | # Local configuration file (sdk path, etc)
49 |
50 | # Proguard folder generated by Eclipse
51 | proguard/
52 |
53 | # Log Files
54 | *.log
55 |
56 | # Android Studio Navigation editor temp files
57 | .navigation/
58 |
59 | # Android Studio captures folder
60 | captures/
61 |
62 | # Intellij
63 | *.iml
64 | .idea
65 |
66 | # Keystore files
67 | *.jks
68 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "library/src/main/jni/leveldb"]
2 | path = library/src/main/jni/leveldb
3 | url = https://github.com/Mojang/leveldb-mcpe.git
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributor guidelines
2 |
3 | TODO: guidelines
4 |
5 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | # Maintainer
2 |
3 | @litl
4 |
5 |
6 | # Forks
7 |
8 | @zhuowei
9 |
10 | > Added first support for the leveldb-mcpe fork.
11 |
12 | @protolambda
13 |
14 | > Updated android-leveldb to a less archaic, more modern android standard.
15 |
16 |
17 | # Contributors
18 |
19 | Feel free to add yourself if you contribute.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 litl, LLC
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * Neither the name of the copyright holder nor the names of its
14 | contributors may be used to endorse or promote products derived from
15 | this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | ==========================
30 |
31 | The Google LevelDB library is included as a git-submodule under the following BSD-style license:
32 |
33 | Copyright (c) 2011 The LevelDB Authors. All rights reserved.
34 |
35 | Redistribution and use in source and binary forms, with or without
36 | modification, are permitted provided that the following conditions are
37 | met:
38 |
39 | * Redistributions of source code must retain the above copyright
40 | notice, this list of conditions and the following disclaimer.
41 | * Redistributions in binary form must reproduce the above
42 | copyright notice, this list of conditions and the following disclaimer
43 | in the documentation and/or other materials provided with the
44 | distribution.
45 | * Neither the name of Google Inc. nor the names of its
46 | contributors may be used to endorse or promote products derived from
47 | this software without specific prior written permission.
48 |
49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # leveldb-android
2 |
3 | [leveldb](https://github.com/google/leveldb) for Android.
4 |
5 | Very simple bindings for using Leveldb from android.
6 | There is an ~~excellent~~ outdated project [leveldbjni](https://github.com/fusesource/leveldbjni)
7 | out there for using leveldb from Java but seems to be a bit too much.
8 | It has a bunch of dependencies, including a code generator,
9 | which might or might not work on Android. At least it is not trivial to get started.
10 |
11 |
12 | ## Dependencies
13 |
14 | The only external dependencies are Android SDK and NDK.
15 |
16 |
17 | ## Building.
18 |
19 | 1. Clone the project with git. (Including the leveldb git-submodule, change it to a different fork if you want)
20 | 2. Open it with Android Studio. (Easiest way, but building could also be done with just gradle)
21 | 3. Build the project with gradle (if it was not already started automatically)
22 | 4. Make the project (Build > Make project)
23 | 5. Library should be ready now!
24 |
25 |
26 | ## Installation
27 |
28 | After building, include the library module in your own project like this:
29 |
30 | `your-project/settings.gradle`
31 |
32 | include ':android-leveldb'
33 | project(':android-leveldb').projectDir = new File(rootProject.projectDir, '../android-leveldb/library')
34 |
35 | This assumes that you cloned the android-leveldb git repository in the parent-folder of your-project.
36 |
37 | And add the module as dependency in `your-project/app/build.gradle`:
38 |
39 | //include .so files in the build (native libraries)
40 | compile fileTree(include: ['*.jar', '*.so'], dir: 'libs')
41 |
42 | //include the android-leveldb library (see settings.gradle)
43 | compile project(':android-leveldb')
44 |
45 |
46 |
47 | ## License
48 |
49 | Please see the [LICENSE](LICENSE) file.
50 |
51 |
52 | ## Contributing
53 |
54 | Contributions are always welcome.
55 |
56 | See [CONTRIBUTORS.md](CONTRIBUTORS.md) for a list of contributors, forks, etc.
57 |
58 | ### TODO
59 |
60 | Contributor guidelines are not set up yet.
61 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | maven {
5 | url 'https://maven.google.com/'
6 | name 'Google'
7 | }
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.2.1'
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | jcenter()
17 | maven {
18 | url 'https://maven.google.com/'
19 | name 'Google'
20 | }
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MithrilMania/android-leveldb/6e44cd947dc61064182d9cf16f5c994b48d12b9e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jan 08 22:03:20 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 | defaultConfig {
7 | minSdkVersion 16
8 | targetSdkVersion 26
9 | }
10 |
11 | buildTypes {
12 | debug {
13 | minifyEnabled false
14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
15 | ndk {
16 | abiFilters 'armeabi-v7a'
17 | }
18 | }
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | ndk {
23 | abiFilters 'armeabi-v7a'
24 | }
25 | }
26 | }
27 |
28 | externalNativeBuild {
29 | ndkBuild {
30 | path "src/main/jni/Android.mk"
31 | }
32 | }
33 |
34 | }
35 |
36 | dependencies {
37 | implementation fileTree(include: ['*.jar', '*.so'], dir: 'libs')
38 | testImplementation 'junit:junit:4.12'
39 | }
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in *android*/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Keep LevelDB classes, native methods may not be obfuscated!
20 | -keep public class com.litl.leveldb.** {
21 | public private protected *;
22 | }
23 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/litl/leveldb/test/DBTests.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb.test;
2 |
3 | import java.io.File;
4 | import java.io.UnsupportedEncodingException;
5 | import java.nio.ByteBuffer;
6 | import java.util.Arrays;
7 |
8 | import android.test.AndroidTestCase;
9 |
10 | import com.litl.leveldb.DB;
11 | import com.litl.leveldb.Iterator;
12 | import com.litl.leveldb.WriteBatch;
13 |
14 | public class DBTests extends AndroidTestCase {
15 | private File mPath;
16 | private DB mDb;
17 |
18 | @Override
19 | protected void setUp() throws Exception {
20 | super.setUp();
21 | mPath = new File(getContext().getCacheDir(), "db-tests");
22 | mDb = new DB(mPath);
23 | mDb.open();
24 | }
25 |
26 | @Override
27 | protected void tearDown() throws Exception {
28 | super.tearDown();
29 | mDb.close();
30 | DB.destroy(mPath);
31 | }
32 |
33 | private byte[] bytes(String str) {
34 | try {
35 | return str.getBytes("UTF-8");
36 | } catch (UnsupportedEncodingException e) {
37 | throw new RuntimeException(e);
38 | }
39 | }
40 |
41 | public void testBasics() {
42 | mDb.put(bytes("hello"), bytes("world"));
43 | mDb.put(bytes("bye"), bytes("moon"));
44 |
45 | byte[] val = mDb.get(bytes("hello"));
46 | assertNotNull(val);
47 | assertTrue(Arrays.equals(val, bytes("world")));
48 |
49 | val = mDb.get(bytes("bye"));
50 | assertNotNull(val);
51 | assertTrue(Arrays.equals(val, bytes("moon")));
52 |
53 | val = mDb.get(bytes("boo"));
54 | assertNull(val);
55 |
56 | final ByteBuffer bb = ByteBuffer.allocate(20);
57 | bb.put(bytes("boo hello world"));
58 | bb.flip();
59 |
60 | // Search for "hello"
61 | bb.position(4).limit(bb.position() + 5);
62 | val = mDb.get(bb);
63 | assertNotNull(val);
64 | assertTrue(Arrays.equals(val, bytes("world")));
65 |
66 | // Search for "boo"
67 | bb.position(0).limit(4);
68 | bb.flip();
69 | val = mDb.get(bb);
70 | assertNull(val);
71 | }
72 |
73 | public void testBatchAndIterator() {
74 | final String[] keys = { "foo1", "foo2", "foo3", "foo4", "foo5" };
75 | final String[] vals = { "bar1", "bar2", "bar3", "bar4", "bar5" };
76 |
77 | final WriteBatch batch = new WriteBatch();
78 | try {
79 | final ByteBuffer key = ByteBuffer.allocate(10);
80 | final ByteBuffer val = ByteBuffer.allocate(10);
81 | for (int i = 0; i < keys.length; i++) {
82 | key.clear();
83 | key.put(bytes(keys[i]));
84 | key.flip();
85 |
86 | val.clear();
87 | val.put(bytes(vals[i]));
88 | val.flip();
89 |
90 | batch.put(key, val);
91 | }
92 |
93 | mDb.write(batch);
94 | } finally {
95 | batch.close();
96 | }
97 |
98 | final Iterator iter = mDb.iterator();
99 | try {
100 | int i = 0;
101 | for (iter.seekToFirst(); iter.isValid(); iter.next()) {
102 | assertTrue(i < keys.length);
103 |
104 | final byte[] key = iter.getKey();
105 | final byte[] val = iter.getValue();
106 |
107 | assertTrue(Arrays.equals(bytes(keys[i]), key));
108 | assertTrue(Arrays.equals(bytes(vals[i]), val));
109 |
110 | i++;
111 | }
112 | assertTrue(i == keys.length);
113 | } finally {
114 | iter.close();
115 | }
116 | }
117 |
118 | public void testSnapshots() {
119 | mDb.put(bytes("hello"), bytes("one"));
120 | mDb.put(bytes("bye"), bytes("one"));
121 | mDb.put(bytes("hi"), bytes("one"));
122 |
123 | final DB.Snapshot snapshot = mDb.getSnapshot();
124 | final Iterator iter = mDb.iterator(snapshot);
125 | try {
126 | mDb.put(bytes("hello"), bytes("two"));
127 | mDb.delete(bytes("bye"));
128 |
129 | assertTrue(Arrays.equals(mDb.get(snapshot, bytes("hello")), bytes("one")));
130 | assertTrue(Arrays.equals(mDb.get(snapshot, bytes("bye")), bytes("one")));
131 | assertTrue(Arrays.equals(mDb.get(snapshot, bytes("hi")), bytes("one")));
132 |
133 | int i = 0;
134 | for (iter.seekToFirst(); iter.isValid(); iter.next()) {
135 | i++;
136 | assertTrue(Arrays.equals(iter.getValue(), bytes("one")));
137 | }
138 | assertEquals(3, i);
139 | } finally {
140 | iter.close();
141 | snapshot.close();
142 | }
143 |
144 | assertTrue(Arrays.equals(mDb.get(bytes("hello")), bytes("two")));
145 | assertTrue(Arrays.equals(mDb.get(bytes("hi")), bytes("one")));
146 | assertNull(mDb.get(bytes("bye")));
147 | }
148 |
149 | public void testSeek() {
150 | mDb.put(bytes("01"), bytes("foo"));
151 | mDb.put(bytes("02"), bytes("foo"));
152 | mDb.put(bytes("11"), bytes("foo"));
153 | mDb.put(bytes("12"), bytes("foo"));
154 | mDb.put(bytes("13"), bytes("foo"));
155 | mDb.put(bytes("21"), bytes("foo"));
156 |
157 | Iterator iter = mDb.iterator();
158 | try {
159 | iter.seek(bytes("1"));
160 | assertTrue(iter.isValid());
161 | assertTrue(Arrays.equals(bytes("11"), iter.getKey()));
162 |
163 | iter.seek(bytes("2"));
164 | assertTrue(iter.isValid());
165 | assertTrue(Arrays.equals(bytes("21"), iter.getKey()));
166 |
167 | iter.seek(bytes("3"));
168 | assertFalse(iter.isValid());
169 | } finally {
170 | iter.close();
171 | }
172 |
173 | iter = mDb.iterator();
174 | try {
175 | // Iterate over all values starting with "1"
176 | int i = 0;
177 | final byte[] searchByte = new byte[] { '1' };
178 | for (iter.seek(searchByte); iter.isValid(); iter.next()) {
179 | final byte[] key = iter.getKey();
180 | if (key[0] != searchByte[0]) {
181 | break;
182 | }
183 |
184 | i++;
185 | }
186 |
187 | assertEquals(3, i);
188 | } finally {
189 | iter.close();
190 | }
191 | }
192 |
193 | public void testWriteBatch() {
194 | final ByteBuffer managedBuf = ByteBuffer.allocate(10);
195 | final ByteBuffer directBuf = ByteBuffer.allocateDirect(10);
196 |
197 | final WriteBatch putBatch = new WriteBatch();
198 | try {
199 | directBuf.clear();
200 | directBuf.put(bytes("hello"));
201 | directBuf.flip();
202 | managedBuf.clear();
203 | managedBuf.put(bytes("world"));
204 | managedBuf.flip();
205 | putBatch.put(directBuf, managedBuf);
206 |
207 | managedBuf.clear();
208 | managedBuf.put(bytes("bye"));
209 | managedBuf.flip();
210 | directBuf.clear();
211 | directBuf.put(bytes("moon"));
212 | directBuf.flip();
213 | putBatch.put(managedBuf, directBuf);
214 |
215 | mDb.write(putBatch);
216 | } finally {
217 | putBatch.close();
218 | }
219 |
220 | final Iterator iter1 = mDb.iterator();
221 | try {
222 | iter1.seekToFirst();
223 | assertTrue(iter1.isValid());
224 | assertTrue(Arrays.equals(bytes("bye"), iter1.getKey()));
225 | assertTrue(Arrays.equals(bytes("moon"), iter1.getValue()));
226 | iter1.next();
227 | assertTrue(iter1.isValid());
228 | assertTrue(Arrays.equals(bytes("hello"), iter1.getKey()));
229 | assertTrue(Arrays.equals(bytes("world"), iter1.getValue()));
230 | iter1.next();
231 | assertFalse(iter1.isValid());
232 | } finally {
233 | iter1.close();
234 | }
235 |
236 | final WriteBatch deleteBatch = new WriteBatch();
237 | try {
238 | managedBuf.clear();
239 | managedBuf.put(bytes("hello"));
240 | managedBuf.flip();
241 | deleteBatch.delete(managedBuf);
242 |
243 | directBuf.clear();
244 | directBuf.put(bytes("bye"));
245 | directBuf.flip();
246 | deleteBatch.delete(directBuf);
247 |
248 | mDb.write(deleteBatch);
249 | } finally {
250 | deleteBatch.close();
251 | }
252 |
253 | final Iterator iter2 = mDb.iterator();
254 | try {
255 | iter2.seekToFirst();
256 | assertFalse(iter2.isValid());
257 | } finally {
258 | iter2.close();
259 | }
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/Chunk.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | import java.io.File;
4 | import java.nio.ByteBuffer;
5 |
6 | public class Chunk extends NativeObject {
7 |
8 | public Chunk(DB db, int x, int z, int dim) {
9 | super();
10 | mPtr = nativeOpen(db.getPtr(), x, z, dim);
11 | }
12 |
13 | public int getBlock(int x, int y, int z) {
14 | return nativeGetBlock(mPtr, x, y, z);
15 | }
16 |
17 | public void close() {
18 | closeNativeObject(mPtr);
19 | }
20 |
21 | @Override
22 | protected void closeNativeObject(long ptr) {
23 | nativeClose(ptr);
24 | }
25 |
26 | private static native long nativeOpen(long dbptr, int x, int z, int dim);
27 |
28 | private static native int nativeGetBlock(long ckptr, int x, int y, int z);
29 |
30 | private static native void nativeClose(long ckPtr);
31 |
32 | {
33 | System.loadLibrary("leveldbjni");
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/DB.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | import java.io.File;
4 | import java.nio.ByteBuffer;
5 |
6 | public class DB extends NativeObject {
7 | public abstract static class Snapshot extends NativeObject {
8 | Snapshot(long ptr) {
9 | super(ptr);
10 | }
11 | }
12 |
13 | private final File mPath;
14 | private boolean mDestroyOnClose = false;
15 |
16 | public DB(File path) {
17 | super();
18 |
19 | if (path == null) {
20 | throw new NullPointerException();
21 | }
22 | mPath = path;
23 | }
24 |
25 | public void open() {
26 | mPtr = nativeOpen(mPath.getAbsolutePath());
27 | }
28 |
29 | @Override
30 | protected void closeNativeObject(long ptr) {
31 | nativeClose(ptr);
32 |
33 | if (mDestroyOnClose) {
34 | destroy(mPath);
35 | }
36 | }
37 |
38 | public void put(byte[] key, byte[] value) {
39 | assertOpen("Database is closed");
40 | if (key == null) {
41 | throw new NullPointerException("key");
42 | }
43 | if (value == null) {
44 | throw new NullPointerException("value");
45 | }
46 |
47 | nativePut(mPtr, key, value);
48 | }
49 |
50 | public byte[] get(byte[] key) {
51 | return get(null, key);
52 | }
53 |
54 | public byte[] get(Snapshot snapshot, byte[] key) {
55 | assertOpen("Database is closed");
56 | if (key == null) {
57 | throw new NullPointerException();
58 | }
59 |
60 | return nativeGet(mPtr, snapshot != null ? snapshot.getPtr() : 0, key);
61 | }
62 |
63 | public byte[] get(ByteBuffer key) {
64 | return get(null, key);
65 | }
66 |
67 | public byte[] get(Snapshot snapshot, ByteBuffer key) {
68 | assertOpen("Database is closed");
69 | if (key == null) {
70 | throw new NullPointerException();
71 | }
72 |
73 | return nativeGet(mPtr, snapshot != null ? snapshot.getPtr() : 0, key);
74 | }
75 |
76 | public void delete(byte[] key) {
77 | assertOpen("Database is closed");
78 | if (key == null) {
79 | throw new NullPointerException();
80 | }
81 |
82 | nativeDelete(mPtr, key);
83 | }
84 |
85 | public void write(WriteBatch batch) {
86 | assertOpen("Database is closed");
87 | if (batch == null) {
88 | throw new NullPointerException();
89 | }
90 |
91 | nativeWrite(mPtr, batch.getPtr());
92 | }
93 |
94 | public Iterator iterator() {
95 | return iterator(null);
96 | }
97 |
98 | public Iterator iterator(final Snapshot snapshot) {
99 | assertOpen("Database is closed");
100 |
101 | ref();
102 |
103 | if (snapshot != null) {
104 | snapshot.ref();
105 | }
106 |
107 | return new Iterator(nativeIterator(mPtr, snapshot != null ? snapshot.getPtr() : 0)) {
108 | @Override
109 | protected void closeNativeObject(long ptr) {
110 | super.closeNativeObject(ptr);
111 | if (snapshot != null) {
112 | snapshot.unref();
113 | }
114 |
115 | DB.this.unref();
116 | }
117 | };
118 | }
119 |
120 | public Snapshot getSnapshot() {
121 | assertOpen("Database is closed");
122 | ref();
123 | return new Snapshot(nativeGetSnapshot(mPtr)) {
124 | protected void closeNativeObject(long ptr) {
125 | nativeReleaseSnapshot(DB.this.getPtr(), getPtr());
126 | DB.this.unref();
127 | }
128 | };
129 | }
130 |
131 | public void destroy() {
132 | mDestroyOnClose = true;
133 | if (getPtr() == 0) {
134 | destroy(mPath);
135 | }
136 | }
137 |
138 | public static void destroy(File path) {
139 | nativeDestroy(path.getAbsolutePath());
140 | }
141 |
142 | private static native long nativeOpen(String dbpath);
143 |
144 | private static native void nativeClose(long dbPtr);
145 |
146 | private static native void nativePut(long dbPtr, byte[] key, byte[] value);
147 |
148 | private static native byte[] nativeGet(long dbPtr, long snapshotPtr, byte[] key);
149 |
150 | private static native byte[] nativeGet(long dbPtr, long snapshotPtr, ByteBuffer key);
151 |
152 | private static native void nativeDelete(long dbPtr, byte[] key);
153 |
154 | private static native void nativeWrite(long dbPtr, long batchPtr);
155 |
156 | private static native void nativeDestroy(String dbpath);
157 |
158 | private static native long nativeIterator(long dbPtr, long snapshotPtr);
159 |
160 | private static native long nativeGetSnapshot(long dbPtr);
161 |
162 | private static native void nativeReleaseSnapshot(long dbPtr, long snapshotPtr);
163 |
164 | public static native String stringFromJNI();
165 |
166 | {
167 | System.loadLibrary("leveldbjni");
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/DatabaseCorruptException.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | public class DatabaseCorruptException extends LevelDBException {
4 | private static final long serialVersionUID = -2110293580518875321L;
5 |
6 | public DatabaseCorruptException() {
7 | }
8 |
9 | public DatabaseCorruptException(String error) {
10 | super(error);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/Iterator.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | public class Iterator extends NativeObject {
4 | Iterator(long iterPtr) {
5 | super(iterPtr);
6 | }
7 |
8 | @Override
9 | protected void closeNativeObject(long ptr) {
10 | nativeDestroy(ptr);
11 | }
12 |
13 | public void seekToFirst() {
14 | assertOpen("Iterator is closed");
15 | nativeSeekToFirst(mPtr);
16 | }
17 |
18 | public void seekToLast() {
19 | assertOpen("Iterator is closed");
20 | nativeSeekToLast(mPtr);
21 | }
22 |
23 | public void seek(byte[] target) {
24 | assertOpen("Iterator is closed");
25 | if (target == null) {
26 | throw new IllegalArgumentException();
27 | }
28 | nativeSeek(mPtr, target);
29 | }
30 |
31 | public boolean isValid() {
32 | assertOpen("Iterator is closed");
33 | return nativeValid(mPtr);
34 | }
35 |
36 | public void next() {
37 | assertOpen("Iterator is closed");
38 | nativeNext(mPtr);
39 | }
40 |
41 | public void prev() {
42 | assertOpen("Iterator is closed");
43 | nativePrev(mPtr);
44 | }
45 |
46 | public byte[] getKey() {
47 | assertOpen("Iterator is closed");
48 | return nativeKey(mPtr);
49 | }
50 |
51 | public byte[] getValue() {
52 | assertOpen("Iterator is closed");
53 | return nativeValue(mPtr);
54 | }
55 |
56 | private static native void nativeDestroy(long ptr);
57 |
58 | private static native void nativeSeekToFirst(long ptr);
59 |
60 | private static native void nativeSeekToLast(long ptr);
61 |
62 | private static native void nativeSeek(long ptr, byte[] key);
63 |
64 | private static native boolean nativeValid(long ptr);
65 |
66 | private static native void nativeNext(long ptr);
67 |
68 | private static native void nativePrev(long ptr);
69 |
70 | private static native byte[] nativeKey(long dbPtr);
71 |
72 | private static native byte[] nativeValue(long dbPtr);
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/LevelDBException.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | public class LevelDBException extends RuntimeException {
4 | private static final long serialVersionUID = 2903013251786326801L;
5 |
6 | public LevelDBException() {
7 | }
8 |
9 | public LevelDBException(String error) {
10 | super(error);
11 | }
12 |
13 | public LevelDBException(String error, Throwable cause) {
14 | super(error, cause);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/NativeObject.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | import java.io.Closeable;
4 |
5 | import android.text.TextUtils;
6 | import android.util.Log;
7 |
8 | abstract class NativeObject implements Closeable {
9 | private static final String TAG = NativeObject.class.getSimpleName();
10 | protected long mPtr;
11 | private int mRefCount = 0;
12 |
13 | protected NativeObject() {
14 | // The Java wrapper counts as one reference, will
15 | // be released when closed
16 | ref();
17 | }
18 |
19 | protected NativeObject(long ptr) {
20 | this();
21 |
22 | if (ptr == 0) {
23 | throw new OutOfMemoryError("Failed to allocate native object");
24 | }
25 |
26 | mPtr = ptr;
27 | }
28 |
29 | synchronized protected long getPtr() {
30 | return mPtr;
31 | }
32 |
33 | synchronized public boolean isClosed(){
34 | return getPtr() == 0;
35 | }
36 |
37 | protected void assertOpen(String message) {
38 | if (getPtr() == 0) {
39 | throw new IllegalStateException(message);
40 | }
41 | }
42 |
43 | synchronized void ref() {
44 | mRefCount++;
45 | }
46 |
47 | synchronized void unref() {
48 | if (mRefCount <= 0) {
49 | throw new IllegalStateException("Reference count is already 0");
50 | }
51 |
52 | mRefCount--;
53 |
54 | if (mRefCount == 0) {
55 | closeNativeObject(mPtr);
56 | mPtr = 0;
57 | }
58 | }
59 |
60 | protected abstract void closeNativeObject(long ptr);
61 |
62 | @Override
63 | public synchronized void close() {
64 | if (mPtr != 0) {
65 | unref();
66 | }
67 | }
68 |
69 | @Override
70 | protected void finalize() throws Throwable {
71 | if (mPtr != 0) {
72 | Class> clazz = getClass();
73 | String name = clazz.getSimpleName();
74 | while (TextUtils.isEmpty(name)) {
75 | clazz = clazz.getSuperclass();
76 | name = clazz.getSimpleName();
77 | }
78 |
79 | Log.w(TAG, "NativeObject " + name + " refcount: " + mRefCount
80 | + " id: " + System.identityHashCode(this)
81 | + " was finalized before native resource was closed, did you forget to call close()?");
82 | }
83 |
84 | super.finalize();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/NotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | public class NotFoundException extends LevelDBException {
4 | private static final long serialVersionUID = 6207999645579440001L;
5 |
6 | public NotFoundException() {
7 | }
8 |
9 | public NotFoundException(String error) {
10 | super(error);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/library/src/main/java/com/litl/leveldb/WriteBatch.java:
--------------------------------------------------------------------------------
1 | package com.litl.leveldb;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | public class WriteBatch extends NativeObject {
6 | public WriteBatch() {
7 | super(nativeCreate());
8 | }
9 |
10 | @Override
11 | protected void closeNativeObject(long ptr) {
12 | nativeDestroy(ptr);
13 | }
14 |
15 | public void delete(ByteBuffer key) {
16 | assertOpen("WriteBatch is closed");
17 | if (key == null) {
18 | throw new NullPointerException("key");
19 | }
20 |
21 | nativeDelete(mPtr, key);
22 | }
23 |
24 | public void put(ByteBuffer key, ByteBuffer value) {
25 | assertOpen("WriteBatch is closed");
26 | if (key == null) {
27 | throw new NullPointerException("key");
28 | }
29 | if (value == null) {
30 | throw new NullPointerException("value");
31 | }
32 |
33 | nativePut(mPtr, key, value);
34 | }
35 |
36 | public void clear() {
37 | assertOpen("WriteBatch is closed");
38 | nativeClear(mPtr);
39 | }
40 |
41 | private static native long nativeCreate();
42 |
43 | private static native void nativeDestroy(long ptr);
44 |
45 | private static native void nativeDelete(long ptr, ByteBuffer key);
46 |
47 | private static native void nativePut(long ptr, ByteBuffer key, ByteBuffer val);
48 |
49 | private static native void nativeClear(long ptr);
50 | }
51 |
--------------------------------------------------------------------------------
/library/src/main/jni/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 |
3 | include $(CLEAR_VARS)
4 | LOCAL_MODULE := leveldbjni
5 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/leveldb/include $(LOCAL_PATH)/leveldb/include/leveldb
6 | LOCAL_CPP_EXTENSION := .cc
7 | LOCAL_CFLAGS := -DLEVELDB_PLATFORM_ANDROID -std=gnu++11 -DDLLX=
8 | LOCAL_SRC_FILES := com_litl_leveldb_DB.cc com_litl_leveldb_Iterator.cc\
9 | com_litl_leveldb_WriteBatch.cc leveldbjni.cc com_litl_leveldb_Chunk.cc\
10 | subchunk.cc Chunk.cc blocknames.cc
11 | LOCAL_STATIC_LIBRARIES += leveldb
12 | LOCAL_LDLIBS += -llog -ldl -lz
13 |
14 | include $(BUILD_SHARED_LIBRARY)
15 |
16 |
17 |
18 | include $(CLEAR_VARS)
19 | LOCAL_MODULE := leveldb
20 | LOCAL_CFLAGS := -O3 -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX -DNDEBUG -std=gnu++11 -DDLLX=
21 | LOCAL_CPP_EXTENSION := .cc
22 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/leveldb $(LOCAL_PATH)/leveldb/include $(LOCAL_PATH)/leveldb/include/leveldb
23 | LOCAL_SRC_FILES := leveldb/db/builder.cc leveldb/db/c.cc leveldb/db/dbformat.cc leveldb/db/db_impl.cc leveldb/db/db_iter.cc leveldb/db/dumpfile.cc leveldb/db/filename.cc leveldb/db/log_reader.cc leveldb/db/log_writer.cc leveldb/db/memtable.cc leveldb/db/repair.cc leveldb/db/table_cache.cc leveldb/db/version_edit.cc leveldb/db/version_set.cc leveldb/db/write_batch.cc leveldb/db/zlib_compressor.cc leveldb/table/block_builder.cc leveldb/table/block.cc leveldb/table/filter_block.cc leveldb/table/format.cc leveldb/table/iterator.cc leveldb/table/merger.cc leveldb/table/table_builder.cc leveldb/table/table.cc leveldb/table/two_level_iterator.cc leveldb/util/arena.cc leveldb/util/bloom.cc leveldb/util/cache.cc leveldb/util/coding.cc leveldb/util/comparator.cc leveldb/util/crc32c.cc leveldb/util/env_boost.cc leveldb/util/env.cc leveldb/util/env_posix.cc leveldb/util/env_win.cc leveldb/util/filter_policy.cc leveldb/util/hash.cc leveldb/util/histogram.cc leveldb/util/logging.cc leveldb/util/options.cc leveldb/util/status.cc leveldb/util/win_logger.cc leveldb/port/port_posix.cc leveldb/port/port_posix_sse.cc
24 |
25 | include $(BUILD_STATIC_LIBRARY)
--------------------------------------------------------------------------------
/library/src/main/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_PLATFORM=android-16
2 | APP_ABI := armeabi-v7a x86 x86_64 arm64-v8a
3 | APP_STL := c++_static
4 |
--------------------------------------------------------------------------------
/library/src/main/jni/Chunk.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/3/23.
3 | //
4 |
5 |
6 | #include
7 | #include "Chunk.h"
8 | #include "mapkey.h"
9 | #include "qstr.h"
10 | #include
11 | #include
12 | #include
13 |
14 | #ifdef LOG_CHUNK_LOADSAVE
15 | #define LOGE_LS(x, ...) LOGE(CAT("Chunk: ", x), ##__VA_ARGS__);
16 | #else
17 | #define LOGE_LS(x, ...)
18 | #endif
19 |
20 | #ifdef LOG_CHUNK_OPERATION
21 | #define LOGE_OP(x, ...) LOGE(CAT("Chunk: ", x), ##__VA_ARGS__);
22 | #else
23 | #define LOGE_OP(x, ...)
24 | #endif
25 |
26 | //Init constants.
27 |
28 | const int32_t Chunk::msk[] = {0b1, 0b11, 0b111, 0b1111, 0b11111, 0b111111, 0b1111111,
29 | 0b11111111,
30 | 0b111111111, 0b1111111111, 0b11111111111,
31 | 0b111111111111,
32 | 0b1111111111111, 0b11111111111111, 0b11111111111111};
33 |
34 | const char Chunk::pattern_name[] = {0x0a, 0x00, 0x00, 0x08, 0x04, 0x00, 'n', 'a', 'm',
35 | 'e'};
36 |
37 | const char Chunk::pattern_val[] = {0x02, 0x03, 0x00, 'v', 'a', 'l'};
38 |
39 | Chunk::Chunk(leveldb::DB *db, mapkey_t key)
40 | : key(key) {
41 | std::string str;
42 | memset(subchunks, 0, sizeof(subchunks));
43 | for (int i = 0; i < 16; i++) {
44 | loadSubChunk(db, i);
45 | }
46 | }
47 |
48 | void Chunk::loadSubChunk(leveldb::DB *db, unsigned char which) {
49 | LDBKEY_SUBCHUNK(this->key, which)
50 | leveldb::Slice slice(key, 0 == this->key.dimension ? 10 : 14);
51 | std::string val;
52 | leveldb::ReadOptions readOptions;
53 | readOptions.decompress_allocator = new leveldb::DecompressAllocator;
54 | bool hit = db->Get(readOptions, slice, &val).ok();
55 | if (hit) {//Found, detect version.
56 | switch (val[0]) {
57 | case 0://Aligned subchunk.
58 | case 2://All
59 | case 3://The
60 | case 4://Same
61 | case 5://Really
62 | case 6://Wierd
63 | case 7://Ahhh
64 | break;
65 | case 8://Current paletted format
66 | subchunks[which] = new SubChunk(val, true);
67 | break;
68 | case 1: //Previous paletted version
69 | subchunks[which] = new SubChunk(val, false);
70 | break;
71 | default:
72 | //Unsupported format.
73 | break;
74 | }
75 | }
76 | }
77 |
78 | uint16_t Chunk::getBlock(unsigned char x, unsigned char y, unsigned char z) {
79 | unsigned char sub = y >> 4;
80 | if (subchunks[sub] == nullptr)return 0;
81 | return subchunks[sub]->getBlock(x, static_cast(y & 0xf), z);
82 | }
83 |
84 | Chunk::~Chunk() {
85 | for (int i = 0; i < 16; i++) {
86 | delete subchunks[i];
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/library/src/main/jni/Chunk.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/3/23.
3 | //
4 |
5 | #ifndef CONVARTER_CHUNK_H
6 | #define CONVARTER_CHUNK_H
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include "mapkey.h"
13 | #include "debug_conf.h"
14 | #include "qstr.h"
15 |
16 | class Chunk {
17 | private:
18 |
19 | //Constants.
20 |
21 | static const int32_t msk[];
22 |
23 | static const char pattern_name[];
24 |
25 | static const char pattern_val[];
26 |
27 | //Member vars.
28 |
29 | mapkey_t key;
30 |
31 | SubChunk *subchunks[16];
32 |
33 | void loadSubChunk(leveldb::DB *db, unsigned char which);
34 |
35 | public:
36 |
37 | Chunk(leveldb::DB *db, mapkey_t key);
38 |
39 | ~Chunk();
40 |
41 | uint16_t getBlock(unsigned char x, unsigned char y, unsigned char z);
42 | };
43 |
44 | #endif //CONVARTER_CHUNK_H
45 |
--------------------------------------------------------------------------------
/library/src/main/jni/blocknames.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/3/30.
3 | //
4 |
5 | #include
6 | #include
7 | #include "blocknames.h"
8 |
9 | char BlockNames::names[256][32] = {"air",
10 | "stone",
11 | "grass",
12 | "dirt",
13 | "cobblestone",
14 | "planks",
15 | "sapling",
16 | "bedrock",
17 | "flowing_water",
18 | "water",
19 | "flowing_lava",
20 | "lava",
21 | "sand",
22 | "gravel",
23 | "gold_ore",
24 | "iron_ore",
25 | "coal_ore",
26 | "log",
27 | "leaves",
28 | "sponge",
29 | "glass",
30 | "lapis_ore",
31 | "lapis_block",
32 | "dispenser",
33 | "sandstone",
34 | "noteblock",
35 | "bed",
36 | "golden_rail",
37 | "detector_rail",
38 | "sticky_piston",
39 | "web",
40 | "tallgrass",
41 | "deadbush",
42 | "piston",
43 | "pistonarmcollision",
44 | "wool",
45 | "air",
46 | "yellow_flower",
47 | "red_flower",
48 | "brown_mushroom",
49 | "red_mushroom",
50 | "gold_block",
51 | "iron_block",
52 | "double_stone_slab",
53 | "stone_slab",
54 | "brick_block",
55 | "tnt",
56 | "bookshelf",
57 | "mossy_cobblestone",
58 | "obsidian",
59 | "torch",
60 | "fire",
61 | "mob_spawner",
62 | "oak_stairs",
63 | "chest",
64 | "redstone_wire",
65 | "diamond_ore",
66 | "diamond_block",
67 | "crafting_table",
68 | "wheat",
69 | "farmland",
70 | "furnace",
71 | "lit_furnace",
72 | "standing_sign",
73 | "wooden_door",
74 | "ladder",
75 | "rail",
76 | "stone_stairs",
77 | "wall_sign",
78 | "lever",
79 | "stone_pressure_plate",
80 | "iron_door",
81 | "oak_pressure_plate",
82 | "redstone_ore",
83 | "lit_redstone_ore",
84 | "unlit_redstone_torch",
85 | "lit_redstone_torch",
86 | "stone_button",
87 | "snow_layer",
88 | "ice",
89 | "snow",
90 | "cactus",
91 | "clay",
92 | "reeds",
93 | "jukebox",
94 | "fence",
95 | "pumpkin",
96 | "netherrack",
97 | "soul_sand",
98 | "glowstone",
99 | "portal",
100 | "lit_pumpkin",
101 | "cake",
102 | "unpowered_repeater",
103 | "powered_repeater",
104 | "invisiblebedrock",
105 | "oak_trapdoor",
106 | "monster_egg",
107 | "stonebrick",
108 | "brown_mushroom_block",
109 | "red_mushroom_block",
110 | "iron_bars",
111 | "glass_pane",
112 | "melon_block",
113 | "pumpkin_stem",
114 | "melon_stem",
115 | "vine",
116 | "fence_gate",
117 | "brick_stairs",
118 | "stone_brick_stairs",
119 | "mycelium",
120 | "waterlily",
121 | "nether_brick",
122 | "nether_brick_fence",
123 | "nether_brick_stairs",
124 | "nether_wart",
125 | "enchanting_table",
126 | "brewing_stand",
127 | "cauldron",
128 | "end_portal",
129 | "end_portal_frame",
130 | "end_stone",
131 | "dragon_egg",
132 | "redstone_lamp",
133 | "lit_redstone_lamp",
134 | "dropper",
135 | "activator_rail",
136 | "cocoa",
137 | "sandstone_stairs",
138 | "emerald_ore",
139 | "ender_chest",
140 | "tripwire_hook",
141 | "tripwire",
142 | "emerald_block",
143 | "spruce_stairs",
144 | "birch_stairs",
145 | "jungle_stairs",
146 | "command_block",
147 | "beacon",
148 | "cobblestone_wall",
149 | "flower_pot",
150 | "carrots",
151 | "potatoes",
152 | "oak_button",
153 | "skull",
154 | "anvil",
155 | "trapped_chest",
156 | "light_weighted_pressure_plate",
157 | "heavy_weighted_pressure_plate",
158 | "unpowered_comparator",
159 | "powered_comparator",
160 | "daylight_detector",
161 | "redstone_block",
162 | "quartz_ore",
163 | "hopper",
164 | "quartz_block",
165 | "quartz_stairs",
166 | "double_wooden_slab",
167 | "wooden_slab",
168 | "stained_hardened_clay",
169 | "stained_glass_pane",
170 | "leaves2",
171 | "log2",
172 | "acacia_stairs",
173 | "dark_oak_stairs",
174 | "slime",
175 | "air",
176 | "iron_trapdoor",
177 | "prismarine",
178 | "sealantern",
179 | "hay_block",
180 | "carpet",
181 | "terracotta",
182 | "coal_block",
183 | "packed_ice",
184 | "double_plant",
185 | "standing_banner",
186 | "wall_banner",
187 | "daylight_detector_inverted",
188 | "red_sandstone",
189 | "red_sandstone_stairs",
190 | "double_stone_slab2",
191 | "stone_slab2",
192 | "spruce_fence_gate",
193 | "birch_fence_gate",
194 | "jungle_fence_gate",
195 | "dark_oak_fence_gate",
196 | "acacia_fence_gate",
197 | "repeating_command_block",
198 | "chain_command_block",
199 | "air",
200 | "air",
201 | "air",
202 | "spruce_door",
203 | "birch_door",
204 | "jungle_door",
205 | "acacia_door",
206 | "dark_oak_door",
207 | "grass_path",
208 | "frame",
209 | "chorus_flower",
210 | "purpur_block",
211 | "purpur_stairs",
212 | "air",
213 | "air",
214 | "undyed_shulker_box",
215 | "end_bricks",
216 | "frosted_ice",
217 | "end_rod",
218 | "end_gateway",
219 | "air",
220 | "air",
221 | "air",
222 | "magma",
223 | "nether_wart_block",
224 | "red_nether_brick",
225 | "bone_block",
226 | "air",
227 | "shulker_box",
228 | "purple_glazed_terracotta",
229 | "white_glazed_terracotta",
230 | "orange_glazed_terracotta",
231 | "magenta_glazed_terracotta",
232 | "light_blue_glazed_terracotta",
233 | "yellow_glazed_terracotta",
234 | "lime_glazed_terracotta",
235 | "pink_glazed_terracotta",
236 | "gray_glazed_terracotta",
237 | "silver_glazed_terracotta",
238 | "cyan_glazed_terracotta",
239 | "air",
240 | "blue_glazed_terracotta",
241 | "brown_glazed_terracotta",
242 | "green_glazed_terracotta",
243 | "red_glazed_terracotta",
244 | "black_glazed_terracotta",
245 | "concrete",
246 | "concretepowder",
247 | "air",
248 | "air",
249 | "chorus_plant",
250 | "stained_glass",
251 | "air",
252 | "podzol",
253 | "beetroot",
254 | "stonecutter",
255 | "glowingobsidian",
256 | "netherreactor",
257 | "info_update",
258 | "info_update2",
259 | "movingblock",
260 | "observer",
261 | "structure_block",
262 | "air",
263 | "air",
264 | "reserved6"};
265 |
266 | unsigned char BlockNames::resolve(qstr name) {
267 | if (name.str[9] == ':') {
268 | name.str += 10;
269 | name.length -= 10;
270 | }
271 | for (int i = 0; i < 256; i++) {
272 | char *nam = names[i];
273 | if (memcmp(nam, name.str, name.length) != 0)continue;
274 | return static_cast(i);
275 | }
276 | return 0;
277 | }
278 |
--------------------------------------------------------------------------------
/library/src/main/jni/blocknames.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/3/29.
3 | //
4 |
5 | #ifndef CONVARTER_BLOCKNAMES_H
6 | #define CONVARTER_BLOCKNAMES_H
7 |
8 | #include "qstr.h"
9 |
10 | class BlockNames {
11 | public:
12 | static char names[256][32];
13 |
14 | static unsigned char resolve(qstr name);
15 | };
16 |
17 | #endif //CONVARTER_BLOCKNAMES_H
18 |
--------------------------------------------------------------------------------
/library/src/main/jni/com_litl_leveldb_Chunk.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "leveldbjni.h"
10 | #include "Chunk.h"
11 |
12 | static jlong nativeOpen(JNIEnv *env, jclass clazz, jlong dbptr, jint x, jint z, jint dim) {
13 | leveldb::DB *db = reinterpret_cast(dbptr);
14 | Chunk *chunk = new Chunk(db, LDBKEY_STRUCT(x, z, dim));
15 | return reinterpret_cast(chunk);
16 | }
17 |
18 | static jint nativeGetBlock(JNIEnv *env, jclass clazz, jlong ckptr, jint x, jint y, jint z) {
19 | Chunk *chunk = reinterpret_cast(ckptr);
20 | return chunk->getBlock(static_cast(x), static_cast(y),
21 | static_cast(z));
22 | }
23 |
24 | static void nativeClose(JNIEnv *env, jclass clazz, jlong ckptr) {
25 | Chunk *chunk = reinterpret_cast(ckptr);
26 | delete chunk;
27 | }
28 |
29 | static JNINativeMethod sMethods[] =
30 | {
31 | {"nativeOpen", "(JIII)J", (void *) nativeOpen},
32 | {"nativeGetBlock", "(JIII)I", (void *) nativeGetBlock},
33 | {"nativeClose", "(J)V", (void *) nativeClose}
34 | };
35 |
36 | int
37 | register_com_litl_leveldb_Chunk(JNIEnv *env) {
38 | jclass clazz = env->FindClass("com/litl/leveldb/Chunk");
39 | if (!clazz) {
40 | LOGE("Can't find class com.litl.leveldb.Chunk");
41 | return 0;
42 | }
43 |
44 | return env->RegisterNatives(clazz, sMethods, NELEM(sMethods));
45 | }
46 |
--------------------------------------------------------------------------------
/library/src/main/jni/com_litl_leveldb_DB.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "leveldbjni.h"
9 |
10 | #include "leveldb/db.h"
11 | #include "leveldb/write_batch.h"
12 | #include "leveldb/zlib_compressor.h"
13 | #include "leveldb/filter_policy.h"
14 | #include "leveldb/cache.h"
15 | #include "leveldb/options.h"
16 | #include "leveldb/decompress_allocator.h"
17 | #include "leveldb/env.h"
18 |
19 | static jmethodID gByteBuffer_isDirectMethodID;
20 | static jmethodID gByteBuffer_positionMethodID;
21 | static jmethodID gByteBuffer_limitMethodID;
22 | static jmethodID gByteBuffer_arrayMethodID;
23 |
24 | static leveldb::ZlibCompressor* zlibCompressorInstance;
25 |
26 | class NullLogger : public leveldb::Logger {
27 | public:
28 | void Logv(const char*, va_list) override {
29 | }
30 | };
31 |
32 | static jlong
33 | nativeOpen(JNIEnv* env,
34 | jclass clazz,
35 | jstring dbpath)
36 | {
37 | static bool gInited;
38 |
39 | if (!gInited) {
40 | jclass byteBuffer_Clazz = env->FindClass("java/nio/ByteBuffer");
41 | gByteBuffer_isDirectMethodID = env->GetMethodID(byteBuffer_Clazz,
42 | "isDirect", "()Z");
43 | gByteBuffer_positionMethodID = env->GetMethodID(byteBuffer_Clazz,
44 | "position", "()I");
45 | gByteBuffer_limitMethodID = env->GetMethodID(byteBuffer_Clazz,
46 | "limit", "()I");
47 | gByteBuffer_arrayMethodID = env->GetMethodID(byteBuffer_Clazz,
48 | "array", "()[B");
49 | gInited = true;
50 | }
51 |
52 | const char *path = env->GetStringUTFChars(dbpath, 0);
53 | LOGI("Opening database %s", path);
54 |
55 | leveldb::DB* db;
56 | leveldb::Options options;
57 | options.create_if_missing = true;
58 | options.paranoid_checks = true;
59 | if (zlibCompressorInstance == NULL) {
60 | zlibCompressorInstance = new leveldb::ZlibCompressor();
61 | }
62 |
63 | //create a bloom filter to quickly tell if a key is in the database or not
64 | options.filter_policy = leveldb::NewBloomFilterPolicy(10);
65 |
66 | //create a 40 mb cache (we use this on ~1gb devices)
67 | options.block_cache = leveldb::NewLRUCache(40 * 1024 * 1024);
68 |
69 | //create a 4mb write buffer, to improve compression and touch the disk less
70 | options.write_buffer_size = 4 * 1024 * 1024;
71 |
72 | //disable internal logging. The default logger will still print out things to a file
73 | options.info_log = new NullLogger();
74 |
75 | //use the new raw-zip compressor to write (and read)
76 | options.compressors[0] = new leveldb::ZlibCompressorRaw(-1);
77 |
78 | options.compressors[1] = zlibCompressorInstance;
79 | leveldb::Status status = leveldb::DB::Open(options, path, &db);
80 | env->ReleaseStringUTFChars(dbpath, path);
81 |
82 | if (!status.ok()) {
83 | throwException(env, status);
84 | } else {
85 | LOGI("Opened database");
86 | }
87 |
88 | return reinterpret_cast(db);
89 | }
90 |
91 | static void
92 | nativeClose(JNIEnv* env,
93 | jclass clazz,
94 | jlong dbPtr)
95 | {
96 | leveldb::DB* db = reinterpret_cast(dbPtr);
97 | if (db) {
98 | delete db;
99 | }
100 |
101 | LOGI("Database closed");
102 | }
103 |
104 | static jbyteArray
105 | nativeGet(JNIEnv * env,
106 | jclass clazz,
107 | jlong dbPtr,
108 | jlong snapshotPtr,
109 | jbyteArray keyObj)
110 | {
111 | leveldb::DB* db = reinterpret_cast(dbPtr);
112 | leveldb::ReadOptions options = leveldb::ReadOptions();
113 | options.decompress_allocator = new leveldb::DecompressAllocator();
114 | options.snapshot = reinterpret_cast(snapshotPtr);
115 |
116 | size_t keyLen = env->GetArrayLength(keyObj);
117 | jbyte *buffer = env->GetByteArrayElements(keyObj, NULL);
118 | jbyteArray result;
119 |
120 | leveldb::Slice key = leveldb::Slice((const char *)buffer, keyLen);
121 | leveldb::Iterator* iter = db->NewIterator(options);
122 | iter->Seek(key);
123 | if (iter->Valid() && key == iter->key()) {
124 | leveldb::Slice value = iter->value();
125 | size_t len = value.size();
126 | result = env->NewByteArray(len);
127 | env->SetByteArrayRegion(result, 0, len, (const jbyte *) value.data());
128 | } else {
129 | result = NULL;
130 | }
131 |
132 | env->ReleaseByteArrayElements(keyObj, buffer, JNI_ABORT);
133 | delete iter;
134 |
135 | return result;
136 | }
137 |
138 | static jbyteArray
139 | nativeGetBB(JNIEnv * env,
140 | jclass clazz,
141 | jlong dbPtr,
142 | jlong snapshotPtr,
143 | jobject keyObj)
144 | {
145 | leveldb::DB* db = reinterpret_cast(dbPtr);
146 | leveldb::ReadOptions options = leveldb::ReadOptions();
147 | options.snapshot = reinterpret_cast(snapshotPtr);
148 |
149 | jint keyPos = env->CallIntMethod(keyObj, gByteBuffer_positionMethodID);
150 | jint keyLimit = env->CallIntMethod(keyObj, gByteBuffer_limitMethodID);
151 | jboolean keyIsDirect = env->CallBooleanMethod(keyObj, gByteBuffer_isDirectMethodID);
152 | jbyteArray keyArray;
153 | void* key;
154 | if (keyIsDirect) {
155 | key = env->GetDirectBufferAddress(keyObj);
156 | keyArray = NULL;
157 | } else {
158 | keyArray = (jbyteArray) env->CallObjectMethod(keyObj, gByteBuffer_arrayMethodID);
159 | key = (void*) env->GetByteArrayElements(keyArray, NULL);
160 | }
161 |
162 | jbyteArray result;
163 | leveldb::Slice keySlice = leveldb::Slice((const char *) key + keyPos, keyLimit - keyPos);
164 | leveldb::Iterator* iter = db->NewIterator(options);
165 | iter->Seek(keySlice);
166 | if (iter->Valid() && keySlice == iter->key()) {
167 | leveldb::Slice value = iter->value();
168 | size_t len = value.size();
169 | result = env->NewByteArray(len);
170 | env->SetByteArrayRegion(result, 0, len, (const jbyte *) value.data());
171 | } else {
172 | result = NULL;
173 | }
174 |
175 | if (keyArray) {
176 | env->ReleaseByteArrayElements(keyArray, (jbyte*) key, JNI_ABORT);
177 | }
178 |
179 | delete iter;
180 |
181 | return result;
182 | }
183 |
184 | static void
185 | nativePut(JNIEnv *env,
186 | jclass clazz,
187 | jlong dbPtr,
188 | jbyteArray keyObj,
189 | jbyteArray valObj)
190 | {
191 | leveldb::DB* db = reinterpret_cast(dbPtr);
192 |
193 | size_t keyLen = env->GetArrayLength(keyObj);
194 | jbyte *keyBuf = env->GetByteArrayElements(keyObj, NULL);
195 |
196 | size_t valLen = env->GetArrayLength(valObj);
197 | jbyte *valBuf = env->GetByteArrayElements(valObj, NULL);
198 |
199 | leveldb::Status status = db->Put(leveldb::WriteOptions(),
200 | leveldb::Slice((const char *) keyBuf, keyLen),
201 | leveldb::Slice((const char *) valBuf, valLen));
202 |
203 | env->ReleaseByteArrayElements(keyObj, keyBuf, JNI_ABORT);
204 | env->ReleaseByteArrayElements(valObj, valBuf, JNI_ABORT);
205 |
206 | if (!status.ok()) {
207 | throwException(env, status);
208 | }
209 | }
210 |
211 | static void
212 | nativeDelete(JNIEnv *env,
213 | jclass clazz,
214 | jlong dbPtr,
215 | jbyteArray keyObj)
216 | {
217 | leveldb::DB* db = reinterpret_cast(dbPtr);
218 |
219 | size_t keyLen = env->GetArrayLength(keyObj);
220 | jbyte *buffer = env->GetByteArrayElements(keyObj, NULL);
221 |
222 | leveldb::Status status = db->Delete(leveldb::WriteOptions(), leveldb::Slice((const char *) buffer, keyLen));
223 | env->ReleaseByteArrayElements(keyObj, buffer, JNI_ABORT);
224 |
225 | if (!status.ok()) {
226 | throwException(env, status);
227 | }
228 | }
229 |
230 | static void
231 | nativeWrite(JNIEnv *env,
232 | jclass clazz,
233 | jlong dbPtr,
234 | jlong batchPtr)
235 | {
236 | leveldb::DB* db = reinterpret_cast(dbPtr);
237 |
238 | leveldb::WriteBatch *batch = (leveldb::WriteBatch *) batchPtr;
239 | leveldb::Status status = db->Write(leveldb::WriteOptions(), batch);
240 | if (!status.ok()) {
241 | throwException(env, status);
242 | }
243 | }
244 |
245 | static jlong
246 | nativeIterator(JNIEnv* env,
247 | jclass clazz,
248 | jlong dbPtr,
249 | jlong snapshotPtr)
250 | {
251 | leveldb::DB* db = reinterpret_cast(dbPtr);
252 | leveldb::ReadOptions options = leveldb::ReadOptions();
253 | options.snapshot = reinterpret_cast(snapshotPtr);
254 |
255 | leveldb::Iterator *iter = db->NewIterator(options);
256 | return reinterpret_cast(iter);
257 | }
258 |
259 | static jlong
260 | nativeGetSnapshot(JNIEnv *env,
261 | jclass clazz,
262 | jlong dbPtr)
263 | {
264 | leveldb::DB* db = reinterpret_cast(dbPtr);
265 | const leveldb::Snapshot* snapshot = db->GetSnapshot();
266 | return reinterpret_cast(snapshot);
267 | }
268 |
269 | static void
270 | nativeReleaseSnapshot(JNIEnv *env,
271 | jclass clazz,
272 | jlong dbPtr,
273 | jlong snapshotPtr)
274 | {
275 | leveldb::DB* db = reinterpret_cast(dbPtr);
276 | const leveldb::Snapshot *snapshot = reinterpret_cast(snapshotPtr);
277 | db->ReleaseSnapshot(snapshot);
278 | }
279 |
280 | static void
281 | nativeDestroy(JNIEnv *env,
282 | jclass clazz,
283 | jstring dbpath)
284 | {
285 | const char* path = env->GetStringUTFChars(dbpath,0);
286 | leveldb::Options options;
287 | options.create_if_missing = true;
288 | leveldb::Status status = DestroyDB(path, options);
289 | if (!status.ok()) {
290 | throwException(env, status);
291 | }
292 | }
293 |
294 | static JNINativeMethod sMethods[] =
295 | {
296 | { "nativeOpen", "(Ljava/lang/String;)J", (void*) nativeOpen },
297 | { "nativeClose", "(J)V", (void*) nativeClose },
298 | { "nativeGet", "(JJ[B)[B", (void*) nativeGet },
299 | { "nativeGet", "(JJLjava/nio/ByteBuffer;)[B", (void*) nativeGetBB },
300 | { "nativePut", "(J[B[B)V", (void*) nativePut },
301 | { "nativeDelete", "(J[B)V", (void*) nativeDelete },
302 | { "nativeWrite", "(JJ)V", (void*) nativeWrite },
303 | { "nativeIterator", "(JJ)J", (void*) nativeIterator },
304 | { "nativeGetSnapshot", "(J)J", (void*) nativeGetSnapshot },
305 | { "nativeReleaseSnapshot", "(JJ)V", (void*) nativeReleaseSnapshot },
306 | { "nativeDestroy", "(Ljava/lang/String;)V", (void*) nativeDestroy }
307 | };
308 |
309 | int
310 | register_com_litl_leveldb_DB(JNIEnv *env) {
311 | jclass clazz = env->FindClass("com/litl/leveldb/DB");
312 | if (!clazz) {
313 | LOGE("Can't find class com.litl.leveldb.DB");
314 | return 0;
315 | }
316 |
317 | return env->RegisterNatives(clazz, sMethods, NELEM(sMethods));
318 | }
319 |
--------------------------------------------------------------------------------
/library/src/main/jni/com_litl_leveldb_Iterator.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "leveldbjni.h"
5 |
6 | #include "leveldb/iterator.h"
7 |
8 | static void
9 | nativeDestroy(JNIEnv* env,
10 | jclass clazz,
11 | jlong ptr)
12 | {
13 | leveldb::Iterator* iter = reinterpret_cast(ptr);
14 |
15 | delete iter;
16 | }
17 |
18 | static void
19 | nativeSeekToFirst(JNIEnv* env,
20 | jclass clazz,
21 | jlong iterPtr)
22 | {
23 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
24 | iter->SeekToFirst();
25 | }
26 |
27 | static void
28 | nativeSeekToLast(JNIEnv* env,
29 | jclass clazz,
30 | jlong iterPtr)
31 | {
32 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
33 | iter->SeekToLast();
34 | }
35 |
36 | static void
37 | nativeSeek(JNIEnv* env,
38 | jclass clazz,
39 | jlong iterPtr,
40 | jbyteArray keyObj)
41 | {
42 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
43 |
44 | size_t keyLen = env->GetArrayLength(keyObj);
45 | jbyte *buffer = env->GetByteArrayElements(keyObj, NULL);
46 |
47 | iter->Seek(leveldb::Slice((const char *)buffer, keyLen));
48 | env->ReleaseByteArrayElements(keyObj, buffer, JNI_ABORT);
49 | }
50 |
51 | static jboolean
52 | nativeValid(JNIEnv* env,
53 | jclass clazz,
54 | jlong iterPtr)
55 | {
56 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
57 | return iter->Valid();
58 | }
59 |
60 | static void
61 | nativeNext(JNIEnv* env,
62 | jclass clazz,
63 | jlong iterPtr)
64 | {
65 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
66 | iter->Next();
67 | }
68 |
69 | static void
70 | nativePrev(JNIEnv* env,
71 | jclass clazz,
72 | jlong iterPtr)
73 | {
74 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
75 | iter->Prev();
76 | }
77 |
78 | static jbyteArray
79 | nativeKey(JNIEnv* env,
80 | jclass clazz,
81 | jlong iterPtr)
82 | {
83 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
84 | leveldb::Slice key = iter->key();
85 |
86 | size_t len = key.size();
87 | jbyteArray result = env->NewByteArray(len);
88 | env->SetByteArrayRegion(result, 0, len, (const jbyte *) key.data());
89 | return result;
90 | }
91 |
92 | static jbyteArray
93 | nativeValue(JNIEnv* env,
94 | jclass clazz,
95 | jlong iterPtr)
96 | {
97 | leveldb::Iterator* iter = reinterpret_cast(iterPtr);
98 | leveldb::Slice value = iter->value();
99 |
100 | size_t len = value.size();
101 | jbyteArray result = env->NewByteArray(len);
102 | env->SetByteArrayRegion(result, 0, len, (const jbyte *) value.data());
103 | return result;
104 | }
105 |
106 | static JNINativeMethod sMethods[] =
107 | {
108 | { "nativeDestroy", "(J)V", (void*) nativeDestroy },
109 | { "nativeSeekToFirst", "(J)V", (void*) nativeSeekToFirst },
110 | { "nativeSeekToLast", "(J)V", (void*) nativeSeekToLast },
111 | { "nativeSeek", "(J[B)V", (void*) nativeSeek },
112 | { "nativeValid", "(J)Z", (void*) nativeValid },
113 | { "nativeNext", "(J)V", (void*) nativeNext },
114 | { "nativePrev", "(J)V", (void*) nativePrev },
115 | { "nativeKey", "(J)[B", (void*) nativeKey },
116 | { "nativeValue", "(J)[B", (void*) nativeValue }
117 | };
118 |
119 | int
120 | register_com_litl_leveldb_Iterator(JNIEnv *env) {
121 | jclass clazz = env->FindClass("com/litl/leveldb/Iterator");
122 | if (!clazz) {
123 | LOGE("Can't find class com.litl.leveldb.Iterator");
124 | return 0;
125 | }
126 |
127 | return env->RegisterNatives(clazz, sMethods, NELEM(sMethods));
128 | }
129 |
--------------------------------------------------------------------------------
/library/src/main/jni/com_litl_leveldb_WriteBatch.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "leveldbjni.h"
8 |
9 | #include "leveldb/write_batch.h"
10 |
11 | static jmethodID gByteBuffer_isDirectMethodID;
12 | static jmethodID gByteBuffer_positionMethodID;
13 | static jmethodID gByteBuffer_limitMethodID;
14 | static jmethodID gByteBuffer_arrayMethodID;
15 |
16 | static jlong
17 | nativeCreate(JNIEnv* env,
18 | jclass clazz)
19 | {
20 | static bool gInited;
21 |
22 | if (!gInited) {
23 | jclass byteBuffer_Clazz = env->FindClass("java/nio/ByteBuffer");
24 | gByteBuffer_isDirectMethodID = env->GetMethodID(byteBuffer_Clazz,
25 | "isDirect", "()Z");
26 | gByteBuffer_positionMethodID = env->GetMethodID(byteBuffer_Clazz,
27 | "position", "()I");
28 | gByteBuffer_limitMethodID = env->GetMethodID(byteBuffer_Clazz,
29 | "limit", "()I");
30 | gByteBuffer_arrayMethodID = env->GetMethodID(byteBuffer_Clazz,
31 | "array", "()[B");
32 | gInited = true;
33 | }
34 |
35 | leveldb::WriteBatch* batch = new leveldb::WriteBatch();
36 | return reinterpret_cast(batch);
37 | }
38 |
39 | static void
40 | nativeDestroy(JNIEnv* env,
41 | jclass clazz,
42 | jlong ptr)
43 | {
44 | leveldb::WriteBatch* batch = reinterpret_cast(ptr);
45 |
46 | delete batch;
47 | }
48 |
49 | static void
50 | nativeDelete(JNIEnv* env,
51 | jclass clazz,
52 | jlong ptr,
53 | jobject buffer)
54 | {
55 | leveldb::WriteBatch* batch = reinterpret_cast(ptr);
56 |
57 | jint pos = env->CallIntMethod(buffer, gByteBuffer_positionMethodID);
58 | jint limit = env->CallIntMethod(buffer, gByteBuffer_limitMethodID);
59 | jboolean isDirect = env->CallBooleanMethod(buffer, gByteBuffer_isDirectMethodID);
60 | if (isDirect) {
61 | const char *bytes = (const char *) env->GetDirectBufferAddress(buffer);
62 | batch->Delete(leveldb::Slice(bytes + pos, limit - pos));
63 | } else {
64 | jbyteArray array = (jbyteArray) env->CallObjectMethod(buffer, gByteBuffer_arrayMethodID);
65 | jbyte *bytes = env->GetByteArrayElements(array, NULL);
66 | batch->Delete(leveldb::Slice((const char *) bytes + pos, limit - pos));
67 | env->ReleaseByteArrayElements(array, bytes, JNI_ABORT);
68 | }
69 | }
70 |
71 | static void
72 | nativePut(JNIEnv* env,
73 | jclass clazz,
74 | jlong ptr,
75 | jobject keyObj,
76 | jobject valObj)
77 | {
78 | leveldb::WriteBatch* batch = reinterpret_cast(ptr);
79 |
80 | jint keyPos = env->CallIntMethod(keyObj, gByteBuffer_positionMethodID);
81 | jint keyLimit = env->CallIntMethod(keyObj, gByteBuffer_limitMethodID);
82 | jboolean keyIsDirect = env->CallBooleanMethod(keyObj, gByteBuffer_isDirectMethodID);
83 | jbyteArray keyArray;
84 | void* key;
85 | if (keyIsDirect) {
86 | key = env->GetDirectBufferAddress(keyObj);
87 | keyArray = NULL;
88 | } else {
89 | keyArray = (jbyteArray) env->CallObjectMethod(keyObj, gByteBuffer_arrayMethodID);
90 | key = (void*) env->GetByteArrayElements(keyArray, NULL);
91 | }
92 |
93 | jint valPos = env->CallIntMethod(valObj, gByteBuffer_positionMethodID);
94 | jint valLimit = env->CallIntMethod(valObj, gByteBuffer_limitMethodID);
95 | jboolean valIsDirect = env->CallBooleanMethod(valObj, gByteBuffer_isDirectMethodID);
96 | jbyteArray valArray;
97 | void* val;
98 | if (valIsDirect) {
99 | val = env->GetDirectBufferAddress(valObj);
100 | valArray = NULL;
101 | } else {
102 | valArray = (jbyteArray) env->CallObjectMethod(valObj, gByteBuffer_arrayMethodID);
103 | val = (void*) env->GetByteArrayElements(valArray, NULL);
104 | }
105 |
106 | batch->Put(leveldb::Slice((const char *) key + keyPos, keyLimit - keyPos),
107 | leveldb::Slice((const char *) val + valPos, valLimit - valPos));
108 |
109 | if (keyArray) {
110 | env->ReleaseByteArrayElements(keyArray, (jbyte*) key, JNI_ABORT);
111 | }
112 | if (valArray) {
113 | env->ReleaseByteArrayElements(valArray, (jbyte*) val, JNI_ABORT);
114 | }
115 | }
116 |
117 | static void
118 | nativeClear(JNIEnv* env,
119 | jclass clazz,
120 | jlong ptr)
121 | {
122 | leveldb::WriteBatch* batch = reinterpret_cast(ptr);
123 | batch->Clear();
124 | }
125 |
126 | static JNINativeMethod sMethods[] =
127 | {
128 | { "nativeCreate", "()J", (void*) nativeCreate },
129 | { "nativeDestroy", "(J)V", (void*) nativeDestroy },
130 | { "nativeDelete", "(JLjava/nio/ByteBuffer;)V", (void*) nativeDelete },
131 | { "nativePut", "(JLjava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)V", (void*) nativePut },
132 | { "nativeClear", "(J)V", (void*) nativeClear }
133 | };
134 |
135 | int
136 | register_com_litl_leveldb_WriteBatch(JNIEnv *env) {
137 | jclass clazz = env->FindClass("com/litl/leveldb/WriteBatch");
138 | if (!clazz) {
139 | LOGE("Can't find class com.litl.leveldb.WriteBatch");
140 | return 0;
141 | }
142 |
143 | return env->RegisterNatives(clazz, sMethods, NELEM(sMethods));
144 | }
145 |
--------------------------------------------------------------------------------
/library/src/main/jni/debug_conf.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/4/12.
3 | //
4 |
5 | #ifndef CONVARTER_DEBUG_CONF_H
6 | #define CONVARTER_DEBUG_CONF_H
7 |
8 | //Chunk
9 | //#define LOG_CHUNK_OPERATION
10 | #define LOG_CHUNK_LOADSAVE
11 |
12 | //World
13 | //#define LOG_SAVDB_OPERATION
14 | #define LOG_SAVDB_LOADSAVE
15 | #define LOG_SAVDB_LRU
16 |
17 | #ifdef LOG_CHUNK_OPERATION
18 | #ifndef LOG_CHUNK_LOADSAVE
19 | #define LOG_CHUNK_LOADSAVE
20 | #endif
21 | #endif
22 |
23 | #ifdef LOG_SAVDB_OPERATION
24 | #ifndef LOG_SAVDB_LOADSAVE
25 | #define LOG_SAVDB_LOADSAVE
26 | #endif
27 | #ifndef LOG_SAVDB_LRU
28 | #define LOG_SAVDB_LRU
29 | #endif
30 | #endif
31 |
32 | #define CAT(x, y) x y
33 |
34 | #endif //CONVARTER_DEBUG_CONF_H
35 |
--------------------------------------------------------------------------------
/library/src/main/jni/leveldbjni.cc:
--------------------------------------------------------------------------------
1 | #include "leveldbjni.h"
2 |
3 | extern int register_com_litl_leveldb_DB(JNIEnv *env);
4 |
5 | extern int register_com_litl_leveldb_WriteBatch(JNIEnv *env);
6 |
7 | extern int register_com_litl_leveldb_Iterator(JNIEnv *env);
8 |
9 | extern int register_com_litl_leveldb_Chunk(JNIEnv *env);
10 |
11 | jint
12 | throwException(JNIEnv *env, leveldb::Status status) {
13 | const char *exceptionClass;
14 |
15 | if (status.IsNotFound()) {
16 | exceptionClass = "com/litl/leveldb/NotFoundException";
17 | } else if (status.IsCorruption()) {
18 | exceptionClass = "com/litl/leveldb/DatabaseCorruptException";
19 | } else if (status.IsIOError()) {
20 | exceptionClass = "java/io/IOException";
21 | } else {
22 | return 0;
23 | }
24 |
25 | jclass clazz = env->FindClass(exceptionClass);
26 | if (!clazz) {
27 | LOGE("Can't find exception class %s", exceptionClass);
28 | return -1;
29 | }
30 |
31 | return env->ThrowNew(clazz, status.ToString().c_str());
32 | }
33 |
34 | jint JNI_OnLoad(JavaVM *vm, void *reserved) {
35 | JNIEnv *env;
36 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) {
37 | return -1;
38 | }
39 |
40 | register_com_litl_leveldb_DB(env);
41 | register_com_litl_leveldb_WriteBatch(env);
42 | register_com_litl_leveldb_Iterator(env);
43 | register_com_litl_leveldb_Chunk(env);
44 |
45 | return JNI_VERSION_1_6;
46 | }
47 |
--------------------------------------------------------------------------------
/library/src/main/jni/leveldbjni.h:
--------------------------------------------------------------------------------
1 | #ifndef LEVELDBJNI_H_
2 | #define LEVELDBJNI_H_
3 |
4 | #include
5 | #include
6 | #include "leveldb/status.h"
7 |
8 | # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
9 | #define LOG_TAG "LevelDB"
10 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
11 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
12 |
13 | jint throwException(JNIEnv* env, leveldb::Status status);
14 |
15 | #endif /* LEVELDBJNI_H_ */
16 |
--------------------------------------------------------------------------------
/library/src/main/jni/mapkey.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/3/27.
3 | //
4 |
5 | #ifndef CONVARTER_MAPKEY_H
6 | #define CONVARTER_MAPKEY_H
7 |
8 | #include
9 |
10 | typedef struct {
11 | int32_t x_div16;
12 | int32_t z_div16;
13 | int32_t dimension;
14 | } mapkey_t;
15 |
16 | #define LDBKEY_STRUCT(x, z, dim) mapkey_t{x >> 4, z >> 4, dim}
17 |
18 | #define LDBKEY_SUBCHUNK(k, ydiv) \
19 | char key[14];\
20 | if(true){\
21 | char* ptr = key;\
22 | *(int32_t*)ptr = k.x_div16;\
23 | ptr+=4;\
24 | *(int32_t*)ptr = k.z_div16;\
25 | ptr += 4;\
26 | if(k.dimension != 0){\
27 | *(int32_t*)ptr = k.dimension;\
28 | ptr += 4;\
29 | }\
30 | *ptr = 0x2f;\
31 | ptr++;\
32 | *ptr = ydiv;\
33 | }
34 |
35 | #define LDBKEY_VERSION(k) \
36 | char key_db[14];\
37 | if(true){\
38 | char* ptr = key_db;\
39 | *(int32_t*)ptr = k.x_div16;\
40 | ptr+=4;\
41 | *(int32_t*)ptr = k.z_div16;\
42 | ptr += 4;\
43 | if(k.dimension != 0){\
44 | *(int32_t*)ptr = k.dimension;\
45 | ptr += 4;\
46 | }\
47 | *ptr = 0x76;\
48 | ptr++;\
49 | }
50 |
51 | #endif //CONVARTER_MAPKEY_H
52 |
--------------------------------------------------------------------------------
/library/src/main/jni/qstr.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/3/24.
3 | //
4 |
5 | #ifndef CONVARTER_QSTR_H
6 | #define CONVARTER_QSTR_H
7 |
8 | typedef struct {
9 | unsigned int length;
10 | char *str;
11 | } qstr;
12 |
13 | typedef struct {
14 | unsigned int length;
15 | const char *str;
16 | } qcstr;
17 |
18 | typedef struct {
19 | unsigned int length;
20 | unsigned char *str;
21 | } qustr;
22 |
23 | #endif //CONVARTER_QSTR_H
24 |
--------------------------------------------------------------------------------
/library/src/main/jni/subchunk.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/12/26.
3 | //
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | ////////////////
12 | //
13 |
14 | char SubChunk::pattern_name[] = {0x0a, 0x00, 0x00, 0x08, 0x04, 0x00, 'n', 'a', 'm',
15 | 'e'};
16 | char SubChunk::pattern_val[] = {0x02, 0x03, 0x00, 'v', 'a', 'l'};
17 |
18 | const int32_t SubChunk::msk[] = {0b1, 0b11, 0b111, 0b1111, 0b11111, 0b111111, 0b1111111,
19 | 0b11111111,
20 | 0b111111111, 0b1111111111, 0b11111111111,
21 | 0b111111111111,
22 | 0b1111111111111, 0b11111111111111, 0b11111111111111};
23 |
24 | SubChunk::SubChunk(const std::string &buf, bool hasMultiStorage) {
25 |
26 | storages[0].storage = nullptr;
27 | storages[0].palette = nullptr;
28 |
29 | const char *cbuf = buf.c_str();
30 | const char *ptr = cbuf + 1;
31 | if (hasMultiStorage) {
32 | ptr++;
33 | loadStorage(ptr, cbuf + buf.length(), 0);
34 | } else {
35 | loadStorage(ptr, cbuf + buf.length(), 0);
36 | }
37 | }
38 |
39 | SubChunk::~SubChunk() {
40 | delete[] storages[0].storage;
41 | delete[] storages[0].palette;
42 | }
43 |
44 | const char *SubChunk::loadStorage(const char *ptr, const char *max, int which) {
45 |
46 | #ifdef DEBUG_SUBCHUNK
47 | //lowest bit should be 0.
48 | if (((*ptr) & 1) != 0 || max - ptr < 2) {
49 | //
50 | }
51 | #endif
52 |
53 | //Length of each block, in bits.
54 | storages[which].blen = static_cast(*ptr >> 1);
55 |
56 | ptr++;
57 |
58 | //How many uint32s do it need to store all blocks?
59 | div_t res = div(4096, (32 / storages[which].blen));
60 | size_t bufsize = static_cast(res.quot);
61 | if (res.rem != 0)bufsize++;
62 |
63 | #ifdef DEBUG_SUBCHUNK
64 | if (max - ptr < (bufsize << 2)) {
65 | //
66 | }
67 | #endif
68 |
69 | //Copy 'em up. bufsize is 4-bytes long and memcpy requires count of bytes so x4.
70 | storages[which].storage = new uint32_t[bufsize];
71 | memcpy(storages[which].storage, ptr, bufsize << 2);
72 |
73 | //Move the pointer to the end of uint32s.
74 | ptr += bufsize << 2;
75 |
76 | //Here records how many types of blocks are in this subchunk.
77 | storages[which].types = *(uint16_t *) ptr;
78 | ptr += 4;
79 |
80 | storages[which].palette = new uint16_t[storages[which].types];
81 |
82 | for (uint16_t i = 0; i < storages[which].types; i++) {
83 | #ifdef DEBUG_SUBCHUNK
84 | if (max - ptr < sizeof(pattern_name)) {
85 | //
86 | }
87 | if (memcmp(ptr, pattern_name, sizeof(pattern_name)) != 0) {
88 | //Something has gone wrong.
89 | }
90 | #endif
91 | ptr += sizeof(pattern_name);
92 | qstr name;
93 | #ifdef DEBUG_SUBCHUNK
94 | if (max - ptr < 2) {
95 | //
96 | }
97 | #endif
98 | name.length = *(uint16_t *) ptr;
99 | ptr += 2;
100 | #ifdef DEBUG_SUBCHUNK
101 | if (max - ptr < name.length) {
102 | //
103 | }
104 | #endif
105 | name.str = new char[name.length];
106 | memcpy(name.str, ptr, name.length);
107 | ptr += name.length;
108 | #ifdef DEBUG_SUBCHUNK
109 | if (max - ptr < sizeof(pattern_val) + 3) {
110 | //
111 | }
112 | if (memcmp(ptr, pattern_val, sizeof(pattern_val)) != 0) {
113 | //
114 | }
115 | #endif
116 | ptr += sizeof(pattern_val);
117 | storages[which].palette[i] = BlockNames::resolve(name);
118 | delete[] name.str;
119 | storages[which].palette[i] <<= 8;
120 | storages[which].palette[i] |= *ptr;
121 | ptr += 3;
122 | }
123 | return ptr;
124 | }
125 |
126 | uint16_t
127 | SubChunk::getBlockCode(unsigned char x, unsigned char y, unsigned char z, uint8_t which) {
128 |
129 | //If there's only one storage than getBlockCode or other storages can just return 0.
130 | if (which == 0 && storages[which].storage == nullptr)return 0;
131 |
132 | BlockStorage &thiz = storages[which];
133 |
134 | //Get the index among all blocks.
135 | int index = x;
136 | index <<= 4;
137 | index |= z;
138 | index <<= 4;
139 | index |= y;
140 |
141 | //How many blox can each stick hold.
142 | int capa = (32 / thiz.blen);
143 |
144 | //Stick that hold this block.
145 | uint32_t stick = *(thiz.storage + (index / capa));
146 |
147 | //The bits for this block is index in palette.
148 | //No need care about endian but not very efficiency, i guess?
149 | uint32_t ind = (stick >> (index % capa * thiz.blen)) & msk[thiz.blen - 1];
150 |
151 | //Return the record.
152 | return thiz.palette[ind];
153 | }
154 |
155 | uint16_t SubChunk::getBlock(unsigned char x, unsigned char y, unsigned char z) {
156 | return getBlockCode(x, y, z, 0);
157 | }
158 |
159 | uint16_t SubChunk::getBlock3(unsigned char x, unsigned char y, unsigned char z,
160 | unsigned char layer) {
161 | if (layer != 0 && layer != 1)return 0;
162 | return getBlockCode(x, y, z, layer);
163 | }
164 |
--------------------------------------------------------------------------------
/library/src/main/jni/subchunk.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by barco on 2018/12/24.
3 | //
4 |
5 | #ifndef CONVARTER_SUBCHUNK_H
6 | #define CONVARTER_SUBCHUNK_H
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | #define DEBUG_SUBCHUNK
13 |
14 | struct BlockStorage {
15 | uint8_t blen;//Length per block
16 | uint16_t types;//Types of blocks
17 | uint16_t *palette;//Palette
18 | uint32_t *storage;//Storage
19 | };
20 |
21 | class SubChunk {
22 | private:
23 |
24 | static const int32_t msk[15];
25 |
26 | static char pattern_name[10];
27 |
28 | static char pattern_val[6];
29 |
30 | BlockStorage storages[1];
31 |
32 | const char *loadStorage(const char *ptr, const char *max, int which);
33 |
34 | uint16_t getBlockCode(unsigned char x, unsigned char y, unsigned char z, uint8_t which);
35 |
36 | public:
37 | SubChunk(const std::string &buf, bool hasMultiStorage);
38 |
39 | ~SubChunk();
40 |
41 | uint16_t getBlock(unsigned char x, unsigned char y, unsigned char z);
42 |
43 | uint16_t
44 | getBlock3(unsigned char x, unsigned char y, unsigned char z, unsigned char layer);
45 |
46 | };
47 |
48 | #endif //CONVARTER_SUBCHUNK_H
49 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':library'
2 |
--------------------------------------------------------------------------------