reformat xlsx_consumer.cpp

This commit is contained in:
Thomas Fussell 2016-11-19 17:19:38 -05:00
parent c89b36f749
commit daab3cf8ba

View File

@ -24,14 +24,14 @@
#include <cctype> #include <cctype>
#include <numeric> // for std::accumulate #include <numeric> // for std::accumulate
#include <detail/xlsx_consumer.hpp>
#include <detail/constants.hpp> #include <detail/constants.hpp>
#include <detail/custom_value_traits.hpp> #include <detail/custom_value_traits.hpp>
#include <detail/workbook_impl.hpp> #include <detail/workbook_impl.hpp>
#include <detail/xlsx_consumer.hpp>
#include <detail/zip.hpp> #include <detail/zip.hpp>
#include <xlnt/cell/cell.hpp> #include <xlnt/cell/cell.hpp>
#include <xlnt/utils/path.hpp>
#include <xlnt/packaging/manifest.hpp> #include <xlnt/packaging/manifest.hpp>
#include <xlnt/utils/path.hpp>
#include <xlnt/workbook/const_worksheet_iterator.hpp> #include <xlnt/workbook/const_worksheet_iterator.hpp>
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/worksheet.hpp> #include <xlnt/worksheet/worksheet.hpp>
@ -134,9 +134,9 @@ std::vector<xlnt::relationship> read_relationships(const xlnt::path &part, xlnt:
parser.next_expect(xml::parser::event_type::start_element, xmlns, "Relationship"); parser.next_expect(xml::parser::event_type::start_element, xmlns, "Relationship");
relationships.emplace_back(parser.attribute("Id"), relationships.emplace_back(parser.attribute("Id"),
parser.attribute<xlnt::relationship::type>("Type"), source, parser.attribute<xlnt::relationship::type>("Type"), source,
xlnt::uri(parser.attribute("Target")), xlnt::target_mode::internal); xlnt::uri(parser.attribute("Target")),
parser.next_expect(xml::parser::event_type::end_element, xlnt::target_mode::internal);
xlnt::constants::get_namespace("relationships"), "Relationship"); parser.next_expect(xml::parser::event_type::end_element, xmlns, "Relationship");
} }
parser.next_expect(xml::parser::event_type::end_element, xmlns, "Relationships"); parser.next_expect(xml::parser::event_type::end_element, xmlns, "Relationships");
@ -146,8 +146,8 @@ std::vector<xlnt::relationship> read_relationships(const xlnt::path &part, xlnt:
void check_document_type(const std::string &document_content_type) void check_document_type(const std::string &document_content_type)
{ {
if (document_content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" if (document_content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" &&
&& document_content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml ") document_content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml ")
{ {
throw xlnt::invalid_file(document_content_type); throw xlnt::invalid_file(document_content_type);
} }
@ -177,6 +177,7 @@ xml::parser &xlsx_consumer::parser()
void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain) void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
{ {
// ignore namespace declarations except in parts of these types
const auto using_namespaces = std::vector<relationship::type> const auto using_namespaces = std::vector<relationship::type>
{ {
relationship::type::office_document, relationship::type::office_document,
@ -216,7 +217,6 @@ void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
break; break;
case relationship::type::office_document: case relationship::type::office_document:
check_document_type(manifest.get_content_type(part_path));
read_workbook(); read_workbook();
break; break;
@ -272,24 +272,60 @@ void xlsx_consumer::read_part(const std::vector<relationship> &rel_chain)
read_worksheet(rel_chain.back().get_id()); read_worksheet(rel_chain.back().get_id());
break; break;
case relationship::type::thumbnail: break; case relationship::type::thumbnail:
case relationship::type::calculation_chain: break; break;
case relationship::type::hyperlink: break;
case relationship::type::comments: break; case relationship::type::calculation_chain:
case relationship::type::vml_drawing: break; read_calculation_chain();
case relationship::type::unknown: break; break;
case relationship::type::printer_settings: break;
case relationship::type::custom_property: break; case relationship::type::hyperlink:
case relationship::type::drawings: break; break;
case relationship::type::pivot_table_cache_definition: break;
case relationship::type::pivot_table_cache_records: break; case relationship::type::comments:
case relationship::type::query_table: break; break;
case relationship::type::shared_workbook: break;
case relationship::type::revision_log: break; case relationship::type::vml_drawing:
case relationship::type::shared_workbook_user_data: break; break;
case relationship::type::single_cell_table_definitions: break;
case relationship::type::table_definition: break; case relationship::type::unknown:
case relationship::type::image: break; break;
case relationship::type::printer_settings:
break;
case relationship::type::custom_property:
break;
case relationship::type::drawings:
break;
case relationship::type::pivot_table_cache_definition:
break;
case relationship::type::pivot_table_cache_records:
break;
case relationship::type::query_table:
break;
case relationship::type::shared_workbook:
break;
case relationship::type::revision_log:
break;
case relationship::type::shared_workbook_user_data:
break;
case relationship::type::single_cell_table_definitions:
break;
case relationship::type::table_definition:
break;
case relationship::type::image:
break;
} }
parser_ = nullptr; parser_ = nullptr;
@ -327,8 +363,7 @@ void xlsx_consumer::populate_workbook()
} }
} }
const auto workbook_rel = manifest.get_relationship(root_path, const auto workbook_rel = manifest.get_relationship(root_path, relationship::type::office_document);
relationship::type::office_document);
const auto workbook_parts_first = std::vector<relationship::type> const auto workbook_parts_first = std::vector<relationship::type>
{ {
@ -392,14 +427,18 @@ void xlsx_consumer::read_manifest()
if (parser.name() == "Default") if (parser.name() == "Default")
{ {
manifest.register_default_type(parser.attribute("Extension"), auto extension = parser.attribute("Extension");
parser.attribute("ContentType")); auto content_type = parser.attribute("ContentType");
manifest.register_default_type(extension, content_type);
parser.next_expect(xml::parser::event_type::end_element, xmlns, "Default"); parser.next_expect(xml::parser::event_type::end_element, xmlns, "Default");
} }
else if (parser.name() == "Override") else if (parser.name() == "Override")
{ {
manifest.register_override_type(path(parser.attribute("PartName")), auto part_name = parser.attribute("PartName");
parser.attribute("ContentType")); auto content_type = parser.attribute("ContentType");
manifest.register_override_type(path(part_name), content_type);
parser.next_expect(xml::parser::event_type::end_element, xmlns, "Override"); parser.next_expect(xml::parser::event_type::end_element, xmlns, "Override");
} }
} }
@ -408,6 +447,12 @@ void xlsx_consumer::read_manifest()
for (const auto &package_rel : package_rels) for (const auto &package_rel : package_rels)
{ {
if (package_rel.get_type() == relationship::type::office_document)
{
auto content_type = manifest.get_content_type(manifest.canonicalize({ package_rel }));
check_document_type(content_type);
}
manifest.register_relationship(uri("/"), manifest.register_relationship(uri("/"),
package_rel.get_type(), package_rel.get_type(),
package_rel.get_target(), package_rel.get_target(),
@ -419,8 +464,7 @@ void xlsx_consumer::read_manifest()
{ {
auto relationship_source = path(relationship_source_string); auto relationship_source = path(relationship_source_string);
if (relationship_source == path("_rels/.rels") if (relationship_source == path("_rels/.rels") || relationship_source.extension() != "rels") continue;
|| relationship_source.extension() != "rels") continue;
path part(relationship_source.parent().parent()); path part(relationship_source.parent().parent());
part = part.append(relationship_source.split_extension().first); part = part.append(relationship_source.split_extension().first);
@ -433,8 +477,11 @@ void xlsx_consumer::read_manifest()
for (const auto &part_rel : part_rels) for (const auto &part_rel : part_rels)
{ {
path target_path(source_directory.append(part_rel.get_target().get_path())); path target_path(source_directory.append(part_rel.get_target().get_path()));
manifest.register_relationship(source, part_rel.get_type(), manifest.register_relationship(source,
part_rel.get_target(), part_rel.get_target_mode(), part_rel.get_id()); part_rel.get_type(),
part_rel.get_target(),
part_rel.get_target_mode(),
part_rel.get_id());
} }
} }
} }
@ -451,73 +498,43 @@ void xlsx_consumer::read_extended_properties()
{ {
{ {
xml::qname(xmlns, "Application"), xml::qname(xmlns, "Application"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_application(c.read_text()); }
{
c.target_.set_application(c.read_text());
}
}, },
{ {
xml::qname(xmlns, "DocSecurity"), xml::qname(xmlns, "DocSecurity"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_doc_security(std::stoi(c.read_text())); }
{
c.target_.set_doc_security(std::stoi(c.read_text()));
}
}, },
{ {
xml::qname(xmlns, "ScaleCrop"), xml::qname(xmlns, "ScaleCrop"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_scale_crop(is_true(c.read_text())); }
{
c.target_.set_scale_crop(is_true(c.read_text()));
}
}, },
{ {
xml::qname(xmlns, "Company"), xml::qname(xmlns, "Company"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_company(c.read_text()); }
{
c.target_.set_company(c.read_text());
}
}, },
{ {
xml::qname(xmlns, "SharedDoc"), xml::qname(xmlns, "SharedDoc"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_shared_doc(is_true(c.read_text())); }
{
c.target_.set_shared_doc(is_true(c.read_text()));
}
}, },
{ {
xml::qname(xmlns, "HyperlinksChanged"), xml::qname(xmlns, "HyperlinksChanged"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_hyperlinks_changed(is_true(c.read_text())); }
{
c.target_.set_hyperlinks_changed(is_true(c.read_text()));
}
}, },
{ {
xml::qname(xmlns, "AppVersion"), xml::qname(xmlns, "AppVersion"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_app_version(c.read_text()); }
{
c.target_.set_app_version(c.read_text());
}
}, },
{ {
xml::qname(xmlns, "LinksUpToDate"), xml::qname(xmlns, "LinksUpToDate"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.target_.set_links_up_to_date(is_true(c.read_text())); }
{
c.target_.set_links_up_to_date(is_true(c.read_text()));
}
}, },
{ {
xml::qname(xmlns, "Template"), xml::qname(xmlns, "Template"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.read_text(); }
{
c.read_text();
}
}, },
{ {
xml::qname(xmlns, "TotalTime"), xml::qname(xmlns, "TotalTime"),
[](xlsx_consumer &c) [](xlsx_consumer &c) { c.read_text(); }
{
c.read_text();
}
}, },
{ {
xml::qname(xmlns, "HeadingPairs"), xml::qname(xmlns, "HeadingPairs"),
@ -567,7 +584,7 @@ void xlsx_consumer::read_extended_properties()
c.parser().next_expect(xml::parser::event_type::end_element, xmlns_vt, "vector"); c.parser().next_expect(xml::parser::event_type::end_element, xmlns_vt, "vector");
} }
}, }
}); });
} }
@ -655,8 +672,9 @@ void xlsx_consumer::read_workbook()
while (true) while (true)
{ {
if (parser().peek() == xml::parser::event_type::end_element if (parser().peek() == xml::parser::event_type::end_element ||
|| parser().peek() == xml::parser::event_type::end_namespace_decl) break; parser().peek() == xml::parser::event_type::end_namespace_decl)
break;
parser().next_expect(xml::parser::event_type::start_element); parser().next_expect(xml::parser::event_type::start_element);
parser().content(xml::parser::content_type::complex); parser().content(xml::parser::content_type::complex);
@ -667,6 +685,7 @@ void xlsx_consumer::read_workbook()
{ {
target_.d_->has_file_version_ = true; target_.d_->has_file_version_ = true;
target_.d_->file_version_.app_name = parser().attribute("appName"); target_.d_->file_version_.app_name = parser().attribute("appName");
if (parser().attribute_present("lastEdited")) if (parser().attribute_present("lastEdited"))
{ {
target_.d_->file_version_.last_edited = string_to_size_t(parser().attribute("lastEdited")); target_.d_->file_version_.last_edited = string_to_size_t(parser().attribute("lastEdited"));
@ -897,8 +916,8 @@ void xlsx_consumer::read_workbook()
} }
else if (qname == xml::qname(xmlns, "workbookProtection")) else if (qname == xml::qname(xmlns, "workbookProtection"))
{ {
while (parser().peek() != xml::parser::event_type::end_element while (parser().peek() != xml::parser::event_type::end_element ||
|| parser().qname() != xml::qname(xmlns, "workbookProtection")) parser().qname() != xml::qname(xmlns, "workbookProtection"))
{ {
parser().next(); parser().next();
} }
@ -1419,8 +1438,8 @@ void xlsx_consumer::read_stylesheet()
} }
else if (parser().qname() == xml::qname(xmlns, "colors")) else if (parser().qname() == xml::qname(xmlns, "colors"))
{ {
while (parser().peek() != xml::parser::event_type::end_element while (parser().peek() != xml::parser::event_type::end_element ||
|| parser().qname() != xml::qname(xmlns, "colors")) parser().qname() != xml::qname(xmlns, "colors"))
{ {
if (parser().next() == xml::parser::event_type::start_element) if (parser().next() == xml::parser::event_type::start_element)
{ {
@ -1471,8 +1490,8 @@ void xlsx_consumer::read_stylesheet()
throw xlnt::exception("counts don't match"); throw xlnt::exception("counts don't match");
} }
} }
else if (parser().qname() == xml::qname(xmlns, "cellStyleXfs") else if (parser().qname() == xml::qname(xmlns, "cellStyleXfs") ||
|| parser().qname() == xml::qname(xmlns, "cellXfs")) parser().qname() == xml::qname(xmlns, "cellXfs"))
{ {
auto in_style_records = parser().name() == "cellStyleXfs"; auto in_style_records = parser().name() == "cellStyleXfs";
auto count = parser().attribute<std::size_t>("count"); auto count = parser().attribute<std::size_t>("count");
@ -1489,8 +1508,7 @@ void xlsx_consumer::read_stylesheet()
: style_records.emplace(style_records.end())); : style_records.emplace(style_records.end()));
auto apply_alignment_present = parser().attribute_present("applyAlignment"); auto apply_alignment_present = parser().attribute_present("applyAlignment");
auto alignment_applied = apply_alignment_present auto alignment_applied = apply_alignment_present && is_true(parser().attribute("applyAlignment"));
&& is_true(parser().attribute("applyAlignment"));
record.alignment.second = alignment_applied; record.alignment.second = alignment_applied;
auto border_applied = parser().attribute_present("applyBorder") auto border_applied = parser().attribute_present("applyBorder")
@ -1537,34 +1555,38 @@ void xlsx_consumer::read_stylesheet()
{ {
if (parser().attribute_present("wrapText")) if (parser().attribute_present("wrapText"))
{ {
record.alignment.first.wrap(is_true(parser().attribute("wrapText"))); auto value = is_true(parser().attribute("wrapText"));
record.alignment.first.wrap(value);
} }
if (parser().attribute_present("shrinkToFit")) if (parser().attribute_present("shrinkToFit"))
{ {
record.alignment.first.shrink(is_true(parser().attribute("shrinkToFit"))); auto value = is_true(parser().attribute("shrinkToFit"));
record.alignment.first.shrink(value);
} }
if (parser().attribute_present("indent")) if (parser().attribute_present("indent"))
{ {
record.alignment.first.indent(parser().attribute<int>("indent")); auto value = parser().attribute<int>("indent");
record.alignment.first.indent(value);
} }
if (parser().attribute_present("textRotation")) if (parser().attribute_present("textRotation"))
{ {
record.alignment.first.rotation(parser().attribute<int>("textRotation")); auto value = parser().attribute<int>("textRotation");
record.alignment.first.rotation(value);
} }
if (parser().attribute_present("vertical")) if (parser().attribute_present("vertical"))
{ {
record.alignment.first.vertical( auto value = parser().attribute<xlnt::vertical_alignment>("vertical");
parser().attribute<xlnt::vertical_alignment>("vertical")); record.alignment.first.vertical(value);
} }
if (parser().attribute_present("horizontal")) if (parser().attribute_present("horizontal"))
{ {
record.alignment.first.horizontal( auto value = parser().attribute<xlnt::horizontal_alignment>("horizontal");
parser().attribute<xlnt::horizontal_alignment>("horizontal")); record.alignment.first.horizontal(value);
} }
record.alignment.second = !apply_alignment_present || alignment_applied; record.alignment.second = !apply_alignment_present || alignment_applied;
@ -1580,11 +1602,10 @@ void xlsx_consumer::read_stylesheet()
} }
parser().next_expect(xml::parser::event_type::end_element, xmlns, "xf"); parser().next_expect(xml::parser::event_type::end_element, xmlns, "xf");
} }
if ((in_style_records && count != style_records.size()) if ((in_style_records && count != style_records.size()) ||
|| (!in_style_records && count != format_records.size())) (!in_style_records && count != format_records.size()))
{ {
throw xlnt::exception("counts don't match"); throw xlnt::exception("counts don't match");
} }
@ -1766,10 +1787,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(), auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
target_.d_->sheet_title_rel_id_map_.end(), target_.d_->sheet_title_rel_id_map_.end(),
[&](const std::pair<std::string, std::string> &p) [&](const std::pair<std::string, std::string> &p) { return p.second == rel_id; })->first;
{
return p.second == rel_id;
})->first;
auto id = sheet_title_id_map_[title]; auto id = sheet_title_id_map_[title];
auto index = sheet_title_index_map_[title]; auto index = sheet_title_index_map_[title];
@ -1982,8 +2000,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
else if (parser().qname() == xml::qname(xmlns, "f")) else if (parser().qname() == xml::qname(xmlns, "f"))
{ {
has_formula = true; has_formula = true;
has_shared_formula = parser().attribute_present("t") has_shared_formula = parser().attribute_present("t") && parser().attribute("t") == "shared";
&& parser().attribute("t") == "shared";
parser().next_expect(xml::parser::event_type::characters); parser().next_expect(xml::parser::event_type::characters);
formula_value_string = parser().value(); formula_value_string = parser().value();
} }
@ -2134,8 +2151,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
{ {
parser().attribute_map(); parser().attribute_map();
while (parser().peek() != xml::parser::event_type::end_element while (parser().peek() != xml::parser::event_type::end_element ||
|| parser().qname() != xml::qname(xmlns, "sheetPr")) parser().qname() != xml::qname(xmlns, "sheetPr"))
{ {
if (parser().next() == xml::parser::event_type::start_element) if (parser().next() == xml::parser::event_type::start_element)
{ {
@ -2149,8 +2166,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
{ {
parser().attribute_map(); parser().attribute_map();
while (parser().peek() != xml::parser::event_type::end_element while (parser().peek() != xml::parser::event_type::end_element ||
|| parser().qname() != xml::qname(xmlns, "headerFooter")) parser().qname() != xml::qname(xmlns, "headerFooter"))
{ {
if (parser().next() == xml::parser::event_type::start_element) if (parser().next() == xml::parser::event_type::start_element)
{ {
@ -2169,8 +2186,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
{ {
parser().attribute_map(); parser().attribute_map();
while (parser().peek() != xml::parser::event_type::end_element while (parser().peek() != xml::parser::event_type::end_element ||
|| parser().qname() != xml::qname(xmlns, "protectedRanges")) parser().qname() != xml::qname(xmlns, "protectedRanges"))
{ {
if (parser().next() == xml::parser::event_type::start_element) if (parser().next() == xml::parser::event_type::start_element)
{ {
@ -2191,8 +2208,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
if (manifest.has_relationship(sheet_path, xlnt::relationship::type::comments)) if (manifest.has_relationship(sheet_path, xlnt::relationship::type::comments))
{ {
auto comments_part = manifest.canonicalize({workbook_rel, sheet_rel, auto comments_part = manifest.canonicalize(
manifest.get_relationship(sheet_path, xlnt::relationship::type::comments)}); {workbook_rel, sheet_rel, manifest.get_relationship(sheet_path, xlnt::relationship::type::comments)});
auto receive = xml::parser::receive_default; auto receive = xml::parser::receive_default;
xml::parser parser(archive_->open(comments_part.string()), comments_part.string(), receive); xml::parser parser(archive_->open(comments_part.string()), comments_part.string(), receive);
@ -2218,7 +2235,6 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
void xlsx_consumer::read_vml_drawings(worksheet ws) void xlsx_consumer::read_vml_drawings(worksheet ws)
{ {
} }
void xlsx_consumer::read_comments(worksheet ws) void xlsx_consumer::read_comments(worksheet ws)