// Copyright (c) 2014-2016 Thomas Fussell // Copyright (c) 2010-2015 openpyxl // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE // // @license: http://www.opensource.org/licenses/mit-license.php // @author: see AUTHORS file #include #include // for std::tolower #include #include #include // for std::move #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { // Miscellaneous Functions struct EnumClassHash { template std::size_t operator()(T t) const { return static_cast(t); } }; std::string string_lower(std::string str) { for (std::size_t i = 0; i < str.size(); i++) { str[i] = std::tolower(str[i]); } return str; } bool is_true(const std::string &bool_string) { return bool_string == "1" || bool_string == "true"; } bool is_false(const std::string &bool_string) { return bool_string == "0" || bool_string == "false"; } std::size_t string_to_size_t(const std::string &s) { #if ULLONG_MAX == SIZE_MAX return std::stoull(s); #else return std::stoul(s); #endif } // // enum serialization // // protection::type serialization xlnt::protection::type protection_type_from_string(const std::string &type_string) { auto lower = string_lower(type_string); if (lower == "inherit") return xlnt::protection::type::inherit; if (is_true(lower)) return xlnt::protection::type::protected_; if (!is_false(lower)) { throw std::runtime_error("bad enum " + type_string); } return xlnt::protection::type::unprotected; }; std::string protection_type_to_string(xlnt::protection::type type) { switch (type) { case xlnt::protection::type::inherit: return "inherit"; case xlnt::protection::type::protected_: return "true"; case xlnt::protection::type::unprotected: return "false"; } throw std::runtime_error("bad enum " + std::to_string(static_cast(type))); } // font::underline_style serialization const std::unordered_map &get_string_underline_style_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map { { "double", xlnt::font::underline_style::double_ }, { "double-accounting", xlnt::font::underline_style::double_accounting }, { "none", xlnt::font::underline_style::none }, { "single", xlnt::font::underline_style::single }, { "single-accounting", xlnt::font::underline_style::single_accounting } }; } return *map; } const std::unordered_map &get_underline_style_string_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map; for (auto pair : get_string_underline_style_map()) { map->emplace(pair.second, pair.first); } } return *map; } xlnt::font::underline_style underline_style_from_string(const std::string &underline_string) { return get_string_underline_style_map().at(string_lower(underline_string)); } std::string underline_style_to_string(xlnt::font::underline_style underline_style) { return get_underline_style_string_map().at(underline_style); } // fill::pattern_type serialization const std::unordered_map &get_string_pattern_fill_type_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map { { "darkdown", xlnt::fill::pattern_type::darkdown }, { "darkgray", xlnt::fill::pattern_type::darkgray }, { "darkgrid", xlnt::fill::pattern_type::darkgrid }, { "darkhorizontal", xlnt::fill::pattern_type::darkhorizontal }, { "darktrellis", xlnt::fill::pattern_type::darktrellis }, { "darkup", xlnt::fill::pattern_type::darkup }, { "darkvertical", xlnt::fill::pattern_type::darkvertical }, { "gray0625", xlnt::fill::pattern_type::gray0625 }, { "gray125", xlnt::fill::pattern_type::gray125 }, { "lightdown", xlnt::fill::pattern_type::lightdown }, { "lightgray", xlnt::fill::pattern_type::lightgray }, { "lightgrid", xlnt::fill::pattern_type::lightgrid }, { "lighthorizontal", xlnt::fill::pattern_type::lighthorizontal }, { "lighttrellis", xlnt::fill::pattern_type::lighttrellis }, { "lightup", xlnt::fill::pattern_type::lightup }, { "lightvertical", xlnt::fill::pattern_type::lightvertical }, { "mediumgray", xlnt::fill::pattern_type::mediumgray }, { "none", xlnt::fill::pattern_type::none }, { "solid", xlnt::fill::pattern_type::solid } }; } return *map; } const std::unordered_map &get_pattern_fill_type_string_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map; for (auto pair : get_string_pattern_fill_type_map()) { map->emplace(pair.second, pair.first); } } return *map; } xlnt::fill::pattern_type pattern_fill_type_from_string(const std::string &fill_type) { return get_string_pattern_fill_type_map().at(string_lower(fill_type)); }; std::string pattern_fill_type_to_string(xlnt::fill::pattern_type fill_type) { return get_pattern_fill_type_string_map().at(fill_type); } // border_style serialization const std::unordered_map &get_string_border_style_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map { { "dashdot", xlnt::border_style::dashdot }, { "dashdotdot", xlnt::border_style::dashdotdot }, { "dashed", xlnt::border_style::dashed }, { "dotted", xlnt::border_style::dotted }, { "double", xlnt::border_style::double_ }, { "hair", xlnt::border_style::hair }, { "medium", xlnt::border_style::medium }, { "mediumdashdot", xlnt::border_style::mediumdashdot }, { "mediumdashdotdot", xlnt::border_style::mediumdashdotdot }, { "mediumdashed", xlnt::border_style::mediumdashed }, { "none", xlnt::border_style::none }, { "slantdashdot", xlnt::border_style::slantdashdot }, { "thick", xlnt::border_style::thick }, { "thin", xlnt::border_style::thin } }; } return *map; } const std::unordered_map &get_border_style_string_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map; for (auto pair : get_string_border_style_map()) { map->emplace(pair.second, pair.first); } } return *map; } xlnt::border_style border_style_from_string(const std::string &border_style_string) { return get_string_border_style_map().at(string_lower(border_style_string)); } std::string border_style_to_string(xlnt::border_style border_style) { return get_border_style_string_map().at(border_style); } // vertical_alignment serialization const std::unordered_map &get_string_vertical_alignment_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map { { "bottom", xlnt::vertical_alignment::bottom }, { "center", xlnt::vertical_alignment::center }, { "justify", xlnt::vertical_alignment::justify }, { "none", xlnt::vertical_alignment::none }, { "top", xlnt::vertical_alignment::top } }; } return *map; } const std::unordered_map &get_vertical_alignment_string_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map; for (auto pair : get_string_vertical_alignment_map()) { map->emplace(pair.second, pair.first); } } return *map; } xlnt::vertical_alignment vertical_alignment_from_string(const std::string &vertical_alignment_string) { return get_string_vertical_alignment_map().at(string_lower(vertical_alignment_string)); } std::string vertical_alignment_to_string(xlnt::vertical_alignment vertical_alignment) { return get_vertical_alignment_string_map().at(vertical_alignment); } // horizontal_alignment const std::unordered_map &get_string_horizontal_alignment_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map { { "center", xlnt::horizontal_alignment::center }, { "center-continous", xlnt::horizontal_alignment::center_continuous }, { "general", xlnt::horizontal_alignment::general }, { "justify", xlnt::horizontal_alignment::justify }, { "left", xlnt::horizontal_alignment::left }, { "none", xlnt::horizontal_alignment::none }, { "right", xlnt::horizontal_alignment::right } }; } return *map; } const std::unordered_map &get_horizontal_alignment_string_map() { static std::unordered_map *map = nullptr; if (map == nullptr) { map = new std::unordered_map; for (auto pair : get_string_horizontal_alignment_map()) { map->emplace(pair.second, pair.first); } } return *map; } xlnt::horizontal_alignment horizontal_alignment_from_string(const std::string &horizontal_alignment_string) { return get_string_horizontal_alignment_map().at(string_lower(horizontal_alignment_string)); } std::string horizontal_alignment_to_string(xlnt::horizontal_alignment horizontal_alignment) { return get_horizontal_alignment_string_map().at(horizontal_alignment); } // Reading xlnt::protection read_protection(const pugi::xml_node protection_node) { xlnt::protection prot; prot.set_locked(protection_type_from_string(protection_node.attribute("locked").value())); prot.set_hidden(protection_type_from_string(protection_node.attribute("hidden").value())); return std::move(prot); } xlnt::alignment read_alignment(const pugi::xml_node alignment_node) { xlnt::alignment align; align.set_wrap_text(is_true(alignment_node.attribute("wrapText").value())); align.set_shrink_to_fit(is_true(alignment_node.attribute("shrinkToFit").value())); if (alignment_node.attribute("vertical")) { std::string vertical = alignment_node.attribute("vertical").value(); align.set_vertical(vertical_alignment_from_string(vertical)); } if (alignment_node.attribute("horizontal")) { std::string horizontal = alignment_node.attribute("horizontal").value(); align.set_horizontal(horizontal_alignment_from_string(horizontal)); } return align; } void read_number_formats(const pugi::xml_node number_formats_node, std::vector &number_formats) { number_formats.clear(); for (auto num_fmt_node : number_formats_node.children("numFmt")) { std::string format_string(num_fmt_node.attribute("formatCode").value()); if (format_string == "GENERAL") { format_string = "General"; } xlnt::number_format nf; nf.set_format_string(format_string); nf.set_id(string_to_size_t(num_fmt_node.attribute("numFmtId").value())); number_formats.push_back(nf); } } xlnt::color read_color(const pugi::xml_node &color_node) { if (color_node.attribute("rgb")) { return xlnt::color(xlnt::color::type::rgb, color_node.attribute("rgb").value()); } else if (color_node.attribute("theme")) { return xlnt::color(xlnt::color::type::theme, string_to_size_t(color_node.attribute("theme").value())); } else if (color_node.attribute("indexed")) { return xlnt::color(xlnt::color::type::indexed, string_to_size_t(color_node.attribute("indexed").value())); } else if (color_node.attribute("auto")) { return xlnt::color(xlnt::color::type::auto_, string_to_size_t(color_node.attribute("auto").value())); } throw std::runtime_error("bad color"); } xlnt::font read_font(const pugi::xml_node font_node) { xlnt::font new_font; new_font.set_size(string_to_size_t(font_node.child("sz").attribute("val").value())); new_font.set_name(font_node.child("name").attribute("val").value()); if (font_node.child("color")) { new_font.set_color(read_color(font_node.child("color"))); } if (font_node.child("family")) { new_font.set_family(string_to_size_t(font_node.child("family").attribute("val").value())); } if (font_node.child("scheme")) { new_font.set_scheme(font_node.child("scheme").attribute("val").value()); } if (font_node.child("b")) { if(font_node.child("b").attribute("val")) { new_font.set_bold(is_true(font_node.child("b").attribute("val").value())); } else { new_font.set_bold(true); } } if (font_node.child("strike")) { if(font_node.child("strike").attribute("val")) { new_font.set_strikethrough(is_true(font_node.child("strike").attribute("val").value())); } else { new_font.set_strikethrough(true); } } if (font_node.child("i")) { if(font_node.child("i").attribute("val")) { new_font.set_italic(is_true(font_node.child("i").attribute("val").value())); } else { new_font.set_italic(true); } } if (font_node.child("u")) { if (font_node.child("u").attribute("val")) { std::string underline_string = font_node.child("u").attribute("val").value(); new_font.set_underline(underline_style_from_string(underline_string)); } else { new_font.set_underline(xlnt::font::underline_style::single); } } return new_font; } void read_fonts(const pugi::xml_node &fonts_node, std::vector &fonts) { fonts.clear(); for (auto font_node : fonts_node.children()) { fonts.push_back(read_font(font_node)); } } void read_indexed_colors(const pugi::xml_node &indexed_colors_node, std::vector &colors) { for (auto color_node : indexed_colors_node.children()) { colors.push_back(read_color(color_node)); } } void read_colors(const pugi::xml_node &colors_node, std::vector &colors) { colors.clear(); if (colors_node.child("indexedColors")) { read_indexed_colors(colors_node.child("indexedColors"), colors); } } xlnt::fill read_fill(const pugi::xml_node &fill_node) { xlnt::fill new_fill; if (fill_node.child("patternFill")) { new_fill.set_type(xlnt::fill::type::pattern); auto pattern_fill_node = fill_node.child("patternFill"); std::string pattern_fill_type_string = pattern_fill_node.attribute("patternType").value(); if (!pattern_fill_type_string.empty()) { new_fill.set_pattern_type(pattern_fill_type_from_string(pattern_fill_type_string)); if (pattern_fill_node.child("bgColor")) { new_fill.get_background_color() = read_color(pattern_fill_node.child("bgColor")); } if (pattern_fill_node.child("fgColor")) { new_fill.get_foreground_color() = read_color(pattern_fill_node.child("fgColor")); } } } return new_fill; } void read_fills(const pugi::xml_node &fills_node, std::vector &fills) { fills.clear(); for (auto fill_node : fills_node.children()) { fills.emplace_back(); fills.back() = read_fill(fill_node); } } xlnt::side read_side(const pugi::xml_node &side_node) { xlnt::side new_side; if (side_node.attribute("style")) { new_side.get_border_style() = border_style_from_string(side_node.attribute("style").value()); } if (side_node.child("color")) { new_side.get_color() = read_color(side_node.child("color")); } return new_side; } xlnt::border read_border(const pugi::xml_node &border_node) { xlnt::border new_border; if (border_node.child("start")) { new_border.get_start() = read_side(border_node.child("start")); } if (border_node.child("end")) { new_border.get_end() = read_side(border_node.child("end")); } if (border_node.child("left")) { new_border.get_left() = read_side(border_node.child("left")); } if (border_node.child("right")) { new_border.get_right() = read_side(border_node.child("right")); } if (border_node.child("top")) { new_border.get_top() = read_side(border_node.child("top")); } if (border_node.child("bottom")) { new_border.get_bottom() = read_side(border_node.child("bottom")); } if (border_node.child("diagonal")) { new_border.get_diagonal() = read_side(border_node.child("diagonal")); } if (border_node.child("vertical")) { new_border.get_vertical() = read_side(border_node.child("vertical")); } if (border_node.child("horizontal")) { new_border.get_horizontal() = read_side(border_node.child("horizontal")); } return new_border; } void read_borders(const pugi::xml_node &borders_node, std::vector &borders) { borders.clear(); for (auto border_node : borders_node.children()) { borders.push_back(read_border(border_node)); } } bool read_base_format(const pugi::xml_node &format_node, const xlnt::detail::stylesheet &stylesheet, xlnt::base_format &f) { // Alignment f.alignment_applied(format_node.child("alignment") || is_true(format_node.attribute("applyAlignment").value())); if (f.alignment_applied()) { auto inline_alignment = read_alignment(format_node.child("alignment")); f.set_alignment(inline_alignment); } // Border auto border_index = format_node.attribute("borderId") ? string_to_size_t(format_node.attribute("borderId").value()) : 0; f.set_border(stylesheet.borders.at(border_index)); f.border_applied(is_true(format_node.attribute("applyBorder").value())); // Fill auto fill_index = format_node.attribute("fillId") ? string_to_size_t(format_node.attribute("fillId").value()) : 0; f.set_fill(stylesheet.fills.at(fill_index)); f.fill_applied(is_true(format_node.attribute("applyFill").value())); // Font auto font_index = format_node.attribute("fontId") ? string_to_size_t(format_node.attribute("fontId").value()) : 0; f.set_font(stylesheet.fonts.at(font_index)); f.font_applied(is_true(format_node.attribute("applyFont").value())); // Number Format auto number_format_id = string_to_size_t(format_node.attribute("numFmtId").value()); bool builtin_format = true; for (const auto &num_fmt : stylesheet.number_formats) { if (static_cast(num_fmt.get_id()) == number_format_id) { f.set_number_format(num_fmt); builtin_format = false; break; } } if (builtin_format) { f.set_number_format(xlnt::number_format::from_builtin_id(number_format_id)); } f.number_format_applied(is_true(format_node.attribute("applyNumberFormat").value())); // Protection f.protection_applied(format_node.attribute("protection") || is_true(format_node.attribute("applyProtection").value())); if (f.protection_applied()) { auto inline_protection = read_protection(format_node.child("protection")); f.set_protection(inline_protection); } return true; } void read_formats(const pugi::xml_node &formats_node, const xlnt::detail::stylesheet &stylesheet, std::vector &formats, std::vector &format_styles) { for (auto format_node : formats_node.children("xf")) { xlnt::format format; read_base_format(format_node, stylesheet, format); // TODO do all formats have xfId? if(format_node.attribute("xfId")) { auto style_index = string_to_size_t(format_node.attribute("xfId").value()); auto style_name = stylesheet.style_name_map.at(style_index); format_styles.push_back(style_name); } else { format_styles.push_back(""); } formats.push_back(format); } } xlnt::style read_style(const pugi::xml_node &style_node, const pugi::xml_node &style_format_node, const xlnt::detail::stylesheet &stylesheet) { xlnt::style s; read_base_format(style_format_node, stylesheet, s); s.set_name(style_node.attribute("name").value()); s.set_hidden(style_node.attribute("hidden") && is_true(style_node.attribute("hidden").value())); s.set_builtin_id(string_to_size_t(style_node.attribute("builtinId").value())); return s; } void read_styles(const pugi::xml_node &styles_node, const pugi::xml_node &style_formats_node, const xlnt::detail::stylesheet stylesheet, std::vector &styles, std::unordered_map &style_names) { std::size_t style_index = 0; for (auto cell_style_format_node : style_formats_node.children()) { bool match = false; for (auto cell_style_node : styles_node.children()) { auto cell_style_format_index = std::stoull(cell_style_node.attribute("xfId").value()); if (cell_style_format_index == style_index) { styles.push_back(read_style(cell_style_node, cell_style_format_node, stylesheet)); style_names[style_index] = styles.back().get_name(); match = true; break; } } style_index++; } } bool write_color(const xlnt::color &color, pugi::xml_node color_node) { switch (color.get_type()) { case xlnt::color::type::auto_: color_node.append_attribute("auto").set_value(std::to_string(color.get_auto()).c_str()); break; case xlnt::color::type::theme: color_node.append_attribute("theme").set_value(std::to_string(color.get_theme()).c_str()); break; case xlnt::color::type::indexed: color_node.append_attribute("indexed").set_value(std::to_string(color.get_index()).c_str()); break; case xlnt::color::type::rgb: color_node.append_attribute("rgb").set_value(color.get_rgb_string().c_str()); break; default: throw std::runtime_error("bad type"); } return true; } bool write_fonts(const std::vector &fonts, pugi::xml_node &fonts_node) { fonts_node.append_attribute("count").set_value(std::to_string(fonts.size()).c_str()); // TODO: what does this do? // fonts_node.append_attribute("x14ac:knownFonts", "1"); for (auto &f : fonts) { auto font_node = fonts_node.append_child("font"); if (f.is_bold()) { auto bold_node = font_node.append_child("b"); bold_node.append_attribute("val").set_value("1"); } if (f.is_italic()) { auto italic_node = font_node.append_child("i"); italic_node.append_attribute("val").set_value("1"); } if (f.is_underline()) { auto underline_node = font_node.append_child("u"); underline_node.append_attribute("val").set_value(underline_style_to_string(f.get_underline()).c_str()); } if (f.is_strikethrough()) { auto strike_node = font_node.append_child("strike"); strike_node.append_attribute("val").set_value("1"); } auto size_node = font_node.append_child("sz"); size_node.append_attribute("val").set_value(std::to_string(f.get_size()).c_str()); auto color_node = font_node.append_child("color"); write_color(f.get_color(), color_node); auto name_node = font_node.append_child("name"); name_node.append_attribute("val").set_value(f.get_name().c_str()); if (f.has_family()) { auto family_node = font_node.append_child("family"); family_node.append_attribute("val").set_value(std::to_string(f.get_family()).c_str()); } if (f.has_scheme()) { auto scheme_node = font_node.append_child("scheme"); scheme_node.append_attribute("val").set_value("minor"); } } return true; } bool write_fills(const std::vector &fills, pugi::xml_node &fills_node) { fills_node.append_attribute("count").set_value(std::to_string(fills.size()).c_str()); for (auto &fill_ : fills) { auto fill_node = fills_node.append_child("fill"); if (fill_.get_type() == xlnt::fill::type::pattern) { auto pattern_fill_node = fill_node.append_child("patternFill"); pattern_fill_node.append_attribute("patternType").set_value(pattern_fill_type_to_string(fill_.get_pattern_type()).c_str()); if (fill_.get_pattern_type() != xlnt::fill::pattern_type::solid) continue; if (fill_.get_foreground_color()) { write_color(*fill_.get_foreground_color(), pattern_fill_node.append_child("fgColor")); } if (fill_.get_background_color()) { write_color(*fill_.get_background_color(), pattern_fill_node.append_child("bgColor")); } } else if (fill_.get_type() == xlnt::fill::type::solid) { auto solid_fill_node = fill_node.append_child("solidFill"); solid_fill_node.append_child("color"); } else if (fill_.get_type() == xlnt::fill::type::gradient) { auto gradient_fill_node = fill_node.append_child("gradientFill"); if (fill_.get_gradient_type() == xlnt::fill::gradient_type::linear) { gradient_fill_node.append_attribute("degree").set_value(std::to_string(fill_.get_rotation()).c_str()); } else if (fill_.get_gradient_type() == xlnt::fill::gradient_type::path) { gradient_fill_node.append_attribute("left").set_value(std::to_string(fill_.get_gradient_left()).c_str()); gradient_fill_node.append_attribute("right").set_value(std::to_string(fill_.get_gradient_right()).c_str()); gradient_fill_node.append_attribute("top").set_value(std::to_string(fill_.get_gradient_top()).c_str()); gradient_fill_node.append_attribute("bottom").set_value(std::to_string(fill_.get_gradient_bottom()).c_str()); auto start_node = gradient_fill_node.append_child("stop"); start_node.append_attribute("position").set_value("0"); auto end_node = gradient_fill_node.append_child("stop"); end_node.append_attribute("position").set_value("1"); } } } return true; } bool write_borders(const std::vector &borders, pugi::xml_node &borders_node) { borders_node.append_attribute("count").set_value(std::to_string(borders.size()).c_str()); for (const auto &border_ : borders) { auto border_node = borders_node.append_child("border"); std::vector>> sides; sides.push_back(std::make_tuple("start", border_.get_start())); sides.push_back(std::make_tuple("end", border_.get_end())); sides.push_back(std::make_tuple("left", border_.get_left())); sides.push_back(std::make_tuple("right", border_.get_right())); sides.push_back(std::make_tuple("top", border_.get_top())); sides.push_back(std::make_tuple("bottom", border_.get_bottom())); sides.push_back(std::make_tuple("diagonal", border_.get_diagonal())); sides.push_back(std::make_tuple("vertical", border_.get_vertical())); sides.push_back(std::make_tuple("horizontal", border_.get_horizontal())); for (const auto &side_tuple : sides) { std::string current_name = std::get<0>(side_tuple); const auto current_side = std::get<1>(side_tuple); if (current_side) { auto side_node = border_node.append_child(current_name.c_str()); if (current_side->get_border_style()) { auto style_string = border_style_to_string(*current_side->get_border_style()); side_node.append_attribute("style").set_value(style_string.c_str()); } if (current_side->get_color()) { auto color_node = side_node.append_child("color"); write_color(*current_side->get_color(), color_node); } } } } return true; } bool write_base_format(const xlnt::base_format &xf, const xlnt::detail::stylesheet &stylesheet, pugi::xml_node xf_node) { xf_node.append_attribute("numFmtId").set_value(std::to_string(xf.get_number_format().get_id()).c_str()); auto font_id = std::distance(stylesheet.fonts.begin(), std::find(stylesheet.fonts.begin(), stylesheet.fonts.end(), xf.get_font())); xf_node.append_attribute("fontId").set_value(std::to_string(font_id).c_str()); auto fill_id = std::distance(stylesheet.fills.begin(), std::find(stylesheet.fills.begin(), stylesheet.fills.end(), xf.get_fill())); xf_node.append_attribute("fillId").set_value(std::to_string(fill_id).c_str()); auto border_id = std::distance(stylesheet.borders.begin(), std::find(stylesheet.borders.begin(), stylesheet.borders.end(), xf.get_border())); xf_node.append_attribute("borderId").set_value(std::to_string(border_id).c_str()); if(xf.number_format_applied()) xf_node.append_attribute("applyNumberFormat").set_value("1"); if(xf.fill_applied()) xf_node.append_attribute("applyFill").set_value("1"); if(xf.font_applied()) xf_node.append_attribute("applyFont").set_value("1"); if(xf.border_applied()) xf_node.append_attribute("applyBorder").set_value("1"); if(xf.alignment_applied()) xf_node.append_attribute("applyAlignment").set_value("1"); if(xf.protection_applied()) xf_node.append_attribute("applyProtection").set_value("1"); if (xf.alignment_applied()) { auto alignment_node = xf_node.append_child("alignment"); if (xf.get_alignment().has_vertical()) { alignment_node.append_attribute("vertical").set_value(vertical_alignment_to_string(xf.get_alignment().get_vertical()).c_str()); } if (xf.get_alignment().has_horizontal()) { alignment_node.append_attribute("horizontal").set_value(horizontal_alignment_to_string(xf.get_alignment().get_horizontal()).c_str()); } if (xf.get_alignment().get_wrap_text()) { alignment_node.append_attribute("wrapText").set_value("1"); } if (xf.get_alignment().get_shrink_to_fit()) { alignment_node.append_attribute("shrinkToFit").set_value("1"); } } if (xf.protection_applied()) { auto protection_node = xf_node.append_child("protection"); protection_node.append_attribute("locked").set_value(protection_type_to_string(xf.get_protection().get_locked()).c_str()); protection_node.append_attribute("hidden").set_value(protection_type_to_string(xf.get_protection().get_hidden()).c_str()); } return true; } bool write_styles(const xlnt::detail::stylesheet &stylesheet, pugi::xml_node &styles_node, pugi::xml_node &style_formats_node) { style_formats_node.append_attribute("count").set_value(std::to_string(stylesheet.styles.size()).c_str()); styles_node.append_attribute("count").set_value(std::to_string(stylesheet.styles.size()).c_str()); std::size_t style_index = 0; for(auto ¤t_style : stylesheet.styles) { auto xf_node = style_formats_node.append_child("xf"); write_base_format(current_style, stylesheet, xf_node); auto cell_style_node = styles_node.append_child("cellStyle"); cell_style_node.append_attribute("name").set_value(current_style.get_name().c_str()); cell_style_node.append_attribute("xfId").set_value(std::to_string(style_index++).c_str()); cell_style_node.append_attribute("builtinId").set_value(std::to_string(current_style.get_builtin_id()).c_str()); if (current_style.get_hidden()) { cell_style_node.append_attribute("hidden").set_value("1"); } } return true; } bool write_formats(const xlnt::detail::stylesheet &stylesheet, pugi::xml_node &formats_node) { formats_node.append_attribute("count").set_value(std::to_string(stylesheet.formats.size()).c_str()); auto format_style_iterator = stylesheet.format_styles.begin(); for(auto ¤t_format : stylesheet.formats) { auto xf_node = formats_node.append_child("xf"); write_base_format(current_format, stylesheet, xf_node); const auto format_style_name = *(format_style_iterator++); if(!format_style_name.empty()) { auto style = std::find_if(stylesheet.styles.begin(), stylesheet.styles.end(), [&](const xlnt::style &s) { return s.get_name() == format_style_name; }); auto style_index = std::distance(stylesheet.styles.begin(), style); xf_node.append_attribute("xfId").set_value(std::to_string(style_index).c_str()); } } return true; } bool write_dxfs(pugi::xml_node &dxfs_node) { dxfs_node.append_attribute("count").set_value("0"); return true; } bool write_table_styles(pugi::xml_node &table_styles_node) { table_styles_node.append_attribute("count").set_value("0"); table_styles_node.append_attribute("defaultTableStyle").set_value("TableStyleMedium9"); table_styles_node.append_attribute("defaultPivotStyle").set_value("PivotStyleMedium7"); return true; } bool write_colors(const std::vector &colors, pugi::xml_node &colors_node) { auto indexed_colors_node = colors_node.append_child("indexedColors"); for (auto &c : colors) { indexed_colors_node.append_child("rgbColor").append_attribute("rgb").set_value(c.get_rgb_string().c_str()); } return true; } bool write_ext_list(pugi::xml_node &ext_list_node) { auto ext_node = ext_list_node.append_child("ext"); ext_node.append_attribute("uri").set_value("{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}"); ext_node.append_attribute("xmlns:x14").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"); ext_node.append_child("x14:slicerStyles").append_attribute("defaultSlicerStyle").set_value("SlicerStyleLight1"); return true; } bool write_number_formats(const std::vector &number_formats, pugi::xml_node &number_formats_node) { number_formats_node.append_attribute("count").set_value(std::to_string(number_formats.size()).c_str()); for (const auto &num_fmt : number_formats) { auto num_fmt_node = number_formats_node.append_child("numFmt"); num_fmt_node.append_attribute("numFmtId").set_value(std::to_string(num_fmt.get_id()).c_str()); num_fmt_node.append_attribute("formatCode").set_value(num_fmt.get_format_string().c_str()); } return true; } } // namespace namespace xlnt { style_serializer::style_serializer(detail::stylesheet &stylesheet) : stylesheet_(stylesheet) { } bool style_serializer::read_stylesheet(const pugi::xml_document &xml) { auto stylesheet_node = xml.child("styleSheet"); read_borders(stylesheet_node.child("borders"), stylesheet_.borders); read_fills(stylesheet_node.child("fills"), stylesheet_.fills); read_fonts(stylesheet_node.child("fonts"), stylesheet_.fonts); read_number_formats(stylesheet_node.child("numFmts"), stylesheet_.number_formats); read_colors(stylesheet_node.child("colors"), stylesheet_.colors); read_styles(stylesheet_node.child("cellStyles"), stylesheet_node.child("cellStyleXfs"), stylesheet_, stylesheet_.styles, stylesheet_.style_name_map); read_formats(stylesheet_node.child("cellXfs"), stylesheet_, stylesheet_.formats, stylesheet_.format_styles); return true; } bool style_serializer::write_stylesheet(pugi::xml_document &doc) { auto root_node = doc.append_child("styleSheet"); root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); root_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006"); root_node.append_attribute("mc:Ignorable").set_value("x14ac"); root_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"); if (!stylesheet_.number_formats.empty()) { auto number_formats_node = root_node.append_child("numFmts"); write_number_formats(stylesheet_.number_formats, number_formats_node); } if (!stylesheet_.fonts.empty()) { auto fonts_node = root_node.append_child("fonts"); write_fonts(stylesheet_.fonts, fonts_node); } if (!stylesheet_.fills.empty()) { auto fills_node = root_node.append_child("fills"); write_fills(stylesheet_.fills, fills_node); } if (!stylesheet_.borders.empty()) { auto borders_node = root_node.append_child("borders"); write_borders(stylesheet_.borders, borders_node); } auto cell_style_xfs_node = root_node.append_child("cellStyleXfs"); auto cell_xfs_node = root_node.append_child("cellXfs"); write_formats(stylesheet_, cell_xfs_node); auto cell_styles_node = root_node.append_child("cellStyles"); write_styles(stylesheet_, cell_styles_node, cell_style_xfs_node); auto dxfs_node = root_node.append_child("dxfs"); write_dxfs(dxfs_node); auto table_styles_node = root_node.append_child("tableStyles"); write_table_styles(table_styles_node); if(!stylesheet_.colors.empty()) { auto colors_node = root_node.append_child("colors"); write_colors(stylesheet_.colors, colors_node); } auto ext_list_node = root_node.append_child("extLst"); write_ext_list(ext_list_node); return true; } } // namespace xlnt