Skip to content

Commit 16cf8ac

Browse files
authored
fix exception handling in hostFileNative (#399)
1 parent 201f6db commit 16cf8ac

File tree

1 file changed

+148
-135
lines changed

1 file changed

+148
-135
lines changed

app/src/main/cpp/CoreWrapper.cpp

Lines changed: 148 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -17,61 +17,61 @@
1717

1818
namespace {
1919

20-
std::string convertString(JNIEnv *env, jstring string) {
21-
jboolean isCopy;
22-
const char *cstring = env->GetStringUTFChars(string, &isCopy);
23-
auto cppstring = std::string(cstring, env->GetStringUTFLength(string));
24-
env->ReleaseStringUTFChars(string, cstring);
25-
return cppstring;
26-
}
20+
std::string convertString(JNIEnv *env, jstring string) {
21+
jboolean isCopy;
22+
const char *cstring = env->GetStringUTFChars(string, &isCopy);
23+
auto cppstring = std::string(cstring, env->GetStringUTFLength(string));
24+
env->ReleaseStringUTFChars(string, cstring);
25+
return cppstring;
26+
}
2727

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

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

39-
class AndroidLogger final : public odr::Logger {
40-
public:
41-
static int to_android_log_level(odr::LogLevel level) {
42-
switch (level) {
43-
case odr::LogLevel::verbose:
44-
return ANDROID_LOG_VERBOSE;
45-
case odr::LogLevel::debug:
46-
return ANDROID_LOG_DEBUG;
47-
case odr::LogLevel::info:
48-
return ANDROID_LOG_INFO;
49-
case odr::LogLevel::warning:
50-
return ANDROID_LOG_WARN;
51-
case odr::LogLevel::error:
52-
return ANDROID_LOG_ERROR;
53-
case odr::LogLevel::fatal:
54-
return ANDROID_LOG_FATAL;
55-
default:
56-
return ANDROID_LOG_UNKNOWN;
39+
class AndroidLogger final : public odr::Logger {
40+
public:
41+
static int to_android_log_level(odr::LogLevel level) {
42+
switch (level) {
43+
case odr::LogLevel::verbose:
44+
return ANDROID_LOG_VERBOSE;
45+
case odr::LogLevel::debug:
46+
return ANDROID_LOG_DEBUG;
47+
case odr::LogLevel::info:
48+
return ANDROID_LOG_INFO;
49+
case odr::LogLevel::warning:
50+
return ANDROID_LOG_WARN;
51+
case odr::LogLevel::error:
52+
return ANDROID_LOG_ERROR;
53+
case odr::LogLevel::fatal:
54+
return ANDROID_LOG_FATAL;
55+
default:
56+
return ANDROID_LOG_UNKNOWN;
57+
}
5758
}
58-
}
5959

60-
void flush() override {}
60+
void flush() override {}
6161

62-
[[nodiscard]] bool will_log(odr::LogLevel level) const override {
63-
return true;
64-
}
62+
[[nodiscard]] bool will_log(odr::LogLevel level) const override {
63+
return true;
64+
}
6565

66-
protected:
67-
void log_impl(Time time, odr::LogLevel level, const std::string &message,
68-
const std::source_location &location) override {
69-
__android_log_print(to_android_log_level(level), "smn", "%s", message.c_str());
70-
}
66+
protected:
67+
void log_impl(Time time, odr::LogLevel level, const std::string &message,
68+
const std::source_location &location) override {
69+
__android_log_print(to_android_log_level(level), "smn", "%s", message.c_str());
70+
}
7171

72-
private:
72+
private:
7373

74-
};
74+
};
7575

7676
}
7777

@@ -300,7 +300,7 @@ std::optional<odr::HttpServer> s_server;
300300

301301
JNIEXPORT void JNICALL
302302
Java_at_tomtasche_reader_background_CoreWrapper_createServerNative(JNIEnv *env, jclass clazz,
303-
jstring cachePath) {
303+
jstring cachePath) {
304304
__android_log_print(ANDROID_LOG_INFO, "smn", "create server");
305305

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

315315
JNIEXPORT jobject JNICALL
316-
Java_at_tomtasche_reader_background_CoreWrapper_hostFileNative(JNIEnv *env, jclass clazz, jstring prefix,
317-
jobject options) {
316+
Java_at_tomtasche_reader_background_CoreWrapper_hostFileNative(JNIEnv *env, jclass clazz,
317+
jstring prefix,
318+
jobject options) {
318319
__android_log_print(ANDROID_LOG_INFO, "smn", "host file");
319320

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

333-
s_server->clear();
334-
335-
jclass optionsClass = env->GetObjectClass(options);
334+
try {
335+
s_server->clear();
336336

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

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

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

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

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

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

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

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

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

369-
if (file.password_encrypted()) {
370-
if (!passwordCpp.has_value()) {
371-
env->SetIntField(result, errorField, -2);
372-
return result;
373-
}
374366
try {
375-
file = file.decrypt(passwordCpp.value());
376-
} catch (...) {
377-
env->SetIntField(result, errorField, -2);
378-
return result;
379-
}
380-
}
381-
382-
if (file.is_document_file()) {
383-
// TODO this will cause a second load
384-
s_document = file.as_document_file().document();
385-
}
367+
odr::DecodePreference decodePreference;
368+
decodePreference.engine_priority = {odr::DecoderEngine::poppler,
369+
odr::DecoderEngine::wvware,
370+
odr::DecoderEngine::odr};
371+
odr::DecodedFile file = odr::open(inputPathCpp, decodePreference, *logger);
386372

387-
odr::HtmlConfig htmlConfig;
388-
htmlConfig.embed_images = false;
389-
htmlConfig.embed_shipped_resources = true;
390-
htmlConfig.relative_resource_paths = false;
391-
htmlConfig.text_document_margin = paging;
392-
htmlConfig.editable = editable;
373+
if (file.password_encrypted()) {
374+
if (!passwordCpp.has_value()) {
375+
env->SetIntField(result, errorField, -2);
376+
return result;
377+
}
378+
try {
379+
file = file.decrypt(passwordCpp.value());
380+
} catch (...) {
381+
env->SetIntField(result, errorField, -2);
382+
return result;
383+
}
384+
}
393385

394-
try {
395-
std::string output_tmp = outputPathCpp + "/tmp";
396-
std::filesystem::create_directories(output_tmp);
397-
odr::HtmlService service = odr::html::translate(file, output_tmp, htmlConfig, logger);
398-
s_server->connect_service(service, prefixCpp);
399-
odr::HtmlViews htmlViews = service.list_views();
400-
401-
for (const auto &view: htmlViews) {
402-
__android_log_print(ANDROID_LOG_INFO, "smn", "view name=%s path=%s", view.name().c_str(), view.path().c_str());
403-
if (file.is_document_file() && (
404-
(((file.as_document_file().document_type() == odr::DocumentType::presentation) ||
405-
(file.as_document_file().document_type() == odr::DocumentType::drawing)) &&
406-
(view.name() != "document")) ||
407-
((file.as_document_file().document_type() == odr::DocumentType::spreadsheet) &&
408-
(view.name() == "document")))) {
409-
continue;
386+
if (file.is_document_file()) {
387+
// TODO this will cause a second load
388+
s_document = file.as_document_file().document();
410389
}
411390

412-
jstring pageName = env->NewStringUTF(view.name().c_str());
413-
env->CallBooleanMethod(pageNames, addMethod, pageName);
391+
odr::HtmlConfig htmlConfig;
392+
htmlConfig.embed_images = false;
393+
htmlConfig.embed_shipped_resources = true;
394+
htmlConfig.relative_resource_paths = false;
395+
htmlConfig.text_document_margin = paging;
396+
htmlConfig.editable = editable;
397+
398+
std::string output_tmp = outputPathCpp + "/tmp";
399+
std::filesystem::create_directories(output_tmp);
400+
odr::HtmlService service = odr::html::translate(file, output_tmp, htmlConfig, logger);
401+
s_server->connect_service(service, prefixCpp);
402+
odr::HtmlViews htmlViews = service.list_views();
403+
404+
for (const auto &view: htmlViews) {
405+
__android_log_print(ANDROID_LOG_INFO, "smn", "view name=%s path=%s",
406+
view.name().c_str(), view.path().c_str());
407+
if (file.is_document_file() && (
408+
(((file.as_document_file().document_type() ==
409+
odr::DocumentType::presentation) ||
410+
(file.as_document_file().document_type() ==
411+
odr::DocumentType::drawing)) &&
412+
(view.name() != "document")) ||
413+
((file.as_document_file().document_type() ==
414+
odr::DocumentType::spreadsheet) &&
415+
(view.name() == "document")))) {
416+
continue;
417+
}
418+
419+
jstring pageName = env->NewStringUTF(view.name().c_str());
420+
env->CallBooleanMethod(pageNames, addMethod, pageName);
414421

415-
std::string pagePathCpp =
416-
"http://localhost:29665/file/" + prefixCpp + "/" + view.path();
417-
jstring pagePath = env->NewStringUTF(pagePathCpp.c_str());
418-
env->CallBooleanMethod(pagePaths, addMethod, pagePath);
422+
std::string pagePathCpp =
423+
"http://localhost:29665/file/" + prefixCpp + "/" + view.path();
424+
jstring pagePath = env->NewStringUTF(pagePathCpp.c_str());
425+
env->CallBooleanMethod(pagePaths, addMethod, pagePath);
426+
}
427+
} catch (const odr::UnknownFileType &e) {
428+
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unknown file type: %s", e.what());
429+
env->SetIntField(result, errorField, -5);
430+
return result;
431+
} catch (const odr::UnsupportedFileType &e) {
432+
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unsupported file type: %s", e.what());
433+
env->SetIntField(result, errorField, -5);
434+
return result;
435+
} catch (const std::exception &e) {
436+
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ exception: %s", e.what());
437+
env->SetIntField(result, errorField, -4);
438+
return result;
439+
} catch (...) {
440+
__android_log_print(ANDROID_LOG_ERROR, "smn",
441+
"Unhandled C++ exception without further information");
442+
env->SetIntField(result, errorField, -4);
443+
return result;
419444
}
420-
} catch (const std::exception &e) {
421-
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ exception: %s", e.what());
422-
env->SetIntField(result, errorField, -1);
423-
return result;
424-
} catch (const std::string &s) {
425-
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ string exception: %s", s.c_str());
426-
env->SetIntField(result, errorField, -1);
427-
return result;
428-
} catch (int i) {
429-
__android_log_print(ANDROID_LOG_ERROR, "smn", "Unhandled C++ int exception: %i", i);
430-
env->SetIntField(result, errorField, -1);
431-
return result;
432445
} catch (...) {
433-
__android_log_print(ANDROID_LOG_ERROR, "smn",
434-
"Unhandled C++ exception without further information");
435-
env->SetIntField(result, errorField, -1);
446+
env->SetIntField(result, errorField, -3);
436447
return result;
437448
}
438449

450+
env->SetIntField(result, errorField, 0);
439451
return result;
440452
}
441453

442454
JNIEXPORT void JNICALL
443-
Java_at_tomtasche_reader_background_CoreWrapper_listenServerNative(JNIEnv *env, jclass clazz, jint port) {
455+
Java_at_tomtasche_reader_background_CoreWrapper_listenServerNative(JNIEnv *env, jclass clazz,
456+
jint port) {
444457
__android_log_print(ANDROID_LOG_INFO, "smn", "listen ...");
445458

446459
s_server->listen("127.0.0.1", port);

0 commit comments

Comments
 (0)