Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
283 changes: 148 additions & 135 deletions app/src/main/cpp/CoreWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,61 +17,61 @@

namespace {

std::string convertString(JNIEnv *env, jstring string) {
jboolean isCopy;
const char *cstring = env->GetStringUTFChars(string, &isCopy);
auto cppstring = std::string(cstring, env->GetStringUTFLength(string));
env->ReleaseStringUTFChars(string, cstring);
return cppstring;
}
std::string convertString(JNIEnv *env, jstring string) {
jboolean isCopy;
const char *cstring = env->GetStringUTFChars(string, &isCopy);
auto cppstring = std::string(cstring, env->GetStringUTFLength(string));
env->ReleaseStringUTFChars(string, cstring);
return cppstring;
}

std::string getStringField(JNIEnv *env, jclass clazz, jobject object, const char *name) {
jfieldID field = env->GetFieldID(clazz, name, "Ljava/lang/String;");
auto string = (jstring) env->GetObjectField(object, field);
return convertString(env, string);
}
std::string getStringField(JNIEnv *env, jclass clazz, jobject object, const char *name) {
jfieldID field = env->GetFieldID(clazz, name, "Ljava/lang/String;");
auto string = (jstring) env->GetObjectField(object, field);
return convertString(env, string);
}

std::string getStringField(JNIEnv *env, jobject object, const char *name) {
jclass clazz = env->GetObjectClass(object);
return getStringField(env, clazz, object, name);
}
std::string getStringField(JNIEnv *env, jobject object, const char *name) {
jclass clazz = env->GetObjectClass(object);
return getStringField(env, clazz, object, name);
}

class AndroidLogger final : public odr::Logger {
public:
static int to_android_log_level(odr::LogLevel level) {
switch (level) {
case odr::LogLevel::verbose:
return ANDROID_LOG_VERBOSE;
case odr::LogLevel::debug:
return ANDROID_LOG_DEBUG;
case odr::LogLevel::info:
return ANDROID_LOG_INFO;
case odr::LogLevel::warning:
return ANDROID_LOG_WARN;
case odr::LogLevel::error:
return ANDROID_LOG_ERROR;
case odr::LogLevel::fatal:
return ANDROID_LOG_FATAL;
default:
return ANDROID_LOG_UNKNOWN;
class AndroidLogger final : public odr::Logger {
public:
static int to_android_log_level(odr::LogLevel level) {
switch (level) {
case odr::LogLevel::verbose:
return ANDROID_LOG_VERBOSE;
case odr::LogLevel::debug:
return ANDROID_LOG_DEBUG;
case odr::LogLevel::info:
return ANDROID_LOG_INFO;
case odr::LogLevel::warning:
return ANDROID_LOG_WARN;
case odr::LogLevel::error:
return ANDROID_LOG_ERROR;
case odr::LogLevel::fatal:
return ANDROID_LOG_FATAL;
default:
return ANDROID_LOG_UNKNOWN;
}
}
}

void flush() override {}
void flush() override {}

[[nodiscard]] bool will_log(odr::LogLevel level) const override {
return true;
}
[[nodiscard]] bool will_log(odr::LogLevel level) const override {
return true;
}

protected:
void log_impl(Time time, odr::LogLevel level, const std::string &message,
const std::source_location &location) override {
__android_log_print(to_android_log_level(level), "smn", "%s", message.c_str());
}
protected:
void log_impl(Time time, odr::LogLevel level, const std::string &message,
const std::source_location &location) override {
__android_log_print(to_android_log_level(level), "smn", "%s", message.c_str());
}

private:
private:

};
};

}

Expand Down Expand Up @@ -300,7 +300,7 @@ std::optional<odr::HttpServer> s_server;

JNIEXPORT void JNICALL
Java_at_tomtasche_reader_background_CoreWrapper_createServerNative(JNIEnv *env, jclass clazz,
jstring cachePath) {
jstring cachePath) {
__android_log_print(ANDROID_LOG_INFO, "smn", "create server");

std::string cachePathCpp = convertString(env, cachePath);
Expand All @@ -313,8 +313,9 @@ Java_at_tomtasche_reader_background_CoreWrapper_createServerNative(JNIEnv *env,
}

JNIEXPORT jobject JNICALL
Java_at_tomtasche_reader_background_CoreWrapper_hostFileNative(JNIEnv *env, jclass clazz, jstring prefix,
jobject options) {
Java_at_tomtasche_reader_background_CoreWrapper_hostFileNative(JNIEnv *env, jclass clazz,
jstring prefix,
jobject options) {
__android_log_print(ANDROID_LOG_INFO, "smn", "host file");

auto logger = std::make_shared<AndroidLogger>();
Expand All @@ -330,117 +331,129 @@ Java_at_tomtasche_reader_background_CoreWrapper_hostFileNative(JNIEnv *env, jcla
return result;
}

s_server->clear();

jclass optionsClass = env->GetObjectClass(options);
try {
Comment thread
andiwand marked this conversation as resolved.
s_server->clear();

std::optional<std::string> passwordCpp;
jfieldID passwordField = env->GetFieldID(optionsClass, "password", "Ljava/lang/String;");
auto password = (jstring) env->GetObjectField(options, passwordField);
if (password != nullptr) {
passwordCpp = convertString(env, password);
}
jclass optionsClass = env->GetObjectClass(options);

jfieldID pagingField = env->GetFieldID(optionsClass, "paging", "Z");
jboolean paging = env->GetBooleanField(options, pagingField);
std::optional<std::string> passwordCpp;
jfieldID passwordField = env->GetFieldID(optionsClass, "password", "Ljava/lang/String;");
auto password = (jstring) env->GetObjectField(options, passwordField);
if (password != nullptr) {
passwordCpp = convertString(env, password);
}

jfieldID editableField = env->GetFieldID(optionsClass, "editable", "Z");
jboolean editable = env->GetBooleanField(options, editableField);
jfieldID pagingField = env->GetFieldID(optionsClass, "paging", "Z");
jboolean paging = env->GetBooleanField(options, pagingField);

std::string outputPathCpp = getStringField(env, optionsClass, options, "outputPath");
jfieldID editableField = env->GetFieldID(optionsClass, "editable", "Z");
jboolean editable = env->GetBooleanField(options, editableField);

jclass listClass = env->FindClass("java/util/List");
jmethodID addMethod = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
std::string outputPathCpp = getStringField(env, optionsClass, options, "outputPath");

jfieldID pageNamesField = env->GetFieldID(resultClass, "pageNames", "Ljava/util/List;");
auto pageNames = (jobject) env->GetObjectField(result, pageNamesField);
jclass listClass = env->FindClass("java/util/List");
jmethodID addMethod = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");

jfieldID pagePathsField = env->GetFieldID(resultClass, "pagePaths", "Ljava/util/List;");
auto pagePaths = (jobject) env->GetObjectField(result, pagePathsField);
jfieldID pageNamesField = env->GetFieldID(resultClass, "pageNames", "Ljava/util/List;");
auto pageNames = (jobject) env->GetObjectField(result, pageNamesField);

std::string inputPathCpp = getStringField(env, options, "inputPath");
std::string prefixCpp = convertString(env, prefix);
jfieldID pagePathsField = env->GetFieldID(resultClass, "pagePaths", "Ljava/util/List;");
auto pagePaths = (jobject) env->GetObjectField(result, pagePathsField);

odr::DecodePreference decodePreference;
decodePreference.engine_priority = {odr::DecoderEngine::poppler, odr::DecoderEngine::wvware,
odr::DecoderEngine::odr};
odr::DecodedFile file = odr::open(inputPathCpp, decodePreference, *logger);
std::string inputPathCpp = getStringField(env, options, "inputPath");
std::string prefixCpp = convertString(env, prefix);

if (file.password_encrypted()) {
if (!passwordCpp.has_value()) {
env->SetIntField(result, errorField, -2);
return result;
}
try {
file = file.decrypt(passwordCpp.value());
} catch (...) {
env->SetIntField(result, errorField, -2);
return result;
}
}

if (file.is_document_file()) {
// TODO this will cause a second load
s_document = file.as_document_file().document();
}
odr::DecodePreference decodePreference;
decodePreference.engine_priority = {odr::DecoderEngine::poppler,
odr::DecoderEngine::wvware,
odr::DecoderEngine::odr};
odr::DecodedFile file = odr::open(inputPathCpp, decodePreference, *logger);

odr::HtmlConfig htmlConfig;
htmlConfig.embed_images = false;
htmlConfig.embed_shipped_resources = true;
htmlConfig.relative_resource_paths = false;
htmlConfig.text_document_margin = paging;
htmlConfig.editable = editable;
if (file.password_encrypted()) {
if (!passwordCpp.has_value()) {
env->SetIntField(result, errorField, -2);
return result;
}
try {
file = file.decrypt(passwordCpp.value());
} catch (...) {
env->SetIntField(result, errorField, -2);
return result;
}
}

try {
std::string output_tmp = outputPathCpp + "/tmp";
std::filesystem::create_directories(output_tmp);
odr::HtmlService service = odr::html::translate(file, output_tmp, htmlConfig, logger);
s_server->connect_service(service, prefixCpp);
odr::HtmlViews htmlViews = service.list_views();

for (const auto &view: htmlViews) {
__android_log_print(ANDROID_LOG_INFO, "smn", "view name=%s path=%s", view.name().c_str(), view.path().c_str());
if (file.is_document_file() && (
(((file.as_document_file().document_type() == odr::DocumentType::presentation) ||
(file.as_document_file().document_type() == odr::DocumentType::drawing)) &&
(view.name() != "document")) ||
((file.as_document_file().document_type() == odr::DocumentType::spreadsheet) &&
(view.name() == "document")))) {
continue;
if (file.is_document_file()) {
// TODO this will cause a second load
s_document = file.as_document_file().document();
}

jstring pageName = env->NewStringUTF(view.name().c_str());
env->CallBooleanMethod(pageNames, addMethod, pageName);
odr::HtmlConfig htmlConfig;
htmlConfig.embed_images = false;
htmlConfig.embed_shipped_resources = true;
htmlConfig.relative_resource_paths = false;
htmlConfig.text_document_margin = paging;
htmlConfig.editable = editable;

std::string output_tmp = outputPathCpp + "/tmp";
std::filesystem::create_directories(output_tmp);
odr::HtmlService service = odr::html::translate(file, output_tmp, htmlConfig, logger);
s_server->connect_service(service, prefixCpp);
odr::HtmlViews htmlViews = service.list_views();

for (const auto &view: htmlViews) {
__android_log_print(ANDROID_LOG_INFO, "smn", "view name=%s path=%s",
view.name().c_str(), view.path().c_str());
if (file.is_document_file() && (
(((file.as_document_file().document_type() ==
odr::DocumentType::presentation) ||
(file.as_document_file().document_type() ==
odr::DocumentType::drawing)) &&
(view.name() != "document")) ||
((file.as_document_file().document_type() ==
odr::DocumentType::spreadsheet) &&
(view.name() == "document")))) {
continue;
}

jstring pageName = env->NewStringUTF(view.name().c_str());
env->CallBooleanMethod(pageNames, addMethod, pageName);

std::string pagePathCpp =
"http://localhost:29665/file/" + prefixCpp + "/" + view.path();
jstring pagePath = env->NewStringUTF(pagePathCpp.c_str());
env->CallBooleanMethod(pagePaths, addMethod, pagePath);
std::string pagePathCpp =
"http://localhost:29665/file/" + prefixCpp + "/" + view.path();
jstring pagePath = env->NewStringUTF(pagePathCpp.c_str());
env->CallBooleanMethod(pagePaths, addMethod, pagePath);
Comment thread
andiwand marked this conversation as resolved.
}
} catch (const odr::UnknownFileType &e) {
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unknown file type: %s", e.what());
env->SetIntField(result, errorField, -5);
return result;
} catch (const odr::UnsupportedFileType &e) {
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unsupported file type: %s", e.what());
env->SetIntField(result, errorField, -5);
return result;
} catch (const std::exception &e) {
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ exception: %s", e.what());
env->SetIntField(result, errorField, -4);
return result;
} catch (...) {
__android_log_print(ANDROID_LOG_ERROR, "smn",
"Unhandled C++ exception without further information");
env->SetIntField(result, errorField, -4);
return result;
}
} catch (const std::exception &e) {
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ exception: %s", e.what());
env->SetIntField(result, errorField, -1);
return result;
} catch (const std::string &s) {
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ string exception: %s", s.c_str());
env->SetIntField(result, errorField, -1);
return result;
} catch (int i) {
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ int exception: %i", i);
env->SetIntField(result, errorField, -1);
return result;
} catch (...) {
__android_log_print(ANDROID_LOG_ERROR, "smn",
"Unhandled C++ exception without further information");
env->SetIntField(result, errorField, -1);
env->SetIntField(result, errorField, -3);
return result;
}

env->SetIntField(result, errorField, 0);
Comment thread
andiwand marked this conversation as resolved.
return result;
}

JNIEXPORT void JNICALL
Java_at_tomtasche_reader_background_CoreWrapper_listenServerNative(JNIEnv *env, jclass clazz, jint port) {
Java_at_tomtasche_reader_background_CoreWrapper_listenServerNative(JNIEnv *env, jclass clazz,
jint port) {
__android_log_print(ANDROID_LOG_INFO, "smn", "listen ...");

s_server->listen("127.0.0.1", port);
Expand Down
Loading