diff --git a/.gitignore b/.gitignore index f4a4218ae..2d491d0fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/ *.swp subprojects/googletest-release* +*.class diff --git a/android-kiwix-lib-publisher/kiwixLibAndroid/src/main/AndroidManifest.xml b/android-kiwix-lib-publisher/kiwixLibAndroid/src/main/AndroidManifest.xml index b32776b6c..e9b809a88 100644 --- a/android-kiwix-lib-publisher/kiwixLibAndroid/src/main/AndroidManifest.xml +++ b/android-kiwix-lib-publisher/kiwixLibAndroid/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="org.kiwix.kiwixlib"> =5.0.0', static:static_deps) diff --git a/meson_options.txt b/meson_options.txt index cbcf49359..fbcf81d6f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,2 @@ -option('android', type : 'boolean', value : false, - description : 'Do we make a kiwix-lib for android') +option('wrapper', type:'array', choices:['java', 'android'], value:[], + description: 'The wrapper to generate.') diff --git a/src/android/kiwixlibrary.cpp b/src/android/kiwixlibrary.cpp deleted file mode 100644 index 5b2b6be22..000000000 --- a/src/android/kiwixlibrary.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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_kiwixlib_JNIKiwixLibrary.h" - -#include "library.h" -#include "reader.h" -#include "utils.h" - -/* Kiwix Reader JNI functions */ -JNIEXPORT jlong JNICALL Java_org_kiwix_kiwixlib_JNIKiwixLibrary_getNativeLibrary( - JNIEnv* env, jobject obj) -{ - __android_log_print(ANDROID_LOG_INFO, "kiwix", "Attempting to create library"); - Lock l; - try { - kiwix::Library* library = new kiwix::Library(); - return reinterpret_cast(new Handle(library)); - } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_WARN, "kiwix", "Error creating ZIM library"); - __android_log_print(ANDROID_LOG_WARN, "kiwix", e.what()); - return 0; - } -} - -JNIEXPORT void JNICALL -Java_org_kiwix_kiwixlib_JNIKiwixLibrary_dispose(JNIEnv* env, jobject obj) -{ - Handle::dispose(env, obj); -} - -#define LIBRARY (Handle::getHandle(env, obj)) - -/* Kiwix library functions */ -JNIEXPORT jboolean JNICALL -Java_org_kiwix_kiwixlib_JNIKiwixLibrary_addBook(JNIEnv* env, jobject obj, jstring path) -{ - std::string cPath = jni2c(path, env); - bool ret; - - try { - kiwix::Reader reader(cPath); - kiwix::Book book; - book.update(reader); - ret = LIBRARY->addBook(book); - } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to add the book"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); - ret = false; - } - return ret; -} diff --git a/src/android/meson.build b/src/android/meson.build deleted file mode 100644 index 2755f5d2e..000000000 --- a/src/android/meson.build +++ /dev/null @@ -1,32 +0,0 @@ - -kiwix_jni = custom_target('jni', - input: ['org/kiwix/kiwixlib/JNIICU.java', - 'org/kiwix/kiwixlib/JNIKiwixReader.java', - 'org/kiwix/kiwixlib/JNIKiwixLibrary.java', - 'org/kiwix/kiwixlib/JNIKiwixSearcher.java', - 'org/kiwix/kiwixlib/JNIKiwixServer.java', - 'org/kiwix/kiwixlib/JNIKiwixInt.java', - 'org/kiwix/kiwixlib/JNIKiwixString.java', - 'org/kiwix/kiwixlib/JNIKiwixBool.java', - 'org/kiwix/kiwixlib/JNIKiwixException.java', - 'org/kiwix/kiwixlib/Pair.java'], - output: ['org_kiwix_kiwixlib_JNIKiwix.h', - 'org_kiwix_kiwixlib_JNIKiwixReader.h', - 'org_kiwix_kiwixlib_JNIKiwixLibrary.h', - 'org_kiwix_kiwixlib_JNIKiwixServer.h', - 'org_kiwix_kiwixlib_JNIKiwixSearcher.h', - 'org_kiwix_kiwixlib_JNIKiwixSearcher_Result.h'], - command:['javac', '-d', '@OUTDIR@', '-h', '@OUTDIR@', '@INPUT@'] -) - -kiwix_sources += [ - 'android/kiwixicu.cpp', - 'android/kiwixreader.cpp', - 'android/kiwixlibrary.cpp', - 'android/kiwixsearcher.cpp', - 'android/kiwixserver.cpp', - kiwix_jni] - -install_subdir('org', install_dir: 'kiwix-lib/java') -install_subdir('res', install_dir: 'kiwix-lib') -install_data('AndroidManifest.xml', install_dir: 'kiwix-lib') diff --git a/src/meson.build b/src/meson.build index 08da8652a..7418fd28e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -32,13 +32,16 @@ else kiwix_sources += 'subprocess_unix.cpp' endif -if get_option('android') - subdir('android') +if 'android' in wrapper install_dir = 'kiwix-lib/jniLibs/' + meson.get_cross_property('android_abi') else install_dir = get_option('libdir') endif +if 'android' in wrapper or 'java' in wrapper + subdir('wrapper/java') +endif + config_h = configure_file(output : 'kiwix_config.h', configuration : conf, input : 'config.h.in') diff --git a/src/android/AndroidManifest.xml b/src/wrapper/java/AndroidManifest.xml similarity index 100% rename from src/android/AndroidManifest.xml rename to src/wrapper/java/AndroidManifest.xml diff --git a/src/wrapper/java/book.cpp b/src/wrapper/java/book.cpp new file mode 100644 index 000000000..b76492c31 --- /dev/null +++ b/src/wrapper/java/book.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "org_kiwix_kiwixlib_Book.h" + +#include "utils.h" +#include "book.h" + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_Book_allocate( + JNIEnv* env, jobject thisObj) +{ + allocate(env, thisObj); +} + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_Book_dispose(JNIEnv* env, jobject thisObj) +{ + dispose(env, thisObj); +} + +#define BOOK (getPtr(env, thisObj)) + +#define GETTER(retType, name) JNIEXPORT retType JNICALL \ +Java_org_kiwix_kiwixlib_Book_##name (JNIEnv* env, jobject thisObj) \ +{ \ + auto cRet = BOOK->name(); \ + retType ret = c2jni(cRet, env); \ + return ret; \ +} + +GETTER(jstring, getId) +GETTER(jstring, getPath) +GETTER(jboolean, isPathValid) +GETTER(jstring, getTitle) +GETTER(jstring, getDescription) +GETTER(jstring, getLanguage) +GETTER(jstring, getCreator) +GETTER(jstring, getPublisher) +GETTER(jstring, getDate) +GETTER(jstring, getUrl) +GETTER(jstring, getName) +GETTER(jstring, getTags) +GETTER(jlong, getArticleCount) +GETTER(jlong, getMediaCount) +GETTER(jlong, getSize) +GETTER(jstring, getFavicon) +GETTER(jstring, getFaviconUrl) +GETTER(jstring, getFaviconMimeType) + +#undef GETTER diff --git a/src/wrapper/java/filter.cpp b/src/wrapper/java/filter.cpp new file mode 100644 index 000000000..09c07343d --- /dev/null +++ b/src/wrapper/java/filter.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019-2020 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 "org_kiwix_kiwixlib_Filter.h" + +#include "library.h" +#include "utils.h" + +/* Kiwix Reader JNI functions */ +METHOD0(void, Filter, allocate) { + allocate(env, thisObj); +} + +METHOD0(void, Filter, dispose) { + dispose(env, thisObj); +} + +#define FILTER (getPtr(env, thisObj)) + +#define FORWARD(name, args_type) \ +METHOD(jobject, Filter, name, args_type value) { \ + FILTER->name(jni2c(value, env)); \ + return thisObj; \ +} + +#define FORWARDA(name, args_type) \ +METHOD(jobject, Filter, name, jobjectArray value) { \ + FILTER->name(jni2c(value, env)); \ + return thisObj; \ +} + + + +FORWARD(local, jboolean) +FORWARD(remote, jboolean) +FORWARD(valid, jboolean) +FORWARDA(acceptTags, jstring) +FORWARDA(rejectTags, jstring) +FORWARD(lang, jstring) +FORWARD(publisher, jstring) +FORWARD(creator, jstring) +FORWARD(maxSize, jlong) +FORWARD(query, jstring) + + diff --git a/src/android/kiwixicu.cpp b/src/wrapper/java/kiwixicu.cpp similarity index 93% rename from src/android/kiwixicu.cpp rename to src/wrapper/java/kiwixicu.cpp index f6af17d6c..0c604ebdd 100644 --- a/src/android/kiwixicu.cpp +++ b/src/wrapper/java/kiwixicu.cpp @@ -28,7 +28,11 @@ #include "utils.h" +#if __ANDROID__ pthread_mutex_t globalLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; +#else +pthread_mutex_t globalLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#endif JNIEXPORT void JNICALL Java_org_kiwix_kiwixlib_JNIICU_setDataDirectory( JNIEnv* env, jclass kclass, jstring dirStr) diff --git a/src/android/kiwixreader.cpp b/src/wrapper/java/kiwixreader.cpp similarity index 74% rename from src/android/kiwixreader.cpp rename to src/wrapper/java/kiwixreader.cpp index 891b6650a..7bc61ebd8 100644 --- a/src/android/kiwixreader.cpp +++ b/src/wrapper/java/kiwixreader.cpp @@ -21,7 +21,6 @@ #include #include -#include #include "org_kiwix_kiwixlib_JNIKiwixReader.h" #include "tools/base64.h" @@ -34,14 +33,14 @@ JNIEXPORT jlong JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getNativeReader( { std::string cPath = jni2c(filename, env); - __android_log_print(ANDROID_LOG_INFO, "kiwix", "Attempting to create reader with: %s", cPath.c_str()); + LOG("Attempting to create reader with: %s", cPath.c_str()); Lock l; try { kiwix::Reader* reader = new kiwix::Reader(cPath); return reinterpret_cast(new Handle(reader)); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_WARN, "kiwix", "Error opening ZIM file"); - __android_log_print(ANDROID_LOG_WARN, "kiwix", e.what()); + LOG("Error opening ZIM file"); + LOG(e.what()); return 0; } } @@ -64,8 +63,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getMainPage(JNIEnv* env, jobject obj) std::string cUrl = READER->getMainPage().getPath(); url = c2jni(cUrl, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM main page"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM main page"); + LOG(e.what()); url = NULL; } return url; @@ -80,8 +79,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getId(JNIEnv* env, jobject obj) std::string cId = READER->getId(); id = c2jni(cId, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM id"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM id"); + LOG(e.what()); id = NULL; } @@ -95,10 +94,10 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getFileSize(JNIEnv* env, jobject obj) try { int cSize = READER->getFileSize(); - size = c2jni(cSize); + size = c2jni(cSize, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM file size"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM file size"); + LOG(e.what()); } return size; @@ -113,8 +112,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getCreator(JNIEnv* env, jobject obj) std::string cCreator = READER->getCreator(); creator = c2jni(cCreator, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM creator"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM creator"); + LOG(e.what()); creator = NULL; } @@ -130,8 +129,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getPublisher(JNIEnv* env, jobject obj) std::string cPublisher = READER->getPublisher(); publisher = c2jni(cPublisher, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM publish"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM publish"); + LOG(e.what()); publisher = NULL; } return publisher; @@ -146,8 +145,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getName(JNIEnv* env, jobject obj) std::string cName = READER->getName(); name = c2jni(cName, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM name"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM name"); + LOG(e.what()); name = NULL; } return name; @@ -166,8 +165,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getFavicon(JNIEnv* env, jobject obj) base64_encode(cContent), env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM favicon"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM favicon"); + LOG(e.what()); favicon = NULL; } return favicon; @@ -182,8 +181,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getDate(JNIEnv* env, jobject obj) std::string cDate = READER->getDate(); date = c2jni(cDate, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM date"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM date"); + LOG(e.what()); date = NULL; } return date; @@ -198,8 +197,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getLanguage(JNIEnv* env, jobject obj) std::string cLanguage = READER->getLanguage(); language = c2jni(cLanguage, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM language"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get ZIM language"); + LOG(e.what()); language = NULL; } @@ -217,8 +216,8 @@ JNIEXPORT jstring JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getMimeType( auto cMimeType = entry.getMimetype(); mimeType = c2jni(cMimeType, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get mime-type for url: %s", cUrl.c_str()); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get mime-type for url: %s", cUrl.c_str()); + LOG(e.what()); mimeType = NULL; } return mimeType; @@ -234,7 +233,7 @@ JNIEXPORT jstring JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_checkUrl( entry = entry.getFinalEntry(); finalUrl = c2jni(entry.getPath(), env); } catch (std::exception& e) { - finalUrl = c2jni("", env); + finalUrl = c2jni(std::string(), env); } return finalUrl; } @@ -268,8 +267,8 @@ JNIEXPORT jbyteArray JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getContent( data, 0, cSize, reinterpret_cast(entry.getBlob().data())); } } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get content for url: %s", cUrl.c_str()); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get content for url: %s", cUrl.c_str()); + LOG(e.what()); } return data; @@ -284,8 +283,8 @@ JNIEXPORT jbyteArray JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getContentPa /* Default values */ /* Retrieve the content */ std::string cUrl = jni2c(url, env); - unsigned int cOffset = jni2c(offset); - unsigned int cLen = jni2c(len); + unsigned int cOffset = jni2c(offset, env); + unsigned int cLen = jni2c(len, env); try { auto entry = READER->getEntryFromEncodedPath(cUrl); entry = entry.getFinalEntry(); @@ -300,8 +299,8 @@ JNIEXPORT jbyteArray JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getContentPa setIntObjValue(cLen, sizeObj, env); } } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get partial content for url: %s (%u : %u)", cUrl.c_str(), cOffset, cLen); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get partial content for url: %s (%u : %u)", cUrl.c_str(), cOffset, cLen); + LOG(e.what()); } return data; } @@ -322,8 +321,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getDirectAccessInformation( auto part_info = entry.getDirectAccessInfo(); setPairObjValue(part_info.first, part_info.second, pair, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get direct access info for url: %s", cUrl.c_str()); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get direct access info for url: %s", cUrl.c_str()); + LOG(e.what()); } return pair; } @@ -336,15 +335,15 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_searchSuggestions(JNIEnv* env, { jboolean retVal = JNI_FALSE; std::string cPrefix = jni2c(prefix, env); - unsigned int cCount = jni2c(count); + unsigned int cCount = jni2c(count, env); try { if (READER->searchSuggestionsSmart(cPrefix, cCount)) { retVal = JNI_TRUE; } } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_WARN, "kiwix", "Unable to get search results for pattern: %s", cPrefix.c_str()); - __android_log_print(ANDROID_LOG_WARN, "kiwix", e.what()); + LOG("Unable to get search results for pattern: %s", cPrefix.c_str()); + LOG(e.what()); } return retVal; @@ -367,8 +366,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getNextSuggestion(JNIEnv* env, retVal = JNI_TRUE; } } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_WARN, "kiwix", "Unable to get next suggestion"); - __android_log_print(ANDROID_LOG_WARN, "kiwix", e.what()); + LOG("Unable to get next suggestion"); + LOG(e.what()); } return retVal; @@ -388,8 +387,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getPageUrlFromTitle(JNIEnv* env, setStringObjValue(entry.getPath(), urlObj, env); return JNI_TRUE; } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_WARN, "kiwix", "Unable to get url for title %s: ", cTitle.c_str()); - __android_log_print(ANDROID_LOG_WARN, "kiwix", e.what()); + LOG("Unable to get url for title %s: ", cTitle.c_str()); + LOG(e.what()); } return JNI_FALSE; @@ -404,8 +403,8 @@ JNIEXPORT jstring JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getTitle( std::string cTitle = READER->getTitle(); title = c2jni(cTitle, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get zim title"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get zim title"); + LOG(e.what()); title = NULL; } return title; @@ -420,8 +419,8 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getDescription(JNIEnv* env, jobject obj) std::string cDescription = READER->getDescription(); description = c2jni(cDescription, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get zim description"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get zim description"); + LOG(e.what()); description = NULL; } return description; @@ -433,10 +432,10 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getArticleCount(JNIEnv* env, jobject obj) jint articleCount = 0; try { auto cArticleCount = READER->getArticleCount(); - articleCount = c2jni(cArticleCount); + articleCount = c2jni(cArticleCount, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get article count."); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get article count."); + LOG(e.what()); } return articleCount; } @@ -447,10 +446,10 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getMediaCount(JNIEnv* env, jobject obj) jint mediaCount = 0; try { auto cMediaCount = READER->getMediaCount(); - mediaCount = c2jni(cMediaCount); + mediaCount = c2jni(cMediaCount, env); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get media count."); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get media count."); + LOG(e.what()); } return mediaCount; } @@ -467,8 +466,8 @@ JNIEXPORT jboolean JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getRandomPage( setStringObjValue(cUrl, urlObj, env); retVal = JNI_TRUE; } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get random page"); - __android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what()); + LOG("Unable to get random page"); + LOG(e.what()); } return retVal; } diff --git a/src/android/kiwixsearcher.cpp b/src/wrapper/java/kiwixsearcher.cpp similarity index 98% rename from src/android/kiwixsearcher.cpp rename to src/wrapper/java/kiwixsearcher.cpp index 1c46836d0..de5f078fa 100644 --- a/src/android/kiwixsearcher.cpp +++ b/src/wrapper/java/kiwixsearcher.cpp @@ -59,7 +59,7 @@ JNIEXPORT void JNICALL Java_org_kiwix_kiwixlib_JNIKiwixSearcher_search( JNIEnv* env, jobject obj, jstring query, jint count) { std::string cquery = jni2c(query, env); - unsigned int ccount = jni2c(count); + unsigned int ccount = jni2c(count, env); SEARCHER->search(cquery, 0, ccount); } diff --git a/src/android/kiwixserver.cpp b/src/wrapper/java/kiwixserver.cpp similarity index 87% rename from src/android/kiwixserver.cpp rename to src/wrapper/java/kiwixserver.cpp index 0e6668b1f..7242c4cd4 100644 --- a/src/android/kiwixserver.cpp +++ b/src/wrapper/java/kiwixserver.cpp @@ -21,7 +21,6 @@ #include #include -#include #include "org_kiwix_kiwixlib_JNIKiwixServer.h" #include "tools/base64.h" @@ -32,15 +31,15 @@ JNIEXPORT jlong JNICALL Java_org_kiwix_kiwixlib_JNIKiwixServer_getNativeServer( JNIEnv* env, jobject obj, jobject jLibrary) { - __android_log_print(ANDROID_LOG_INFO, "kiwix", "Attempting to create server"); + LOG("Attempting to create server"); Lock l; try { - auto library = Handle::getHandle(env, jLibrary); - kiwix::Server* server = new kiwix::Server(*library); + auto library = getPtr(env, jLibrary); + kiwix::Server* server = new kiwix::Server(library); return reinterpret_cast(new Handle(server)); } catch (std::exception& e) { - __android_log_print(ANDROID_LOG_WARN, "kiwix", "Error creating the server"); - __android_log_print(ANDROID_LOG_WARN, "kiwix", e.what()); + LOG("Error creating the server"); + LOG(e.what()); return 0; } } diff --git a/src/wrapper/java/library.cpp b/src/wrapper/java/library.cpp new file mode 100644 index 000000000..f2a084646 --- /dev/null +++ b/src/wrapper/java/library.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019-2020 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 "org_kiwix_kiwixlib_Library.h" + +#include "library.h" +#include "reader.h" +#include "utils.h" + +/* Kiwix Reader JNI functions */ +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_Library_allocate( + JNIEnv* env, jobject thisObj) +{ + allocate(env, thisObj); +} + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_Library_dispose(JNIEnv* env, jobject thisObj) +{ + dispose(env, thisObj); +} + +#define LIBRARY (getPtr(env, thisObj)) + +/* Kiwix library functions */ +JNIEXPORT jboolean JNICALL +Java_org_kiwix_kiwixlib_Library_addBook( + JNIEnv* env, jobject thisObj, jstring path) +{ + auto cPath = jni2c(path, env); + + try { + kiwix::Reader reader(cPath); + kiwix::Book book; + book.update(reader); + return LIBRARY->addBook(book); + } catch (std::exception& e) { + LOG("Unable to add the book"); + LOG(e.what()); } + return false; +} + +METHOD(jobject, Library, getBookById, jstring id) { + auto cId = jni2c(id, env); + auto cBook = new kiwix::Book(LIBRARY->getBookById(cId)); + jclass cls = env->FindClass("org/kiwix/kiwixlib/Book"); + jmethodID constructorId = env->GetMethodID(cls, "", "()V"); + jobject book = env->NewObject(cls, constructorId); + setPtr(env, book, cBook); + return book; +} + +METHOD(jint, Library, getBookCount, jboolean localBooks, jboolean remoteBooks) { + return LIBRARY->getBookCount(localBooks, remoteBooks); +} + +METHOD0(jobjectArray, Library, getBooksIds) { + return c2jni(LIBRARY->getBooksIds(), env); +} + +METHOD(jobjectArray, Library, filter, jobject filterObj) { + auto filter = getPtr(env, filterObj); + return c2jni(LIBRARY->filter(*filter), env); +} + +METHOD0(jobjectArray, Library, getBooksLanguages) { + return c2jni(LIBRARY->getBooksLanguages(), env); +} + +METHOD0(jobjectArray, Library, getBooksCreators) { + return c2jni(LIBRARY->getBooksCreators(), env); +} + +METHOD0(jobjectArray, Library, getBooksPublisher) { + return c2jni(LIBRARY->getBooksPublishers(), env); +} + diff --git a/src/wrapper/java/manager.cpp b/src/wrapper/java/manager.cpp new file mode 100644 index 000000000..b2e94d9ed --- /dev/null +++ b/src/wrapper/java/manager.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020 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_kiwixlib_Manager.h" + +#include "manager.h" +#include "utils.h" + + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_Manager_allocate( + JNIEnv* env, jobject thisObj, jobject libraryObj) +{ + auto lib = getPtr(env, libraryObj); + allocate(env, thisObj, lib); +} + +JNIEXPORT void JNICALL +Java_org_kiwix_kiwixlib_Manager_dispose(JNIEnv* env, jobject thisObj) +{ + dispose(env, thisObj); +} + +#define MANAGER (getPtr(env, thisObj)) + +/* Kiwix manager functions */ +JNIEXPORT jboolean JNICALL +Java_org_kiwix_kiwixlib_Manager_readFile( + JNIEnv* env, jobject thisObj, jstring path) +{ + auto cPath = jni2c(path, env); + + try { + return MANAGER->readFile(cPath); + } catch (std::exception& e) { + LOG("Unable to get readFile"); + LOG(e.what()); + } + return false; +} + +JNIEXPORT jboolean JNICALL +Java_org_kiwix_kiwixlib_Manager_readXml( + JNIEnv* env, jobject thisObj, jstring content, jstring libraryPath) +{ + auto cContent = jni2c(content, env); + auto cPath = jni2c(libraryPath, env); + + try { + return MANAGER->readXml(cContent, false, cPath); + } catch (std::exception& e) { + LOG("Unable to get ZIM id"); + LOG(e.what()); + } + + return false; +} + +JNIEXPORT jboolean JNICALL +Java_org_kiwix_kiwixlib_Manager_readOpds( + JNIEnv* env, jobject thisObj, jstring content, jstring urlHost) +{ + auto cContent = jni2c(content, env); + auto cUrl = jni2c(urlHost, env); + + try { + return MANAGER->readOpds(cContent, cUrl); + } catch (std::exception& e) { + LOG("Unable to get ZIM id"); + LOG(e.what()); + } + + return false; +} + +JNIEXPORT jboolean JNICALL +Java_org_kiwix_kiwixlib_Manager_readBookmarkFile( + JNIEnv* env, jobject thisObj, jstring path) +{ + auto cPath = jni2c(path, env); + + try { + return MANAGER->readBookmarkFile(cPath); + } catch (std::exception& e) { + LOG("Unable to get ZIM id"); + LOG(e.what()); + } + + return false; +} + +JNIEXPORT jstring JNICALL +Java_org_kiwix_kiwixlib_Manager_addBookFromPath( + JNIEnv* env, jobject thisObj, + jstring pathToOpen, jstring pathToSave, jstring url, jboolean checkMetaData) +{ + auto cPathToOpen = jni2c(pathToOpen, env); + auto cPathToSave = jni2c(pathToSave, env); + auto cUrl = jni2c(url, env); + jstring id = NULL; + + try { + auto cId = MANAGER->addBookFromPathAndGetId(cPathToOpen, cPathToSave, cUrl, checkMetaData); + if ( !cId.empty() ) { + id = c2jni(cId, env); + } + } catch (std::exception& e) { + LOG("Unable to get ZIM file size"); + LOG(e.what()); + } + + return id; +} diff --git a/src/wrapper/java/meson.build b/src/wrapper/java/meson.build new file mode 100644 index 000000000..034173045 --- /dev/null +++ b/src/wrapper/java/meson.build @@ -0,0 +1,55 @@ + +java_sources = files([ + 'org/kiwix/kiwixlib/JNIICU.java', + 'org/kiwix/kiwixlib/Book.java', + 'org/kiwix/kiwixlib/JNIKiwixReader.java', + 'org/kiwix/kiwixlib/Library.java', + 'org/kiwix/kiwixlib/Manager.java', + 'org/kiwix/kiwixlib/Filter.java', + 'org/kiwix/kiwixlib/JNIKiwixSearcher.java', + 'org/kiwix/kiwixlib/JNIKiwixServer.java', + 'org/kiwix/kiwixlib/JNIKiwixInt.java', + 'org/kiwix/kiwixlib/JNIKiwixString.java', + 'org/kiwix/kiwixlib/JNIKiwixBool.java', + 'org/kiwix/kiwixlib/JNIKiwixException.java', + 'org/kiwix/kiwixlib/Pair.java' +]) + +kiwix_jni = custom_target('jni', + input: java_sources, + output: ['org_kiwix_kiwixlib_JNIKiwix.h', + 'org_kiwix_kiwixlib_Book.h', + 'org_kiwix_kiwixlib_JNIKiwixReader.h', + 'org_kiwix_kiwixlib_Library.h', + 'org_kiwix_kiwixlib_Manager.h', + 'org_kiwix_kiwixlib_Filter.h', + 'org_kiwix_kiwixlib_JNIKiwixServer.h', + 'org_kiwix_kiwixlib_JNIKiwixSearcher.h', + 'org_kiwix_kiwixlib_JNIKiwixSearcher_Result.h'], + command:['javac', '-d', '@OUTDIR@', '-h', '@OUTDIR@', '@INPUT@'] +) + +jni_sources = files([ + 'kiwixicu.cpp', + 'book.cpp', + 'kiwixreader.cpp', + 'library.cpp', + 'manager.cpp', + 'filter.cpp', + 'kiwixsearcher.cpp', + 'kiwixserver.cpp', +]) + +kiwix_sources += jni_sources + [kiwix_jni] + +if 'java' in wrapper + kiwix_jar = jar('kiwixlib', java_sources) + #junit_jar = files('org/kiwix/testing/junit-4.13.jar') + #test_jar = jar('testing', 'org/kiwix/testing/test.java', + # link_with: [kiwix_jar, junit_jar]) + #test('javatest', test_jar) +endif + +install_subdir('org', install_dir: 'kiwix-lib/java', exclude_directories: ['kiwix/testing']) +install_subdir('res', install_dir: 'kiwix-lib') +install_data('AndroidManifest.xml', install_dir: 'kiwix-lib') diff --git a/src/wrapper/java/org/kiwix/kiwixlib/Book.java b/src/wrapper/java/org/kiwix/kiwixlib/Book.java new file mode 100644 index 000000000..06b72e11d --- /dev/null +++ b/src/wrapper/java/org/kiwix/kiwixlib/Book.java @@ -0,0 +1,35 @@ + +package org.kiwix.kiwixlib; + +public class Book +{ + public Book() { allocate(); } + + @Override + protected void finalize() { dispose(); } + + public native String getId(); + public native String getPath(); + public native boolean isPathValid(); + public native String getTitle(); + public native String getDescription(); + public native String getLanguage(); + public native String getCreator(); + public native String getPublisher(); + public native String getDate(); + public native String getUrl(); + public native String getName(); + public native String getTags(); + + public native long getArticleCount(); + public native long getMediaCount(); + public native long getSize(); + + public native String getFavicon(); + public native String getFaviconUrl(); + public native String getFaviconMimeType(); + + private native void allocate(); + private native void dispose(); + private long nativeHandle; +} diff --git a/src/wrapper/java/org/kiwix/kiwixlib/Filter.java b/src/wrapper/java/org/kiwix/kiwixlib/Filter.java new file mode 100644 index 000000000..bf9e719df --- /dev/null +++ b/src/wrapper/java/org/kiwix/kiwixlib/Filter.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019-2020 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.kiwixlib; + +public class Filter +{ + + public native Filter local(boolean accept); + public native Filter remote(boolean accept); + public native Filter valid(boolean accept); + public native Filter acceptTags(String[] tags); + public native Filter rejectTags(String[] tags); + public native Filter lang(String lang); + public native Filter publisher(String publisher); + public native Filter creator(String creator); + public native Filter maxSize(long size); + public native Filter query(String query); + + + public Filter() { allocate(); } + + @Override + protected void finalize() { dispose(); } + private native void allocate(); + private native void dispose(); + private long nativeHandle; +} diff --git a/src/android/org/kiwix/kiwixlib/JNIICU.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIICU.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIICU.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIICU.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwix.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwix.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIKiwix.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwix.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixBool.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixBool.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIKiwixBool.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixBool.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixException.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixException.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIKiwixException.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixException.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixInt.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixInt.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIKiwixInt.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixInt.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixReader.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixReader.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIKiwixReader.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixReader.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixSearcher.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixSearcher.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIKiwixSearcher.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixSearcher.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixServer.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixServer.java similarity index 89% rename from src/android/org/kiwix/kiwixlib/JNIKiwixServer.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixServer.java index 75fd11507..578e2f4de 100644 --- a/src/android/org/kiwix/kiwixlib/JNIKiwixServer.java +++ b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixServer.java @@ -20,7 +20,7 @@ package org.kiwix.kiwixlib; import org.kiwix.kiwixlib.JNIKiwixException; -import org.kiwix.kiwixlib.JNIKiwixLibrary; +import org.kiwix.kiwixlib.Library; public class JNIKiwixServer { @@ -38,11 +38,11 @@ public class JNIKiwixServer public native void stop(); - public JNIKiwixServer(JNIKiwixLibrary library) + public JNIKiwixServer(Library library) { nativeHandle = getNativeServer(library); } - private native long getNativeServer(JNIKiwixLibrary library); + private native long getNativeServer(Library library); private long nativeHandle; } diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixString.java b/src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixString.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/JNIKiwixString.java rename to src/wrapper/java/org/kiwix/kiwixlib/JNIKiwixString.java diff --git a/src/android/org/kiwix/kiwixlib/JNIKiwixLibrary.java b/src/wrapper/java/org/kiwix/kiwixlib/Library.java similarity index 59% rename from src/android/org/kiwix/kiwixlib/JNIKiwixLibrary.java rename to src/wrapper/java/org/kiwix/kiwixlib/Library.java index 5ab779767..68aa7d22f 100644 --- a/src/android/org/kiwix/kiwixlib/JNIKiwixLibrary.java +++ b/src/wrapper/java/org/kiwix/kiwixlib/Library.java @@ -1,6 +1,5 @@ /* - * Copyright (C) 2013 Emmanuel Engelhart - * Copyright (C) 2017 Matthieu Gautier + * Copyright (C) 2019-2020 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 @@ -20,19 +19,31 @@ package org.kiwix.kiwixlib; +import org.kiwix.kiwixlib.Book; import org.kiwix.kiwixlib.JNIKiwixException; -public class JNIKiwixLibrary +public class Library { public native boolean addBook(String path) throws JNIKiwixException; - public JNIKiwixLibrary() + public native Book getBookById(String id); + public native int getBookCount(boolean localBooks, boolean remoteBooks); + + public native String[] getBooksIds(); + public native String[] filter(Filter filter); + + public native String[] getBooksLanguages(); + public native String[] getBooksCreators(); + public native String[] getBooksPublishers(); + + public Library() { - nativeHandle = getNativeLibrary(); + allocate(); } - public native void dispose(); - - private native long getNativeLibrary(); + @Override + protected void finalize() { dispose(); } + private native void allocate(); + private native void dispose(); private long nativeHandle; } diff --git a/src/wrapper/java/org/kiwix/kiwixlib/Manager.java b/src/wrapper/java/org/kiwix/kiwixlib/Manager.java new file mode 100644 index 000000000..2772ca942 --- /dev/null +++ b/src/wrapper/java/org/kiwix/kiwixlib/Manager.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020 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.kiwixlib; + +import org.kiwix.kiwixlib.Library; + +public class Manager +{ + /** + * Read a `library.xml` file and add books in the library. + * + * @param path The (utf8) path to the `library.xml` file. + * @return True if the file has been properly parsed. + */ + public native boolean readFile(String path); + + /** + * Load a library content stored in a string (at `library.xml` format). + * + * @param content The content corresponding of the library xml. + * @param libraryPath The library path (used to resolve relative paths) + * @return True if the content has been properly parsed. + */ + public native boolean readXml(String content, String libraryPath); + + /** + * Load a library content stored in a string (at OPDS stream format) + * + * @param content the content of the OPDS stream. + * @param urlHost the url of the stream (used to resolve relative url) + * @return True if the content has been properly parsed. + */ + public native boolean readOpds(String content, String urlHost); + + /** + * Load a bookmark file + * + * @param path The path of the file to read. + * @return True if the content has been properly parsed + */ + public native boolean readBookmarkFile(String path); + + /** + * Add a book to the library. + * + * @param pathToOpen The path of the zim file to add. + * @param pathToSave The path to store in the library in place of + * pathToOpen. + * @param url The url of the book to store in the library + * (useful for kiiwix-serve catalog) + * @param checkMetaData Tell if we check metadata before adding a book to the + * library. + * @return The id of te book if the book has been added to the library. + * Empty string if not. + */ + public native String addBookFromPath(String pathToOpen, + String pathToSave, + String url, + boolean checkMetaData); + + public Manager(Library library) { + allocate(library); + _library = library; + } + + private Library _library; + + @Override + protected void finalize() { dispose(); } + private native void allocate(Library library); + private native void dispose(); + private long nativeHandle; +} diff --git a/src/android/org/kiwix/kiwixlib/Pair.java b/src/wrapper/java/org/kiwix/kiwixlib/Pair.java similarity index 100% rename from src/android/org/kiwix/kiwixlib/Pair.java rename to src/wrapper/java/org/kiwix/kiwixlib/Pair.java diff --git a/src/wrapper/java/org/kiwix/testing/compile_test.sh b/src/wrapper/java/org/kiwix/testing/compile_test.sh new file mode 100755 index 000000000..a98569935 --- /dev/null +++ b/src/wrapper/java/org/kiwix/testing/compile_test.sh @@ -0,0 +1,26 @@ +#!/usr/bin/bash + +# This script compile the unit test to test the java wrapper. +# This is not integrated in meson because ... this is not so easy. + + +KIWIX_LIB_JAR=$1 +if [ -z $KIWIX_LIB_JAR ] +then + echo "You must give the path to the kiwixlib.jar as first argument" + exit 1 +fi + +KIWIX_LIB_DIR=$2 +if [ -z $KIWIX_LIB_DIR ] +then + echo "You must give the path to directory containing libkiwix.so as second argument" + exit 1 +fi +TEST_SOURCE_DIR=$(dirname $(readlink -f $0)) + + +javac -g -d . -s . -cp $TEST_SOURCE_DIR/junit-4.13.jar:$KIWIX_LIB_JAR $TEST_SOURCE_DIR/test.java + +java -Djava.library.path=$KIWIX_LIB_DIR -cp $TEST_SOURCE_DIR/junit-4.13.jar:$TEST_SOURCE_DIR/hamcrest-core-1.3.jar:$KIWIX_LIB_JAR:. org.junit.runner.JUnitCore test + diff --git a/src/wrapper/java/org/kiwix/testing/hamcrest-core-1.3.jar b/src/wrapper/java/org/kiwix/testing/hamcrest-core-1.3.jar new file mode 100644 index 000000000..9d5fe16e3 Binary files /dev/null and b/src/wrapper/java/org/kiwix/testing/hamcrest-core-1.3.jar differ diff --git a/src/wrapper/java/org/kiwix/testing/junit-4.13.jar b/src/wrapper/java/org/kiwix/testing/junit-4.13.jar new file mode 100644 index 000000000..acc3c4320 Binary files /dev/null and b/src/wrapper/java/org/kiwix/testing/junit-4.13.jar differ diff --git a/src/wrapper/java/org/kiwix/testing/test.java b/src/wrapper/java/org/kiwix/testing/test.java new file mode 100644 index 000000000..671b0b46e --- /dev/null +++ b/src/wrapper/java/org/kiwix/testing/test.java @@ -0,0 +1,53 @@ + +import java.io.*; +import java.util.*; +import org.junit.Test; +import static org.junit.Assert.*; +import org.kiwix.kiwixlib.*; + +public class test { +static { + System.loadLibrary("kiwix"); +} + +private static String getCatalogContent() +throws IOException +{ + BufferedReader reader = new BufferedReader(new FileReader("catalog.xml")); + String line; + StringBuilder sb = new StringBuilder(); + while ((line = reader.readLine()) != null) + { + sb.append(line + "\n"); + } + reader.close(); + return sb.toString(); +} + +@Test +public void testSome() +throws IOException +{ + Library lib = new Library(); + Manager manager = new Manager(lib); + String content = getCatalogContent(); + manager.readOpds(content, "https://library.kiwix.org"); + assertEquals(lib.getBookCount(true, true), 10); + String[] bookIds = lib.getBooksIds(); + assertEquals(bookIds.length, 10); + Book book = lib.getBookById(bookIds[0]); + assertEquals(book.getTitle(), "Wikisource"); + assertEquals(book.getTags(), "wikisource;_category:wikisource;_pictures:no;_videos:no;_details:yes;_ftindex:yes"); + assertEquals(book.getFaviconUrl(), "https://library.kiwix.org/meta?name=favicon&content=wikisource_fr_all_nopic_2020-01"); + assertEquals(book.getUrl(), "http://download.kiwix.org/zim/wikisource/wikisource_fr_all_nopic_2020-01.zim.meta4"); +} + +static +public void main(String[] args) { + Library lib = new Library(); + lib.getBookCount(true, true); +} + + + +} diff --git a/src/android/res/values/strings.xml b/src/wrapper/java/res/values/strings.xml similarity index 100% rename from src/android/res/values/strings.xml rename to src/wrapper/java/res/values/strings.xml diff --git a/src/android/utils.h b/src/wrapper/java/utils.h similarity index 53% rename from src/android/utils.h rename to src/wrapper/java/utils.h index aeb5a4d35..7fa32a161 100644 --- a/src/android/utils.h +++ b/src/wrapper/java/utils.h @@ -26,9 +26,55 @@ #include #include +#include +#include + +#if __ANDROID__ + #include + #define LOG(...) __android_log_print(ANDROID_LOG_ERROR, "kiwix", __VA_ARGS__) +#else + #define LOG(...) +#endif extern pthread_mutex_t globalLock; +template +void setPtr(JNIEnv* env, jobject thisObj, T* ptr) +{ + jclass thisClass = env->GetObjectClass(thisObj); + jfieldID fieldId = env->GetFieldID(thisClass, "nativeHandle", "J"); + env->SetLongField(thisObj, fieldId, reinterpret_cast(ptr)); +} + +template +void allocate(JNIEnv* env, jobject thisObj, Args && ...args) +{ + T* ptr = new T(std::forward(args)...); + setPtr(env, thisObj, ptr); +} + +template +T* getPtr(JNIEnv* env, jobject thisObj) +{ + jclass thisClass = env->GetObjectClass(thisObj); + jfieldID fidNumber = env->GetFieldID(thisClass, "nativeHandle", "J"); + return reinterpret_cast(env->GetLongField(thisObj, fidNumber)); +} + +template +void dispose(JNIEnv* env, jobject thisObj) +{ + delete getPtr(env, thisObj); +} + +#define METHOD0(retType, class, name) \ +JNIEXPORT retType JNICALL Java_org_kiwix_kiwixlib_##class##_##name( \ + JNIEnv* env, jobject thisObj) + +#define METHOD(retType, class, name, ...) \ +JNIEXPORT retType JNICALL Java_org_kiwix_kiwixlib_##class##_##name( \ + JNIEnv* env, jobject thisObj, __VA_ARGS__) + inline jfieldID getHandleField(JNIEnv* env, jobject obj) { jclass c = env->GetObjectClass(obj); @@ -36,6 +82,12 @@ inline jfieldID getHandleField(JNIEnv* env, jobject obj) return env->GetFieldID(c, "nativeHandle", "J"); } +inline jobjectArray createArray(JNIEnv* env, size_t length, const std::string& type_sig) +{ + jclass c = env->FindClass(type_sig.c_str()); + return env->NewObjectArray(length, c, NULL); +} + class Lock { protected: @@ -91,19 +143,67 @@ struct LockedHandle : public Lock { T* operator->() { return h->h; } T* operator*() { return h->h; } operator bool() const { return (h->h != nullptr); } + operator T*() const { return h->h; } }; -/* c2jni type conversion functions */ -inline jboolean c2jni(const bool& val) { return val ? JNI_TRUE : JNI_FALSE; } +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 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 +inline typename JType::type_t c2jni(const T& val, JNIEnv* env) { + return static_cast::type_t>(val); +} + +template<> +inline jboolean c2jni(const bool& val, JNIEnv* env) { return val ? JNI_TRUE : JNI_FALSE; } + +template<> inline jstring c2jni(const std::string& val, JNIEnv* env) { return env->NewStringUTF(val.c_str()); } -inline jint c2jni(const int val) { return (jint)val; } -inline jint c2jni(const unsigned val) { return (unsigned)val; } +template<> +inline jobjectArray c2jni(const std::vector& val, JNIEnv* env) +{ + auto array = createArray(env, val.size(), "java/lang/String"); + size_t index = 0; + for (auto& elem: val) { + auto jElem = c2jni(elem, env); + env->SetObjectArrayElement(array, index++, jElem); + } + return array; +} + +template +struct CType { }; + +template<> struct CType{ typedef bool type_t; }; +template<> struct CType{ typedef int type_t; }; +template<> struct CType{ typedef long type_t; }; +template<> struct CType{ typedef std::string type_t; }; + +template +struct CType{ typedef std::vector::type_t> type_t; }; + /* jni2c type conversion functions */ -inline bool jni2c(const jboolean& val) { return val == JNI_TRUE; } +template +inline typename CType::type_t jni2c(const T& val, JNIEnv* env) { + return static_cast::type_t>(val); +} + +template<> +inline bool jni2c(const jboolean& val, JNIEnv* env) { return val == JNI_TRUE; } + +template<> inline std::string jni2c(const jstring& val, JNIEnv* env) { const char* chars = env->GetStringUTFChars(val, 0); @@ -112,7 +212,21 @@ inline std::string jni2c(const jstring& val, JNIEnv* env) return ret; } -inline int jni2c(const jint val) { return (int)val; } +template +inline typename CType::type_t jni2c(const jobjectArray& val, JNIEnv* env) +{ + jsize length = env->GetArrayLength(val); + typename CType::type_t v(length); + + int i; + for (i = 0; i < length; i++) { + U obj = (U) env->GetObjectArrayElement(val, i); + auto cobj = jni2c(obj, env); + v.push_back(cobj); + } + return v; +} + /* Method to deal with variable passed by reference */ inline std::string getStringObjValue(const jobject obj, JNIEnv* env) { @@ -141,7 +255,7 @@ inline void setBoolObjValue(const bool value, const jobject obj, JNIEnv* env) { jclass objClass = env->GetObjectClass(obj); jfieldID objFid = env->GetFieldID(objClass, "value", "Z"); - env->SetIntField(obj, objFid, c2jni(value)); + env->SetIntField(obj, objFid, c2jni(value, env)); } inline void setPairObjValue(const std::string& filename, const int offset,