Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ The release run heads these entries with the version and opens a fresh

## Unreleased

- Java bindings reject out-of-range coordinates, style channels, CSV delimiters
and rendering limits instead of silently wrapping their integer values.

- Java bindings preserve supplementary Unicode in exception messages, reject
unpaired UTF-16 surrogates, and replace invalid native UTF-8 sequences.

Expand Down
3 changes: 3 additions & 0 deletions jni/java/app/opendocument/core/Sheet.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public TableDimensions content(TableDimensions range) {
if (range == null) {
return contentNative(handle(), -1, -1);
}
if (range.rows < 0 || range.columns < 0) {
throw new IllegalArgumentException("range dimensions must be nonnegative");
}
return contentNative(handle(), range.rows, range.columns);
}

Expand Down
15 changes: 9 additions & 6 deletions jni/src/jni_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace {

using odr_jni::checked_integer;
using odr_jni::from_handle;
using odr_jni::guarded;
using odr_jni::make_file_type_capabilities;
Expand Down Expand Up @@ -277,10 +278,12 @@ Java_app_opendocument_core_Odr_openWithOptionsNative(
options.csv.encoding = static_cast<odr::TextEncoding>(csv_encoding);
}
if (csv_separator >= 0) {
options.csv.separator = static_cast<char>(csv_separator);
options.csv.separator =
static_cast<char>(checked_integer<std::uint8_t>(csv_separator));
}
if (csv_quote >= 0) {
options.csv.quote = static_cast<char>(csv_quote);
options.csv.quote =
static_cast<char>(checked_integer<std::uint8_t>(csv_quote));
}
return make_handle(odr::open(to_string(env, path), options));
});
Expand Down Expand Up @@ -340,7 +343,7 @@ extern "C" JNIEXPORT jint JNICALL
Java_app_opendocument_core_TablePosition_toColumnNum(JNIEnv *env, jclass,
jstring string) {
return guarded(env, [&] {
return static_cast<jint>(
return checked_integer<jint>(
odr::TablePosition::to_column_num(to_string(env, string)));
});
}
Expand All @@ -349,7 +352,7 @@ extern "C" JNIEXPORT jint JNICALL
Java_app_opendocument_core_TablePosition_toRowNum(JNIEnv *env, jclass,
jstring string) {
return guarded(env, [&] {
return static_cast<jint>(
return checked_integer<jint>(
odr::TablePosition::to_row_num(to_string(env, string)));
});
}
Expand All @@ -359,7 +362,7 @@ Java_app_opendocument_core_TablePosition_toColumnString(JNIEnv *env, jclass,
jint column) {
return guarded(env, [&] {
return to_jstring(env, odr::TablePosition::to_column_string(
static_cast<std::uint32_t>(column)));
checked_integer<std::uint32_t>(column)));
});
}

Expand All @@ -368,6 +371,6 @@ Java_app_opendocument_core_TablePosition_toRowString(JNIEnv *env, jclass,
jint row) {
return guarded(env, [&] {
return to_jstring(env, odr::TablePosition::to_row_string(
static_cast<std::uint32_t>(row)));
checked_integer<std::uint32_t>(row)));
});
}
55 changes: 31 additions & 24 deletions jni/src/jni_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace {

using odr_jni::checked_integer;
using odr_jni::destroy_handle;
using odr_jni::from_handle;
using odr_jni::guarded;
Expand Down Expand Up @@ -76,14 +77,14 @@ Java_app_opendocument_core_Document_recalculateNative(JNIEnv *env, jobject,
std::vector<jint> stated;
for (const auto *positions :
{&result.changed(), &result.circular(), &result.unevaluated()}) {
stated.push_back(static_cast<jint>(positions->size()));
stated.push_back(checked_integer<jint>(positions->size()));
}
for (const auto *positions :
{&result.changed(), &result.circular(), &result.unevaluated()}) {
for (const odr::SheetPosition &position : *positions) {
stated.push_back(static_cast<jint>(position.sheet));
stated.push_back(static_cast<jint>(position.cell.column));
stated.push_back(static_cast<jint>(position.cell.row));
stated.push_back(checked_integer<jint>(position.sheet));
stated.push_back(checked_integer<jint>(position.cell.column));
stated.push_back(checked_integer<jint>(position.cell.row));
}
}
jintArray array = env->NewIntArray(static_cast<jsize>(stated.size()));
Expand Down Expand Up @@ -477,9 +478,9 @@ Java_app_opendocument_core_Sheet_contentNative(JNIEnv *env, jobject,
jint columns) {
return guarded(env, [&] {
std::optional<odr::TableDimensions> range;
if (rows >= 0 && columns >= 0) {
range = odr::TableDimensions(static_cast<std::uint32_t>(rows),
static_cast<std::uint32_t>(columns));
if (rows != -1 || columns != -1) {
range = odr::TableDimensions(checked_integer<std::uint32_t>(rows),
checked_integer<std::uint32_t>(columns));
}
return odr_jni::make_table_dimensions(
env, element(handle).as_sheet().content(range));
Expand All @@ -489,8 +490,9 @@ Java_app_opendocument_core_Sheet_contentNative(JNIEnv *env, jobject,
extern "C" JNIEXPORT jlong JNICALL Java_app_opendocument_core_Sheet_cellNative(
JNIEnv *env, jobject, jlong handle, jint column, jint row) {
return guarded(env, [&] {
return wrap_element(element(handle).as_sheet().cell(
static_cast<std::uint32_t>(column), static_cast<std::uint32_t>(row)));
return wrap_element(
element(handle).as_sheet().cell(checked_integer<std::uint32_t>(column),
checked_integer<std::uint32_t>(row)));
});
}

Expand All @@ -516,7 +518,7 @@ Java_app_opendocument_core_Sheet_columnStyleNative(JNIEnv *env, jobject,
return guarded(env, [&] {
return odr_jni::make_table_column_style(
env, element(handle).as_sheet().column_style(
static_cast<std::uint32_t>(column)));
checked_integer<std::uint32_t>(column)));
});
}

Expand All @@ -525,8 +527,8 @@ Java_app_opendocument_core_Sheet_rowStyleNative(JNIEnv *env, jobject,
jlong handle, jint row) {
return guarded(env, [&] {
return odr_jni::make_table_row_style(
env,
element(handle).as_sheet().row_style(static_cast<std::uint32_t>(row)));
env, element(handle).as_sheet().row_style(
checked_integer<std::uint32_t>(row)));
});
}

Expand All @@ -537,8 +539,8 @@ Java_app_opendocument_core_Sheet_cellStyleNative(JNIEnv *env, jobject,
return guarded(env, [&] {
return odr_jni::make_table_cell_style(
env, element(handle).as_sheet().cell_style(
static_cast<std::uint32_t>(column),
static_cast<std::uint32_t>(row)));
checked_integer<std::uint32_t>(column),
checked_integer<std::uint32_t>(row)));
});
}

Expand All @@ -550,7 +552,8 @@ Java_app_opendocument_core_Sheet_setCellStyleNative(JNIEnv *env, jobject,
jobject text_style) {
guarded(env, [&] {
element(handle).as_sheet().set_cell_style(
static_cast<std::uint32_t>(column), static_cast<std::uint32_t>(row),
checked_integer<std::uint32_t>(column),
checked_integer<std::uint32_t>(row),
odr_jni::table_cell_style_from_java(env, cell_style),
odr_jni::text_style_from_java(env, text_style));
});
Expand All @@ -563,7 +566,7 @@ Java_app_opendocument_core_Sheet_setRowStyleNative(JNIEnv *env, jobject,
jobject text_style) {
guarded(env, [&] {
element(handle).as_sheet().set_row_style(
static_cast<std::uint32_t>(row),
checked_integer<std::uint32_t>(row),
odr_jni::table_cell_style_from_java(env, cell_style),
odr_jni::text_style_from_java(env, text_style));
});
Expand All @@ -576,7 +579,7 @@ Java_app_opendocument_core_Sheet_setColumnStyleNative(JNIEnv *env, jobject,
jobject text_style) {
guarded(env, [&] {
element(handle).as_sheet().set_column_style(
static_cast<std::uint32_t>(column),
checked_integer<std::uint32_t>(column),
odr_jni::table_cell_style_from_java(env, cell_style),
odr_jni::text_style_from_java(env, text_style));
});
Expand All @@ -587,8 +590,9 @@ Java_app_opendocument_core_Sheet_insertRowsNative(JNIEnv *env, jobject,
jlong handle, jint row,
jint count) {
guarded(env, [&] {
element(handle).as_sheet().insert_rows(static_cast<std::uint32_t>(row),
static_cast<std::uint32_t>(count));
element(handle).as_sheet().insert_rows(
checked_integer<std::uint32_t>(row),
checked_integer<std::uint32_t>(count));
});
}

Expand All @@ -597,8 +601,9 @@ Java_app_opendocument_core_Sheet_deleteRowsNative(JNIEnv *env, jobject,
jlong handle, jint row,
jint count) {
guarded(env, [&] {
element(handle).as_sheet().delete_rows(static_cast<std::uint32_t>(row),
static_cast<std::uint32_t>(count));
element(handle).as_sheet().delete_rows(
checked_integer<std::uint32_t>(row),
checked_integer<std::uint32_t>(count));
});
}

Expand All @@ -608,7 +613,8 @@ Java_app_opendocument_core_Sheet_insertColumnsNative(JNIEnv *env, jobject,
jint count) {
guarded(env, [&] {
element(handle).as_sheet().insert_columns(
static_cast<std::uint32_t>(column), static_cast<std::uint32_t>(count));
checked_integer<std::uint32_t>(column),
checked_integer<std::uint32_t>(count));
});
}

Expand All @@ -618,7 +624,8 @@ Java_app_opendocument_core_Sheet_deleteColumnsNative(JNIEnv *env, jobject,
jint count) {
guarded(env, [&] {
element(handle).as_sheet().delete_columns(
static_cast<std::uint32_t>(column), static_cast<std::uint32_t>(count));
checked_integer<std::uint32_t>(column),
checked_integer<std::uint32_t>(count));
});
}

Expand Down Expand Up @@ -833,7 +840,7 @@ Java_app_opendocument_core_ListItem_numberNative(JNIEnv *env, jobject,
if (const std::optional<std::uint32_t> value =
element(handle).as_list_item().number();
value.has_value()) {
number = static_cast<std::int32_t>(*value);
number = checked_integer<std::int32_t>(*value);
}
return odr_jni::make_integer_opt(env, number);
});
Expand Down
40 changes: 21 additions & 19 deletions jni/src/jni_style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ jobject box_long(JNIEnv *env, const std::optional<std::uint32_t> &value) {
return nullptr;
}
return call_static_object(env, "java/lang/Long", "valueOf",
"(J)Ljava/lang/Long;", static_cast<jlong>(*value));
"(J)Ljava/lang/Long;",
checked_integer<jlong>(*value));
}

jobject box_integer(JNIEnv *env, const std::optional<std::uint32_t> &value) {
Expand All @@ -80,15 +81,16 @@ jobject box_integer(JNIEnv *env, const std::optional<std::uint32_t> &value) {
}
return call_static_object(env, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;",
static_cast<jint>(*value));
checked_integer<jint>(*value));
}

jobject box_long(JNIEnv *env, const std::optional<std::uint64_t> &value) {
if (!value.has_value()) {
return nullptr;
}
return call_static_object(env, "java/lang/Long", "valueOf",
"(J)Ljava/lang/Long;", static_cast<jlong>(*value));
"(J)Ljava/lang/Long;",
checked_integer<jlong>(*value));
}

/// Looks up an enum constant by its C++ code (= Java ordinal).
Expand Down Expand Up @@ -145,7 +147,7 @@ jobject make_integer_opt(JNIEnv *env,
}
return call_static_object(env, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;",
static_cast<jint>(*value));
checked_integer<jint>(*value));
}

jobject make_measure(JNIEnv *env, const odr::Measure &value) {
Expand Down Expand Up @@ -263,7 +265,7 @@ std::optional<odr::Color> color_from_java(JNIEnv *env, const jobject value) {
}
jclass cls = env->GetObjectClass(value);
const auto channel = [&](const char *name) {
return static_cast<std::uint8_t>(
return checked_integer<std::uint8_t>(
env->GetIntField(value, env->GetFieldID(cls, name, "I")));
};
const odr::Color result(channel("red"), channel("green"), channel("blue"),
Expand Down Expand Up @@ -562,8 +564,8 @@ jobject make_page_layout(JNIEnv *env, const odr::PageLayout &layout) {
jobject make_table_dimensions(JNIEnv *env,
const odr::TableDimensions &dimensions) {
return new_object(env, "app/opendocument/core/TableDimensions", "(II)V",
static_cast<jint>(dimensions.rows),
static_cast<jint>(dimensions.columns));
checked_integer<jint>(dimensions.rows),
checked_integer<jint>(dimensions.columns));
}

jobject make_html_sheet_cut(JNIEnv *env,
Expand All @@ -580,8 +582,8 @@ jobject make_html_sheet_cut(JNIEnv *env,

jobject make_table_position(JNIEnv *env, const odr::TablePosition &position) {
return new_object(env, "app/opendocument/core/TablePosition", "(II)V",
static_cast<jint>(position.column),
static_cast<jint>(position.row));
checked_integer<jint>(position.column),
checked_integer<jint>(position.row));
}

jobject make_file_meta(JNIEnv *env, const odr::FileMeta &meta) {
Expand Down Expand Up @@ -692,7 +694,7 @@ jobject html_config_to_java(JNIEnv *env, const odr::HtmlConfig &config) {
box_long(env, config.spreadsheet_cell_limit));
set_boolean("spreadsheetLimitByContent", config.spreadsheet_limit_by_content);
set_long("spreadsheetStyleBuffer",
static_cast<jlong>(config.spreadsheet_style_buffer));
checked_integer<jlong>(config.spreadsheet_style_buffer));
set_object("spreadsheetGridlines",
"Lapp/opendocument/core/HtmlTableGridlines;",
enum_from_code(env, "app/opendocument/core/HtmlTableGridlines",
Expand All @@ -717,7 +719,7 @@ jobject html_config_to_java(JNIEnv *env, const odr::HtmlConfig &config) {
set_boolean("formatHtml", config.format_html);
set_int("htmlIndent", config.html_indent);
set_string("htmlIndentString", config.html_indent_string);
set_int("pageRangeBegin", static_cast<jint>(config.page_range_begin));
set_int("pageRangeBegin", checked_integer<jint>(config.page_range_begin));
set_object("pageRangeEnd", "Ljava/lang/Integer;",
box_integer(env, config.page_range_end));
set_object("pdfTextMode", "Lapp/opendocument/core/PdfTextMode;",
Expand Down Expand Up @@ -841,8 +843,8 @@ odr::HtmlConfig html_config_from_java(JNIEnv *env, jobject config) {
const jint columns = env->GetIntField(
limit, env->GetFieldID(dimensions_cls, "columns", "I"));
result.spreadsheet_limit =
odr::TableDimensions(static_cast<std::uint32_t>(rows),
static_cast<std::uint32_t>(columns));
odr::TableDimensions(checked_integer<std::uint32_t>(rows),
checked_integer<std::uint32_t>(columns));
env->DeleteLocalRef(dimensions_cls);
}
}
Expand All @@ -853,13 +855,13 @@ odr::HtmlConfig html_config_from_java(JNIEnv *env, jobject config) {
} else {
jclass long_cls = env->GetObjectClass(cell_limit);
jmethodID long_value = env->GetMethodID(long_cls, "longValue", "()J");
result.spreadsheet_cell_limit = static_cast<std::uint64_t>(
result.spreadsheet_cell_limit = checked_integer<std::uint64_t>(
env->CallLongMethod(cell_limit, long_value));
env->DeleteLocalRef(long_cls);
}
}
result.spreadsheet_style_buffer =
static_cast<std::uint64_t>(get_long("spreadsheetStyleBuffer"));
checked_integer<std::uint64_t>(get_long("spreadsheetStyleBuffer"));
result.spreadsheet_limit_by_content =
get_boolean("spreadsheetLimitByContent");
{
Expand Down Expand Up @@ -895,7 +897,7 @@ odr::HtmlConfig html_config_from_java(JNIEnv *env, jobject config) {
jclass integer_cls = env->GetObjectClass(width);
jmethodID int_value = env->GetMethodID(integer_cls, "intValue", "()I");
result.viewport_width =
static_cast<std::uint32_t>(env->CallIntMethod(width, int_value));
checked_integer<std::uint32_t>(env->CallIntMethod(width, int_value));
env->DeleteLocalRef(integer_cls);
}
env->DeleteLocalRef(width);
Expand All @@ -920,10 +922,10 @@ odr::HtmlConfig html_config_from_java(JNIEnv *env, jobject config) {
env->DeleteLocalRef(margin);
}
result.format_html = get_boolean("formatHtml");
result.html_indent = static_cast<std::uint8_t>(get_int("htmlIndent"));
result.html_indent = checked_integer<std::uint8_t>(get_int("htmlIndent"));
result.html_indent_string = get_string("htmlIndentString");
result.page_range_begin =
static_cast<std::uint32_t>(get_int("pageRangeBegin"));
checked_integer<std::uint32_t>(get_int("pageRangeBegin"));
{
jobject end = get_object("pageRangeEnd", "Ljava/lang/Integer;");
if (end == nullptr) {
Expand All @@ -932,7 +934,7 @@ odr::HtmlConfig html_config_from_java(JNIEnv *env, jobject config) {
jclass integer_cls = env->GetObjectClass(end);
jmethodID int_value = env->GetMethodID(integer_cls, "intValue", "()I");
result.page_range_end =
static_cast<std::uint32_t>(env->CallIntMethod(end, int_value));
checked_integer<std::uint32_t>(env->CallIntMethod(end, int_value));
env->DeleteLocalRef(integer_cls);
}
}
Expand Down
Loading
Loading