diff --git a/.gitignore b/.gitignore index 15f02b0..a72e5fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .gradle local.properties build +lib/.cxx diff --git a/lib/build.gradle b/lib/build.gradle index 9a58b87..395b15c 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -59,7 +59,7 @@ android { } externalNativeBuild { cmake { - path file('src/cpp/CMakeLists.txt') + path file('src/main/cpp/CMakeLists.txt') version '3.18.1' } } @@ -285,5 +285,5 @@ task checkCurrentJavaVersion() { task generateHeaderFilesFromJavaWrapper(type: Exec) { workingDir "${projectDir}/src/main/java/org/kiwix/" - commandLine 'bash', '-c', "javac -h ${buildDir}/include/javah_generated/ -d ${buildDir}/kiwixlib/ kiwixlib/Book.java kiwixlib/DirectAccessInfo.java kiwixlib/Filter.java kiwixlib/JNIICU.java kiwixlib/JNIKiwixBool.java kiwixlib/JNIKiwixException.java kiwixlib/JNIKiwixInt.java kiwixlib/JNIKiwixReader.java kiwixlib/JNIKiwixSearcher.java kiwixlib/JNIKiwixServer.java kiwixlib/JNIKiwixString.java kiwixlib/Library.java kiwixlib/Manager.java" + commandLine 'bash', '-c', "javac -h ${buildDir}/include/javah_generated/ -d ${buildDir}/libzim/ libzim/Archive.java libzim/Blob.java libzim/Entry.java libzim/Item.java libzim/ZimFileFormatException.java" } diff --git a/lib/src/main/cpp/CMakeLists.txt b/lib/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..cfa907f --- /dev/null +++ b/lib/src/main/cpp/CMakeLists.txt @@ -0,0 +1,53 @@ + +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) +cmake_minimum_required(VERSION 3.18.1) + +set(CMAKE_ANDROID_STL_TYPE llvm-libc++_static) + +project("libzim_wrapper") + +add_library( + libzim_wrapper + + SHARED + common.cpp + libzim/archive.cpp + libzim/entry.cpp + libzim/item.cpp + libzim/blob.cpp +) + +find_library(libzim + zim + PATHS + ${BUILD_DIR}/jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libzim) +if (NOT libzim) + message(FATAL_ERROR "libzim not found!") +endif() +add_library(libzim SHARED IMPORTED) + +set_property(TARGET + libzim + PROPERTY + IMPORTED_LOCATION + ${BUILD_DIR}/jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libzim/libzim.so) + +include_directories( +${CMAKE_SOURCE_DIR} +${BUILD_DIR}/include/libkiwix +${BUILD_DIR}/include/libzim +${BUILD_DIR}/include/javah_generated +#${CMAKE_SOURCE_DIR}/include/utils +) + +find_library( + log-lib + log) + +target_link_libraries( + libzim_wrapper + libzim + + ${log-lib} + ) + diff --git a/lib/src/main/cpp/book.cpp b/lib/src/main/cpp/book.cpp index 157cc52..238f490 100644 --- a/lib/src/main/cpp/book.cpp +++ b/lib/src/main/cpp/book.cpp @@ -23,6 +23,7 @@ #include "utils.h" #include "book.h" +#include JNIEXPORT void JNICALL Java_org_kiwix_kiwixlib_Book_allocate( @@ -46,7 +47,7 @@ METHOD(void, Book, update__Lorg_kiwix_kiwixlib_Book_2, jobject otherBook) METHOD(void, Book, update__Lorg_kiwix_kiwixlib_JNIKiwixReader_2, jobject reader) { - BOOK->update(**Handle::getHandle(env, reader)); + BOOK->update(**Handle::getHandle(env, reader)); } #define GETTER(retType, name) JNIEXPORT retType JNICALL \ diff --git a/lib/src/main/cpp/common.cpp b/lib/src/main/cpp/common.cpp new file mode 100644 index 0000000..f510798 --- /dev/null +++ b/lib/src/main/cpp/common.cpp @@ -0,0 +1,4 @@ + +#include + +std::mutex globalLock; diff --git a/lib/src/main/cpp/libzim/archive.cpp b/lib/src/main/cpp/libzim/archive.cpp new file mode 100644 index 0000000..065393d --- /dev/null +++ b/lib/src/main/cpp/libzim/archive.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2013 Emmanuel Engelhart + * Copyright (C) 2017 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "org_kiwix_libzim_Archive.h" + +#include + +#include +#include + +#include +#include + +/* Kiwix Reader JNI functions */ +JNIEXPORT jlong JNICALL Java_org_kiwix_libzim_Archive_getNativeArchive( + JNIEnv* env, jobject obj, jstring filename) +{ + std::string cPath = TO_C(filename); + + LOG("Attempting to create reader with: %s", cPath.c_str()); + Lock l; + try { + zim::Archive* reader = new zim::Archive(cPath); + return reinterpret_cast(new Handle(reader)); + } catch (std::exception& e) { + LOG("Error opening ZIM file"); + LOG("%s", e.what()); + return 0; + } +} + +namespace +{ + +int jni2fd(const jobject& fdObj, JNIEnv* env) +{ + jclass class_fdesc = env->FindClass("java/io/FileDescriptor"); + jfieldID field_fd = env->GetFieldID(class_fdesc, "fd", "I"); + if ( field_fd == NULL ) + { + env->ExceptionClear(); + // Under Android the (private) 'fd' field of java.io.FileDescriptor has been + // renamed to 'descriptor'. See, for example, + // https://android.googlesource.com/platform/libcore/+/refs/tags/android-8.1.0_r1/ojluni/src/main/java/java/io/FileDescriptor.java#55 + field_fd = env->GetFieldID(class_fdesc, "descriptor", "I"); + } + return env->GetIntField(fdObj, field_fd); +} + +} // unnamed namespace + +JNIEXPORT jlong JNICALL Java_org_kiwix_libzim_Archive_getNativeArchiveByFD( + JNIEnv* env, jobject obj, jobject fdObj) +{ +#ifndef _WIN32 + int fd = jni2fd(fdObj, env); + + LOG("Attempting to create reader with fd: %d", fd); + Lock l; + try { + zim::Archive* reader = new zim::Archive(fd); + return reinterpret_cast(new Handle(reader)); + } catch (std::exception& e) { + LOG("Error opening ZIM file"); + LOG("%s", e.what()); + return 0; + } +#else + jclass exception = env->FindClass("java/lang/UnsupportedOperationException"); + env->ThrowNew(exception, "org.kiwix.libzim.Archive.getNativeArchiveByFD() is not supported under Windows"); + return 0; +#endif +} + +JNIEXPORT jlong JNICALL Java_org_kiwix_libzim_Archive_getNativeArchiveEmbedded( + JNIEnv* env, jobject obj, jobject fdObj, jlong offset, jlong size) +{ +#ifndef _WIN32 + int fd = jni2fd(fdObj, env); + + LOG("Attempting to create reader with fd: %d", fd); + Lock l; + try { + zim::Archive* reader = new zim::Archive(fd, offset, size); + return reinterpret_cast(new Handle(reader)); + } catch (std::exception& e) { + LOG("Error opening ZIM file"); + LOG("%s", e.what()); + return 0; + } +#else + jclass exception = env->FindClass("java/lang/UnsupportedOperationException"); + env->ThrowNew(exception, "org.kiwix.libzim.Archive.getNativeArchiveEmbedded() is not supported under Windows"); + return 0; +#endif +} + +JNIEXPORT void JNICALL +Java_org_kiwix_libzim_Archive_dispose(JNIEnv* env, jobject thisObj) +{ + dispose(env, thisObj); +} + +#define THIS (Handle::getHandle(env, thisObj)) +#define GETTER(retType, name) JNIEXPORT retType JNICALL \ +Java_org_kiwix_libzim_Archive_##name (JNIEnv* env, jobject thisObj) \ +{ \ + return TO_JNI(THIS->name()); \ +} + + +GETTER(jstring, getFilename) +GETTER(jlong, getFilesize) +GETTER(jint, getAllEntryCount) +GETTER(jint, getEntryCount) +GETTER(jint, getArticleCount) +GETTER(jint, getMediaCount) + +METHOD0(jstring, Archive, getUuid) { + return TO_JNI(std::string(THIS->getUuid())); +} + +METHOD(jstring, Archive, getMetadata, jstring name) { + return TO_JNI(THIS->getMetadata(TO_C(name))); +} + +METHOD(jobject, Archive, getMetadataItem, jstring name) { + auto item = THIS->getMetadataItem(TO_C(name)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Item", item); + return obj; +} + +GETTER(jobjectArray, getMetadataKeys) + +METHOD(jobject, Archive, getIllustrationItem, jint size) { + auto item = THIS->getIllustrationItem(TO_C(size)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Item", item); + return obj; +} + +METHOD(jboolean, Archive, hasIllustration, jint size) { + return TO_JNI(THIS->hasIllustration(TO_C(size))); +} + +GETTER(jlongArray, getIllustrationSizes) + +METHOD(jobject, Archive, getEntryByPath, jlong index) { + auto entry = THIS->getEntryByPath(TO_C(index)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} + +METHOD(jobject, Archive, getEntryByPath, jstring path) { + auto entry = THIS->getEntryByPath(TO_C(path)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} + +METHOD(jobject, Archive, getEntryByTitle, jlong index) { + auto entry = THIS->getEntryByTitle(TO_C(index)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} + +METHOD(jobject, Archive, getEntryByTitle, jstring title) { + auto entry = THIS->getEntryByTitle(TO_C(title)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} + +METHOD(jobject, Archive, getEntryByClusterOrder, jlong index) { + auto entry = THIS->getEntryByClusterOrder(TO_C(index)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} + +METHOD0(jobject, Archive, getMainEntry) { + auto entry = THIS->getMainEntry(); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} + +METHOD0(jobject, Archive, getRandomEntry) { + auto entry = THIS->getRandomEntry(); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} + +METHOD(jboolean, Archive, hasEntryByPath, jstring path) { + return TO_JNI(THIS->hasEntryByPath(TO_C(path))); +} + +METHOD(jboolean, Archive, hasEntryByTitle, jstring title) { + return TO_JNI(THIS->hasEntryByPath(TO_C(title))); +} + +GETTER(jboolean, hasMainEntry) + +METHOD(jboolean, Archive, hasIllustration, jlong size) { + return TO_JNI(THIS->hasIllustration(TO_C(size))); +} + +GETTER(jboolean, hasFulltextIndex) +GETTER(jboolean, hasTitleIndex) +GETTER(jboolean, hasChecksum) +GETTER(jstring, getChecksum) +GETTER(jboolean, check) + +GETTER(jboolean, isMultiPart) +GETTER(jboolean, hasNewNamespaceScheme) + + + diff --git a/lib/src/main/cpp/libzim/blob.cpp b/lib/src/main/cpp/libzim/blob.cpp new file mode 100644 index 0000000..27f5ee6 --- /dev/null +++ b/lib/src/main/cpp/libzim/blob.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013 Emmanuel Engelhart + * Copyright (C) 2017 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "org_kiwix_libzim_Blob.h" + +#include "utils.h" + +#include + +#include + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_libzim_Blob_dispose(JNIEnv* env, jobject thisObj) +{ + dispose(env, thisObj); +} + +#define THIS (Handle::getHandle(env, thisObj)) +#define GETTER(retType, name) JNIEXPORT retType JNICALL \ +Java_org_kiwix_libzim_Blob__##name (JNIEnv* env, jobject thisObj) \ +{ \ + return TO_JNI(THIS->name()); \ +} + +METHOD0(jstring, Blob, getData) { + return TO_JNI(std::string(**THIS)); +} +GETTER(jlong, size) diff --git a/lib/src/main/cpp/libzim/entry.cpp b/lib/src/main/cpp/libzim/entry.cpp new file mode 100644 index 0000000..d71f0d5 --- /dev/null +++ b/lib/src/main/cpp/libzim/entry.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 Emmanuel Engelhart + * Copyright (C) 2017 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "org_kiwix_libzim_Entry.h" + +#include + +#include + +#include +#include + +#define NATIVE_TYPE zim::Entry + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_libzim_Entry_dispose(JNIEnv* env, jobject thisObj) +{ + dispose(env, thisObj); +} + +#define THIS (Handle::getHandle(env, thisObj)) +#define GETTER(retType, name) JNIEXPORT retType JNICALL \ +Java_org_kiwix_libzim_Entry__##name (JNIEnv* env, jobject thisObj) \ +{ \ + return TO_JNI(THIS->name()); \ +} + + +GETTER(jboolean, isRedirect) +GETTER(jstring, getTitle) +GETTER(jstring, getPath) +METHOD(jobject, Entry, getItem, jboolean follow) { + auto item = THIS->getItem(TO_C(follow)); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Item", item); + return obj; +} + +METHOD0(jobject, Entry, getRedirect) { + auto item = THIS->getRedirect(); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Item", item); + return obj; +} + +METHOD0(jobject, Entry, getRedirectEntry) { + auto entry = THIS->getRedirectEntry(); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Entry", entry); + return obj; +} diff --git a/lib/src/main/cpp/libzim/item.cpp b/lib/src/main/cpp/libzim/item.cpp new file mode 100644 index 0000000..1168a2d --- /dev/null +++ b/lib/src/main/cpp/libzim/item.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Emmanuel Engelhart + * Copyright (C) 2017 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "org_kiwix_libzim_Item.h" + +#include + +#include + +#include + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_libzim_Item_dispose(JNIEnv* env, jobject thisObj) +{ + dispose(env, thisObj); +} + +#define THIS (Handle::getHandle(env, thisObj)) +#define GETTER(retType, name) JNIEXPORT retType JNICALL \ +Java_org_kiwix_libzim_Item__##name (JNIEnv* env, jobject thisObj) \ +{ \ + return TO_JNI(THIS->name()); \ +} + +GETTER(jstring, getTitle) +GETTER(jstring, getPath) +GETTER(jstring, getMimetype) + +METHOD0(jobject, Item, getData) { + auto blob = THIS->getData(); + auto obj = CREATE_WRAPPER("org/kiwix/libzim/Blob", blob); + return obj; +} + +GETTER(jlong, getSize) diff --git a/lib/src/main/cpp/utils.h b/lib/src/main/cpp/utils.h index 232071d..e5475e8 100644 --- a/lib/src/main/cpp/utils.h +++ b/lib/src/main/cpp/utils.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #if __ANDROID__ @@ -68,11 +69,11 @@ void dispose(JNIEnv* env, jobject thisObj) } #define METHOD0(retType, class, name) \ -JNIEXPORT retType JNICALL Java_org_kiwix_kiwixlib_##class##_##name( \ +JNIEXPORT retType JNICALL Java_org_kiwix_libzim_##class##_##name( \ JNIEnv* env, jobject thisObj) #define METHOD(retType, class, name, ...) \ -JNIEXPORT retType JNICALL Java_org_kiwix_kiwixlib_##class##_##name( \ +JNIEXPORT retType JNICALL Java_org_kiwix_libzim_##class##_##name( \ JNIEnv* env, jobject thisObj, __VA_ARGS__) inline jfieldID getHandleField(JNIEnv* env, jobject obj) @@ -88,6 +89,9 @@ inline jobjectArray createArray(JNIEnv* env, size_t length, const std::string& t return env->NewObjectArray(length, c, NULL); } + +// A mixin class which will lock the globalLock when a instance is created +// This avoid the cration of two instance inheriting from Lock in the same time. class Lock : public std::unique_lock { public: @@ -97,14 +101,19 @@ class Lock : public std::unique_lock template class LockedHandle; + +/* + * A handle to a shared_ptr + * Not usable by itself, you must get a LockedHandle to access the value. + */ template class Handle { protected: - T* h; + std::shared_ptr value; public: - Handle(T* h) : h(h){}; + Handle(T* v) : value(v){}; // No destructor. This must and will be handled by dispose method. @@ -118,34 +127,42 @@ class Handle { auto lHandle = getHandle(env, obj); auto handle = lHandle.h; - delete handle->h; delete handle; } friend class LockedHandle; }; +/* + * A locked handle. + * Only one LockedHandle can exist at the same time. + * As LockedHandle is the + */ template struct LockedHandle : public Lock { Handle* h; LockedHandle(Handle* h) : h(h) {} - T* operator->() { return h->h; } - T* operator*() { return h->h; } - operator bool() const { return (h->h != nullptr); } - operator T*() const { return h->h; } + T* operator->() { return h->value.get(); } + T* operator*() { return h->value.get(); } + operator bool() const { return (h->value); } + operator T*() const { return h->value.get(); } }; +// --------------------------------------------------------------------------- +// Convert things to JAVA +// --------------------------------------------------------------------------- + template struct JType { }; template<> struct JType{ typedef jboolean type_t; }; -template<> struct JType{ typedef jint type_t; }; -template<> struct JType{ typedef jlong type_t; }; +template<> struct JType{ typedef jint type_t; }; +template<> struct JType{ typedef jlong type_t; }; template<> struct JType { typedef jlong type_t; }; template<> struct JType { typedef jlong type_t; }; template<> struct JType{ typedef jstring type_t; }; -template<> struct JType>{ typedef jobjectArray type_t; }; -template + +template inline typename JType::type_t c2jni(const T& val, JNIEnv* env) { return static_cast::type_t>(val); } @@ -159,6 +176,70 @@ inline jstring c2jni(const std::string& val, JNIEnv* env) return env->NewStringUTF(val.c_str()); } + +template +struct JTypeArray {}; +template<> struct JTypeArray{ + typedef jbooleanArray type_t; + static jbooleanArray createArray(JNIEnv* env, size_t length) { + return env->NewBooleanArray(length); + } + static void setArray(JNIEnv* env, jbooleanArray array, const bool* data, size_t length) { + env->SetBooleanArrayRegion(array, 0, length, reinterpret_cast(data)); + } +}; +template<> struct JTypeArray{ + typedef jintArray type_t; + static jintArray createArray(JNIEnv* env, size_t length) { + return env->NewIntArray(length); + } + static void setArray(JNIEnv* env, jintArray array, const int32_t* data, size_t length) { + env->SetIntArrayRegion(array, 0, length, data); + } +}; +template<> struct JTypeArray{ + typedef jlongArray type_t; + static jlongArray createArray(JNIEnv* env, size_t length) { + return env->NewLongArray(length); + } + static void setArray(JNIEnv* env, jlongArray array, const int64_t* data, size_t length) { + env->SetLongArrayRegion(array, 0, length, data); + } +}; +template<> struct JTypeArray { + typedef jlongArray type_t; + static jlongArray createArray(JNIEnv* env, size_t length) { + return env->NewLongArray(length); + } + static void setArray(JNIEnv* env, jlongArray array, const uint64_t* data, size_t length) { + env->SetLongArrayRegion(array, 0, length, reinterpret_cast(data)); + } +}; +template<> struct JTypeArray { + typedef jlongArray type_t; + static jlongArray createArray(JNIEnv* env, size_t length) { + return env->NewLongArray(length); + } + static void setArray(JNIEnv* env, jlongArray array, const uint32_t* data, size_t length) { + std::vector temp(data, data+length); + env->SetLongArrayRegion(array, 0, length, temp.data()); + } +}; +template<> struct JTypeArray{ + typedef jobjectArray type_t; + static jobjectArray createArray(JNIEnv* env, size_t length) { + return ::createArray(env, length, "java/lang/String"); + } + static void setArray(JNIEnv* env, jobjectArray array, const std::string* data, size_t length) { + size_t index = 0; + for(size_t index=0; indexSetObjectArrayElement(array, index, jElem); + } + } +}; + +/* template<> inline jobjectArray c2jni(const std::vector& val, JNIEnv* env) { @@ -169,8 +250,31 @@ inline jobjectArray c2jni(const std::vector& val, JNIEnv* env) env->SetObjectArrayElement(array, index++, jElem); } return array; +}*/ + +template +inline typename JTypeArray::type_t c2jni(const std::vector& val, JNIEnv* env) +{ + auto array = JTypeArray::createArray(env, val.size()); + JTypeArray::setArray(env, array, val.data(), val.size()); + return array; } +template +inline typename JTypeArray::type_t c2jni(const std::set& val, JNIEnv* env) +{ + std::vector temp(val.begin(), val.end()); + return c2jni(temp, env); +} + +#define TO_JNI(VAL) c2jni(VAL, env) + + +// --------------------------------------------------------------------------- +// Convert things to C +// --------------------------------------------------------------------------- + + template struct CType { }; @@ -215,6 +319,8 @@ inline typename CType::type_t jni2c(const jobjectArray& val, JN return v; } +#define TO_C(VAL) jni2c(VAL, env) + /* Method to deal with variable passed by reference */ inline std::string getStringObjValue(const jobject obj, JNIEnv* env) { @@ -256,4 +362,15 @@ inline void setDaiObjValue(const std::string& filename, const long offset, env->SetLongField(obj, offsetFid, offset); } +template +inline jobject createWrapper(const char* className, T && nativeObj, JNIEnv* env) { + jclass objClass = env->FindClass(className); + jmethodID initMethod = env->GetMethodID(objClass, "", "(J)V"); + jlong nativeHandle = reinterpret_cast(new Handle(new T(std::forward(nativeObj)))); + jobject object = env->NewObject(objClass, initMethod, nativeHandle); + return object; +} + +#define CREATE_WRAPPER(CLASSNAME, OBJ) createWrapper(CLASSNAME, std::move(OBJ), env) + #endif // _ANDROID_JNI_UTILS_H diff --git a/lib/src/main/java/org/kiwix/libzim/Archive.java b/lib/src/main/java/org/kiwix/libzim/Archive.java new file mode 100644 index 0000000..b6d8104 --- /dev/null +++ b/lib/src/main/java/org/kiwix/libzim/Archive.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.kiwix.libzim; + +import org.kiwix.libzim.ZimFileFormatException; +import org.kiwix.libzim.Entry; +import org.kiwix.libzim.Item; +import java.io.FileDescriptor; + +public class Archive +{ + + public Archive(String filename) throws ZimFileFormatException + { + nativeHandle = getNativeArchive(filename); + if (nativeHandle == 0) { + throw new ZimFileFormatException("Cannot open zimfile "+filename); + } + } + + public Archive(FileDescriptor fd) throws ZimFileFormatException + { + nativeHandle = getNativeArchiveByFD(fd); + if (nativeHandle == 0) { + throw new ZimFileFormatException("Cannot open zimfile by fd "+fd.toString()); + } + } + + public Archive(FileDescriptor fd, long offset, long size) + throws ZimFileFormatException + { + nativeHandle = getNativeArchiveEmbedded(fd, offset, size); + if (nativeHandle == 0) { + throw new ZimFileFormatException(String.format("Cannot open embedded zimfile (fd=%s, offset=%d, size=%d)", fd, offset, size)); + } + } + + public native String getFilename(); + public native long getFilesize(); + public native int getAllEntryCount(); + public native int getEntryCount(); + public native int getArticleCount(); + public native int getMediaCount(); + public native String getUuid(); + public native String getMetadata(String name); + public native Item getMetadataItem(String name); + public native String[] getMetadataKeys(); + + public native Item getIllustrationItem(int size); + public native boolean hasIllustration(int size); + public native long[] getIllustrationSizes(); + + public native Entry getEntryByPath(String path); + public native Entry getEntryByPath(int index); + public native boolean hasEntryByPath(String path); + + public native Entry getEntryByTitle(String title); + public native Entry getEntryByTitle(int index); + public native boolean hasEntryByTitle(String title); + + public native Entry getEntryByClusterOrder(int index); + + public native Entry getMainEntry(); + public native boolean hasMainEntry(); + + public native Entry getRandomEntry(); + + public native boolean hasFulltextIndex(); + public native boolean hasTitleIndex(); + + public native boolean hasChecksum(); + public native String getChecksum(); + public native boolean check(); + + public native boolean isMultiPart(); + public native boolean hasNewNamespaceScheme(); + + + private native long getNativeArchive(String filename); + private native long getNativeArchiveByFD(FileDescriptor fd); + private native long getNativeArchiveEmbedded(FileDescriptor fd, long offset, long size); + + +///--------- The wrapper thing + // To delete our native wrapper + public native void dispose(); + + // A pointer (as a long) to a native Handle + private long nativeHandle; +} diff --git a/lib/src/main/java/org/kiwix/libzim/Blob.java b/lib/src/main/java/org/kiwix/libzim/Blob.java new file mode 100644 index 0000000..c6ccf6c --- /dev/null +++ b/lib/src/main/java/org/kiwix/libzim/Blob.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.kiwix.libzim; + +import org.kiwix.libzim.Blob; + +public class Blob +{ + private Blob(long handle) {nativeHandle = handle;} + + public native String getData(); + public native long size(); + + protected void finalize() { + dispose(); + } + +///--------- The wrapper thing + // To delete our native wrapper + public native void dispose(); + + // A pointer (as a long) to a native Handle + private long nativeHandle; +} diff --git a/lib/src/main/java/org/kiwix/libzim/Entry.java b/lib/src/main/java/org/kiwix/libzim/Entry.java new file mode 100644 index 0000000..713691b --- /dev/null +++ b/lib/src/main/java/org/kiwix/libzim/Entry.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.kiwix.libzim; + +import org.kiwix.libzim.Item; + +public class Entry +{ + private Entry(long handle) {nativeHandle = handle;} + + public native boolean isRedirect(); + public native String getTitle(); + public native String getPath(); + + public native Item getItem(boolean follow); + public native Item getRedirect(); + public native Entry getRedirectEntry(); + + protected void finalize() { + dispose(); + } + +///--------- The wrapper thing + // To delete our native wrapper + private native void dispose(); + + // A pointer (as a long) to a native Handle + private long nativeHandle; +} diff --git a/lib/src/main/java/org/kiwix/libzim/Item.java b/lib/src/main/java/org/kiwix/libzim/Item.java new file mode 100644 index 0000000..e96b2a7 --- /dev/null +++ b/lib/src/main/java/org/kiwix/libzim/Item.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.kiwix.libzim; + +import org.kiwix.libzim.Blob; + +public class Item +{ + private Item(long handle) {nativeHandle = handle;} + + public native String getTitle(); + public native String getPath(); + public native String getMimeType(); + + public native Blob getData(); + public native long getSize(); + + protected void finalize() { + dispose(); + } + +///--------- The wrapper thing + // To delete our native wrapper + private native void dispose(); + + // A pointer (as a long) to a native Handle + private long nativeHandle; +} diff --git a/lib/src/main/java/org/kiwix/libzim/ZimFileFormatException.java b/lib/src/main/java/org/kiwix/libzim/ZimFileFormatException.java new file mode 100644 index 0000000..72a2897 --- /dev/null +++ b/lib/src/main/java/org/kiwix/libzim/ZimFileFormatException.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.kiwix.libzim; + +public class ZimFileFormatException extends Exception +{ + public ZimFileFormatException(String message) { + super(message); + } +}