From 49663bc483f424f26ffa18f8bfb2dba86395c699 Mon Sep 17 00:00:00 2001 From: Johann1994 <37308757+Johann1994@users.noreply.github.com> Date: Wed, 18 Dec 2019 13:50:34 +0100 Subject: [PATCH 01/10] Sharedstringtable Same strings in shared stringtable makes it not possible to open a xlsx file. --- source/workbook/workbook.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index fcea0b12..59f9a8af 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -1374,9 +1374,18 @@ std::size_t workbook::add_shared_string(const rich_text &shared, bool allow_dupl } } - auto sz = d_->shared_strings_ids_.size(); - d_->shared_strings_ids_[shared] = sz; + //it can happen that similar strings are more then onetime in the shared stringtable (Excel bugfix?) + //shared_strings_values map should start on position 0 + auto sz = d_->shared_strings_values_.size(); + if (d_->shared_strings_values_.count(sz) > 0) + { + // something went wrong! + throw invalid_file("Error in shared string table!"); + } + d_->shared_strings_values_[sz] = shared; + d_->shared_strings_ids_[shared] = sz; + return sz; } From d6262df55583bd88f7bb402a01685a6dd5b1744e Mon Sep 17 00:00:00 2001 From: Johann1994 <37308757+Johann1994@users.noreply.github.com> Date: Wed, 18 Dec 2019 13:53:23 +0100 Subject: [PATCH 02/10] Shared strings It can happen that some strings are not unique in sharedstring table --- source/detail/serialization/xlsx_consumer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index 2f29e19f..3fdbad1b 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -1923,13 +1923,15 @@ void xlsx_consumer::read_shared_string_table() { expect_start_element(qn("spreadsheetml", "si"), xml::content::complex); auto rt = read_rich_text(qn("spreadsheetml", "si")); - target_.add_shared_string(rt); + //by reading in it can happen we have similar strings from modified excel worksheets... + //so allow to add duplicates + target_.add_shared_string(rt, true); expect_end_element(qn("spreadsheetml", "si")); } expect_end_element(qn("spreadsheetml", "sst")); - if (has_unique_count && unique_count != target_.shared_strings().size()) + if (has_unique_count && unique_count != target_.shared_strings_by_id().size()) { throw invalid_file("sizes don't match"); } From 319c4197c19db4fa0f2e8998bd9ef56a5b20a865 Mon Sep 17 00:00:00 2001 From: Adam Hooper Date: Tue, 28 Jul 2020 15:29:12 -0400 Subject: [PATCH 03/10] Streaming: skip empty rows in has_cell()/read_cell() Previously, an empty row would mess with the parser: if we're in an empty row, our helper methods don't detect us as being in the "row" _or_ in the "sheetData". So `has_cell()` would return false when it shouldn't. Similarly, `read_cell()` wouldn't skip rows; so `read_cell()` would return an invalid cell when placed in an empty row, causing a segfault when the caller tried to use the cell. Callers must take care to call `has_next()` before `read_next()`. In the future, perhaps we can make `read_next()` return a `std::optional` and nix `has_next()` altogether? [Closes #492] --- source/detail/serialization/xlsx_consumer.cpp | 337 +++++++++--------- source/detail/serialization/xlsx_consumer.hpp | 2 - tests/data/Issue492_empty_row.xlsx | Bin 0 -> 4573 bytes tests/workbook/serialization_test_suite.cpp | 18 + 4 files changed, 188 insertions(+), 169 deletions(-) create mode 100644 tests/data/Issue492_empty_row.xlsx diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index 62d9c418..071c92c3 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -21,6 +21,7 @@ // @license: http://www.opensource.org/licenses/mit-license.php // @author: see AUTHORS file +#include #include #include // for std::accumulate #include @@ -406,171 +407,7 @@ void xlsx_consumer::open(std::istream &source) cell xlsx_consumer::read_cell() { - if (!has_cell()) - { - return cell(nullptr); - } - - auto ws = worksheet(current_worksheet_); - - if (in_element(qn("spreadsheetml", "sheetData"))) - { - expect_start_element(qn("spreadsheetml", "row"), xml::content::complex); // CT_Row - auto row_index = static_cast(std::stoul(parser().attribute("r"))); - auto &row_properties = ws.row_properties(row_index); - - if (parser().attribute_present("ht")) - { - row_properties.height = converter_.deserialise(parser().attribute("ht")); - } - - if (parser().attribute_present("customHeight")) - { - row_properties.custom_height = is_true(parser().attribute("customHeight")); - } - - if (parser().attribute_present("hidden") && is_true(parser().attribute("hidden"))) - { - row_properties.hidden = true; - } - - if (parser().attribute_present(qn("x14ac", "dyDescent"))) - { - row_properties.dy_descent = converter_.deserialise(parser().attribute(qn("x14ac", "dyDescent"))); - } - - if (parser().attribute_present("spans")) - { - row_properties.spans = parser().attribute("spans"); - } - - skip_attributes({"customFormat", "s", "customFont", - "outlineLevel", "collapsed", "thickTop", "thickBot", - "ph"}); - } - - if (!in_element(qn("spreadsheetml", "row"))) - { - return cell(nullptr); - } - - expect_start_element(qn("spreadsheetml", "c"), xml::content::complex); - - auto cell = streaming_ - ? xlnt::cell(streaming_cell_.get()) - : ws.cell(cell_reference(parser().attribute("r"))); - auto reference = cell_reference(parser().attribute("r")); - cell.d_->parent_ = current_worksheet_; - cell.d_->column_ = reference.column_index(); - cell.d_->row_ = reference.row(); - - if (parser().attribute_present("ph")) - { - cell.d_->phonetics_visible_ = parser().attribute("ph"); - } - - auto has_type = parser().attribute_present("t"); - auto type = has_type ? parser().attribute("t") : "n"; - - if (parser().attribute_present("s")) - { - cell.format(target_.format(static_cast(std::stoull(parser().attribute("s"))))); - } - - auto has_value = false; - auto value_string = std::string(); - - auto has_formula = false; - auto has_shared_formula = false; - auto formula_value_string = std::string(); - - while (in_element(qn("spreadsheetml", "c"))) - { - auto current_element = expect_start_element(xml::content::mixed); - - if (current_element == qn("spreadsheetml", "v")) // s:ST_Xstring - { - has_value = true; - value_string = read_text(); - } - else if (current_element == qn("spreadsheetml", "f")) // CT_CellFormula - { - has_formula = true; - - if (parser().attribute_present("t")) - { - has_shared_formula = parser().attribute("t") == "shared"; - } - - skip_attributes({"aca", "ref", "dt2D", "dtr", "del1", - "del2", "r1", "r2", "ca", "si", "bx"}); - - formula_value_string = read_text(); - } - else if (current_element == qn("spreadsheetml", "is")) // CT_Rst - { - expect_start_element(qn("spreadsheetml", "t"), xml::content::simple); - has_value = true; - value_string = read_text(); - expect_end_element(qn("spreadsheetml", "t")); - } - else - { - unexpected_element(current_element); - } - - expect_end_element(current_element); - } - - expect_end_element(qn("spreadsheetml", "c")); - - if (has_formula && !has_shared_formula) - { - cell.formula(formula_value_string); - } - - if (has_value) - { - if (type == "str") - { - cell.d_->value_text_ = value_string; - cell.data_type(cell::type::formula_string); - } - else if (type == "inlineStr") - { - cell.d_->value_text_ = value_string; - cell.data_type(cell::type::inline_string); - } - else if (type == "s") - { - cell.d_->value_numeric_ = converter_.deserialise(value_string); - cell.data_type(cell::type::shared_string); - } - else if (type == "b") // boolean - { - cell.value(is_true(value_string)); - } - else if (type == "n") // numeric - { - cell.value(converter_.deserialise(value_string)); - } - else if (!value_string.empty() && value_string[0] == '#') - { - cell.error(value_string); - } - } - - if (!in_element(qn("spreadsheetml", "row"))) - { - expect_end_element(qn("spreadsheetml", "row")); - - if (!in_element(qn("spreadsheetml", "sheetData"))) - { - expect_end_element(qn("spreadsheetml", "sheetData")); - } - } - - return cell; + return cell(streaming_cell_.get()); } void xlsx_consumer::read_worksheet(const std::string &rel_id) @@ -1411,8 +1248,174 @@ xml::parser &xlsx_consumer::parser() bool xlsx_consumer::has_cell() { - return in_element(qn("spreadsheetml", "row")) - || in_element(qn("spreadsheetml", "sheetData")); + auto ws = worksheet(current_worksheet_); + + while (streaming_cell_ // we're not at the end of the file + && !in_element(qn("spreadsheetml", "row"))) // we're at the end of a row, or between rows + { + if (parser().peek() == xml::parser::event_type::end_element + && stack_.back() == qn("spreadsheetml", "row")) + { + // We're at the end of a row. + expect_end_element(qn("spreadsheetml", "row")); + // ... and keep parsing. + } + + if (parser().peek() == xml::parser::event_type::end_element + && stack_.back() == qn("spreadsheetml", "sheetData")) + { + // End of sheet. Mark it by setting streaming_cell_ to nullptr, so we never get here again. + expect_end_element(qn("spreadsheetml", "sheetData")); + streaming_cell_.reset(nullptr); + break; + } + + expect_start_element(qn("spreadsheetml", "row"), xml::content::complex); // CT_Row + auto row_index = static_cast(std::stoul(parser().attribute("r"))); + auto &row_properties = ws.row_properties(row_index); + + if (parser().attribute_present("ht")) + { + row_properties.height = converter_.deserialise(parser().attribute("ht")); + } + + if (parser().attribute_present("customHeight")) + { + row_properties.custom_height = is_true(parser().attribute("customHeight")); + } + + if (parser().attribute_present("hidden") && is_true(parser().attribute("hidden"))) + { + row_properties.hidden = true; + } + + if (parser().attribute_present(qn("x14ac", "dyDescent"))) + { + row_properties.dy_descent = converter_.deserialise(parser().attribute(qn("x14ac", "dyDescent"))); + } + + if (parser().attribute_present("spans")) + { + row_properties.spans = parser().attribute("spans"); + } + + skip_attributes({"customFormat", "s", "customFont", + "outlineLevel", "collapsed", "thickTop", "thickBot", + "ph"}); + } + + if (!streaming_cell_) + { + // We're at the end of the worksheet + return false; + } + + expect_start_element(qn("spreadsheetml", "c"), xml::content::complex); + + assert(streaming_); + auto cell = xlnt::cell(streaming_cell_.get()); + auto reference = cell_reference(parser().attribute("r")); + cell.d_->parent_ = current_worksheet_; + cell.d_->column_ = reference.column_index(); + cell.d_->row_ = reference.row(); + + if (parser().attribute_present("ph")) + { + cell.d_->phonetics_visible_ = parser().attribute("ph"); + } + + auto has_type = parser().attribute_present("t"); + auto type = has_type ? parser().attribute("t") : "n"; + + if (parser().attribute_present("s")) + { + cell.format(target_.format(static_cast(std::stoull(parser().attribute("s"))))); + } + + auto has_value = false; + auto value_string = std::string(); + + auto has_formula = false; + auto has_shared_formula = false; + auto formula_value_string = std::string(); + + while (in_element(qn("spreadsheetml", "c"))) + { + auto current_element = expect_start_element(xml::content::mixed); + + if (current_element == qn("spreadsheetml", "v")) // s:ST_Xstring + { + has_value = true; + value_string = read_text(); + } + else if (current_element == qn("spreadsheetml", "f")) // CT_CellFormula + { + has_formula = true; + + if (parser().attribute_present("t")) + { + has_shared_formula = parser().attribute("t") == "shared"; + } + + skip_attributes({"aca", "ref", "dt2D", "dtr", "del1", + "del2", "r1", "r2", "ca", "si", "bx"}); + + formula_value_string = read_text(); + } + else if (current_element == qn("spreadsheetml", "is")) // CT_Rst + { + expect_start_element(qn("spreadsheetml", "t"), xml::content::simple); + has_value = true; + value_string = read_text(); + expect_end_element(qn("spreadsheetml", "t")); + } + else + { + unexpected_element(current_element); + } + + expect_end_element(current_element); + } + + expect_end_element(qn("spreadsheetml", "c")); + + if (has_formula && !has_shared_formula) + { + cell.formula(formula_value_string); + } + + if (has_value) + { + if (type == "str") + { + cell.d_->value_text_ = value_string; + cell.data_type(cell::type::formula_string); + } + else if (type == "inlineStr") + { + cell.d_->value_text_ = value_string; + cell.data_type(cell::type::inline_string); + } + else if (type == "s") + { + cell.d_->value_numeric_ = converter_.deserialise(value_string); + cell.data_type(cell::type::shared_string); + } + else if (type == "b") // boolean + { + cell.value(is_true(value_string)); + } + else if (type == "n") // numeric + { + cell.value(converter_.deserialise(value_string)); + } + else if (!value_string.empty() && value_string[0] == '#') + { + cell.error(value_string); + } + } + + return true; } std::vector xlsx_consumer::read_relationships(const path &part) diff --git a/source/detail/serialization/xlsx_consumer.hpp b/source/detail/serialization/xlsx_consumer.hpp index c9a987ee..2dbafa01 100644 --- a/source/detail/serialization/xlsx_consumer.hpp +++ b/source/detail/serialization/xlsx_consumer.hpp @@ -413,8 +413,6 @@ private: std::unique_ptr streaming_cell_; - detail::cell_impl *current_cell_; - detail::worksheet_impl *current_worksheet_; number_serialiser converter_; }; diff --git a/tests/data/Issue492_empty_row.xlsx b/tests/data/Issue492_empty_row.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..32b6da5aaee2633288a1b6f8e3bf43fc6d0e4874 GIT binary patch literal 4573 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, std::string("a")); } + + void test_Issue492_stream_empty_row() + { + xlnt::streaming_workbook_reader wbr; + wbr.open(path_helper::test_file("Issue492_empty_row.xlsx")); + wbr.begin_worksheet("BLS Data Series"); + xlnt_assert(wbr.has_cell()); + xlnt_assert_equals(wbr.read_cell().reference(), "A1"); + xlnt_assert(wbr.has_cell()); + xlnt_assert_equals(wbr.read_cell().reference(), "A2"); + xlnt_assert(wbr.has_cell()); + xlnt_assert_equals(wbr.read_cell().reference(), "A4"); + xlnt_assert(wbr.has_cell()); + xlnt_assert_equals(wbr.read_cell().reference(), "B4"); + xlnt_assert(!wbr.has_cell()); + } }; static serialization_test_suite x; From 4da7183b1cd9e8ad349353365ec12bdb0824a512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=89=91=E6=B3=A2?= <940930034@qq.com> Date: Wed, 12 Aug 2020 16:36:30 +0800 Subject: [PATCH 04/10] Fixed an exception that was thrown when the namespace in the external link is a web address. --- source/packaging/ext_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/packaging/ext_list.cpp b/source/packaging/ext_list.cpp index c7b3a75f..2d78e9fd 100644 --- a/source/packaging/ext_list.cpp +++ b/source/packaging/ext_list.cpp @@ -32,7 +32,7 @@ xlnt::uri roundtrip(xml::parser &p, xml::serializer &s) } for (auto &ele : attribs) { - s.attribute(ele.first.string(), ele.second.value); + s.attribute(ele.first, ele.second.value); } break; } From 0ecad78c1d54a3d2eb9046ee39349db1619198d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=89=91=E6=B3=A2?= <940930034@qq.com> Date: Tue, 25 Aug 2020 09:00:22 +0800 Subject: [PATCH 05/10] Fixed an exception thrown when parsing external links. --- source/detail/serialization/xlsx_consumer.cpp | 5 ++++ tests/data/Issue503_external_link.xlsx | Bin 0 -> 19619 bytes tests/workbook/serialization_test_suite.cpp | 24 +++++++++++++----- 3 files changed, 22 insertions(+), 7 deletions(-) create mode 100755 tests/data/Issue503_external_link.xlsx diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index 62d9c418..0fb7092d 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -243,6 +243,11 @@ xlnt::detail::Cell parse_cell(xlnt::row_t row_arg, xml::parser *parser) throw xlnt::exception("unexcpected XML parsing event"); } } + // Prevents unhandled exceptions from being triggered. + for (auto &attr : parser->attribute_map()) + { + (void)attr; + } } return c; } diff --git a/tests/data/Issue503_external_link.xlsx b/tests/data/Issue503_external_link.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..d7aea8228ab49031643c7ceab29d0a4b0d9a5b17 GIT binary patch literal 19619 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 literal 0 HcmV?d00001 diff --git a/tests/workbook/serialization_test_suite.cpp b/tests/workbook/serialization_test_suite.cpp index 289e08ca..ddad3713 100644 --- a/tests/workbook/serialization_test_suite.cpp +++ b/tests/workbook/serialization_test_suite.cpp @@ -23,28 +23,28 @@ #include +#include #include #include -#include -#include -#include +#include #include +#include #include #include -#include +#include #include #include #include #include #include +#include #include #include #include -#include #include +#include #include #include -#include #include #include #include @@ -93,6 +93,7 @@ public: register_test(test_load_save_german_locale); register_test(test_Issue445_inline_str_load); register_test(test_Issue445_inline_str_streaming_read); + register_test(test_Issue503_external_link_load); } bool workbook_matches_file(xlnt::workbook &wb, const xlnt::path &file) @@ -714,7 +715,7 @@ public: void test_load_save_german_locale() { - /* std::locale current(std::locale::global(std::locale("de-DE"))); + /* std::locale current(std::locale::global(std::locale("de-DE"))); test_round_trip_rw_custom_heights_widths(); std::locale::global(current);*/ } @@ -736,5 +737,14 @@ public: auto cell = wbr.read_cell(); xlnt_assert_equals(cell.value(), std::string("a")); } + + void test_Issue503_external_link_load() + { + xlnt::workbook wb; + wb.load(path_helper::test_file("Issue503_external_link.xlsx")); + auto ws = wb.active_sheet(); + auto cell = ws.cell("A1"); + xlnt_assert_equals(cell.value(), std::string("WDG_IC_00000003.aut")); + } }; static serialization_test_suite x; From dafdfa3ebb64dc29963f6fce7ba0f15179d470cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=89=91=E6=B3=A2?= <940930034@qq.com> Date: Tue, 25 Aug 2020 13:32:21 +0800 Subject: [PATCH 06/10] Add the function of getting table hidden attributes. --- include/xlnt/workbook/workbook.hpp | 7 +++++++ .../detail/implementations/workbook_impl.hpp | 17 ++++++++++------- source/detail/serialization/xlsx_consumer.cpp | 4 +++- source/workbook/workbook.cpp | 10 ++++++++++ tests/data/16_hidden_sheet.xlsx | Bin 0 -> 9297 bytes tests/worksheet/worksheet_test_suite.cpp | 8 ++++++++ 6 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 tests/data/16_hidden_sheet.xlsx diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index 00ad3710..87be789b 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -241,6 +241,13 @@ public: /// const worksheet sheet_by_id(std::size_t id) const; + /// + /// Returns the hidden identifier of the worksheet at the given index. + /// This will throw an exception if index is greater than or equal to the + /// number of sheets in this workbook. + /// + bool sheet_hidden_by_index(std::size_t index) const; + /// /// Returns true if this workbook contains a sheet with the given title. /// diff --git a/source/detail/implementations/workbook_impl.hpp b/source/detail/implementations/workbook_impl.hpp index 710e13e6..07a2e5f3 100644 --- a/source/detail/implementations/workbook_impl.hpp +++ b/source/detail/implementations/workbook_impl.hpp @@ -79,6 +79,7 @@ struct workbook_impl manifest_ = other.manifest_; sheet_title_rel_id_map_ = other.sheet_title_rel_id_map_; + sheet_hidden_ = other.sheet_hidden_; view_ = other.view_; code_name_ = other.code_name_; file_version_ = other.file_version_; @@ -105,6 +106,7 @@ struct workbook_impl && extended_properties_ == other.extended_properties_ && custom_properties_ == other.custom_properties_ && sheet_title_rel_id_map_ == other.sheet_title_rel_id_map_ + && sheet_hidden_ == other.sheet_hidden_ && view_ == other.view_ && code_name_ == other.code_name_ && file_version_ == other.file_version_ @@ -134,16 +136,17 @@ struct workbook_impl std::vector> custom_properties_; std::unordered_map sheet_title_rel_id_map_; + std::vector sheet_hidden_; optional view_; optional code_name_; - struct file_version_t - { - std::string app_name; - std::size_t last_edited; - std::size_t lowest_edited; - std::size_t rup_build; + struct file_version_t + { + std::string app_name; + std::size_t last_edited; + std::size_t lowest_edited; + std::size_t rup_build; bool operator==(const file_version_t& rhs) const { @@ -152,7 +155,7 @@ struct workbook_impl && lowest_edited == rhs.lowest_edited && rup_build == rhs.rup_build; } - }; + }; optional file_version_; optional calculation_properties_; diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index 62d9c418..0a9d1c58 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -1883,12 +1883,14 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_ expect_start_element(qn("spreadsheetml", "sheet"), xml::content::simple); auto title = parser().attribute("name"); - skip_attribute("state"); sheet_title_index_map_[title] = index++; sheet_title_id_map_[title] = parser().attribute("sheetId"); target_.d_->sheet_title_rel_id_map_[title] = parser().attribute(qn("r", "id")); + bool hidden = parser().attribute("state", "") == "hidden"; + target_.d_->sheet_hidden_.push_back(hidden); + expect_end_element(qn("spreadsheetml", "sheet")); } } diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 32217224..b281b736 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -716,6 +716,16 @@ const worksheet workbook::sheet_by_id(std::size_t id) const throw key_not_found(); } +bool workbook::sheet_hidden_by_index(std::size_t index) const +{ + if (index >= d_->sheet_hidden_.size()) + { + throw invalid_parameter(); + } + + return d_->sheet_hidden_.at(index); +} + worksheet workbook::active_sheet() { return sheet_by_index(d_->active_sheet_index_.is_set() ? d_->active_sheet_index_.get() : 0); diff --git a/tests/data/16_hidden_sheet.xlsx b/tests/data/16_hidden_sheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b8093eaa1252e3ac96787d4b9fa03efceb365352 GIT binary patch literal 9297 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 literal 0 HcmV?d00001 diff --git a/tests/worksheet/worksheet_test_suite.cpp b/tests/worksheet/worksheet_test_suite.cpp index 0f88e321..64b47da1 100644 --- a/tests/worksheet/worksheet_test_suite.cpp +++ b/tests/worksheet/worksheet_test_suite.cpp @@ -112,6 +112,7 @@ public: register_test(test_delete_columns); register_test(test_insert_too_many); register_test(test_insert_delete_moves_merges); + register_test(test_hidden_sheet); } void test_new_worksheet() @@ -1582,5 +1583,12 @@ public: xlnt_assert_equals(merged, expected); } } + + void test_hidden_sheet() + { + xlnt::workbook wb; + wb.load(path_helper::test_file("16_hidden_sheet.xlsx")); + xlnt_assert_equals(wb.sheet_hidden_by_index(1), true); + } }; static worksheet_test_suite x; From e8dd38d0d6c7ba3b71ad354758b4d86d288b6041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=89=91=E6=B3=A2?= <940930034@qq.com> Date: Tue, 25 Aug 2020 15:08:20 +0800 Subject: [PATCH 07/10] Fix throwing exception when duplicate shared strings occur. --- include/xlnt/workbook/workbook.hpp | 9 ++------ .../detail/implementations/workbook_impl.hpp | 2 +- source/detail/serialization/xlsx_consumer.cpp | 2 +- source/detail/serialization/xlsx_producer.cpp | 6 ++--- source/workbook/workbook.cpp | 21 ++++++------------ tests/data/Issue494_shared_string.xlsx | Bin 0 -> 15618 bytes tests/workbook/workbook_test_suite.cpp | 10 +++++++++ 7 files changed, 24 insertions(+), 26 deletions(-) create mode 100755 tests/data/Issue494_shared_string.xlsx diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index 00ad3710..275363fb 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -760,11 +760,6 @@ public: /// std::size_t add_shared_string(const rich_text &shared, bool allow_duplicates = false); - /// - /// Returns a reference to the shared string ordered by id - /// - const std::map &shared_strings_by_id() const; - /// /// Returns a reference to the shared string related to the specified index /// @@ -774,13 +769,13 @@ public: /// Returns a reference to the shared strings being used by cells /// in this workbook. /// - std::unordered_map &shared_strings(); + std::vector &shared_strings(); /// /// Returns a reference to the shared strings being used by cells /// in this workbook. /// - const std::unordered_map &shared_strings() const; + const std::vector &shared_strings() const; // Thumbnail diff --git a/source/detail/implementations/workbook_impl.hpp b/source/detail/implementations/workbook_impl.hpp index 710e13e6..76308872 100644 --- a/source/detail/implementations/workbook_impl.hpp +++ b/source/detail/implementations/workbook_impl.hpp @@ -118,7 +118,7 @@ struct workbook_impl std::list worksheets_; std::unordered_map shared_strings_ids_; - std::map shared_strings_values_; + std::vector shared_strings_values_; optional stylesheet_; diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index 62d9c418..ede14048 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -2088,7 +2088,7 @@ void xlsx_consumer::read_shared_string_table() { expect_start_element(qn("spreadsheetml", "si"), xml::content::complex); auto rt = read_rich_text(qn("spreadsheetml", "si")); - target_.add_shared_string(rt); + target_.add_shared_string(rt, true); expect_end_element(qn("spreadsheetml", "si")); } diff --git a/source/detail/serialization/xlsx_producer.cpp b/source/detail/serialization/xlsx_producer.cpp index e6683a31..db8279af 100644 --- a/source/detail/serialization/xlsx_producer.cpp +++ b/source/detail/serialization/xlsx_producer.cpp @@ -944,12 +944,12 @@ void xlsx_producer::write_shared_string_table(const relationship & /*rel*/) } write_attribute("count", string_count); - write_attribute("uniqueCount", source_.shared_strings_by_id().size()); + write_attribute("uniqueCount", source_.shared_strings().size()); - for (const auto &string : source_.shared_strings_by_id()) + for (const auto &text : source_.shared_strings()) { write_start_element(xmlns, "si"); - write_rich_text(xmlns, string.second); + write_rich_text(xmlns, text); write_end_element(xmlns, "si"); } diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 32217224..11c7afa0 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -1348,32 +1348,25 @@ const manifest &workbook::manifest() const return d_->manifest_; } -const std::map &workbook::shared_strings_by_id() const -{ - return d_->shared_strings_values_; -} - const rich_text &workbook::shared_strings(std::size_t index) const { - auto it = d_->shared_strings_values_.find(index); - - if (it != d_->shared_strings_values_.end()) + if (index < d_->shared_strings_values_.size()) { - return it->second; + return d_->shared_strings_values_.at(index); } static rich_text empty; return empty; } -std::unordered_map &workbook::shared_strings() +std::vector &workbook::shared_strings() { - return d_->shared_strings_ids_; + return d_->shared_strings_values_; } -const std::unordered_map &workbook::shared_strings() const +const std::vector &workbook::shared_strings() const { - return d_->shared_strings_ids_; + return d_->shared_strings_values_; } std::size_t workbook::add_shared_string(const rich_text &shared, bool allow_duplicates) @@ -1392,7 +1385,7 @@ std::size_t workbook::add_shared_string(const rich_text &shared, bool allow_dupl auto sz = d_->shared_strings_ids_.size(); d_->shared_strings_ids_[shared] = sz; - d_->shared_strings_values_[sz] = shared; + d_->shared_strings_values_.push_back(shared); return sz; } diff --git a/tests/data/Issue494_shared_string.xlsx b/tests/data/Issue494_shared_string.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..87d8a17d927481cddafee66df37a19dbb4cad2eb GIT binary patch literal 15618 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 Date: Sat, 2 Jan 2021 12:32:51 -0500 Subject: [PATCH 08/10] translate travis to circleci --- .circleci/config.yml | 78 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..7d652a98 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,78 @@ +version: 2.1 + +jobs: + build: + docker: + - image: lycantropos/cmake:3.9.5 + parameters: + benchmarks: + default: "OFF" + type: string + build-type: + default: Release + type: string + coverage: + default: "OFF" + type: string + cxx-ver: + default: "11" + type: string + samples: + default: "OFF" + type: string + static: + default: "ON" + type: string + steps: + - checkout + - run: cmake -D XLNT_CXX_LANG=<< parameters.cxx-ver >> -D STATIC=<< parameters.static >> -D BENCHMARKS=<< parameters.benchmarks >> -D SAMPLES=<< parameters.samples >> -D COVERAGE=<< parameters.coverage >> -D CMAKE_BUILD_TYPE=<< parameters.build-type >> . + - run: cmake --build . -- -j2 + - run: ./tests/xlnt.test + - when: + condition: + equal: [ "ON", << parameters.samples >> ] + steps: + - run: ./samples/sample-decrypt + - run: ./samples/sample-img2xlsx ./samples/data/cafe.jpg img.xlsx + - run: ./samples/sample-documentation + - when: + condition: + equal: [ "ON", << parameters.benchmarks >> ] + steps: + - run: ./benchmarks/benchmark-styles + - run: ./benchmarks/benchmark-writer + - when: + condition: + equal: [ "ON", << parameters.coverage >> ] + steps: + - run: lcov --directory source/CMakeFiles/xlnt.dir --capture --output-file coverage.info --base-directory ../source --no-external --gcov-tool /usr/bin/gcov-6 + - run: lcov --output-file coverage.info --remove coverage.info source/detail/serialization/miniz.cpp + - run: i=$(dirname $(pwd)) + - run: sed -i "s|$i/||" coverage.info + - run: cd .. + - run: coveralls-lcov build/coverage.info + +workflows: + test: + jobs: + - build: + matrix: + parameters: + cxx-ver: + - "11" + - "17" + build-type: + - Release + - Debug + static: + - "ON" + - "OFF" + build: + jobs: + - build: + cxx-ver: "11" + build-type: Debug + static: "ON" + samples: "ON" + benchmarks: "ON" + coverage: "OFF" From e6ecd04265b6eb0690227dfec8d933dd8ab055f9 Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Sat, 2 Jan 2021 12:49:36 -0500 Subject: [PATCH 09/10] use smaller image --- .circleci/config.yml | 10 +- .travis.yml | 231 --------------------------------------- samples/data/penguin.jpg | Bin 0 -> 1267 bytes 3 files changed, 6 insertions(+), 235 deletions(-) delete mode 100644 .travis.yml create mode 100644 samples/data/penguin.jpg diff --git a/.circleci/config.yml b/.circleci/config.yml index 7d652a98..366e91af 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,7 +33,7 @@ jobs: equal: [ "ON", << parameters.samples >> ] steps: - run: ./samples/sample-decrypt - - run: ./samples/sample-img2xlsx ./samples/data/cafe.jpg img.xlsx + - run: ./samples/sample-img2xlsx ./samples/data/penguin.jpg img.xlsx - run: ./samples/sample-documentation - when: condition: @@ -53,9 +53,10 @@ jobs: - run: coveralls-lcov build/coverage.info workflows: - test: + build: jobs: - build: + name: tests matrix: parameters: cxx-ver: @@ -67,12 +68,13 @@ workflows: static: - "ON" - "OFF" - build: - jobs: - build: + name: samples-benchmarks-coverage cxx-ver: "11" build-type: Debug static: "ON" samples: "ON" benchmarks: "ON" coverage: "OFF" + requires: + - tests \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 46619412..00000000 --- a/.travis.yml +++ /dev/null @@ -1,231 +0,0 @@ -# cpp takes longer -language: minimal -sudo: false -dist: trusty - -git: - depth: false - -notifications: - email: false - -# set up build matrix -matrix: - include: - # ============= GCC ================== - # gcc-5, c++11, release build, dynamic linking - - os: linux - compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-5 - env: - - CXX_COMPILER=g++-5 - - C_COMPILER=gcc-5 - - CXX_VER=11 - - BUILD_TYPE=Release - - COVERAGE=OFF - - STATIC=OFF - - SAMPLES=OFF - - BENCHMARKS=OFF - - RELEASE=OFF - - # ============= GCC ================== - # gcc-6, c++11, release build, dynamic linking - - os: linux - compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - env: - - CXX_COMPILER=g++-6 - - C_COMPILER=gcc-6 - - CXX_VER=11 - - BUILD_TYPE=Release - - COVERAGE=OFF - - STATIC=OFF - - SAMPLES=OFF - - BENCHMARKS=OFF - - RELEASE=OFF - - # gcc-7, c++14, release build, static linking - - os: linux - compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-7 - env: - - CXX_COMPILER=g++-7 - - C_COMPILER=gcc-7 - - CXX_VER=14 - - BUILD_TYPE=Release - - COVERAGE=OFF - - STATIC=ON - - SAMPLES=OFF - - BENCHMARKS=OFF - - RELEASE=OFF - - # gcc-8, c++17, release build, static linking, samples + benchmarks compiled and run - - os: linux - compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-8 - env: - - CXX_COMPILER=g++-8 - - C_COMPILER=gcc-8 - - CXX_VER=17 - - BUILD_TYPE=Release - - COVERAGE=OFF - - STATIC=ON - - SAMPLES=ON - - BENCHMARKS=ON - - RELEASE=ON - - # =========== CLANG ============= - # clang 4, c++11, release build, dynamic linking - - os: linux - compiler: clang - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-4.0 - packages: - - clang-4.0 - env: - - CXX_COMPILER=clang++-4.0 - - C_COMPILER=clang-4.0 - - CXX_VER=11 - - BUILD_TYPE=Release - - COVERAGE=OFF - - STATIC=OFF - - SAMPLES=OFF - - BENCHMARKS=OFF - - RELEASE=OFF - - # clang 5, c++14, release build, dynamic linking - - os: linux - compiler: clang - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-5.0 - packages: - - clang-5.0 - env: - - CXX_COMPILER=clang++-5.0 - - C_COMPILER=clang-5.0 - - CXX_VER=14 - - BUILD_TYPE=Release - - COVERAGE=OFF - - STATIC=ON - - SAMPLES=OFF - - BENCHMARKS=OFF - - RELEASE=OFF - - # clang 6, c++17, release build, static linking, samples + benchmarks compiled and run - - os: linux - compiler: clang - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 - packages: - - clang-6.0 - env: - - CXX_COMPILER=clang++-6.0 - - C_COMPILER=clang-6.0 - - CXX_VER=17 - - BUILD_TYPE=Release - - COVERAGE=OFF - - STATIC=ON - - SAMPLES=ON - - BENCHMARKS=ON - - RELEASE=ON - - # ============= CODE COVERAGE =============== - # gcc-6, c++11, debug build, static linking, code coverage enabled - - os: linux - compiler: gcc - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - - lcov - env: - - CXX_COMPILER=g++-6 - - C_COMPILER=gcc-6 - - CXX_VER=11 - - BUILD_TYPE=Debug - - COVERAGE=ON - - STATIC=ON - - SAMPLES=OFF - -before_install: - - export CC=${C_COMPILER} - - export CXX=${CXX_COMPILER} - -install: - - | - if [[ "${COVERAGE}" == "ON" ]]; then - gem install coveralls-lcov; - fi - - ${CXX} --version - - cmake --version - -script: - - mkdir build - - cd build - - cmake .. -DXLNT_CXX_LANG=${CXX_VER} -DSTATIC=$STATIC -DBENCHMARKS=$BENCHMARKS -DSAMPLES=$SAMPLES -DCOVERAGE=$COVERAGE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DRELEASE=$RELEASE - - cmake --build . -- -j2 - - ./tests/xlnt.test - - echo "samples" && echo 'travis_fold:start:samples' - - if [[ "${SAMPLES}" == "ON" ]]; then ./samples/sample-decrypt; fi - - if [[ "${SAMPLES}" == "ON" ]]; then ./samples/sample-img2xlsx "../samples/data/cafe.jpg" "img.xlsx"; fi - - if [[ "${SAMPLES}" == "ON" ]]; then ./samples/sample-documentation; fi - - echo 'travis_fold:end:samples' - - echo "benchmarks" && echo 'travis_fold:start:benchmarks' - - if [[ "${BENCHMARKS}" == "ON" ]]; then ./benchmarks/benchmark-styles; fi - - if [[ "${BENCHMARKS}" == "ON" ]]; then ./benchmarks/benchmark-writer; fi - - echo 'travis_fold:end:benchmarks' - - -after_success: - - | - if [[ "${COVERAGE}" == "ON" ]]; then - lcov --directory source/CMakeFiles/xlnt.dir --capture --output-file coverage.info --base-directory ../source --no-external --gcov-tool /usr/bin/gcov-6 - lcov --output-file coverage.info --remove coverage.info source/detail/serialization/miniz.cpp - i=$(dirname $(pwd)) - sed -i "s|$i/||" coverage.info - cd .. - coveralls-lcov build/coverage.info - fi - -deploy: - provider: releases - api_key: - secure: "EJKEQkbmNFyXAJYOro7/wSlxSns4O4RAmht5PCBYuOgEqIbB1+QbQjNZd18KyCkqaHQEvww4hVGMdcFsTFnsznjGo6NnDtiYTdhiREtdUd6ohUD0eHTZ15ZL7mW1XR8HWqvv33piDX40UI/dFn1XYLnWunaLZvF5WPa9bzTsloaYHbjxoRw5S4fd0VyqZ2w2zuezCCRUezDcNGOxbVTbB3moSh+hpjrNkw7YxoPNm48CwGRVeRj28XuhDjobfRtPSZMb6Y+EDUnrIZI1mKvB1bkL8QR2ndBtqlG0BWvmEcdDuiQnraJk3iRIAU5T/ycyRqR2UKcW2Fv0iVp5SL9VuqhcvIUxTsYXzuNOZ3hKiWRTj6ndG+gDBsD1K5YwScZksAImwvj/VGEla9Q044W3PbYV2GUE++8mtiZUaxbkaP+uDFUBR5eXqAkte9mainwJ3eaMJ7Tx1KCqkzKO011nUasWfmBWxRUA8vm44SfzwzVfjXToLQZGe4KYzF2cHaXo2YIC48vE/DYs3VnVvnrCjNDO8Cr3m+lfdulhjIZlg+WymQcxuJs7LVzCW7mBPNnrUNOOrGCGP4f/hFxBLk8/eJDznIAzbW27Z1zAHn+MlbADRBzC0Y7cmme4Zu2W7Wy9NTvzNsKabOH/Fe1TfGetEEf6mZ5g7Q3+oZPJ2raLFD8=" - file_glob: true - file: build/*.tar.gz - skip_cleanup: true - overwite: true - on: - repo: tfussell/xlnt - tags: true diff --git a/samples/data/penguin.jpg b/samples/data/penguin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7bbaac249504cd9222b28fae95f31acd6a9400b4 GIT binary patch literal 1267 zcmex=PfpQEif~-P{hK_8)fr;!& zg(60c6BlwQJ8e8D8g%i4ig8j=6DOCLxP+vXs+zinrk07RnYo3fm9vYho4bdnS8zyZ zSa?KaRB}pcT6#uiR&hybS$RceRdY*gTYE=m*QCi)rcRqaW9F9X@jO*zpr5PhGlvL#L{}KKmz3FSN_2GY7KMEhpi~rdC zsQs<{N29y@ME=Np_`AKUPOnD$N9+UXd?EkpN9())GsxE&)JXr(|M2;6)Uln9SNHlK zUcmlG`1C(6#ufi=MU@|2&+;ei2kRsLo5|l6|DCtTF?(@M{txl$$Nw3){uF#6cg^SCQ=9v6=bJsDADSP(Klq=aXFlsc z#UI)3*KN4-SN`Z=e#|dbVV2KWe=ux+wtjE?hrqYaUemvse>8uy`a>1}4dKW6NBBFe z%$w`e@^6-V{YZU0zxAHg-xdEPDxUpki1?`AxJAEh{?_&*{I|jn*)!H>zHg2f{>saL zWS;GnKjI(Ej)(t9{kZ$^bbE%&JtrCe1ZwWkd zWuKhIER%;^TOO@S$_!Z^)U(2B^HRTTLC(NAtK6nsnd&Mj$NeGap6!2zrnPk^_e<@6 zFvqHGs`#7yhx2cSKjx9&e*f70_Wuk5CHazdXYOwmoBGlGxV=bC>2JLngAbN)xK4wMCDm#3f*KLV<*pgTuQ>~Jh7kgR5L^BU2K9n+; OY8lkjwd}F{|C<2kiv}(L literal 0 HcmV?d00001 From e702e7e68b8dcae2543cfc4ce625e161cd7b959b Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Sat, 2 Jan 2021 12:50:27 -0500 Subject: [PATCH 10/10] remove requires --- .circleci/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 366e91af..3319b667 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -76,5 +76,3 @@ workflows: samples: "ON" benchmarks: "ON" coverage: "OFF" - requires: - - tests \ No newline at end of file