Branch data TLA Line data Source code
1 : : // Copyright (c) 2014-2022 Thomas Fussell
2 : : // Copyright (c) 2024-2025 xlnt-community
3 : : //
4 : : // Permission is hereby granted, free of charge, to any person obtaining a copy
5 : : // of this software and associated documentation files (the "Software"), to deal
6 : : // in the Software without restriction, including without limitation the rights
7 : : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : : // copies of the Software, and to permit persons to whom the Software is
9 : : // furnished to do so, subject to the following conditions:
10 : : //
11 : : // The above copyright notice and this permission notice shall be included in
12 : : // all copies or substantial portions of the Software.
13 : : //
14 : : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : : // THE SOFTWARE
21 : : //
22 : : // @license: http://www.opensource.org/licenses/mit-license.php
23 : : // @author: see AUTHORS file
24 : :
25 : : #include <cmath>
26 : : #include <numeric> // for std::accumulate
27 : : #include <string>
28 : : #include <unordered_set>
29 : :
30 : : #include <xlnt/cell/cell.hpp>
31 : : #include <xlnt/cell/hyperlink.hpp>
32 : : #include <xlnt/packaging/manifest.hpp>
33 : : #include <xlnt/utils/numeric.hpp>
34 : : #include <xlnt/utils/path.hpp>
35 : : #include <xlnt/utils/scoped_enum_hash.hpp>
36 : : #include <xlnt/workbook/workbook.hpp>
37 : : #include <xlnt/workbook/workbook_view.hpp>
38 : : #include <xlnt/worksheet/header_footer.hpp>
39 : : #include <xlnt/worksheet/worksheet.hpp>
40 : : #include <detail/constants.hpp>
41 : : #include <detail/header_footer/header_footer_code.hpp>
42 : : #include <detail/implementations/workbook_impl.hpp>
43 : : #include <detail/serialization/custom_value_traits.hpp>
44 : : #include <detail/serialization/defined_name.hpp>
45 : : #include <detail/serialization/vector_streambuf.hpp>
46 : : #include <detail/serialization/xlsx_producer.hpp>
47 : : #include <detail/serialization/zstream.hpp>
48 : : #include <detail/serialization/parsers.hpp>
49 : : #include <detail/utils/string_helpers.hpp>
50 : :
51 : : namespace {
52 : :
53 :CBC 358 : std::vector<std::pair<std::string, std::string>> core_property_namespace(xlnt::core_property type)
54 : : {
55 : : using xlnt::constants;
56 : : using xlnt::core_property;
57 : :
58 [ + + ]: 358 : if (type == core_property::created
59 [ + + ]: 286 : || type == core_property::modified)
60 : : {
61 [ + + ]: 152 : return {{constants::ns("dcterms"), "dcterms"},
62 [ + + + + : 912 : {constants::ns("xsi"), "xsi"}};
- - ]
63 : : }
64 [ + + ]: 206 : else if (type == core_property::title
65 [ + + ]: 196 : || type == core_property::subject
66 [ + + ]: 186 : || type == core_property::creator
67 [ + + ]: 110 : || type == core_property::description)
68 : : {
69 [ + + + + : 530 : return {{constants::ns("dc"), "dc"}};
+ - - ]
70 : : }
71 [ + + ]: 100 : else if (type == core_property::keywords)
72 : : {
73 [ + + ]: 8 : return {{constants::ns("core-properties"), "cp"},
74 [ + + + + : 48 : {constants::ns("vt"), "vt"}};
- - ]
75 : : }
76 : :
77 [ + + + + : 460 : return {{constants::ns("core-properties"), "cp"}};
+ - - ]
78 [ + + + + : 876 : }
+ + + + -
- - - - -
- - - - -
- - - -
- ]
79 : :
80 : : } // namespace
81 : :
82 : : namespace xlnt {
83 : : namespace detail {
84 : :
85 : 44 : xlsx_producer::xlsx_producer(const workbook &target)
86 : 44 : : source_(target),
87 [ + ]: 44 : current_part_stream_(nullptr),
88 : 44 : current_cell_(nullptr),
89 : 88 : current_worksheet_(nullptr)
90 : : {
91 : 44 : }
92 : :
93 : 44 : xlsx_producer::~xlsx_producer()
94 : : {
95 [ + + ]:GNC 44 : if (current_cell_)
96 : : {
97 [ + - ]: 1 : delete current_cell_;
98 : 1 : current_cell_ = nullptr;
99 : : }
100 : :
101 [ + + ]: 44 : if (current_worksheet_)
102 : : {
103 [ + - ]: 1 : delete current_worksheet_;
104 : 1 : current_worksheet_ = nullptr;
105 : : }
106 : :
107 :CBC 44 : end_part();
108 : 44 : archive_.reset();
109 : 44 : }
110 : :
111 : 43 : void xlsx_producer::write(std::ostream &destination)
112 : : {
113 [ + - - ]: 43 : archive_.reset(new ozstream(destination));
114 : 43 : populate_archive(false);
115 : 43 : }
116 : :
117 : 1 : void xlsx_producer::open(std::ostream &destination)
118 : : {
119 [ + - - ]: 1 : archive_.reset(new ozstream(destination));
120 : 1 : populate_archive(true);
121 : 1 : }
122 : :
123 : 2 : cell xlsx_producer::add_cell(const cell_reference &ref)
124 : : {
125 : 2 : current_cell_->column_ = ref.column();
126 : 2 : current_cell_->row_ = ref.row();
127 : :
128 [ + ]: 2 : return cell(current_cell_);
129 : : }
130 : :
131 : 1 : worksheet xlsx_producer::add_worksheet(const std::string &title)
132 : : {
133 : 1 : current_worksheet_->title_ = title;
134 : 1 : return worksheet(current_worksheet_);
135 : : }
136 : :
137 : : // Part Writing Methods
138 : :
139 : 44 : void xlsx_producer::populate_archive(bool streaming)
140 : : {
141 : 44 : streaming_ = streaming;
142 : :
143 [ + ]: 44 : write_content_types();
144 : :
145 [ + + + + ]: 132 : const auto root_rels = source_.manifest().relationships(path("/"));
146 [ + + + ]: 44 : write_relationships(root_rels, path("/"));
147 : :
148 [ + + ]: 202 : for (auto &rel : root_rels)
149 : : {
150 : : // thumbnail is binary content so we don't want to open an xml serializer stream
151 [ + + + ]: 158 : if (rel.type() == relationship_type::thumbnail)
152 : : {
153 [ + + + ]: 30 : write_image(rel.target().path());
154 : 30 : continue;
155 : : }
156 : :
157 [ + + + ]: 128 : begin_part(rel.target().path());
158 : :
159 [ + + + ]: 128 : if (rel.type() == relationship_type::core_properties)
160 : : {
161 [ + ]: 41 : write_core_properties(rel);
162 : : }
163 [ + + + ]: 87 : else if (rel.type() == relationship_type::extended_properties)
164 : : {
165 [ + ]: 41 : write_extended_properties(rel);
166 : : }
167 [ + + + ]: 46 : else if (rel.type() == relationship_type::custom_properties)
168 : : {
169 [ + ]: 2 : write_custom_properties(rel);
170 : : }
171 [ + + - ]: 44 : else if (rel.type() == relationship_type::office_document)
172 : : {
173 [ + ]: 44 : write_workbook(rel);
174 : : }
175 : : }
176 : :
177 : : // Unknown Parts
178 : :
179 : : void write_unknown_parts();
180 : : void write_unknown_relationships();
181 : :
182 : 44 : end_part();
183 : 44 : }
184 : :
185 : 579 : void xlsx_producer::end_part()
186 : : {
187 [ + + ]: 579 : if (current_part_serializer_)
188 : : {
189 : 457 : current_part_serializer_.reset();
190 : : }
191 : :
192 : 579 : current_part_streambuf_.reset();
193 : 579 : }
194 : :
195 : 457 : void xlsx_producer::begin_part(const path &part)
196 : : {
197 : 457 : end_part();
198 [ + ]: 457 : current_part_streambuf_ = archive_->open(part);
199 : 457 : current_part_stream_.rdbuf(current_part_streambuf_.get());
200 : :
201 [ + + - - ]: 457 : auto xml_serializer = new xml::serializer(current_part_stream_, part.string(), 0);
202 [ + + + + ]: 2742 : xml_serializer->xml_decl("1.0", "UTF-8", "yes");
203 : 457 : current_part_serializer_.reset(xml_serializer);
204 : 457 : }
205 : :
206 : : // Package Parts
207 : :
208 : 44 : void xlsx_producer::write_content_types()
209 : : {
210 [ + + ]: 44 : const auto content_types_path = path("[Content_Types].xml");
211 [ + ]: 44 : begin_part(content_types_path);
212 : :
213 : 44 : const auto xmlns = "http://schemas.openxmlformats.org/package/2006/content-types";
214 : :
215 [ + + + ]: 176 : write_start_element(xmlns, "Types");
216 [ + + + ]: 132 : write_namespace(xmlns, "");
217 : :
218 [ + + + + ]: 174 : for (const auto &extension : source_.manifest().extensions_with_default_types())
219 : : {
220 [ + + + ]: 390 : write_start_element(xmlns, "Default");
221 [ + + + ]: 390 : write_attribute("Extension", extension);
222 [ + + + + ]: 390 : write_attribute("ContentType", source_.manifest().default_type(extension));
223 [ + + + ]: 520 : write_end_element(xmlns, "Default");
224 : 44 : }
225 : :
226 [ + + + + ]: 357 : for (const auto &part : source_.manifest().parts_with_overriden_types())
227 : : {
228 [ + + + ]: 1252 : write_start_element(xmlns, "Override");
229 [ + + + + : 939 : write_attribute("PartName", part.resolve(path("/")).string());
+ + + ]
230 [ + + + + ]: 939 : write_attribute("ContentType", source_.manifest().override_type(part));
231 [ + + + ]: 1252 : write_end_element(xmlns, "Override");
232 : 44 : }
233 : :
234 [ + + + ]: 132 : write_end_element(xmlns, "Types");
235 : 44 : }
236 : :
237 : 579 : void xlsx_producer::write_property(const std::string &name, const variant &value,
238 : : const std::string &ns, bool custom, std::size_t pid)
239 : : {
240 [ + + ]: 579 : if (custom)
241 : : {
242 [ + + ]: 2 : write_start_element(ns, "property");
243 [ + + + ]: 6 : write_attribute("name", name);
244 : : }
245 : : else
246 : : {
247 : 577 : write_start_element(ns, name);
248 : : }
249 : :
250 [ - + + + : 579 : switch (value.value_type())
+ + - ]
251 : : {
252 :UBC 0 : case variant::type::null: {
253 : 0 : break;
254 : : }
255 : :
256 :CBC 56 : case variant::type::boolean: {
257 [ - + ]: 56 : if (custom)
258 : : {
259 [ # # ]:UBC 0 : write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
260 [ # # ]: 0 : write_attribute("pid", pid);
261 [ # # # # ]: 0 : write_start_element(constants::ns("vt"), "bool");
262 : : }
263 : :
264 [ - + ]:CBC 56 : write_characters(value.get<bool>() ? "true" : "false");
265 : :
266 [ - + ]: 56 : if (custom)
267 : : {
268 [ # # # # ]:UBC 0 : write_end_element(constants::ns("vt"), "bool");
269 : : }
270 : :
271 :CBC 56 : break;
272 : : }
273 : :
274 : 14 : case variant::type::i4: {
275 [ - + ]: 14 : if (custom)
276 : : {
277 [ # # ]:UBC 0 : write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
278 [ # # ]: 0 : write_attribute("pid", pid);
279 [ # # # # ]: 0 : write_start_element(constants::ns("vt"), "i4");
280 : : }
281 : :
282 :CBC 14 : write_characters(value.get<std::int32_t>());
283 : :
284 [ - + ]: 14 : if (custom)
285 : : {
286 [ # # # # ]:UBC 0 : write_end_element(constants::ns("vt"), "i4");
287 : : }
288 : :
289 :CBC 14 : break;
290 : : }
291 : :
292 : 411 : case variant::type::lpstr: {
293 [ + + ]: 411 : if (custom)
294 : : {
295 [ + + ]: 4 : write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
296 [ + + ]: 4 : write_attribute("pid", pid);
297 [ + + + + ]: 8 : write_start_element(constants::ns("vt"), "lpwstr");
298 : : }
299 : :
300 [ + + + + : 1229 : if (!custom && ns == constants::ns("dcterms") && (name == "created" || name == "modified"))
+ + + + +
+ + - + +
+ + + + -
- - - ]
301 : : {
302 [ + + + + : 224 : write_attribute(xml::qname(constants::ns("xsi"), "type"), "dcterms:W3CDTF");
+ ]
303 : : }
304 : :
305 [ + + ]: 411 : write_characters(value.get<std::string>());
306 : :
307 [ + + ]: 411 : if (custom)
308 : : {
309 [ + + + + ]: 8 : write_end_element(constants::ns("vt"), "lpwstr");
310 : : }
311 : :
312 : 411 : break;
313 : : }
314 : :
315 : 20 : case variant::type::date: {
316 [ + + + + : 60 : write_attribute(xml::qname(constants::ns("xsi"), "type"), "dcterms:W3CDTF");
+ ]
317 [ + + + ]: 20 : write_characters(value.get<datetime>().to_iso_string());
318 : :
319 : 20 : break;
320 : : }
321 : :
322 : 78 : case variant::type::vector: {
323 [ + + + + ]: 234 : write_start_element(constants::ns("vt"), "vector");
324 : :
325 [ + ]: 78 : auto vector = value.get<std::vector<variant>>();
326 : 78 : std::unordered_set<variant::type, scoped_enum_hash<variant::type>> types;
327 : :
328 [ + + ]: 211 : for (const auto &element : vector)
329 : : {
330 [ + + ]: 133 : types.insert(element.value_type());
331 : : }
332 : :
333 : 78 : const auto is_mixed = types.size() > 1;
334 [ + + + + : 117 : const auto vector_type = !is_mixed ? to_string(*types.begin()) : "variant";
+ + - - ]
335 : :
336 [ + + ]: 156 : write_attribute("size", vector.size());
337 [ + + + ]: 234 : write_attribute("baseType", vector_type);
338 : :
339 [ + + ]: 211 : for (std::size_t i = 0; i < vector.size(); ++i)
340 : : {
341 [ + ]: 133 : const auto &vector_element = vector.at(i);
342 : :
343 [ + + ]: 133 : if (is_mixed)
344 : : {
345 [ + + + + ]: 320 : write_start_element(constants::ns("vt"), "variant");
346 : : }
347 : :
348 [ + + + ]: 133 : if (vector_element.value_type() == variant::type::lpstr)
349 : : {
350 [ + + + + : 465 : write_element(constants::ns("vt"), "lpstr", vector_element.get<std::string>());
+ ]
351 : : }
352 [ + + - ]: 40 : else if (vector_element.value_type() == variant::type::i4)
353 : : {
354 [ + + + + : 200 : write_element(constants::ns("vt"), "i4", vector_element.get<std::int32_t>());
+ ]
355 : : }
356 : :
357 [ + + ]: 133 : if (is_mixed)
358 : : {
359 [ + + + + ]: 320 : write_end_element(constants::ns("vt"), "variant");
360 : : }
361 : : }
362 : :
363 [ + + + + ]: 234 : write_end_element(constants::ns("vt"), "vector");
364 : :
365 : 78 : break;
366 : 78 : }
367 : : }
368 : :
369 [ + + ]: 579 : if (custom)
370 : : {
371 [ + + ]: 4 : write_end_element(ns, "property");
372 : : }
373 : : else
374 : : {
375 : 577 : write_end_element(ns, name);
376 : : }
377 : 579 : }
378 : :
379 : 41 : void xlsx_producer::write_core_properties(const relationship & /*rel*/)
380 : : {
381 [ + + + + ]: 123 : write_start_element(constants::ns("core-properties"), "coreProperties");
382 : :
383 [ + ]: 41 : auto core_properties = source_.core_properties();
384 : 41 : std::unordered_map<std::string, std::string> namespaces;
385 : :
386 [ + + + + ]: 123 : write_namespace(constants::ns("core-properties"), "cp");
387 : :
388 [ + + ]: 220 : for (const auto &prop : core_properties)
389 : : {
390 [ + + + ]: 438 : for (const auto &ns : core_property_namespace(prop))
391 : : {
392 [ + + + ]: 259 : if (namespaces.count(ns.first) > 0) continue;
393 : :
394 [ + ]: 162 : write_namespace(ns.first, ns.second);
395 [ + ]: 162 : namespaces.emplace(ns);
396 : 179 : }
397 : : }
398 : :
399 [ + + ]: 220 : for (const auto &prop : core_properties)
400 : : {
401 [ + + ]: 179 : write_property(to_string(prop), source_.core_property(prop),
402 [ + + ]: 358 : core_property_namespace(prop).front().first, false, 0);
403 : : }
404 : :
405 [ + + + + ]: 123 : write_end_element(constants::ns("core-properties"), "coreProperties");
406 : 41 : }
407 : :
408 : 41 : void xlsx_producer::write_extended_properties(const relationship & /*rel*/)
409 : : {
410 [ + + + + ]: 164 : write_start_element(constants::ns("extended-properties"), "Properties");
411 [ + + + + ]: 123 : write_namespace(constants::ns("extended-properties"), "");
412 : :
413 : 41 : if (source_.has_extended_property(extended_property::heading_pairs)
414 [ + + - + : 41 : || source_.has_extended_property(extended_property::titles_of_parts))
+ + ]
415 : : {
416 [ + + + + ]: 156 : write_namespace(constants::ns("vt"), "vt");
417 : : }
418 : :
419 [ + + + ]: 439 : for (const auto &prop : source_.extended_properties())
420 : : {
421 [ + + + + ]: 398 : write_property(to_string(prop), source_.extended_property(prop),
422 [ + ]: 1194 : constants::ns("extended-properties"), false, 0);
423 : 41 : }
424 : :
425 [ + + + + ]: 123 : write_end_element(constants::ns("extended-properties"), "Properties");
426 : 41 : }
427 : :
428 : 2 : void xlsx_producer::write_custom_properties(const relationship & /*rel*/)
429 : : {
430 [ + + + + ]: 8 : write_start_element(constants::ns("custom-properties"), "Properties");
431 [ + + + + ]: 8 : write_namespace(constants::ns("custom-properties"), "");
432 [ + + + + ]: 6 : write_namespace(constants::ns("vt"), "vt");
433 : :
434 : 2 : auto pid = std::size_t(2); // why does this start at 2?
435 : :
436 [ + + + ]: 4 : for (const auto &prop : source_.custom_properties())
437 : : {
438 [ + + + ]: 4 : write_property(prop, source_.custom_property(prop),
439 [ + ]: 6 : constants::ns("custom-properties"), true, pid++);
440 : 2 : }
441 : :
442 [ + + + + ]: 6 : write_end_element(constants::ns("custom-properties"), "Properties");
443 : 2 : }
444 : :
445 : : // Write SpreadsheetML-Specific Package Parts
446 : :
447 : 44 : void xlsx_producer::write_workbook(const relationship &rel)
448 : : {
449 : 44 : std::size_t num_visible = 0;
450 : 44 : std::vector<defined_name> defined_names;
451 : :
452 [ + + + + : 97 : for (auto ws : source_)
+ + + ]
453 : : {
454 [ + + + + : 53 : if (!ws.has_page_setup() || ws.page_setup().sheet_state() == sheet_state::visible)
+ + - + +
+ - - - ]
455 : : {
456 : 53 : num_visible++;
457 : : }
458 : :
459 [ + + + ]: 53 : auto title_ref = "'" + ws.title() + "'!";
460 : :
461 [ + + + ]: 53 : if (ws.has_auto_filter())
462 : : {
463 : 1 : defined_name name;
464 [ + ]: 1 : name.sheet_id = ws.id();
465 [ + ]: 1 : name.name = "_xlnm._FilterDatabase";
466 : 1 : name.hidden = true;
467 [ + + + + ]: 1 : name.value = title_ref + range_reference::make_absolute(ws.auto_filter()).to_string();
468 [ + ]: 1 : defined_names.push_back(name);
469 : 1 : }
470 : :
471 [ + + + ]: 53 : if (ws.has_print_area())
472 : : {
473 : 2 : defined_name name;
474 [ + ]: 2 : name.sheet_id = ws.id();
475 [ + ]: 2 : name.name = "_xlnm.Print_Area";
476 : 2 : name.hidden = false;
477 [ + + + + ]: 2 : name.value = title_ref + range_reference::make_absolute(ws.print_area()).to_string();
478 [ + ]: 2 : defined_names.push_back(name);
479 : 2 : }
480 : :
481 [ + + + ]: 53 : if (ws.has_print_titles())
482 : : {
483 : 3 : defined_name name;
484 [ + ]: 3 : name.sheet_id = ws.id();
485 [ + ]: 3 : name.name = "_xlnm.Print_Titles";
486 : 3 : name.hidden = false;
487 : :
488 [ + ]: 3 : auto cols = ws.print_title_cols();
489 [ + + ]: 3 : if (cols.is_set())
490 : : {
491 [ + + + + ]: 4 : name.value = title_ref + "$" + cols.get().first.column_string()
492 [ + + + + : 6 : + ":" + "$" + cols.get().second.column_string();
+ ]
493 : : }
494 [ + ]: 3 : auto rows = ws.print_title_rows();
495 [ + + ]: 3 : if (rows.is_set())
496 : : {
497 [ + + ]: 2 : if (!name.value.empty())
498 : : {
499 [ + ]: 1 : name.value.push_back(',');
500 : : }
501 [ + + + ]: 4 : name.value += title_ref + "$" + std::to_string(rows.get().first)
502 [ + + + + : 6 : + ":" + "$" + std::to_string(rows.get().second);
+ ]
503 : : }
504 : :
505 [ + ]: 3 : defined_names.push_back(name);
506 : 3 : }
507 : 53 : }
508 : :
509 [ - + ]: 44 : if (num_visible == 0)
510 : : {
511 [ # ]:UBC 0 : throw no_visible_worksheets();
512 : : }
513 : :
514 [ + + + - :CBC 46 : static const auto &xmlns = constants::ns("workbook");
+ + - - ]
515 [ + + + - : 46 : static const auto &xmlns_r = constants::ns("r");
+ + - - ]
516 [ + + + - : 46 : static const auto &xmlns_s = constants::ns("spreadsheetml");
+ + - - ]
517 [ + + + - : 46 : static const auto &xmlns_mx = constants::ns("mx");
+ + - - ]
518 [ + + + - : 46 : static const auto &xmlns_x15ac = constants::ns("x15ac");
+ + - - ]
519 [ + + + - : 46 : static const auto &xmlns_x15 = constants::ns("x15");
+ + - - ]
520 [ + + + - : 46 : static const auto &xmlns_mc = constants::ns("mc");
+ + - - ]
521 : :
522 [ + + ]: 88 : write_start_element(xmlns, "workbook");
523 [ + + ]: 88 : write_namespace(xmlns, "");
524 [ + + ]: 44 : write_namespace(xmlns_r, "r");
525 : :
526 [ + + ]: 44 : if (source_.d_->abs_path_.is_set())
527 : : {
528 [ + + ]: 34 : write_namespace(xmlns_mc, "mc");
529 [ + + ]: 34 : write_namespace(xmlns_x15, "x15");
530 [ + + + ]: 34 : write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x15");
531 : : }
532 : :
533 [ + + + ]: 44 : if (source_.has_file_version())
534 : : {
535 [ + + ]: 40 : write_start_element(xmlns, "fileVersion");
536 : :
537 [ + + + ]: 120 : write_attribute("appName", source_.app_name());
538 [ + + + ]: 80 : write_attribute("lastEdited", source_.last_edited());
539 [ + + + ]: 80 : write_attribute("lowestEdited", source_.lowest_edited());
540 [ + + + ]: 120 : write_attribute("rupBuild", source_.rup_build());
541 : :
542 [ + + ]: 80 : write_end_element(xmlns, "fileVersion");
543 : : }
544 : :
545 [ + + ]: 44 : write_start_element(xmlns, "workbookPr");
546 : :
547 [ + - + ]: 44 : if (source_.has_code_name())
548 : : {
549 [ # # # ]:UBC 0 : write_attribute("codeName", source_.code_name());
550 : : }
551 : :
552 [ + + + ]:CBC 44 : if (source_.base_date() == calendar::mac_1904)
553 : : {
554 [ + + ]: 2 : write_attribute("date1904", "1");
555 : : }
556 : :
557 [ + + ]: 44 : write_end_element(xmlns, "workbookPr");
558 : :
559 [ + + ]: 44 : if (source_.d_->abs_path_.is_set())
560 : : {
561 [ + + ]: 34 : write_start_element(xmlns_mc, "AlternateContent");
562 [ + + ]: 34 : write_namespace(xmlns_mc, "mc");
563 [ + + ]: 34 : write_start_element(xmlns_mc, "Choice");
564 [ + + ]: 34 : write_attribute("Requires", "x15");
565 [ + + ]: 34 : write_start_element(xmlns_x15ac, "absPath");
566 [ + + ]: 17 : write_namespace(xmlns_x15ac, "x15ac");
567 [ + + + + ]: 51 : write_attribute("url", source_.d_->abs_path_.get());
568 [ + + ]: 34 : write_end_element(xmlns_x15ac, "absPath");
569 [ + + ]: 34 : write_end_element(xmlns_mc, "Choice");
570 [ + + ]: 34 : write_end_element(xmlns_mc, "AlternateContent");
571 : : }
572 : :
573 [ + + + ]: 44 : if (source_.has_view())
574 : : {
575 [ + + ]: 82 : write_start_element(xmlns, "bookViews");
576 [ + + ]: 41 : write_start_element(xmlns, "workbookView");
577 : :
578 [ + ]: 41 : const auto &view = source_.view();
579 : :
580 [ + + + + : 41 : if (view.active_tab.is_set() && view.active_tab.get() != std::size_t(0))
+ + + ]
581 : : {
582 [ + + + ]: 3 : write_attribute("activeTab", view.active_tab.get());
583 : : }
584 : :
585 [ - + ]: 41 : if (!view.auto_filter_date_grouping)
586 : : {
587 [ # # # ]:UBC 0 : write_attribute("autoFilterDateGrouping", write_bool(view.auto_filter_date_grouping));
588 : : }
589 : :
590 [ - + ]:CBC 41 : if (view.first_sheet.is_set())
591 : : {
592 [ # # # ]:UBC 0 : write_attribute("firstSheet", view.first_sheet.get());
593 : : }
594 : :
595 [ - + ]:CBC 41 : if (view.minimized)
596 : : {
597 [ # # # ]:UBC 0 : write_attribute("minimized", write_bool(view.minimized));
598 : : }
599 : :
600 [ - + ]:CBC 41 : if (!view.show_horizontal_scroll)
601 : : {
602 [ # # # ]:UBC 0 : write_attribute("showHorizontalScroll", write_bool(view.show_horizontal_scroll));
603 : : }
604 : :
605 [ - + ]:CBC 41 : if (!view.show_sheet_tabs)
606 : : {
607 [ # # # ]:UBC 0 : write_attribute("showSheetTabs", write_bool(view.show_sheet_tabs));
608 : : }
609 : :
610 [ - + ]:CBC 41 : if (!view.show_vertical_scroll)
611 : : {
612 [ # # # ]:UBC 0 : write_attribute("showVerticalScroll", write_bool(view.show_vertical_scroll));
613 : : }
614 : :
615 [ - + ]:CBC 41 : if (!view.visible)
616 : : {
617 [ # # # ]:UBC 0 : write_attribute("visibility", write_bool(view.visible));
618 : : }
619 : :
620 [ + - ]:CBC 41 : if (view.x_window.is_set())
621 : : {
622 [ + + + ]: 123 : write_attribute("xWindow", view.x_window.get());
623 : : }
624 : :
625 [ + - ]: 41 : if (view.y_window.is_set())
626 : : {
627 [ + + + ]: 123 : write_attribute("yWindow", view.y_window.get());
628 : : }
629 : :
630 [ + - ]: 41 : if (view.window_width.is_set())
631 : : {
632 [ + + + ]: 123 : write_attribute("windowWidth", view.window_width.get());
633 : : }
634 : :
635 [ + - ]: 41 : if (view.window_height.is_set())
636 : : {
637 [ + + + ]: 123 : write_attribute("windowHeight", view.window_height.get());
638 : : }
639 : :
640 [ + + ]: 41 : if (view.tab_ratio.is_set())
641 : : {
642 [ + + + ]: 96 : write_attribute("tabRatio", view.tab_ratio.get());
643 : : }
644 : :
645 [ + + ]: 82 : write_end_element(xmlns, "workbookView");
646 [ + + ]: 41 : write_end_element(xmlns, "bookViews");
647 : 41 : }
648 : :
649 [ + + ]: 44 : write_start_element(xmlns, "sheets");
650 : :
651 : : #pragma clang diagnostic push
652 : : #pragma clang diagnostic ignored "-Wrange-loop-analysis"
653 [ + + + + : 97 : for (const auto ws : source_)
+ + + ]
654 : : {
655 [ + + + ]: 53 : auto sheet_rel_id = source_.d_->sheet_title_rel_id_map_[ws.title()];
656 [ + + + ]: 53 : auto sheet_rel = source_.d_->manifest_.relationship(rel.target().path(), sheet_rel_id);
657 : :
658 [ + + ]: 53 : write_start_element(xmlns, "sheet");
659 [ + + + ]: 159 : write_attribute("name", ws.title());
660 [ + + + ]: 106 : write_attribute("sheetId", ws.id());
661 : :
662 [ + + + + : 53 : if (ws.has_page_setup() && ws.sheet_state() == xlnt::sheet_state::hidden)
- + - + ]
663 : : {
664 [ # # ]:UBC 0 : write_attribute("state", "hidden");
665 : : }
666 : :
667 [ + + + + ]:CBC 159 : write_attribute(xml::qname(xmlns_r, "id"), sheet_rel_id);
668 [ + + ]: 53 : write_end_element(xmlns, "sheet");
669 : 53 : }
670 : : #pragma clang diagnostic pop
671 : :
672 [ + + ]: 44 : write_end_element(xmlns, "sheets");
673 : :
674 [ + + ]: 44 : if (!defined_names.empty())
675 : : {
676 [ + + ]: 1 : write_start_element(xmlns, "definedNames");
677 [ + + ]: 7 : for (const auto & name : defined_names)
678 : : {
679 [ + + ]: 6 : write_start_element(xmlns, "definedName");
680 [ + + + ]: 18 : write_attribute("name", name.name);
681 [ + + ]: 6 : if (name.hidden)
682 : : {
683 [ + + + ]: 3 : write_attribute("hidden", write_bool(true));
684 : : }
685 : :
686 [ + - ]: 6 : if (name.sheet_id.is_set())
687 : : {
688 [ + + + + ]: 18 : write_attribute("localSheetId", std::to_string(name.sheet_id.get() - 1)); // 0-indexed for some reason
689 : : }
690 [ + + ]: 6 : write_characters(name.value);
691 [ + + ]: 12 : write_end_element(xmlns, "definedName");
692 : : }
693 [ + + ]: 2 : write_end_element(xmlns, "definedNames");
694 : : }
695 : :
696 [ + + + ]: 44 : if (source_.has_calculation_properties())
697 : : {
698 [ + + ]: 41 : write_start_element(xmlns, "calcPr");
699 [ + + + ]: 82 : write_attribute("calcId", source_.calculation_properties().calc_id);
700 : : //write_attribute("calcMode", "auto");
701 : : //write_attribute("fullCalcOnLoad", "1");
702 [ + + + + ]: 123 : write_attribute("concurrentCalc", write_bool(source_.calculation_properties().concurrent_calc));
703 [ + + ]: 82 : write_end_element(xmlns, "calcPr");
704 : : }
705 : :
706 [ + - + ]: 44 : if (!source_.named_ranges().empty())
707 : : {
708 [ # # ]:UBC 0 : write_start_element(xmlns, "definedNames");
709 : :
710 [ # # # ]: 0 : for (auto &named_range : source_.named_ranges())
711 : : {
712 [ # # ]: 0 : write_start_element(xmlns_s, "definedName");
713 [ # # ]: 0 : write_namespace(xmlns_s, "s");
714 [ # # # ]: 0 : write_attribute("name", named_range.name());
715 [ # ]: 0 : const auto &target = named_range.targets().front();
716 [ # # # # : 0 : write_characters("'" + target.first.title() + "\'!" + target.second.to_string());
# # ]
717 [ # # ]: 0 : write_end_element(xmlns_s, "definedName");
718 : 0 : }
719 : :
720 [ # # ]: 0 : write_end_element(xmlns, "definedNames");
721 : : }
722 : :
723 [ + + ]:CBC 44 : if (source_.d_->arch_id_flags_.is_set())
724 : : {
725 [ + + ]: 20 : write_start_element(xmlns, "extLst");
726 [ + + ]: 20 : write_start_element(xmlns, "ext");
727 [ + + ]: 20 : write_namespace(xmlns_mx, "mx");
728 [ + + ]: 20 : write_attribute("uri", "{7523E5D3-25F3-A5E0-1632-64F254C22452}");
729 [ + + ]: 10 : write_start_element(xmlns_mx, "ArchID");
730 [ + + + ]: 30 : write_attribute("Flags", source_.d_->arch_id_flags_.get());
731 [ + + ]: 20 : write_end_element(xmlns_mx, "ArchID");
732 [ + + ]: 20 : write_end_element(xmlns, "ext");
733 [ + + ]: 20 : write_end_element(xmlns, "extLst");
734 : : }
735 : :
736 [ + + ]: 44 : write_end_element(xmlns, "workbook");
737 : :
738 [ + + + + ]: 44 : auto workbook_rels = source_.manifest().relationships(rel.target().path());
739 [ + + + ]: 44 : write_relationships(workbook_rels, rel.target().path());
740 : :
741 [ + + ]: 216 : for (const auto &child_rel : workbook_rels)
742 : : {
743 [ + + + ]: 172 : if (child_rel.type() == relationship_type::calculation_chain)
744 : : {
745 : : // We don't yet have a VBA interpreter which can evaluate formulas.
746 : : // If we write an outdated calculate chain, Excel will treat the XLSX
747 : : // as corrupt. As a workaround, we keep the relationship but don't
748 : : // write the calculation chain file so Excel will recalculate all formulae
749 : : // on load.
750 : 6 : continue;
751 : : }
752 : :
753 [ + + + ]: 167 : auto child_target_path = child_rel.target().path();
754 [ + + + + ]: 167 : path archive_path(child_rel.source().path().parent().append(child_target_path));
755 : :
756 : : // write binary
757 [ + + + ]: 167 : if (child_rel.type() == relationship_type::vbaproject)
758 : : {
759 [ + ]: 1 : write_binary(archive_path);
760 : 1 : continue;
761 : : }
762 : :
763 : : // write xml
764 [ + ]: 166 : begin_part(archive_path);
765 : :
766 [ + - - - : 166 : switch (child_rel.type())
- - - + -
+ + - + -
- - - - -
- - - - -
- - - - -
- - - - -
- - - ]
767 : : {
768 :UBC 0 : case relationship_type::chartsheet:
769 [ # ]: 0 : write_chartsheet(child_rel);
770 : 0 : break;
771 : :
772 : 0 : case relationship_type::connections:
773 [ # ]: 0 : write_connections(child_rel);
774 : 0 : break;
775 : :
776 : 0 : case relationship_type::custom_xml_mappings:
777 [ # ]: 0 : write_custom_xml_mappings(child_rel);
778 : 0 : break;
779 : :
780 : 0 : case relationship_type::dialogsheet:
781 [ # ]: 0 : write_dialogsheet(child_rel);
782 : 0 : break;
783 : :
784 : 0 : case relationship_type::external_workbook_references:
785 [ # ]: 0 : write_external_workbook_references(child_rel);
786 : 0 : break;
787 : :
788 : 0 : case relationship_type::pivot_table:
789 [ # ]: 0 : write_pivot_table(child_rel);
790 : 0 : break;
791 : :
792 :CBC 30 : case relationship_type::shared_string_table:
793 [ + ]: 30 : write_shared_string_table(child_rel);
794 : 30 : break;
795 : :
796 :UBC 0 : case relationship_type::shared_workbook_revision_headers:
797 [ # ]: 0 : write_shared_workbook_revision_headers(child_rel);
798 : 0 : break;
799 : :
800 :CBC 42 : case relationship_type::stylesheet:
801 [ + ]: 42 : write_styles(child_rel);
802 : 42 : break;
803 : :
804 : 41 : case relationship_type::theme:
805 [ + ]: 41 : write_theme(child_rel);
806 : 41 : break;
807 : :
808 :UBC 0 : case relationship_type::volatile_dependencies:
809 [ # ]: 0 : write_volatile_dependencies(child_rel);
810 : 0 : break;
811 : :
812 :CBC 53 : case relationship_type::worksheet:
813 [ + ]: 53 : write_worksheet(child_rel);
814 : 53 : break;
815 : :
816 :UBC 0 : case relationship_type::calculation_chain:
817 : 0 : break;
818 : 0 : case relationship_type::office_document:
819 : 0 : break;
820 : 0 : case relationship_type::thumbnail:
821 : 0 : break;
822 : 0 : case relationship_type::extended_properties:
823 : 0 : break;
824 : 0 : case relationship_type::core_properties:
825 : 0 : break;
826 : 0 : case relationship_type::hyperlink:
827 : 0 : break;
828 : 0 : case relationship_type::comments:
829 : 0 : break;
830 : 0 : case relationship_type::vml_drawing:
831 : 0 : break;
832 : 0 : case relationship_type::unknown:
833 : 0 : break;
834 : 0 : case relationship_type::custom_properties:
835 : 0 : break;
836 : 0 : case relationship_type::printer_settings:
837 : 0 : break;
838 : 0 : case relationship_type::custom_property:
839 : 0 : break;
840 : 0 : case relationship_type::drawings:
841 : 0 : break;
842 : 0 : case relationship_type::pivot_table_cache_definition:
843 : 0 : break;
844 : 0 : case relationship_type::pivot_table_cache_records:
845 : 0 : break;
846 : 0 : case relationship_type::query_table:
847 : 0 : break;
848 : 0 : case relationship_type::shared_workbook:
849 : 0 : break;
850 : 0 : case relationship_type::revision_log:
851 : 0 : break;
852 : 0 : case relationship_type::shared_workbook_user_data:
853 : 0 : break;
854 : 0 : case relationship_type::single_cell_table_definitions:
855 : 0 : break;
856 : 0 : case relationship_type::table_definition:
857 : 0 : break;
858 : 0 : case relationship_type::vbaproject:
859 : 0 : break;
860 : 0 : case relationship_type::image:
861 : 0 : break;
862 : : }
863 [ + + + + ]:CBC 168 : }
864 : 44 : }
865 : :
866 : : // Write Workbook Relationship Target Parts
867 : :
868 :UBC 0 : void xlsx_producer::write_chartsheet(const relationship & /*rel*/)
869 : : {
870 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "chartsheet");
871 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "chartsheet");
872 : 0 : }
873 : :
874 : 0 : void xlsx_producer::write_connections(const relationship & /*rel*/)
875 : : {
876 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "connections");
877 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "connections");
878 : 0 : }
879 : :
880 : 0 : void xlsx_producer::write_custom_xml_mappings(const relationship & /*rel*/)
881 : : {
882 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "MapInfo");
883 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "MapInfo");
884 : 0 : }
885 : :
886 : 0 : void xlsx_producer::write_dialogsheet(const relationship & /*rel*/)
887 : : {
888 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "dialogsheet");
889 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "dialogsheet");
890 : 0 : }
891 : :
892 : 0 : void xlsx_producer::write_external_workbook_references(const relationship & /*rel*/)
893 : : {
894 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "externalLink");
895 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "externalLink");
896 : 0 : }
897 : :
898 : 0 : void xlsx_producer::write_pivot_table(const relationship & /*rel*/)
899 : : {
900 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "pivotTableDefinition");
901 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "pivotTableDefinition");
902 : 0 : }
903 : :
904 :CBC 350 : void xlsx_producer::write_rich_text(const std::string &ns, const xlnt::rich_text &text)
905 : : {
906 [ + + - + : 350 : if (text.runs().size() == 1 && !text.runs().at(0).second.is_set())
+ + + + -
+ - + + -
- - - ]
907 : : {
908 [ + + ]: 334 : write_start_element(ns, "t");
909 [ + + + ]: 334 : write_characters(text.plain_text(), text.runs().front().preserve_space);
910 [ + + ]: 668 : write_end_element(ns, "t");
911 : : }
912 : : else
913 : : {
914 [ + + + ]: 32 : for (const auto &run : text.runs())
915 : : {
916 [ + + ]: 16 : write_start_element(ns, "r");
917 : :
918 [ + - ]: 16 : if (run.second.is_set())
919 : : {
920 [ + + ]: 16 : write_start_element(ns, "rPr");
921 : :
922 [ + + + - ]: 16 : if (run.second.get().bold())
923 : : {
924 [ + + ]: 32 : write_start_element(ns, "b");
925 [ + + ]: 32 : write_end_element(ns, "b");
926 : : }
927 : :
928 [ + + + - ]: 16 : if (run.second.get().has_size())
929 : : {
930 [ + + ]: 16 : write_start_element(ns, "sz");
931 [ + + + + ]: 48 : write_attribute<double>("val", run.second.get().size());
932 [ + + ]: 32 : write_end_element(ns, "sz");
933 : : }
934 : :
935 [ + + + - ]: 16 : if (run.second.get().has_color())
936 : : {
937 [ + + ]: 16 : write_start_element(ns, "color");
938 [ + + + ]: 16 : write_color(run.second.get().color());
939 [ + + ]: 32 : write_end_element(ns, "color");
940 : : }
941 : :
942 [ + + + - ]: 16 : if (run.second.get().has_name())
943 : : {
944 [ + + ]: 16 : write_start_element(ns, "rFont");
945 [ + + + + : 48 : write_attribute("val", run.second.get().name());
+ ]
946 [ + + ]: 32 : write_end_element(ns, "rFont");
947 : : }
948 : :
949 [ + + - + ]: 16 : if (run.second.get().has_family())
950 : : {
951 [ # # ]:UBC 0 : write_start_element(ns, "family");
952 [ # # # # ]: 0 : write_attribute("val", run.second.get().family());
953 [ # # ]: 0 : write_end_element(ns, "family");
954 : : }
955 : :
956 [ + + - + ]:CBC 16 : if (run.second.get().has_scheme())
957 : : {
958 [ # # ]:UBC 0 : write_start_element(ns, "scheme");
959 [ # # # # : 0 : write_attribute("val", run.second.get().scheme());
# ]
960 [ # # ]: 0 : write_end_element(ns, "scheme");
961 : : }
962 : :
963 [ + + ]:CBC 32 : write_end_element(ns, "rPr");
964 : : }
965 : :
966 [ + + + ]: 48 : write_element(ns, "t", run.first, run.preserve_space);
967 [ + + ]: 32 : write_end_element(ns, "r");
968 : 16 : }
969 : : }
970 : :
971 [ + + + ]: 351 : for (const auto &run : text.phonetic_runs())
972 : : {
973 [ + + ]: 1 : write_start_element(ns, "rPh");
974 [ + + ]: 2 : write_attribute("sb", run.start);
975 [ + + ]: 3 : write_attribute("eb", run.end);
976 [ + + ]: 1 : write_start_element(ns, "t");
977 [ + + ]: 1 : write_characters(run.text, run.preserve_space);
978 [ + + ]: 2 : write_end_element(ns, "t");
979 [ + + ]: 2 : write_end_element(ns, "rPh");
980 : 350 : }
981 : :
982 [ + + ]: 350 : if (text.has_phonetic_properties())
983 : : {
984 : 3 : const auto &phonetic_properties = text.phonetic_properties();
985 : :
986 [ + + ]: 3 : write_start_element(ns, "phoneticPr");
987 [ + + ]: 6 : write_attribute("fontId", phonetic_properties.font_id());
988 : :
989 [ + + ]: 3 : if (text.phonetic_properties().has_type())
990 : : {
991 : 2 : const auto type = phonetic_properties.type();
992 [ + + + + ]: 6 : write_attribute("type", phonetic_properties.type_as_string(type));
993 : : }
994 : :
995 [ - + ]: 3 : if (text.phonetic_properties().has_alignment())
996 : : {
997 :UBC 0 : const auto alignment = phonetic_properties.alignment();
998 [ # # # # ]: 0 : write_attribute("alignment", phonetic_properties.alignment_as_string(alignment));
999 : : }
1000 : :
1001 [ + + ]:CBC 6 : write_end_element(ns, "phoneticPr");
1002 : : }
1003 : 350 : }
1004 : :
1005 : 30 : void xlsx_producer::write_shared_string_table(const relationship & /*rel*/)
1006 : : {
1007 [ + + + - : 32 : static const auto &xmlns = constants::ns("spreadsheetml");
+ + - - ]
1008 : :
1009 [ + + ]: 60 : write_start_element(xmlns, "sst");
1010 [ + + ]: 30 : write_namespace(xmlns, "");
1011 : :
1012 : : // todo: is there a more elegant way to get this number?
1013 : 30 : std::size_t string_count = 0;
1014 : :
1015 [ + + + + : 67 : for (const auto ws : source_)
+ + + ]
1016 : : {
1017 [ + ]: 37 : auto dimension = ws.calculate_dimension();
1018 [ + ]: 37 : auto current_cell = dimension.top_left();
1019 : :
1020 [ + + + + : 1677 : while (current_cell.row() <= dimension.bottom_right().row())
+ ]
1021 : : {
1022 [ + + + + : 4244 : while (current_cell.column() <= dimension.bottom_right().column())
+ + ]
1023 : : {
1024 [ + ]: 2604 : auto c_iter = ws.d_->cell_map_.find(current_cell);
1025 [ + + + + : 2604 : if (c_iter != ws.d_->cell_map_.end() && c_iter->second.type_ == cell_type::shared_string)
+ + ]
1026 : : {
1027 : 732 : ++string_count;
1028 : : }
1029 : :
1030 [ + + + ]: 2604 : current_cell.column_index(current_cell.column_index() + 1);
1031 : : }
1032 : :
1033 [ + + ]: 1640 : current_cell.row(current_cell.row() + 1);
1034 [ + + + + ]: 1640 : current_cell.column_index(dimension.top_left().column_index());
1035 : : }
1036 : : }
1037 : :
1038 [ + + ]: 30 : write_attribute("count", string_count);
1039 [ + + ]: 60 : write_attribute("uniqueCount", source_.shared_strings().size());
1040 : :
1041 [ + + + ]: 364 : for (const auto &text : source_.shared_strings())
1042 : : {
1043 [ + + ]: 334 : write_start_element(xmlns, "si");
1044 [ + ]: 334 : write_rich_text(xmlns, text);
1045 [ + + ]: 668 : write_end_element(xmlns, "si");
1046 : : }
1047 : :
1048 [ + + ]: 30 : write_end_element(xmlns, "sst");
1049 : 30 : }
1050 : :
1051 :UBC 0 : void xlsx_producer::write_shared_workbook_revision_headers(const relationship & /*rel*/)
1052 : : {
1053 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "headers");
1054 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "headers");
1055 : 0 : }
1056 : :
1057 : 0 : void xlsx_producer::write_shared_workbook(const relationship & /*rel*/)
1058 : : {
1059 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "revisions");
1060 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "revisions");
1061 : 0 : }
1062 : :
1063 : 0 : void xlsx_producer::write_shared_workbook_user_data(const relationship & /*rel*/)
1064 : : {
1065 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "users");
1066 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "users");
1067 : 0 : }
1068 : :
1069 :CBC 203 : void xlsx_producer::write_font(const font &f)
1070 : : {
1071 [ + + + - : 205 : static const auto &xmlns = constants::ns("spreadsheetml");
+ + - - ]
1072 : :
1073 [ + + ]: 203 : write_start_element(xmlns, "font");
1074 : :
1075 [ + + ]: 203 : if (f.bold())
1076 : : {
1077 [ + + ]: 94 : write_start_element(xmlns, "b");
1078 [ + + ]: 94 : write_end_element(xmlns, "b");
1079 : : }
1080 : :
1081 [ + + ]: 203 : if (f.italic())
1082 : : {
1083 [ + + ]: 40 : write_start_element(xmlns, "i");
1084 [ + + ]: 40 : write_end_element(xmlns, "i");
1085 : : }
1086 : :
1087 [ + + ]: 203 : if (f.strikethrough())
1088 : : {
1089 [ + + ]: 16 : write_start_element(xmlns, "strike");
1090 [ + + ]: 16 : write_end_element(xmlns, "strike");
1091 : : }
1092 : :
1093 [ + + ]: 203 : if (f.underlined())
1094 : : {
1095 [ + + ]: 29 : write_start_element(xmlns, "u");
1096 [ + + ]: 29 : if (f.underline() != font::underline_style::single)
1097 : : {
1098 [ + + ]: 60 : write_attribute("val", f.underline());
1099 : : }
1100 [ + + ]: 58 : write_end_element(xmlns, "u");
1101 : : }
1102 : :
1103 [ + + ]: 203 : if (f.superscript())
1104 : : {
1105 [ + + ]: 8 : write_start_element(xmlns, "vertAlign");
1106 [ + + ]: 8 : write_attribute("val", "superscript");
1107 [ + + ]: 8 : write_end_element(xmlns, "vertAlign");
1108 : : }
1109 [ + + ]: 199 : else if (f.subscript())
1110 : : {
1111 [ + + ]: 16 : write_start_element(xmlns, "vertAlign");
1112 [ + + ]: 16 : write_attribute("val", "subscript");
1113 [ + + ]: 16 : write_end_element(xmlns, "vertAlign");
1114 : : }
1115 : :
1116 [ + + ]: 203 : if (f.has_size())
1117 : : {
1118 [ + + ]: 201 : write_start_element(xmlns, "sz");
1119 [ + + ]: 603 : write_attribute<double>("val", f.size());
1120 [ + + ]: 402 : write_end_element(xmlns, "sz");
1121 : : }
1122 : :
1123 [ + + ]: 203 : if (f.has_color())
1124 : : {
1125 [ + + ]: 193 : write_start_element(xmlns, "color");
1126 [ + + ]: 193 : write_color(f.color());
1127 [ + + ]: 386 : write_end_element(xmlns, "color");
1128 : : }
1129 : :
1130 [ + + ]: 203 : if (f.has_name())
1131 : : {
1132 [ + + ]: 202 : write_start_element(xmlns, "name");
1133 [ + + + + ]: 606 : write_attribute("val", f.name());
1134 [ + + ]: 404 : write_end_element(xmlns, "name");
1135 : : }
1136 : :
1137 [ + + ]: 203 : if (f.has_family())
1138 : : {
1139 [ + + ]: 181 : write_start_element(xmlns, "family");
1140 [ + + ]: 543 : write_attribute("val", f.family());
1141 [ + + ]: 362 : write_end_element(xmlns, "family");
1142 : : }
1143 : :
1144 [ + + ]: 203 : if (f.has_scheme())
1145 : : {
1146 [ + + ]: 182 : write_start_element(xmlns, "scheme");
1147 [ + + + + ]: 546 : write_attribute("val", f.scheme());
1148 [ + + ]: 364 : write_end_element(xmlns, "scheme");
1149 : : }
1150 : :
1151 [ + + ]: 203 : write_end_element(xmlns, "font");
1152 : 203 : }
1153 : :
1154 : 211 : void xlsx_producer::write_fill(const fill &f)
1155 : : {
1156 [ + + + - : 213 : static const auto &xmlns = constants::ns("spreadsheetml");
+ + - - ]
1157 : :
1158 [ + + ]: 211 : write_start_element(xmlns, "fill");
1159 : :
1160 [ + + ]: 211 : if (f.type() == xlnt::fill_type::pattern)
1161 : : {
1162 [ + ]: 210 : const auto &pattern = f.pattern_fill();
1163 : :
1164 [ + + ]: 210 : write_start_element(xmlns, "patternFill");
1165 : :
1166 [ + + + ]: 420 : write_attribute("patternType", pattern.type());
1167 : :
1168 [ + + + ]: 210 : if (pattern.foreground().is_set())
1169 : : {
1170 [ + + ]: 126 : write_start_element(xmlns, "fgColor");
1171 [ + + + ]: 126 : write_color(pattern.foreground().get());
1172 [ + + ]: 252 : write_end_element(xmlns, "fgColor");
1173 : : }
1174 : :
1175 [ + + + ]: 210 : if (pattern.background().is_set())
1176 : : {
1177 [ + + ]: 126 : write_start_element(xmlns, "bgColor");
1178 [ + + + ]: 126 : write_color(pattern.background().get());
1179 [ + + ]: 252 : write_end_element(xmlns, "bgColor");
1180 : : }
1181 : :
1182 [ + + ]: 210 : write_end_element(xmlns, "patternFill");
1183 : 210 : }
1184 [ + - ]: 1 : else if (f.type() == xlnt::fill_type::gradient)
1185 : : {
1186 [ + ]: 1 : const auto &gradient = f.gradient_fill();
1187 : :
1188 [ + + ]: 1 : write_start_element(xmlns, "gradientFill");
1189 [ + + + ]: 2 : write_attribute("gradientType", gradient.type());
1190 : :
1191 [ + - + ]: 1 : if (gradient.degree() != 0.)
1192 : : {
1193 [ # # # ]:UBC 0 : write_attribute<double>("degree", gradient.degree());
1194 : : }
1195 : :
1196 [ + - + ]:CBC 1 : if (gradient.left() != 0.)
1197 : : {
1198 [ # # # ]:UBC 0 : write_attribute<double>("left", gradient.left());
1199 : : }
1200 : :
1201 [ + - + ]:CBC 1 : if (gradient.right() != 0.)
1202 : : {
1203 [ # # # ]:UBC 0 : write_attribute<double>("right", gradient.right());
1204 : : }
1205 : :
1206 [ + - + ]:CBC 1 : if (gradient.top() != 0.)
1207 : : {
1208 [ # # # ]:UBC 0 : write_attribute<double>("top", gradient.top());
1209 : : }
1210 : :
1211 [ + - + ]:CBC 1 : if (gradient.bottom() != 0.)
1212 : : {
1213 [ # # # ]:UBC 0 : write_attribute<double>("bottom", gradient.bottom());
1214 : : }
1215 : :
1216 [ + - + ]:CBC 1 : for (const auto &stop : gradient.stops())
1217 : : {
1218 [ # # ]:UBC 0 : write_start_element(xmlns, "stop");
1219 [ # # ]: 0 : write_attribute<double>("position", stop.first);
1220 [ # # ]: 0 : write_start_element(xmlns, "color");
1221 [ # ]: 0 : write_color(stop.second);
1222 [ # # ]: 0 : write_end_element(xmlns, "color");
1223 [ # # ]: 0 : write_end_element(xmlns, "stop");
1224 :CBC 1 : }
1225 : :
1226 [ + + ]: 1 : write_end_element(xmlns, "gradientFill");
1227 : 1 : }
1228 : :
1229 [ + + ]: 211 : write_end_element(xmlns, "fill");
1230 : 211 : }
1231 : :
1232 : 85 : void xlsx_producer::write_border(const border ¤t_border)
1233 : : {
1234 [ + + + - : 87 : static const auto &xmlns = constants::ns("spreadsheetml");
+ + - - ]
1235 : :
1236 [ + + ]: 85 : write_start_element(xmlns, "border");
1237 : :
1238 [ + - + ]: 85 : if (current_border.diagonal().is_set())
1239 : : {
1240 [ # # ]:UBC 0 : auto up = current_border.diagonal().get() == diagonal_direction::both
1241 [ # # # # : 0 : || current_border.diagonal().get() == diagonal_direction::up;
# # # # #
# # # #
# ]
1242 [ # # # ]: 0 : write_attribute("diagonalUp", write_bool(up));
1243 : :
1244 [ # # ]: 0 : auto down = current_border.diagonal().get() == diagonal_direction::both
1245 [ # # # # : 0 : || current_border.diagonal().get() == diagonal_direction::down;
# # # # #
# # # #
# ]
1246 [ # # # ]: 0 : write_attribute("diagonalDown", write_bool(down));
1247 : : }
1248 : :
1249 [ + + + ]:CBC 680 : for (const auto &side : xlnt::border::all_sides())
1250 : : {
1251 [ + + + ]: 595 : if (current_border.side(side).is_set())
1252 : : {
1253 [ + + ]: 420 : const auto current_side = current_border.side(side).get();
1254 : :
1255 [ + ]: 420 : auto side_name = to_string(side);
1256 [ + ]: 420 : write_start_element(xmlns, side_name);
1257 : :
1258 [ + + + ]: 420 : if (current_side.style().is_set())
1259 : : {
1260 [ + + + + ]: 348 : write_attribute("style", current_side.style().get());
1261 : : }
1262 : :
1263 [ + + + ]: 420 : if (current_side.color().is_set())
1264 : : {
1265 [ + + ]: 116 : write_start_element(xmlns, "color");
1266 [ + + + ]: 116 : write_color(current_side.color().get());
1267 [ + + ]: 232 : write_end_element(xmlns, "color");
1268 : : }
1269 : :
1270 [ + ]: 420 : write_end_element(xmlns, side_name);
1271 : 420 : }
1272 : : }
1273 : :
1274 [ + + ]: 85 : write_end_element(xmlns, "border");
1275 : 85 : }
1276 : :
1277 : 42 : void xlsx_producer::write_styles(const relationship & /*rel*/)
1278 : : {
1279 [ + + + - : 44 : static const auto &xmlns = constants::ns("spreadsheetml");
+ + - - ]
1280 [ + + + - : 44 : static const auto &xmlns_mc = constants::ns("mc");
+ + - - ]
1281 [ + + + - : 44 : static const auto &xmlns_x14 = constants::ns("x14");
+ + - - ]
1282 [ + + + - : 44 : static const auto &xmlns_x14ac = constants::ns("x14ac");
+ + - - ]
1283 : :
1284 [ + + ]: 84 : write_start_element(xmlns, "styleSheet");
1285 [ + + ]: 42 : write_namespace(xmlns, "");
1286 : :
1287 [ + + ]: 42 : const auto &stylesheet = source_.impl().stylesheet_.get();
1288 : :
1289 : 42 : auto using_namespace = [&stylesheet](const std::string &ns) {
1290 [ + - ]: 42 : if (ns == "x14ac")
1291 : : {
1292 : 42 : return stylesheet.known_fonts_enabled;
1293 : : }
1294 : :
1295 :UBC 0 : return false;
1296 :CBC 42 : };
1297 : :
1298 [ + + + + ]: 84 : if (using_namespace("x14ac"))
1299 : : {
1300 [ + + ]: 48 : write_namespace(xmlns_mc, "mc");
1301 [ + + ]: 48 : write_namespace(xmlns_x14ac, "x14ac");
1302 [ + + + ]: 48 : write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x14ac");
1303 : : }
1304 : :
1305 : : // Number Formats
1306 : :
1307 [ + + ]: 42 : if (!stylesheet.number_formats.empty())
1308 : : {
1309 : 16 : const auto &number_formats = stylesheet.number_formats;
1310 : :
1311 [ + ]: 16 : auto num_custom = std::count_if(number_formats.begin(), number_formats.end(),
1312 : 19 : [](const number_format &nf) { return nf.id() >= 164; });
1313 : :
1314 [ + + ]: 16 : if (num_custom > 0)
1315 : : {
1316 [ + + ]: 4 : write_start_element(xmlns, "numFmts");
1317 [ + + ]: 2 : write_attribute("count", num_custom);
1318 : :
1319 [ + + ]: 7 : for (const auto &num_fmt : number_formats)
1320 : : {
1321 [ + + + ]: 5 : if (num_fmt.id() < 164) continue;
1322 [ + + ]: 4 : write_start_element(xmlns, "numFmt");
1323 [ + + + ]: 8 : write_attribute("numFmtId", num_fmt.id());
1324 [ + + + ]: 12 : write_attribute("formatCode", num_fmt.format_string());
1325 [ + + ]: 8 : write_end_element(xmlns, "numFmt");
1326 : : }
1327 : :
1328 [ + + ]: 4 : write_end_element(xmlns, "numFmts");
1329 : : }
1330 : : }
1331 : :
1332 : : // Fonts
1333 : :
1334 [ + - ]: 42 : if (!stylesheet.fonts.empty())
1335 : : {
1336 : 42 : const auto &fonts = stylesheet.fonts;
1337 : :
1338 [ + + ]: 42 : write_start_element(xmlns, "fonts");
1339 [ + + ]: 84 : write_attribute("count", fonts.size());
1340 : :
1341 [ + + ]: 42 : if (stylesheet.known_fonts_enabled)
1342 : : {
1343 : 156 : auto is_known_font = [](const font &f) {
1344 : : const auto known_fonts = std::vector<font>{
1345 [ + + + + : 780 : font().name("Calibri").family(2).size(12).color(theme_color(1)).scheme("minor")};
+ + + + +
+ + + -
- ]
1346 : :
1347 [ + ]: 312 : return std::find(known_fonts.begin(), known_fonts.end(), f) != known_fonts.end();
1348 [ + + - - : 468 : };
- - ]
1349 : :
1350 : 24 : std::size_t num_known_fonts = 0;
1351 : :
1352 [ + + ]: 180 : for (const auto ¤t_font : fonts)
1353 : : {
1354 [ + + + ]: 156 : if (is_known_font(current_font))
1355 : : {
1356 : 24 : num_known_fonts += 1;
1357 : : }
1358 : : }
1359 : :
1360 [ + + + ]: 48 : write_attribute(xml::qname(xmlns_x14ac, "knownFonts"), num_known_fonts);
1361 : : }
1362 : :
1363 [ + + ]: 245 : for (const auto ¤t_font : fonts)
1364 : : {
1365 [ + ]: 203 : write_font(current_font);
1366 : : }
1367 : :
1368 [ + + ]: 84 : write_end_element(xmlns, "fonts");
1369 : : }
1370 : :
1371 : : // Fills
1372 : :
1373 [ + - ]: 42 : if (!stylesheet.fills.empty())
1374 : : {
1375 : 42 : const auto &fills = stylesheet.fills;
1376 : :
1377 [ + + ]: 42 : write_start_element(xmlns, "fills");
1378 [ + + ]: 84 : write_attribute("count", fills.size());
1379 : :
1380 [ + + ]: 253 : for (auto ¤t_fill : fills)
1381 : : {
1382 [ + ]: 211 : write_fill(current_fill);
1383 : : }
1384 : :
1385 [ + + ]: 84 : write_end_element(xmlns, "fills");
1386 : : }
1387 : :
1388 : : // Borders
1389 : :
1390 [ + - ]: 42 : if (!stylesheet.borders.empty())
1391 : : {
1392 : 42 : const auto &borders = stylesheet.borders;
1393 : :
1394 [ + + ]: 42 : write_start_element(xmlns, "borders");
1395 [ + + ]: 84 : write_attribute("count", borders.size());
1396 : :
1397 [ + + ]: 127 : for (const auto ¤t_border : borders)
1398 : : {
1399 [ + ]: 85 : write_border(current_border);
1400 : : }
1401 : :
1402 [ + + ]: 84 : write_end_element(xmlns, "borders");
1403 : : }
1404 : :
1405 : : // Style XFs
1406 [ + - ]: 42 : if (stylesheet.style_impls.size() > 0)
1407 : : {
1408 [ + + ]: 42 : write_start_element(xmlns, "cellStyleXfs");
1409 [ + + ]: 84 : write_attribute("count", stylesheet.style_impls.size());
1410 : :
1411 [ + + ]: 258 : for (const auto ¤t_style_name : stylesheet.style_names)
1412 : : {
1413 [ + ]: 216 : const auto ¤t_style_impl = stylesheet.style_impls.at(current_style_name);
1414 : :
1415 [ + + ]: 216 : write_start_element(xmlns, "xf");
1416 : :
1417 [ + - ]: 216 : if (current_style_impl.number_format_id.is_set())
1418 : : {
1419 [ + + + ]: 648 : write_attribute("numFmtId", current_style_impl.number_format_id.get());
1420 : : }
1421 : :
1422 [ + - ]: 216 : if (current_style_impl.font_id.is_set())
1423 : : {
1424 [ + + + ]: 648 : write_attribute("fontId", current_style_impl.font_id.get());
1425 : : }
1426 : :
1427 [ + + ]: 216 : if (current_style_impl.fill_id.is_set())
1428 : : {
1429 [ + + + ]: 645 : write_attribute("fillId", current_style_impl.fill_id.get());
1430 : : }
1431 : :
1432 [ + + ]: 216 : if (current_style_impl.border_id.is_set())
1433 : : {
1434 [ + + + ]: 645 : write_attribute("borderId", current_style_impl.border_id.get());
1435 : : }
1436 : :
1437 : 216 : if (current_style_impl.number_format_id.is_set()
1438 [ + - + + : 216 : && current_style_impl.number_format_applied.is_set())
+ + ]
1439 : : {
1440 [ + + ]: 170 : write_attribute("applyNumberFormat",
1441 [ + + ]: 340 : write_bool(current_style_impl.number_format_applied.get()));
1442 : : }
1443 : :
1444 : 216 : if (current_style_impl.fill_id.is_set()
1445 [ + + + + : 216 : && current_style_impl.fill_applied.is_set())
+ + ]
1446 : : {
1447 [ + + ]: 41 : write_attribute("applyFill",
1448 [ + + ]: 82 : write_bool(current_style_impl.fill_applied.get()));
1449 : : }
1450 : :
1451 : 216 : if (current_style_impl.font_id.is_set()
1452 [ + - + + : 216 : && current_style_impl.font_applied.is_set())
+ + ]
1453 : : {
1454 [ + + ]: 12 : write_attribute("applyFont",
1455 [ + + ]: 24 : write_bool(current_style_impl.font_applied.get()));
1456 : : }
1457 : :
1458 : 216 : if (current_style_impl.border_id.is_set()
1459 [ + + + + : 216 : && current_style_impl.border_applied.is_set())
+ + ]
1460 : : {
1461 [ + + ]: 135 : write_attribute("applyBorder",
1462 [ + + ]: 270 : write_bool(current_style_impl.border_applied.get()));
1463 : : }
1464 : :
1465 : 216 : if (current_style_impl.alignment_id.is_set()
1466 [ + + + + : 216 : && current_style_impl.alignment_applied.is_set())
+ + ]
1467 : : {
1468 [ + + ]: 43 : write_attribute("applyAlignment",
1469 [ + + ]: 86 : write_bool(current_style_impl.alignment_applied.get()));
1470 : : }
1471 : :
1472 : 216 : if (current_style_impl.protection_id.is_set()
1473 [ - + - - : 216 : && current_style_impl.protection_applied.is_set())
- + ]
1474 : : {
1475 [ # # ]:UBC 0 : write_attribute("applyProtection",
1476 [ # # ]: 0 : write_bool(current_style_impl.protection_applied.get()));
1477 : : }
1478 : :
1479 [ - + ]:CBC 216 : if (current_style_impl.pivot_button_)
1480 : : {
1481 [ # # # ]:UBC 0 : write_attribute("pivotButton", write_bool(true));
1482 : : }
1483 : :
1484 [ - + ]:CBC 216 : if (current_style_impl.quote_prefix_)
1485 : : {
1486 [ # # # ]:UBC 0 : write_attribute("quotePrefix", write_bool(true));
1487 : : }
1488 : :
1489 [ + + ]:CBC 216 : if (current_style_impl.alignment_id.is_set())
1490 : : {
1491 [ + ]: 45 : const auto ¤t_alignment = stylesheet.alignments[current_style_impl.alignment_id.get()];
1492 : :
1493 [ + + ]: 45 : write_start_element(xmlns, "alignment");
1494 : :
1495 [ + + - ]: 45 : if (current_alignment.vertical().is_set())
1496 : : {
1497 [ + + + + ]: 135 : write_attribute("vertical", current_alignment.vertical().get());
1498 : : }
1499 : :
1500 [ + + + ]: 45 : if (current_alignment.horizontal().is_set())
1501 : : {
1502 [ + + + + ]: 3 : write_attribute("horizontal", current_alignment.horizontal().get());
1503 : : }
1504 : :
1505 [ + + + ]: 45 : if (current_alignment.rotation().is_set())
1506 : : {
1507 [ + + + + ]: 3 : write_attribute("textRotation", current_alignment.rotation().get());
1508 : : }
1509 : :
1510 [ + + + ]: 45 : if (current_alignment.wrap())
1511 : : {
1512 [ + + + + ]: 3 : write_attribute("wrapText", write_bool(current_alignment.wrap()));
1513 : : }
1514 : :
1515 [ + + + ]: 45 : if (current_alignment.indent().is_set())
1516 : : {
1517 [ + + + + ]: 3 : write_attribute("indent", current_alignment.indent().get());
1518 : : }
1519 : :
1520 [ + - + ]: 45 : if (current_alignment.shrink())
1521 : : {
1522 [ # # # # ]:UBC 0 : write_attribute("shrinkToFit", write_bool(current_alignment.shrink()));
1523 : : }
1524 : :
1525 [ + + ]:CBC 90 : write_end_element(xmlns, "alignment");
1526 : : }
1527 : :
1528 [ - + ]: 216 : if (current_style_impl.protection_id.is_set())
1529 : : {
1530 [ # ]:UBC 0 : const auto ¤t_protection = stylesheet.protections[current_style_impl.protection_id.get()];
1531 : :
1532 [ # # ]: 0 : write_start_element(xmlns, "protection");
1533 [ # # # # ]: 0 : write_attribute("locked", write_bool(current_protection.locked()));
1534 [ # # # # ]: 0 : write_attribute("hidden", write_bool(current_protection.hidden()));
1535 [ # # ]: 0 : write_end_element(xmlns, "protection");
1536 : : }
1537 : :
1538 [ + + ]:CBC 432 : write_end_element(xmlns, "xf");
1539 : : }
1540 : :
1541 [ + + ]: 84 : write_end_element(xmlns, "cellStyleXfs");
1542 : : }
1543 : :
1544 : : // Format XFs
1545 : :
1546 [ + + ]: 42 : write_start_element(xmlns, "cellXfs");
1547 [ + + ]: 84 : write_attribute("count", stylesheet.format_impls.size());
1548 : :
1549 [ + + ]: 225 : for (auto ¤t_format_item : stylesheet.format_impls)
1550 : : {
1551 : 183 : auto ¤t_format_impl = *current_format_item;
1552 : :
1553 [ + + ]: 183 : write_start_element(xmlns, "xf");
1554 : :
1555 [ + + ]: 183 : if (current_format_impl.number_format_id.is_set())
1556 : : {
1557 [ + + + ]: 531 : write_attribute("numFmtId", current_format_impl.number_format_id.get());
1558 : : }
1559 : :
1560 [ + + ]: 183 : if (current_format_impl.font_id.is_set())
1561 : : {
1562 [ + + + ]: 534 : write_attribute("fontId", current_format_impl.font_id.get());
1563 : : }
1564 : :
1565 [ + + ]: 183 : if (current_format_impl.fill_id.is_set())
1566 : : {
1567 [ + + + ]: 501 : write_attribute("fillId", current_format_impl.fill_id.get());
1568 : : }
1569 : :
1570 [ + + ]: 183 : if (current_format_impl.border_id.is_set())
1571 : : {
1572 [ + + + ]: 510 : write_attribute("borderId", current_format_impl.border_id.get());
1573 : : }
1574 : :
1575 [ + + ]: 183 : if (current_format_impl.style.is_set())
1576 : : {
1577 [ + + + + ]: 531 : write_attribute("xfId", stylesheet.style_index(current_format_impl.style.get()));
1578 : : }
1579 : :
1580 : 183 : if (current_format_impl.number_format_id.is_set()
1581 [ + + + + : 183 : && current_format_impl.number_format_applied.is_set())
+ + ]
1582 : : {
1583 [ + + ]: 15 : write_attribute("applyNumberFormat",
1584 [ + + ]: 30 : write_bool(current_format_impl.number_format_applied.get()));
1585 : : }
1586 : :
1587 : 183 : if (current_format_impl.fill_id.is_set()
1588 [ + + + + : 183 : && current_format_impl.fill_applied.is_set())
+ + ]
1589 : : {
1590 [ + + ]: 5 : write_attribute("applyFill",
1591 [ + + ]: 10 : write_bool(current_format_impl.fill_applied.get()));
1592 : : }
1593 : :
1594 : 183 : if (current_format_impl.font_id.is_set()
1595 [ + + + + : 183 : && current_format_impl.font_applied.is_set())
+ + ]
1596 : : {
1597 [ + + ]: 91 : write_attribute("applyFont",
1598 [ + + ]: 182 : write_bool(current_format_impl.font_applied.get()));
1599 : : }
1600 : :
1601 : 183 : if (current_format_impl.border_id.is_set()
1602 [ + + + + : 183 : && current_format_impl.border_applied.is_set())
+ + ]
1603 : : {
1604 [ + + ]: 9 : write_attribute("applyBorder",
1605 [ + + ]: 18 : write_bool(current_format_impl.border_applied.get()));
1606 : : }
1607 : :
1608 [ + + ]: 183 : if (current_format_impl.alignment_applied.is_set())
1609 : : {
1610 [ + + ]: 58 : write_attribute("applyAlignment",
1611 [ + + ]: 116 : write_bool(current_format_impl.alignment_applied.get()));
1612 : : }
1613 : :
1614 [ + + ]: 183 : if (current_format_impl.protection_applied.is_set())
1615 : : {
1616 [ + + ]: 12 : write_attribute("applyProtection",
1617 [ + + ]: 24 : write_bool(current_format_impl.protection_applied.get()));
1618 : : }
1619 : :
1620 [ - + ]: 183 : if (current_format_impl.pivot_button_)
1621 : : {
1622 [ # # # ]:UBC 0 : write_attribute("pivotButton", write_bool(true));
1623 : : }
1624 : :
1625 [ - + ]:CBC 183 : if (current_format_impl.quote_prefix_)
1626 : : {
1627 [ # # # ]:UBC 0 : write_attribute("quotePrefix", write_bool(true));
1628 : : }
1629 : :
1630 [ + + ]:CBC 183 : if (current_format_impl.alignment_id.is_set())
1631 : : {
1632 [ + ]: 58 : const auto ¤t_alignment = stylesheet.alignments[current_format_impl.alignment_id.get()];
1633 : :
1634 [ + + ]: 58 : write_start_element(xmlns, "alignment");
1635 : :
1636 [ + + + ]: 58 : if (current_alignment.horizontal().is_set())
1637 : : {
1638 [ + + + + ]: 69 : write_attribute("horizontal", current_alignment.horizontal().get());
1639 : : }
1640 : :
1641 [ + + + ]: 58 : if (current_alignment.vertical().is_set())
1642 : : {
1643 [ + + + + ]: 87 : write_attribute("vertical", current_alignment.vertical().get());
1644 : : }
1645 : :
1646 [ + + + ]: 58 : if (current_alignment.rotation().is_set())
1647 : : {
1648 [ + + + + ]: 15 : write_attribute("textRotation", current_alignment.rotation().get());
1649 : : }
1650 : :
1651 [ + + + ]: 58 : if (current_alignment.wrap())
1652 : : {
1653 [ + + + + ]: 54 : write_attribute("wrapText", write_bool(current_alignment.wrap()));
1654 : : }
1655 : :
1656 [ + + + ]: 58 : if (current_alignment.indent().is_set())
1657 : : {
1658 [ + + + + ]: 27 : write_attribute("indent", current_alignment.indent().get());
1659 : : }
1660 : :
1661 [ + + + ]: 58 : if (current_alignment.shrink())
1662 : : {
1663 [ + + + + ]: 24 : write_attribute("shrinkToFit", write_bool(current_alignment.shrink()));
1664 : : }
1665 : :
1666 [ + + ]: 116 : write_end_element(xmlns, "alignment");
1667 : : }
1668 : :
1669 [ + + ]: 183 : if (current_format_impl.protection_id.is_set())
1670 : : {
1671 [ + ]: 1 : const auto ¤t_protection = stylesheet.protections[current_format_impl.protection_id.get()];
1672 : :
1673 [ + + ]: 1 : write_start_element(xmlns, "protection");
1674 [ + + + + ]: 3 : write_attribute("locked", write_bool(current_protection.locked()));
1675 [ + + + + ]: 3 : write_attribute("hidden", write_bool(current_protection.hidden()));
1676 [ + + ]: 2 : write_end_element(xmlns, "protection");
1677 : : }
1678 : :
1679 [ + + ]: 366 : write_end_element(xmlns, "xf");
1680 : : }
1681 : :
1682 [ + + ]: 42 : write_end_element(xmlns, "cellXfs");
1683 : :
1684 : : // Styles
1685 [ + - ]: 42 : if (stylesheet.style_impls.size() > 0)
1686 : : {
1687 [ + + ]: 42 : write_start_element(xmlns, "cellStyles");
1688 [ + + ]: 84 : write_attribute("count", stylesheet.style_impls.size());
1689 : 42 : std::size_t style_index = 0;
1690 : :
1691 [ + + ]: 258 : for (auto ¤t_style_name : stylesheet.style_names)
1692 : : {
1693 [ + ]: 216 : const auto ¤t_style = stylesheet.style_impls.at(current_style_name);
1694 : :
1695 [ + + ]: 216 : write_start_element(xmlns, "cellStyle");
1696 : :
1697 [ + + + ]: 648 : write_attribute("name", current_style.name);
1698 [ + + ]: 432 : write_attribute("xfId", style_index++);
1699 : :
1700 [ + - ]: 216 : if (current_style.builtin_id.is_set())
1701 : : {
1702 [ + + + ]: 648 : write_attribute("builtinId", current_style.builtin_id.get());
1703 : : }
1704 : :
1705 [ - + ]: 216 : if (current_style.hidden_style)
1706 : : {
1707 [ # # # ]:UBC 0 : write_attribute("hidden", write_bool(true));
1708 : : }
1709 : :
1710 [ + - + + :CBC 216 : if (current_style.builtin_id.is_set() && current_style.custom_builtin)
+ + ]
1711 : : {
1712 [ + + + ]: 492 : write_attribute("customBuiltin", write_bool(current_style.custom_builtin));
1713 : : }
1714 : :
1715 [ + + ]: 432 : write_end_element(xmlns, "cellStyle");
1716 : : }
1717 : :
1718 [ + + ]: 84 : write_end_element(xmlns, "cellStyles");
1719 : : }
1720 : :
1721 : : // Conditional Formats
1722 [ + + ]: 42 : write_start_element(xmlns, "dxfs");
1723 [ + + ]: 84 : write_attribute("count", stylesheet.conditional_format_impls.size());
1724 : :
1725 [ - + ]: 42 : for (auto &rule : stylesheet.conditional_format_impls)
1726 : : {
1727 [ # # ]:UBC 0 : write_start_element(xmlns, "dxf");
1728 : :
1729 [ # # ]: 0 : if (rule.border_id.is_set())
1730 : : {
1731 [ # # ]: 0 : const auto ¤t_border = stylesheet.borders.at(rule.border_id.get());
1732 [ # ]: 0 : write_border(current_border);
1733 : : }
1734 : :
1735 [ # # ]: 0 : if (rule.fill_id.is_set())
1736 : : {
1737 [ # # ]: 0 : const auto ¤t_fill = stylesheet.fills.at(rule.fill_id.get());
1738 [ # ]: 0 : write_fill(current_fill);
1739 : : }
1740 : :
1741 [ # # ]: 0 : if (rule.font_id.is_set())
1742 : : {
1743 [ # # ]: 0 : const auto ¤t_font = stylesheet.fonts.at(rule.font_id.get());
1744 [ # ]: 0 : write_font(current_font);
1745 : : }
1746 : :
1747 [ # # ]: 0 : write_end_element(xmlns, "dxf");
1748 : : }
1749 : :
1750 [ + + ]:CBC 84 : write_end_element(xmlns, "dxfs");
1751 : :
1752 [ + + ]: 84 : write_start_element(xmlns, "tableStyles");
1753 [ + + ]: 84 : write_attribute("count", "0");
1754 [ + + ]: 84 : write_attribute("defaultTableStyle", "TableStyleMedium9");
1755 [ + + ]: 84 : write_attribute("defaultPivotStyle", "PivotStyleMedium7");
1756 [ + + ]: 42 : write_end_element(xmlns, "tableStyles");
1757 : :
1758 [ + + ]: 42 : if (!stylesheet.colors.empty())
1759 : : {
1760 [ + + ]: 2 : write_start_element(xmlns, "colors");
1761 [ + + ]: 1 : write_start_element(xmlns, "indexedColors");
1762 : :
1763 [ + + ]: 14 : for (auto &c : stylesheet.colors)
1764 : : {
1765 [ + + ]: 13 : write_start_element(xmlns, "rgbColor");
1766 [ + + + + ]: 39 : write_attribute("rgb", c.rgb().hex_string());
1767 [ + + ]: 26 : write_end_element(xmlns, "rgbColor");
1768 : : }
1769 : :
1770 [ + + ]: 2 : write_end_element(xmlns, "indexedColors");
1771 [ + + ]: 2 : write_end_element(xmlns, "colors");
1772 : : }
1773 : :
1774 : 42 : auto using_extensions = stylesheet.default_slicer_style.is_set();
1775 : :
1776 [ + + ]: 42 : if (using_extensions)
1777 : : {
1778 [ + + ]: 26 : write_start_element(xmlns, "extLst");
1779 : :
1780 [ + - ]: 26 : if (stylesheet.default_slicer_style.is_set())
1781 : : {
1782 [ + + ]: 52 : write_start_element(xmlns, "ext");
1783 [ + + ]: 52 : write_namespace(xmlns_x14, "x14");
1784 [ + + ]: 52 : write_attribute("uri", "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}"); // slicerStyles URI
1785 [ + + ]: 26 : write_start_element(xmlns_x14, "slicerStyles");
1786 [ + + + + ]: 78 : write_attribute("defaultSlicerStyle", stylesheet.default_slicer_style.get());
1787 [ + + ]: 52 : write_end_element(xmlns_x14, "slicerStyles");
1788 [ + + ]: 52 : write_end_element(xmlns, "ext");
1789 : : }
1790 : :
1791 [ + + ]: 52 : write_end_element(xmlns, "extLst");
1792 : : }
1793 : :
1794 [ + + ]: 42 : write_end_element(xmlns, "styleSheet");
1795 : 42 : }
1796 : :
1797 : 41 : void xlsx_producer::write_theme(const relationship &theme_rel)
1798 : : {
1799 [ + + + - : 43 : static const auto &xmlns_a = constants::ns("drawingml");
+ + - - ]
1800 [ + + + - : 43 : static const auto &xmlns_thm15 = constants::ns("thm15");
+ + - - ]
1801 : :
1802 [ + + ]: 82 : write_start_element(xmlns_a, "theme");
1803 [ + + ]: 82 : write_namespace(xmlns_a, "a");
1804 [ + + ]: 82 : write_attribute("name", "Office Theme");
1805 : :
1806 [ + + ]: 82 : write_start_element(xmlns_a, "themeElements");
1807 [ + + ]: 82 : write_start_element(xmlns_a, "clrScheme");
1808 [ + + ]: 41 : write_attribute("name", "Office");
1809 : :
1810 : : struct scheme_element
1811 : : {
1812 : : std::string name;
1813 : : std::string sub_element_name;
1814 : : std::string val;
1815 : : };
1816 : :
1817 : : std::vector<scheme_element> scheme_elements = {
1818 :UBC 0 : {"dk1", "sysClr", "windowText"},
1819 : : {"lt1", "sysClr", "window"},
1820 : : {"dk2", "srgbClr", "44546A"},
1821 : : {"lt2", "srgbClr", "E7E6E6"},
1822 : : {"accent1", "srgbClr", "5B9BD5"},
1823 : : {"accent2", "srgbClr", "ED7D31"},
1824 : : {"accent3", "srgbClr", "A5A5A5"},
1825 : : {"accent4", "srgbClr", "FFC000"},
1826 : : {"accent5", "srgbClr", "4472C4"},
1827 : : {"accent6", "srgbClr", "70AD47"},
1828 : : {"hlink", "srgbClr", "0563C1"},
1829 : : {"folHlink", "srgbClr", "954F72"},
1830 [ + + + - :CBC 574 : };
- ]
1831 : :
1832 [ + + + ]: 533 : for (auto element : scheme_elements)
1833 : : {
1834 [ + ]: 492 : write_start_element(xmlns_a, element.name);
1835 [ + ]: 492 : write_start_element(xmlns_a, element.sub_element_name);
1836 [ + + + ]: 1476 : write_attribute("val", element.val);
1837 : :
1838 [ + + + ]: 492 : if (element.name == "dk1")
1839 : : {
1840 [ + + ]: 82 : write_attribute("lastClr", "000000");
1841 : : }
1842 [ + + + ]: 451 : else if (element.name == "lt1")
1843 : : {
1844 [ + + ]: 82 : write_attribute("lastClr", "FFFFFF");
1845 : : }
1846 : :
1847 [ + ]: 492 : write_end_element(xmlns_a, element.sub_element_name);
1848 [ + ]: 492 : write_end_element(xmlns_a, element.name);
1849 : 492 : }
1850 : :
1851 [ + + ]: 41 : write_end_element(xmlns_a, "clrScheme");
1852 : :
1853 : : struct font_scheme
1854 : : {
1855 : : bool typeface;
1856 : : std::string script;
1857 : : std::string major;
1858 : : std::string minor;
1859 : : };
1860 : :
1861 :UBC 0 : static const auto font_schemes = std::vector<font_scheme>{{true, "latin", "Calibri Light", "Calibri"},
1862 : : {true, "ea", "", ""}, {true, "cs", "", ""}, {false, "Jpan", "Yu Gothic Light", "Yu Gothic"},
1863 : : {false, "Hang", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95",
1864 : : "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95"},
1865 : : {false, "Hans", "DengXian Light", "DengXian"},
1866 : : {false, "Hant", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94",
1867 : : "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94"},
1868 : : {false, "Arab", "Times New Roman", "Arial"}, {false, "Hebr", "Times New Roman", "Arial"},
1869 : : {false, "Thai", "Tahoma", "Tahoma"}, {false, "Ethi", "Nyala", "Nyala"}, {false, "Beng", "Vrinda", "Vrinda"},
1870 : : {false, "Gujr", "Shruti", "Shruti"}, {false, "Khmr", "MoolBoran", "DaunPenh"},
1871 : : {false, "Knda", "Tunga", "Tunga"}, {false, "Guru", "Raavi", "Raavi"}, {false, "Cans", "Euphemia", "Euphemia"},
1872 : : {false, "Cher", "Plantagenet Cherokee", "Plantagenet Cherokee"},
1873 : : {false, "Yiii", "Microsoft Yi Baiti", "Microsoft Yi Baiti"},
1874 : : {false, "Tibt", "Microsoft Himalaya", "Microsoft Himalaya"}, {false, "Thaa", "MV Boli", "MV Boli"},
1875 : : {false, "Deva", "Mangal", "Mangal"}, {false, "Telu", "Gautami", "Gautami"}, {false, "Taml", "Latha", "Latha"},
1876 : : {false, "Syrc", "Estrangelo Edessa", "Estrangelo Edessa"}, {false, "Orya", "Kalinga", "Kalinga"},
1877 : : {false, "Mlym", "Kartika", "Kartika"}, {false, "Laoo", "DokChampa", "DokChampa"},
1878 : : {false, "Sinh", "Iskoola Pota", "Iskoola Pota"}, {false, "Mong", "Mongolian Baiti", "Mongolian Baiti"},
1879 : : {false, "Viet", "Times New Roman", "Arial"}, {false, "Uigh", "Microsoft Uighur", "Microsoft Uighur"},
1880 [ + + + - :CBC 77 : {false, "Geor", "Sylfaen", "Sylfaen"}};
+ + + - -
- - ]
1881 : :
1882 [ + + ]: 82 : write_start_element(xmlns_a, "fontScheme");
1883 [ + + ]: 41 : write_attribute("name", "Office");
1884 : :
1885 [ + + ]: 123 : for (auto major : {true, false})
1886 : : {
1887 [ + + + + ]: 82 : write_start_element(xmlns_a, major ? "majorFont" : "minorFont");
1888 : :
1889 [ + + ]: 2788 : for (const auto &scheme : font_schemes)
1890 : : {
1891 [ + + + ]: 2706 : const auto scheme_value = major ? scheme.major : scheme.minor;
1892 : :
1893 [ + + ]: 2706 : if (scheme.typeface)
1894 : : {
1895 [ + ]: 246 : write_start_element(xmlns_a, scheme.script);
1896 [ + + + ]: 738 : write_attribute("typeface", scheme_value);
1897 : :
1898 [ + + + ]: 246 : if (scheme_value == "Calibri Light")
1899 : : {
1900 [ + + ]: 82 : write_attribute("panose", "020F0302020204030204");
1901 : : }
1902 [ + + + ]: 205 : else if (scheme_value == "Calibri")
1903 : : {
1904 [ + + ]: 82 : write_attribute("panose", "020F0502020204030204");
1905 : : }
1906 : :
1907 [ + ]: 246 : write_end_element(xmlns_a, scheme.script);
1908 : : }
1909 : : else
1910 : : {
1911 [ + + ]: 2460 : write_start_element(xmlns_a, "font");
1912 [ + + + ]: 7380 : write_attribute("script", scheme.script);
1913 [ + + + ]: 7380 : write_attribute("typeface", scheme_value);
1914 [ + + ]: 4920 : write_end_element(xmlns_a, "font");
1915 : : }
1916 : 2706 : }
1917 : :
1918 [ + + + + ]: 164 : write_end_element(xmlns_a, major ? "majorFont" : "minorFont");
1919 : : }
1920 : :
1921 [ + + ]: 82 : write_end_element(xmlns_a, "fontScheme");
1922 : :
1923 [ + + ]: 82 : write_start_element(xmlns_a, "fmtScheme");
1924 [ + + ]: 82 : write_attribute("name", "Office");
1925 : :
1926 [ + + ]: 82 : write_start_element(xmlns_a, "fillStyleLst");
1927 [ + + ]: 82 : write_start_element(xmlns_a, "solidFill");
1928 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
1929 [ + + ]: 82 : write_attribute("val", "phClr");
1930 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
1931 [ + + ]: 82 : write_end_element(xmlns_a, "solidFill");
1932 : :
1933 [ + + ]: 82 : write_start_element(xmlns_a, "gradFill");
1934 [ + + ]: 82 : write_attribute("rotWithShape", "1");
1935 [ + + ]: 82 : write_start_element(xmlns_a, "gsLst");
1936 : :
1937 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
1938 [ + + ]: 82 : write_attribute("pos", "0");
1939 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
1940 [ + + ]: 82 : write_attribute("val", "phClr");
1941 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
1942 [ + + ]: 82 : write_attribute("val", "110000");
1943 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
1944 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
1945 [ + + ]: 82 : write_attribute("val", "105000");
1946 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
1947 [ + + ]: 82 : write_start_element(xmlns_a, "tint");
1948 [ + + ]: 82 : write_attribute("val", "67000");
1949 [ + + ]: 82 : write_end_element(xmlns_a, "tint");
1950 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
1951 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
1952 : :
1953 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
1954 [ + + ]: 82 : write_attribute("pos", "50000");
1955 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
1956 [ + + ]: 82 : write_attribute("val", "phClr");
1957 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
1958 [ + + ]: 82 : write_attribute("val", "105000");
1959 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
1960 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
1961 [ + + ]: 82 : write_attribute("val", "103000");
1962 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
1963 [ + + ]: 82 : write_start_element(xmlns_a, "tint");
1964 [ + + ]: 82 : write_attribute("val", "73000");
1965 [ + + ]: 82 : write_end_element(xmlns_a, "tint");
1966 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
1967 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
1968 : :
1969 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
1970 [ + + ]: 82 : write_attribute("pos", "100000");
1971 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
1972 [ + + ]: 82 : write_attribute("val", "phClr");
1973 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
1974 [ + + ]: 82 : write_attribute("val", "105000");
1975 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
1976 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
1977 [ + + ]: 82 : write_attribute("val", "109000");
1978 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
1979 [ + + ]: 82 : write_start_element(xmlns_a, "tint");
1980 [ + + ]: 82 : write_attribute("val", "81000");
1981 [ + + ]: 82 : write_end_element(xmlns_a, "tint");
1982 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
1983 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
1984 : :
1985 [ + + ]: 82 : write_end_element(xmlns_a, "gsLst");
1986 : :
1987 [ + + ]: 82 : write_start_element(xmlns_a, "lin");
1988 [ + + ]: 82 : write_attribute("ang", "5400000");
1989 [ + + ]: 82 : write_attribute("scaled", "0");
1990 [ + + ]: 82 : write_end_element(xmlns_a, "lin");
1991 : :
1992 [ + + ]: 82 : write_end_element(xmlns_a, "gradFill");
1993 : :
1994 [ + + ]: 82 : write_start_element(xmlns_a, "gradFill");
1995 [ + + ]: 82 : write_attribute("rotWithShape", "1");
1996 [ + + ]: 82 : write_start_element(xmlns_a, "gsLst");
1997 : :
1998 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
1999 [ + + ]: 82 : write_attribute("pos", "0");
2000 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2001 [ + + ]: 82 : write_attribute("val", "phClr");
2002 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
2003 [ + + ]: 82 : write_attribute("val", "103000");
2004 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
2005 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
2006 [ + + ]: 82 : write_attribute("val", "102000");
2007 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
2008 [ + + ]: 82 : write_start_element(xmlns_a, "tint");
2009 [ + + ]: 82 : write_attribute("val", "94000");
2010 [ + + ]: 82 : write_end_element(xmlns_a, "tint");
2011 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2012 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
2013 : :
2014 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
2015 [ + + ]: 82 : write_attribute("pos", "50000");
2016 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2017 [ + + ]: 82 : write_attribute("val", "phClr");
2018 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
2019 [ + + ]: 82 : write_attribute("val", "110000");
2020 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
2021 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
2022 [ + + ]: 82 : write_attribute("val", "100000");
2023 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
2024 [ + + ]: 82 : write_start_element(xmlns_a, "shade");
2025 [ + + ]: 82 : write_attribute("val", "100000");
2026 [ + + ]: 82 : write_end_element(xmlns_a, "shade");
2027 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2028 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
2029 : :
2030 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
2031 [ + + ]: 82 : write_attribute("pos", "100000");
2032 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2033 [ + + ]: 82 : write_attribute("val", "phClr");
2034 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
2035 [ + + ]: 82 : write_attribute("val", "99000");
2036 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
2037 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
2038 [ + + ]: 82 : write_attribute("val", "120000");
2039 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
2040 [ + + ]: 82 : write_start_element(xmlns_a, "shade");
2041 [ + + ]: 82 : write_attribute("val", "78000");
2042 [ + + ]: 82 : write_end_element(xmlns_a, "shade");
2043 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2044 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
2045 : :
2046 [ + + ]: 82 : write_end_element(xmlns_a, "gsLst");
2047 : :
2048 [ + + ]: 82 : write_start_element(xmlns_a, "lin");
2049 [ + + ]: 82 : write_attribute("ang", "5400000");
2050 [ + + ]: 82 : write_attribute("scaled", "0");
2051 [ + + ]: 82 : write_end_element(xmlns_a, "lin");
2052 : :
2053 [ + + ]: 82 : write_end_element(xmlns_a, "gradFill");
2054 [ + + ]: 82 : write_end_element(xmlns_a, "fillStyleLst");
2055 : :
2056 [ + + ]: 82 : write_start_element(xmlns_a, "lnStyleLst");
2057 : :
2058 [ + + ]: 82 : write_start_element(xmlns_a, "ln");
2059 [ + + ]: 82 : write_attribute("w", "6350");
2060 [ + + ]: 82 : write_attribute("cap", "flat");
2061 [ + + ]: 82 : write_attribute("cmpd", "sng");
2062 [ + + ]: 82 : write_attribute("algn", "ctr");
2063 [ + + ]: 82 : write_start_element(xmlns_a, "solidFill");
2064 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2065 [ + + ]: 82 : write_attribute("val", "phClr");
2066 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2067 [ + + ]: 82 : write_end_element(xmlns_a, "solidFill");
2068 [ + + ]: 82 : write_start_element(xmlns_a, "prstDash");
2069 [ + + ]: 82 : write_attribute("val", "solid");
2070 [ + + ]: 82 : write_end_element(xmlns_a, "prstDash");
2071 [ + + ]: 82 : write_start_element(xmlns_a, "miter");
2072 [ + + ]: 82 : write_attribute("lim", "800000");
2073 [ + + ]: 82 : write_end_element(xmlns_a, "miter");
2074 [ + + ]: 82 : write_end_element(xmlns_a, "ln");
2075 : :
2076 [ + + ]: 82 : write_start_element(xmlns_a, "ln");
2077 [ + + ]: 82 : write_attribute("w", "12700");
2078 [ + + ]: 82 : write_attribute("cap", "flat");
2079 [ + + ]: 82 : write_attribute("cmpd", "sng");
2080 [ + + ]: 82 : write_attribute("algn", "ctr");
2081 [ + + ]: 82 : write_start_element(xmlns_a, "solidFill");
2082 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2083 [ + + ]: 82 : write_attribute("val", "phClr");
2084 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2085 [ + + ]: 82 : write_end_element(xmlns_a, "solidFill");
2086 [ + + ]: 82 : write_start_element(xmlns_a, "prstDash");
2087 [ + + ]: 82 : write_attribute("val", "solid");
2088 [ + + ]: 82 : write_end_element(xmlns_a, "prstDash");
2089 [ + + ]: 82 : write_start_element(xmlns_a, "miter");
2090 [ + + ]: 82 : write_attribute("lim", "800000");
2091 [ + + ]: 82 : write_end_element(xmlns_a, "miter");
2092 [ + + ]: 82 : write_end_element(xmlns_a, "ln");
2093 : :
2094 [ + + ]: 82 : write_start_element(xmlns_a, "ln");
2095 [ + + ]: 82 : write_attribute("w", "19050");
2096 [ + + ]: 82 : write_attribute("cap", "flat");
2097 [ + + ]: 82 : write_attribute("cmpd", "sng");
2098 [ + + ]: 82 : write_attribute("algn", "ctr");
2099 [ + + ]: 82 : write_start_element(xmlns_a, "solidFill");
2100 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2101 [ + + ]: 82 : write_attribute("val", "phClr");
2102 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2103 [ + + ]: 82 : write_end_element(xmlns_a, "solidFill");
2104 [ + + ]: 82 : write_start_element(xmlns_a, "prstDash");
2105 [ + + ]: 82 : write_attribute("val", "solid");
2106 [ + + ]: 82 : write_end_element(xmlns_a, "prstDash");
2107 [ + + ]: 82 : write_start_element(xmlns_a, "miter");
2108 [ + + ]: 82 : write_attribute("lim", "800000");
2109 [ + + ]: 82 : write_end_element(xmlns_a, "miter");
2110 [ + + ]: 82 : write_end_element(xmlns_a, "ln");
2111 : :
2112 [ + + ]: 82 : write_end_element(xmlns_a, "lnStyleLst");
2113 : :
2114 [ + + ]: 82 : write_start_element(xmlns_a, "effectStyleLst");
2115 : :
2116 [ + + ]: 82 : write_start_element(xmlns_a, "effectStyle");
2117 [ + + ]: 82 : write_element(xmlns_a, "effectLst", "");
2118 [ + + ]: 82 : write_end_element(xmlns_a, "effectStyle");
2119 : :
2120 [ + + ]: 82 : write_start_element(xmlns_a, "effectStyle");
2121 [ + + ]: 82 : write_element(xmlns_a, "effectLst", "");
2122 [ + + ]: 82 : write_end_element(xmlns_a, "effectStyle");
2123 : :
2124 [ + + ]: 82 : write_start_element(xmlns_a, "effectStyle");
2125 [ + + ]: 82 : write_start_element(xmlns_a, "effectLst");
2126 [ + + ]: 82 : write_start_element(xmlns_a, "outerShdw");
2127 [ + + ]: 82 : write_attribute("blurRad", "57150");
2128 [ + + ]: 82 : write_attribute("dist", "19050");
2129 [ + + ]: 82 : write_attribute("dir", "5400000");
2130 [ + + ]: 82 : write_attribute("algn", "ctr");
2131 [ + + ]: 82 : write_attribute("rotWithShape", "0");
2132 [ + + ]: 82 : write_start_element(xmlns_a, "srgbClr");
2133 [ + + ]: 82 : write_attribute("val", "000000");
2134 [ + + ]: 82 : write_start_element(xmlns_a, "alpha");
2135 [ + + ]: 82 : write_attribute("val", "63000");
2136 [ + + ]: 82 : write_end_element(xmlns_a, "alpha");
2137 [ + + ]: 82 : write_end_element(xmlns_a, "srgbClr");
2138 [ + + ]: 82 : write_end_element(xmlns_a, "outerShdw");
2139 [ + + ]: 82 : write_end_element(xmlns_a, "effectLst");
2140 [ + + ]: 82 : write_end_element(xmlns_a, "effectStyle");
2141 : :
2142 [ + + ]: 82 : write_end_element(xmlns_a, "effectStyleLst");
2143 : :
2144 [ + + ]: 82 : write_start_element(xmlns_a, "bgFillStyleLst");
2145 : :
2146 [ + + ]: 82 : write_start_element(xmlns_a, "solidFill");
2147 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2148 [ + + ]: 82 : write_attribute("val", "phClr");
2149 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2150 [ + + ]: 82 : write_end_element(xmlns_a, "solidFill");
2151 : :
2152 [ + + ]: 82 : write_start_element(xmlns_a, "solidFill");
2153 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2154 [ + + ]: 82 : write_attribute("val", "phClr");
2155 [ + + ]: 82 : write_start_element(xmlns_a, "tint");
2156 [ + + ]: 82 : write_attribute("val", "95000");
2157 [ + + ]: 82 : write_end_element(xmlns_a, "tint");
2158 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
2159 [ + + ]: 82 : write_attribute("val", "170000");
2160 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
2161 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2162 [ + + ]: 82 : write_end_element(xmlns_a, "solidFill");
2163 : :
2164 [ + + ]: 82 : write_start_element(xmlns_a, "gradFill");
2165 [ + + ]: 82 : write_attribute("rotWithShape", "1");
2166 [ + + ]: 82 : write_start_element(xmlns_a, "gsLst");
2167 : :
2168 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
2169 [ + + ]: 82 : write_attribute("pos", "0");
2170 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2171 [ + + ]: 82 : write_attribute("val", "phClr");
2172 [ + + ]: 82 : write_start_element(xmlns_a, "tint");
2173 [ + + ]: 82 : write_attribute("val", "93000");
2174 [ + + ]: 82 : write_end_element(xmlns_a, "tint");
2175 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
2176 [ + + ]: 82 : write_attribute("val", "150000");
2177 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
2178 [ + + ]: 82 : write_start_element(xmlns_a, "shade");
2179 [ + + ]: 82 : write_attribute("val", "98000");
2180 [ + + ]: 82 : write_end_element(xmlns_a, "shade");
2181 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
2182 [ + + ]: 82 : write_attribute("val", "102000");
2183 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
2184 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2185 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
2186 : :
2187 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
2188 [ + + ]: 82 : write_attribute("pos", "50000");
2189 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2190 [ + + ]: 82 : write_attribute("val", "phClr");
2191 [ + + ]: 82 : write_start_element(xmlns_a, "tint");
2192 [ + + ]: 82 : write_attribute("val", "98000");
2193 [ + + ]: 82 : write_end_element(xmlns_a, "tint");
2194 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
2195 [ + + ]: 82 : write_attribute("val", "130000");
2196 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
2197 [ + + ]: 82 : write_start_element(xmlns_a, "shade");
2198 [ + + ]: 82 : write_attribute("val", "90000");
2199 [ + + ]: 82 : write_end_element(xmlns_a, "shade");
2200 [ + + ]: 82 : write_start_element(xmlns_a, "lumMod");
2201 [ + + ]: 82 : write_attribute("val", "103000");
2202 [ + + ]: 82 : write_end_element(xmlns_a, "lumMod");
2203 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2204 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
2205 : :
2206 [ + + ]: 82 : write_start_element(xmlns_a, "gs");
2207 [ + + ]: 82 : write_attribute("pos", "100000");
2208 [ + + ]: 82 : write_start_element(xmlns_a, "schemeClr");
2209 [ + + ]: 82 : write_attribute("val", "phClr");
2210 [ + + ]: 82 : write_start_element(xmlns_a, "shade");
2211 [ + + ]: 82 : write_attribute("val", "63000");
2212 [ + + ]: 82 : write_end_element(xmlns_a, "shade");
2213 [ + + ]: 82 : write_start_element(xmlns_a, "satMod");
2214 [ + + ]: 82 : write_attribute("val", "120000");
2215 [ + + ]: 82 : write_end_element(xmlns_a, "satMod");
2216 [ + + ]: 82 : write_end_element(xmlns_a, "schemeClr");
2217 [ + + ]: 82 : write_end_element(xmlns_a, "gs");
2218 : :
2219 [ + + ]: 82 : write_end_element(xmlns_a, "gsLst");
2220 : :
2221 [ + + ]: 82 : write_start_element(xmlns_a, "lin");
2222 [ + + ]: 82 : write_attribute("ang", "5400000");
2223 [ + + ]: 82 : write_attribute("scaled", "0");
2224 [ + + ]: 82 : write_end_element(xmlns_a, "lin");
2225 : :
2226 [ + + ]: 82 : write_end_element(xmlns_a, "gradFill");
2227 : :
2228 [ + + ]: 82 : write_end_element(xmlns_a, "bgFillStyleLst");
2229 [ + + ]: 82 : write_end_element(xmlns_a, "fmtScheme");
2230 [ + + ]: 82 : write_end_element(xmlns_a, "themeElements");
2231 : :
2232 [ + + ]: 82 : write_element(xmlns_a, "objectDefaults", "");
2233 [ + + ]: 82 : write_element(xmlns_a, "extraClrSchemeLst", "");
2234 : :
2235 [ + + ]: 82 : write_start_element(xmlns_a, "extLst");
2236 [ + + ]: 82 : write_start_element(xmlns_a, "ext");
2237 [ + + ]: 82 : write_attribute("uri", "{05A4C25C-085E-4340-85A3-A5531E510DB2}");
2238 [ + + ]: 82 : write_start_element(xmlns_thm15, "themeFamily");
2239 [ + + ]: 82 : write_namespace(xmlns_thm15, "thm15");
2240 [ + + ]: 82 : write_attribute("name", "Office Theme");
2241 [ + + ]: 82 : write_attribute("id", "{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}");
2242 [ + + ]: 82 : write_attribute("vid", "{4A3C46E8-61CC-4603-A589-7422A47A8E4A}");
2243 [ + + ]: 82 : write_end_element(xmlns_thm15, "themeFamily");
2244 [ + + ]: 82 : write_end_element(xmlns_a, "ext");
2245 [ + + ]: 82 : write_end_element(xmlns_a, "extLst");
2246 : :
2247 [ + + ]: 41 : write_end_element(xmlns_a, "theme");
2248 : :
2249 [ + + + + ]: 82 : const auto workbook_rel = source_.manifest().relationship(path("/"), relationship_type::office_document);
2250 [ + + + + : 205 : const auto theme_part = source_.manifest().canonicalize({workbook_rel, theme_rel});
+ - - ]
2251 [ + + ]: 41 : const auto theme_rels = source_.manifest().relationships(theme_part);
2252 : :
2253 [ + + ]: 41 : if (!theme_rels.empty())
2254 : : {
2255 [ + ]: 1 : write_relationships(theme_rels, theme_part);
2256 : :
2257 [ + + + ]: 2 : for (auto rel : theme_rels)
2258 : : {
2259 [ + + - ]: 1 : if (rel.type() == relationship_type::image)
2260 : : {
2261 [ + + + + : 6 : const auto image_path = source_.manifest().canonicalize({workbook_rel, theme_rel, rel});
+ - - ]
2262 [ + ]: 1 : write_image(image_path);
2263 : 1 : }
2264 : 1 : }
2265 : : }
2266 [ + + + + : 167 : }
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - ]
2267 : :
2268 :UBC 0 : void xlsx_producer::write_volatile_dependencies(const relationship & /*rel*/)
2269 : : {
2270 [ # # # # ]: 0 : write_start_element(constants::ns("spreadsheetml"), "volTypes");
2271 [ # # # # ]: 0 : write_end_element(constants::ns("spreadsheetml"), "volTypes");
2272 : 0 : }
2273 : :
2274 :CBC 53 : void xlsx_producer::write_worksheet(const relationship &rel)
2275 : : {
2276 [ + + + - : 55 : static const auto &xmlns = constants::ns("spreadsheetml");
+ + - - ]
2277 [ + + + - : 55 : static const auto &xmlns_r = constants::ns("r");
+ + - - ]
2278 [ + + + - : 55 : static const auto &xmlns_mc = constants::ns("mc");
+ + - - ]
2279 [ + + + - : 55 : static const auto &xmlns_x14ac = constants::ns("x14ac");
+ + - - ]
2280 : :
2281 [ + + + + : 53 : auto worksheet_part = rel.source().path().parent().append(rel.target().path());
+ + ]
2282 [ + + ]: 53 : auto worksheet_rels = source_.manifest().relationships(worksheet_part);
2283 : :
2284 [ + ]: 53 : auto title = std::find_if(source_.d_->sheet_title_rel_id_map_.begin(), source_.d_->sheet_title_rel_id_map_.end(),
2285 : 64 : [&](const std::pair<std::string, std::string> &p) {
2286 : 64 : return p.second == rel.id();
2287 [ + ]: 53 : })->first;
2288 : :
2289 [ + ]: 53 : auto ws = source_.sheet_by_title(title);
2290 : :
2291 [ + + ]: 106 : write_start_element(xmlns, "worksheet");
2292 [ + + ]: 106 : write_namespace(xmlns, "");
2293 [ + + ]: 53 : write_namespace(xmlns_r, "r");
2294 : :
2295 : 53 : auto using_namespace = [&ws](const std::string &ns) {
2296 [ + - ]: 53 : if (ns == "x14ac")
2297 : : {
2298 [ + + + ]: 53 : if (ws.format_properties().dy_descent.is_set())
2299 : : {
2300 : 30 : return true;
2301 : : }
2302 : :
2303 : 23 : auto highest = ws.highest_row();
2304 [ + + ]: 97 : for (auto row = ws.lowest_row(); row <= highest; ++row)
2305 : : {
2306 [ + + - + : 74 : if (ws.has_row_properties(row) && ws.row_properties(row).dy_descent.is_set())
- + ]
2307 : : {
2308 :UBC 0 : return true;
2309 : : }
2310 : : }
2311 : : }
2312 : :
2313 :CBC 23 : return false;
2314 : 53 : };
2315 : :
2316 [ + + + + ]: 106 : if (using_namespace("x14ac"))
2317 : : {
2318 [ + + ]: 60 : write_namespace(xmlns_mc, "mc");
2319 [ + + ]: 60 : write_namespace(xmlns_x14ac, "x14ac");
2320 [ + + + ]: 60 : write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x14ac");
2321 : : }
2322 : :
2323 [ + + ]: 53 : if (ws.d_->sheet_properties_.is_set())
2324 : : {
2325 [ + + ]: 5 : write_start_element(xmlns, "sheetPr");
2326 [ + ]: 5 : auto &props = ws.d_->sheet_properties_.get();
2327 [ - + ]: 5 : if (props.sync_horizontal.is_set())
2328 : : {
2329 [ # # # ]:UBC 0 : write_attribute("syncHorizontal", props.sync_horizontal.get());
2330 : : }
2331 [ - + ]:CBC 5 : if (props.sync_vertical.is_set())
2332 : : {
2333 [ # # # ]:UBC 0 : write_attribute("syncVertical", props.sync_vertical.get());
2334 : : }
2335 [ - + ]:CBC 5 : if (props.sync_ref.is_set())
2336 : : {
2337 [ # # # # ]:UBC 0 : write_attribute("syncRef", props.sync_ref.get().to_string());
2338 : : }
2339 [ - + ]:CBC 5 : if (props.transition_evaluation.is_set())
2340 : : {
2341 [ # # # ]:UBC 0 : write_attribute("transitionEvaluation", props.transition_evaluation.get());
2342 : : }
2343 [ - + ]:CBC 5 : if (props.transition_entry.is_set())
2344 : : {
2345 [ # # # ]:UBC 0 : write_attribute("transitionEntry", props.transition_entry.get());
2346 : : }
2347 [ - + ]:CBC 5 : if (props.published.is_set())
2348 : : {
2349 [ # # # ]:UBC 0 : write_attribute("published", props.published.get());
2350 : : }
2351 [ + + ]:CBC 5 : if (props.code_name.is_set())
2352 : : {
2353 [ + + + + ]: 3 : write_attribute("codeName", props.code_name.get());
2354 : : }
2355 [ + + ]: 5 : if (props.filter_mode.is_set())
2356 : : {
2357 [ + + + ]: 6 : write_attribute("filterMode", props.filter_mode.get());
2358 : : }
2359 [ - + ]: 5 : if (props.enable_format_condition_calculation.is_set())
2360 : : {
2361 [ # # # ]:UBC 0 : write_attribute("enableFormatConditionsCalculation", props.enable_format_condition_calculation.get());
2362 : : }
2363 : : // outlinePr is optional in the spec but is being written every time?
2364 [ + + ]:CBC 10 : write_start_element(xmlns, "outlinePr");
2365 [ + + ]: 10 : write_attribute("summaryBelow", "1");
2366 [ + + ]: 10 : write_attribute("summaryRight", "1");
2367 [ + + ]: 5 : write_end_element(xmlns, "outlinePr");
2368 : :
2369 [ + + + ]: 5 : if (ws.has_page_setup())
2370 : : {
2371 [ + + ]: 4 : write_start_element(xmlns, "pageSetUpPr");
2372 [ + + + + : 12 : write_attribute("fitToPage", write_bool(ws.page_setup().fit_to_page()));
+ ]
2373 [ + + ]: 8 : write_end_element(xmlns, "pageSetUpPr");
2374 : : }
2375 [ + + ]: 10 : write_end_element(xmlns, "sheetPr");
2376 : : }
2377 : :
2378 [ + + ]: 53 : write_start_element(xmlns, "dimension");
2379 [ + ]: 53 : const auto dimension = ws.calculate_dimension();
2380 [ + + + ]: 159 : write_attribute("ref", dimension.to_string());
2381 [ + + ]: 53 : write_end_element(xmlns, "dimension");
2382 : :
2383 [ + + + ]: 53 : if (ws.has_view())
2384 : : {
2385 [ + + ]: 100 : write_start_element(xmlns, "sheetViews");
2386 [ + + ]: 50 : write_start_element(xmlns, "sheetView");
2387 : :
2388 [ + + ]: 50 : const auto view = ws.view();
2389 : :
2390 [ + + ]: 50 : if (!view.show_grid_lines())
2391 : : {
2392 [ + + + ]: 3 : write_attribute("showGridLines", write_bool(view.show_grid_lines()));
2393 : : }
2394 : :
2395 [ + + + ]: 50 : if (source_.has_view())
2396 : : {
2397 [ + ]: 49 : const auto wb_view = source_.view();
2398 : :
2399 [ + + + + ]: 97 : if ((wb_view.active_tab.is_set() && (ws.id() - 1) == wb_view.active_tab.get())
2400 [ + + + + : 97 : || (!wb_view.active_tab.is_set() && ws.id() == 1))
+ + - +
+ ]
2401 : : {
2402 [ + + + ]: 120 : write_attribute("tabSelected", write_bool(true));
2403 : : }
2404 : 49 : }
2405 [ + + - ]: 1 : else if (ws.id() == 1)
2406 : : {
2407 [ + + + ]: 3 : write_attribute("tabSelected", write_bool(true));
2408 : : }
2409 : :
2410 [ + + ]: 50 : if (view.type() != sheet_view_type::normal)
2411 : : {
2412 [ - + + + ]: 6 : write_attribute("view", view.type() == sheet_view_type::page_break_preview ? "pageBreakPreview" : "pageLayout");
2413 : : }
2414 [ + + ]: 50 : if (view.has_top_left_cell())
2415 : : {
2416 [ + + + + ]: 9 : write_attribute("topLeftCell", view.top_left_cell().to_string());
2417 : : }
2418 : :
2419 [ + + ]: 100 : write_attribute("workbookViewId", view.id());
2420 : :
2421 [ + + ]: 50 : if (view.zoom_scale() != 100)
2422 : : {
2423 [ + + ]: 6 : write_attribute("zoomScale", view.zoom_scale());
2424 : : }
2425 : :
2426 [ + + ]: 50 : if (view.has_pane())
2427 : : {
2428 [ + ]: 2 : const auto ¤t_pane = view.pane();
2429 [ + + ]: 2 : write_start_element(xmlns, "pane"); // CT_Pane
2430 : :
2431 [ + - ]: 2 : if (current_pane.top_left_cell.is_set())
2432 : : {
2433 [ + + + + ]: 6 : write_attribute("topLeftCell", current_pane.top_left_cell.get().to_string());
2434 : : }
2435 : :
2436 [ + + + + : 2 : if (current_pane.x_split + 1 == current_pane.top_left_cell.get().column())
+ + - ]
2437 : : {
2438 [ + + ]: 6 : write_attribute("xSplit", current_pane.x_split.index);
2439 : : }
2440 : :
2441 [ + + + - ]: 2 : if (current_pane.y_split + 1 == current_pane.top_left_cell.get().row())
2442 : : {
2443 [ + + ]: 6 : write_attribute("ySplit", current_pane.y_split);
2444 : : }
2445 : :
2446 [ + - ]: 2 : if (current_pane.active_pane != pane_corner::top_left)
2447 : : {
2448 [ + + ]: 6 : write_attribute("activePane", current_pane.active_pane);
2449 : : }
2450 : :
2451 [ + - ]: 2 : if (current_pane.state != pane_state::split)
2452 : : {
2453 [ + + ]: 6 : write_attribute("state", current_pane.state);
2454 : : }
2455 : :
2456 [ + + ]: 4 : write_end_element(xmlns, "pane");
2457 : : }
2458 : :
2459 [ + + + ]: 77 : for (const auto ¤t_selection : view.selections())
2460 : : {
2461 [ + + ]: 27 : write_start_element(xmlns, "selection"); // CT_Selection
2462 : :
2463 [ + + ]: 27 : if (current_selection.has_active_cell())
2464 : : {
2465 [ + + + + ]: 75 : write_attribute("activeCell", current_selection.active_cell().to_string());
2466 : : }
2467 : :
2468 [ + - ]: 27 : if (current_selection.has_sqref())
2469 : : {
2470 [ + ]: 27 : std::string refs = detail::join(current_selection.sqrefs(), ' ');
2471 [ + + + ]: 81 : write_attribute("sqref", refs);
2472 : 27 : }
2473 : :
2474 [ + + ]: 27 : if (current_selection.pane() != pane_corner::top_left)
2475 : : {
2476 [ + + ]: 12 : write_attribute("pane", current_selection.pane());
2477 : : }
2478 : :
2479 [ + + ]: 54 : write_end_element(xmlns, "selection");
2480 : 50 : }
2481 : :
2482 [ + + ]: 100 : write_end_element(xmlns, "sheetView");
2483 [ + + ]: 50 : write_end_element(xmlns, "sheetViews");
2484 : 50 : }
2485 : :
2486 [ + + ]: 53 : write_start_element(xmlns, "sheetFormatPr");
2487 : 53 : const auto &format_properties = ws.d_->format_properties_;
2488 : :
2489 [ + + ]: 53 : if (format_properties.base_col_width.is_set())
2490 : : {
2491 [ + + ]: 86 : write_attribute<double>("baseColWidth",
2492 [ + ]: 43 : format_properties.base_col_width.get());
2493 : : }
2494 [ + + ]: 53 : if (format_properties.default_column_width.is_set())
2495 : : {
2496 [ + + ]: 8 : write_attribute<double>("defaultColWidth",
2497 [ + ]: 4 : format_properties.default_column_width.get());
2498 : : }
2499 : :
2500 [ + + ]: 53 : write_attribute<double>("defaultRowHeight",
2501 : 53 : format_properties.default_row_height);
2502 : :
2503 [ + + ]: 53 : if (format_properties.dy_descent.is_set())
2504 : : {
2505 [ + + + ]: 60 : write_attribute<double>(xml::qname(xmlns_x14ac, "dyDescent"),
2506 [ + ]: 30 : format_properties.dy_descent.get());
2507 : : }
2508 : :
2509 [ + + ]: 53 : write_end_element(xmlns, "sheetFormatPr");
2510 : :
2511 : 53 : bool has_column_properties = false;
2512 [ + ]: 53 : const auto first_column = ws.lowest_column_or_props();
2513 [ + ]: 53 : const auto last_column = ws.highest_column_or_props();
2514 : :
2515 [ + + + + ]: 1488 : for (auto column = first_column; column <= last_column; column++)
2516 : : {
2517 [ + + + ]: 1435 : if (!ws.has_column_properties(column)) continue;
2518 : :
2519 [ + + ]: 1333 : if (!has_column_properties)
2520 : : {
2521 [ + + ]: 15 : write_start_element(xmlns, "cols");
2522 : 15 : has_column_properties = true;
2523 : : }
2524 : :
2525 [ + ]: 1333 : const auto &props = ws.column_properties(column);
2526 : :
2527 [ + + ]: 1333 : write_start_element(xmlns, "col");
2528 [ + + ]: 2666 : write_attribute("min", column.index);
2529 [ + + ]: 2666 : write_attribute("max", column.index);
2530 : :
2531 [ + - ]: 1333 : if (props.width.is_set())
2532 : : {
2533 [ + ]: 1333 : double width = (props.width.get() * 7 + 5) / 7;
2534 [ + + + ]: 3999 : write_attribute("width", xlnt::detail::serialise(width));
2535 : : }
2536 : :
2537 [ + + ]: 1333 : if (props.best_fit)
2538 : : {
2539 [ + + + ]: 15 : write_attribute("bestFit", write_bool(true));
2540 : : }
2541 : :
2542 [ + + ]: 1333 : if (props.style.is_set())
2543 : : {
2544 [ + + + ]: 3849 : write_attribute("style", props.style.get());
2545 : : }
2546 : :
2547 [ + + ]: 1333 : if (props.hidden)
2548 : : {
2549 [ + + + ]: 6 : write_attribute("hidden", write_bool(true));
2550 : : }
2551 : :
2552 [ + + ]: 1333 : if (props.custom_width)
2553 : : {
2554 [ + + + ]: 918 : write_attribute("customWidth", write_bool(true));
2555 : : }
2556 : :
2557 [ + + ]: 2666 : write_end_element(xmlns, "col");
2558 : : }
2559 : :
2560 [ + + ]: 53 : if (has_column_properties)
2561 : : {
2562 [ + + ]: 30 : write_end_element(xmlns, "cols");
2563 : : }
2564 : :
2565 : 53 : std::vector<std::pair<std::string, hyperlink>> hyperlinks;
2566 : 53 : std::vector<cell_reference> cells_with_comments;
2567 : :
2568 [ + + ]: 53 : write_start_element(xmlns, "sheetData");
2569 [ + ]: 53 : auto first_row = ws.lowest_row_or_props();
2570 [ + ]: 53 : auto last_row = ws.highest_row_or_props();
2571 [ + ]: 53 : auto first_block_column = constants::max_column();
2572 [ + ]: 53 : auto last_block_column = constants::min_column();
2573 : :
2574 [ + + ]: 1715 : for (auto row = first_row; row <= last_row; ++row)
2575 : : {
2576 : 1662 : bool any_non_null = false;
2577 : 1662 : auto first_check_row = row;
2578 : 1662 : auto last_check_row = row;
2579 [ + + + + ]: 1662 : auto first_row_in_block = row == first_row || row % 16 == 1;
2580 : :
2581 : : // See note for CT_Row, span attribute about block optimization
2582 [ + + ]: 1662 : if (first_row_in_block)
2583 : : {
2584 : : // reset block column range
2585 [ + ]: 146 : first_block_column = constants::max_column();
2586 [ + ]: 146 : last_block_column = constants::min_column();
2587 : :
2588 : 146 : first_check_row = row;
2589 : : // round up to the next multiple of 16
2590 : 146 : last_check_row = ((row / 16) + 1) * 16;
2591 : : }
2592 : :
2593 [ + + ]: 5514 : for (auto check_row = first_check_row; check_row <= last_check_row; ++check_row)
2594 : : {
2595 [ + + + + : 10408 : for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
+ + + + ]
2596 : : {
2597 [ + ]: 6556 : auto ref = cell_reference(column, check_row);
2598 [ + ]: 6556 : auto cell = ws.d_->cell_map_.find(ref);
2599 [ + + ]: 6556 : if (cell == ws.d_->cell_map_.end())
2600 : : {
2601 : 4779 : continue;
2602 : : }
2603 [ + + ]: 1779 : if (cell->second.is_garbage_collectible())
2604 : : {
2605 : 2 : continue;
2606 : : }
2607 : :
2608 [ + ]: 1777 : first_block_column = std::min(first_block_column, cell->second.column_);
2609 [ + ]: 1777 : last_block_column = std::max(last_block_column, cell->second.column_);
2610 : :
2611 [ + + ]: 1777 : if (row == check_row)
2612 : : {
2613 : 955 : any_non_null = true;
2614 : : }
2615 : : }
2616 : : }
2617 : :
2618 [ + + + + : 1662 : if (!any_non_null && !ws.has_row_properties(row)) continue;
+ + + ]
2619 : :
2620 [ + + ]: 2600 : write_start_element(xmlns, "row");
2621 [ + + ]: 1300 : write_attribute("r", row);
2622 : :
2623 [ + ]: 2600 : auto span_string = std::to_string(first_block_column.index) + ":"
2624 [ + ]: 3900 : + std::to_string(last_block_column.index);
2625 [ + + + ]: 3900 : write_attribute("spans", span_string);
2626 : :
2627 [ + + + ]: 1300 : if (ws.has_row_properties(row))
2628 : : {
2629 [ + ]: 1282 : const auto &props = ws.row_properties(row);
2630 : :
2631 [ + + ]: 1282 : if (props.style.is_set())
2632 : : {
2633 [ + + + ]: 9 : write_attribute("s", props.style.get());
2634 : : }
2635 [ + + ]: 1282 : if (props.custom_format.is_set())
2636 : : {
2637 [ + + + + ]: 12 : write_attribute("customFormat", write_bool(props.custom_format.get()));
2638 : : }
2639 : :
2640 [ + + ]: 1282 : if (props.height.is_set())
2641 : : {
2642 [ + ]: 1070 : auto height = props.height.get();
2643 [ + + + ]: 3210 : write_attribute("ht", xlnt::detail::serialise(height));
2644 : : }
2645 : :
2646 [ + + ]: 1282 : if (props.hidden)
2647 : : {
2648 [ + + + ]: 18 : write_attribute("hidden", write_bool(true));
2649 : : }
2650 : :
2651 [ + + ]: 1282 : if (props.custom_height)
2652 : : {
2653 [ + + + ]: 3114 : write_attribute("customHeight", write_bool(true));
2654 : : }
2655 : :
2656 [ + + ]: 1282 : if (props.dy_descent.is_set())
2657 : : {
2658 [ + + + + ]: 750 : write_attribute<double>(xml::qname(xmlns_x14ac, "dyDescent"), props.dy_descent.get());
2659 : : }
2660 : : }
2661 : :
2662 [ + + ]: 1300 : if (any_non_null)
2663 : : {
2664 [ + + + + : 1399 : for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
+ + + + ]
2665 : : {
2666 [ + + + + ]: 1108 : if (!ws.has_cell(cell_reference(column, row))) continue;
2667 : :
2668 [ + + ]: 956 : auto cell = ws.cell(cell_reference(column, row));
2669 : :
2670 [ + + + ]: 956 : if (cell.garbage_collectible()) continue;
2671 : :
2672 : : // record data about the cell needed later
2673 : :
2674 [ + + + ]: 955 : if (cell.has_comment())
2675 : : {
2676 [ + + ]: 16 : cells_with_comments.push_back(cell.reference());
2677 : : }
2678 : :
2679 [ + + + ]: 955 : if (cell.has_hyperlink())
2680 : : {
2681 [ + + + + ]: 20 : hyperlinks.push_back(std::make_pair(cell.reference().to_string(), cell.hyperlink()));
2682 : : }
2683 : :
2684 [ + + ]: 955 : write_start_element(xmlns, "c");
2685 : :
2686 : : // begin cell attributes
2687 : :
2688 [ + + + + ]: 2865 : write_attribute("r", cell.reference().to_string());
2689 : :
2690 [ + + + ]: 955 : if (cell.phonetics_visible())
2691 : : {
2692 [ + + + ]: 6 : write_attribute("ph", write_bool(true));
2693 : : }
2694 : :
2695 [ + + + ]: 955 : if (cell.has_format())
2696 : : {
2697 [ + + + ]: 987 : write_attribute("s", cell.format().d_->id);
2698 : : }
2699 : :
2700 [ + + + - : 955 : switch (cell.data_type())
- - + + +
- ]
2701 : : {
2702 : 169 : case cell::type::empty:
2703 : 169 : break;
2704 : :
2705 : 2 : case cell::type::boolean:
2706 [ + + ]: 2 : write_attribute("t", "b");
2707 : 2 : break;
2708 : :
2709 :UBC 0 : case cell::type::date:
2710 [ # # ]: 0 : write_attribute("t", "d");
2711 : 0 : break;
2712 : :
2713 : 0 : case cell::type::error:
2714 [ # # ]: 0 : write_attribute("t", "e");
2715 : 0 : break;
2716 : :
2717 : 0 : case cell::type::inline_string:
2718 [ # # ]: 0 : write_attribute("t", "inlineStr");
2719 : 0 : break;
2720 : :
2721 :CBC 46 : case cell::type::number: // default, don't write it
2722 : : //write_attribute("t", "n");
2723 : 46 : break;
2724 : :
2725 : 732 : case cell::type::shared_string:
2726 [ + + ]: 732 : write_attribute("t", "s");
2727 : 732 : break;
2728 : :
2729 : 6 : case cell::type::formula_string:
2730 [ + + ]: 6 : write_attribute("t", "str");
2731 : 6 : break;
2732 : : }
2733 : :
2734 : : //write_attribute("cm", "");
2735 : : //write_attribute("vm", "");
2736 : : //write_attribute("ph", "");
2737 : :
2738 : : // begin child elements
2739 : :
2740 [ + + + ]: 955 : if (cell.has_formula())
2741 : : {
2742 [ + + + ]: 27 : write_element(xmlns, "f", cell.formula());
2743 : : }
2744 : :
2745 [ + + + - : 955 : switch (cell.data_type())
- - + + +
- ]
2746 : : {
2747 : 169 : case cell::type::empty:
2748 : 169 : break;
2749 : :
2750 : 2 : case cell::type::boolean:
2751 [ + + + + ]: 6 : write_element(xmlns, "v", write_bool(cell.value<bool>()));
2752 : 2 : break;
2753 : :
2754 :UBC 0 : case cell::type::date:
2755 [ # # # ]: 0 : write_element(xmlns, "v", cell.value<std::string>());
2756 : 0 : break;
2757 : :
2758 : 0 : case cell::type::error:
2759 [ # # # ]: 0 : write_element(xmlns, "v", cell.value<std::string>());
2760 : 0 : break;
2761 : :
2762 : 0 : case cell::type::inline_string:
2763 [ # # ]: 0 : write_start_element(xmlns, "is");
2764 [ # # ]: 0 : write_rich_text(xmlns, cell.value<xlnt::rich_text>());
2765 [ # # ]: 0 : write_end_element(xmlns, "is");
2766 : 0 : break;
2767 : :
2768 :CBC 46 : case cell::type::number:
2769 [ + + ]: 46 : write_start_element(xmlns, "v");
2770 [ + + + ]: 46 : write_characters(xlnt::detail::serialise(cell.value<double>()));
2771 [ + + ]: 46 : write_end_element(xmlns, "v");
2772 : 46 : break;
2773 : :
2774 : 732 : case cell::type::shared_string:
2775 [ + + ]: 1464 : write_element(xmlns, "v", static_cast<std::size_t>(cell.d_->value_numeric_));
2776 : 732 : break;
2777 : :
2778 : 6 : case cell::type::formula_string:
2779 [ + + + ]: 18 : write_element(xmlns, "v", cell.value<std::string>());
2780 : 6 : break;
2781 : : }
2782 : :
2783 [ + + ]: 1910 : write_end_element(xmlns, "c");
2784 : : }
2785 : : }
2786 : :
2787 [ + + ]: 1300 : write_end_element(xmlns, "row");
2788 : 1300 : }
2789 : :
2790 [ + + ]: 53 : write_end_element(xmlns, "sheetData");
2791 : :
2792 [ + + + ]: 53 : if (ws.has_auto_filter())
2793 : : {
2794 [ + + ]: 1 : write_start_element(xmlns, "autoFilter");
2795 [ + + + + ]: 3 : write_attribute("ref", ws.auto_filter().to_string());
2796 [ + + ]: 2 : write_end_element(xmlns, "autoFilter");
2797 : : }
2798 : :
2799 [ + + + ]: 53 : if (!ws.merged_ranges().empty())
2800 : : {
2801 [ + + ]: 1 : write_start_element(xmlns, "mergeCells");
2802 [ + + + ]: 3 : write_attribute("count", ws.merged_ranges().size());
2803 : :
2804 [ + + + ]: 2 : for (auto merged_range : ws.merged_ranges())
2805 : : {
2806 [ + + ]: 1 : write_start_element(xmlns, "mergeCell");
2807 [ + + + ]: 3 : write_attribute("ref", merged_range.to_string());
2808 [ + + ]: 2 : write_end_element(xmlns, "mergeCell");
2809 : 1 : }
2810 : :
2811 [ + + ]: 2 : write_end_element(xmlns, "mergeCells");
2812 : : }
2813 : :
2814 [ + + + ]: 53 : if (source_.impl().stylesheet_.is_set())
2815 : : {
2816 [ + + ]: 51 : const auto &stylesheet = source_.impl().stylesheet_.get();
2817 : 51 : const auto &cf_impls = stylesheet.conditional_format_impls;
2818 : :
2819 : 51 : std::unordered_map<std::string, std::vector<const conditional_format_impl *>> range_map;
2820 : :
2821 [ - + ]: 51 : for (auto &cf : cf_impls)
2822 : : {
2823 [ # # ]:UBC 0 : if (cf.target_sheet != ws.d_) continue;
2824 : :
2825 [ # # # # ]: 0 : if (range_map.find(cf.target_range.to_string()) == range_map.end())
2826 : : {
2827 [ # # # ]: 0 : range_map[cf.target_range.to_string()] = {};
2828 : : }
2829 : :
2830 [ # # # ]: 0 : range_map[cf.target_range.to_string()].push_back(&cf);
2831 : : }
2832 : :
2833 [ - + ]:CBC 51 : for (const auto &range_rules_pair : range_map)
2834 : : {
2835 [ # # ]:UBC 0 : write_start_element(xmlns, "conditionalFormatting");
2836 [ # # # ]: 0 : write_attribute("sqref", range_rules_pair.first);
2837 : :
2838 : 0 : std::size_t i = 1;
2839 : :
2840 [ # # ]: 0 : for (auto rule : range_rules_pair.second)
2841 : : {
2842 [ # # ]: 0 : write_start_element(xmlns, "cfRule");
2843 [ # # ]: 0 : write_attribute("type", "containsText");
2844 [ # # ]: 0 : write_attribute("operator", "containsText");
2845 [ # # ]: 0 : write_attribute("dxfId", rule->differential_format_id);
2846 [ # # ]: 0 : write_attribute("priority", i++);
2847 [ # # # ]: 0 : write_attribute("text", rule->when.text_comparand_);
2848 : : //TODO: what does this formula mean and why is it necessary?
2849 [ # # # # ]: 0 : write_element(xmlns, "formula", "NOT(ISERROR(SEARCH(\"" + rule->when.text_comparand_ + "\",A1)))");
2850 [ # # ]: 0 : write_end_element(xmlns, "cfRule");
2851 : : }
2852 : :
2853 [ # # ]: 0 : write_end_element(xmlns, "conditionalFormatting");
2854 : : }
2855 :CBC 51 : }
2856 : :
2857 [ + + ]: 53 : if (!hyperlinks.empty())
2858 : : {
2859 [ + + ]: 8 : write_start_element(xmlns, "hyperlinks");
2860 : :
2861 [ + + ]: 28 : for (const auto &hyperlink : hyperlinks)
2862 : : {
2863 [ + + ]: 20 : write_start_element(xmlns, "hyperlink");
2864 [ + + + ]: 60 : write_attribute("ref", hyperlink.first);
2865 [ + + + ]: 20 : if (hyperlink.second.external())
2866 : : {
2867 [ + + + ]: 32 : write_attribute(xml::qname(xmlns_r, "id"),
2868 [ + + + ]: 32 : hyperlink.second.relationship().id());
2869 : : }
2870 : : else
2871 : : {
2872 [ + + + ]: 12 : write_attribute("location", hyperlink.second.target_range());
2873 [ + + + + ]: 12 : write_attribute("display", hyperlink.second.display());
2874 : : }
2875 [ + + ]: 40 : write_end_element(xmlns, "hyperlink");
2876 : : }
2877 : :
2878 [ + + ]: 16 : write_end_element(xmlns, "hyperlinks");
2879 : : }
2880 : :
2881 [ + + + ]: 53 : if (ws.has_phonetic_properties())
2882 : : {
2883 [ + + ]: 4 : write_start_element(xmlns, phonetic_pr::Serialised_ID());
2884 [ + ]: 4 : const auto &ph_props = ws.phonetic_properties();
2885 [ + + + ]: 8 : write_attribute("fontId", ph_props.font_id());
2886 [ + + + ]: 4 : if (ph_props.has_type())
2887 : : {
2888 [ + + + + : 9 : write_attribute("type", phonetic_pr::type_as_string(ph_props.type()));
+ ]
2889 : : }
2890 [ + - + ]: 4 : if (ph_props.has_alignment())
2891 : : {
2892 [ # # # # :UBC 0 : write_attribute("alignment", phonetic_pr::alignment_as_string(ph_props.alignment()));
# ]
2893 : : }
2894 [ + + ]:CBC 4 : write_end_element(xmlns, phonetic_pr::Serialised_ID());
2895 : : }
2896 : :
2897 [ + + ]: 53 : if (ws.d_->print_options_.is_set())
2898 : : {
2899 [ + ]: 2 : auto &opts = ws.d_->print_options_.get();
2900 [ + + ]: 2 : write_start_element(xmlns, "printOptions");
2901 [ + + ]: 2 : if (opts.print_grid_lines.is_set())
2902 : : {
2903 [ + + + + ]: 3 : write_attribute("gridLines", write_bool(opts.print_grid_lines.get()));
2904 : : }
2905 [ + + ]: 2 : if (opts.grid_lines_set.is_set())
2906 : : {
2907 [ + + + + ]: 3 : write_attribute("gridLineSet", write_bool(opts.grid_lines_set.get()));
2908 : : }
2909 [ + + ]: 2 : if (opts.print_headings.is_set())
2910 : : {
2911 [ + + + + ]: 3 : write_attribute("headings", write_bool(opts.print_headings.get()));
2912 : : }
2913 [ + + ]: 2 : if (opts.horizontal_centered.is_set())
2914 : : {
2915 [ + + + + ]: 3 : write_attribute("horizontalCentered", write_bool(opts.horizontal_centered.get()));
2916 : : }
2917 [ + + ]: 2 : if (opts.vertical_centered.is_set())
2918 : : {
2919 [ + + + + ]: 3 : write_attribute("verticalCentered", write_bool(opts.vertical_centered.get()));
2920 : : }
2921 [ + + ]: 4 : write_end_element(xmlns, "printOptions");
2922 : : }
2923 : :
2924 [ + + + ]: 53 : if (ws.has_page_margins())
2925 : : {
2926 [ + + ]: 46 : write_start_element(xmlns, "pageMargins");
2927 : :
2928 [ + + + + ]: 92 : write_attribute<double>("left", ws.page_margins().left());
2929 [ + + + + ]: 92 : write_attribute<double>("right", ws.page_margins().right());
2930 [ + + + + ]: 92 : write_attribute<double>("top", ws.page_margins().top());
2931 [ + + + + ]: 92 : write_attribute<double>("bottom", ws.page_margins().bottom());
2932 [ + + + + ]: 92 : write_attribute<double>("header", ws.page_margins().header());
2933 [ + + + + ]: 138 : write_attribute<double>("footer", ws.page_margins().footer());
2934 : :
2935 [ + + ]: 92 : write_end_element(xmlns, "pageMargins");
2936 : : }
2937 : :
2938 [ + + + ]: 53 : if (ws.has_page_setup())
2939 : : {
2940 [ + ]: 8 : const xlnt::page_setup &ps = ws.page_setup();
2941 [ + + ]: 8 : write_start_element(xmlns, "pageSetup");
2942 [ + + - ]: 8 : if (ws.page_setup().orientation_.is_set())
2943 : : {
2944 [ + + + + ]: 24 : write_attribute("orientation", ws.page_setup().orientation_.get());
2945 : : }
2946 [ + + + ]: 8 : if (ws.page_setup().horizontal_dpi_.is_set())
2947 : : {
2948 [ + + + + ]: 15 : write_attribute("horizontalDpi", ws.page_setup().horizontal_dpi_.get());
2949 : : }
2950 [ + + + ]: 8 : if (ws.page_setup().vertical_dpi_.is_set())
2951 : : {
2952 [ + + + + ]: 18 : write_attribute("verticalDpi", ws.page_setup().vertical_dpi_.get());
2953 : : }
2954 : :
2955 [ + + + ]: 8 : if (ps.has_paper_size())
2956 : : {
2957 [ + + + ]: 9 : write_attribute("paperSize", static_cast<std::size_t>(ps.paper_size()));
2958 : : }
2959 : :
2960 [ + + + ]: 8 : if (ps.has_scale())
2961 : : {
2962 [ + + + ]: 6 : write_attribute("scale", ps.scale());
2963 : : }
2964 : :
2965 [ + + + ]: 8 : if (ps.has_rel_id())
2966 : : {
2967 [ + + + + : 3 : write_attribute(xml::qname(xmlns_r, "id"), ps.rel_id());
+ ]
2968 : : }
2969 : : /*write_attribute("fitToHeight", write_bool(ws.page_setup().fit_to_height()));
2970 : : write_attribute("fitToWidth", write_bool(ws.page_setup().fit_to_width()));*/
2971 [ + + ]: 8 : write_end_element(xmlns, "pageSetup");
2972 : 8 : }
2973 : :
2974 [ + + + ]: 53 : if (ws.has_header_footer())
2975 : : {
2976 [ + ]: 5 : const auto hf = ws.header_footer();
2977 : :
2978 [ + + ]: 5 : write_start_element(xmlns, "headerFooter");
2979 : :
2980 : 5 : auto odd_header = std::string();
2981 : 5 : auto odd_footer = std::string();
2982 : 5 : auto even_header = std::string();
2983 : 5 : auto even_footer = std::string();
2984 : 5 : auto first_header = std::string();
2985 : 5 : auto first_footer = std::string();
2986 : :
2987 : 5 : const auto locations =
2988 : : {
2989 : : header_footer::location::left,
2990 : : header_footer::location::center,
2991 : 5 : header_footer::location::right};
2992 : :
2993 : : using xlnt::detail::encode_header_footer;
2994 : :
2995 [ + + ]: 20 : for (auto location : locations)
2996 : : {
2997 [ + - + ]: 15 : if (hf.different_odd_even())
2998 : : {
2999 [ # # # ]:UBC 0 : if (hf.has_odd_even_header(location))
3000 : : {
3001 [ # # # ]: 0 : odd_header.append(encode_header_footer(hf.odd_header(location), location));
3002 [ # # # ]: 0 : even_header.append(encode_header_footer(hf.even_header(location), location));
3003 : : }
3004 : :
3005 [ # # # ]: 0 : if (hf.has_odd_even_footer(location))
3006 : : {
3007 [ # # # ]: 0 : odd_footer.append(encode_header_footer(hf.odd_footer(location), location));
3008 [ # # # ]: 0 : even_footer.append(encode_header_footer(hf.even_footer(location), location));
3009 : : }
3010 : : }
3011 : : else
3012 : : {
3013 [ + + + ]:CBC 15 : if (hf.has_header(location))
3014 : : {
3015 [ + + + ]: 8 : odd_header.append(encode_header_footer(hf.header(location), location));
3016 : : }
3017 : :
3018 [ + + + ]: 15 : if (hf.has_footer(location))
3019 : : {
3020 [ + + + ]: 9 : odd_footer.append(encode_header_footer(hf.footer(location), location));
3021 : : }
3022 : : }
3023 : :
3024 [ + - + ]: 15 : if (hf.different_first())
3025 : : {
3026 [ # # # ]:UBC 0 : if (hf.has_first_page_header(location))
3027 : : {
3028 [ # # # ]: 0 : first_header.append(encode_header_footer(hf.first_page_header(location), location));
3029 : : }
3030 : :
3031 [ # # # ]: 0 : if (hf.has_first_page_footer(location))
3032 : : {
3033 [ # # # ]: 0 : first_footer.append(encode_header_footer(hf.first_page_footer(location), location));
3034 : : }
3035 : : }
3036 : : }
3037 : :
3038 [ + + ]:CBC 5 : if (!odd_header.empty())
3039 : : {
3040 [ + + + ]: 12 : write_element(xmlns, "oddHeader", odd_header);
3041 : : }
3042 : :
3043 [ + - ]: 5 : if (!odd_footer.empty())
3044 : : {
3045 [ + + + ]: 15 : write_element(xmlns, "oddFooter", odd_footer);
3046 : : }
3047 : :
3048 [ - + ]: 5 : if (!even_header.empty())
3049 : : {
3050 [ # # # ]:UBC 0 : write_element(xmlns, "evenHeader", even_header);
3051 : : }
3052 : :
3053 [ - + ]:CBC 5 : if (!even_footer.empty())
3054 : : {
3055 [ # # # ]:UBC 0 : write_element(xmlns, "evenFooter", even_footer);
3056 : : }
3057 : :
3058 [ - + ]:CBC 5 : if (!first_header.empty())
3059 : : {
3060 [ # # # ]:UBC 0 : write_element(xmlns, "firstHeader", first_header);
3061 : : }
3062 : :
3063 [ - + ]:CBC 5 : if (!first_footer.empty())
3064 : : {
3065 [ # # # ]:UBC 0 : write_element(xmlns, "firstFooter", first_footer);
3066 : : }
3067 : :
3068 [ + + ]:CBC 5 : write_end_element(xmlns, "headerFooter");
3069 : 5 : }
3070 : :
3071 [ + - + ]: 53 : if (!ws.page_break_rows().empty())
3072 : : {
3073 [ # # ]:UBC 0 : write_start_element(xmlns, "rowBreaks");
3074 : :
3075 [ # # # ]: 0 : write_attribute("count", ws.page_break_rows().size());
3076 [ # # # ]: 0 : write_attribute("manualBreakCount", ws.page_break_rows().size());
3077 : :
3078 [ # # # ]: 0 : for (auto break_id : ws.page_break_rows())
3079 : : {
3080 [ # # ]: 0 : write_start_element(xmlns, "brk");
3081 [ # # ]: 0 : write_attribute("id", break_id);
3082 [ # # ]: 0 : write_attribute("max", 16383);
3083 [ # # ]: 0 : write_attribute("man", 1);
3084 [ # # ]: 0 : write_end_element(xmlns, "brk");
3085 : : }
3086 : :
3087 [ # # ]: 0 : write_end_element(xmlns, "rowBreaks");
3088 : : }
3089 : :
3090 [ + - + ]:CBC 53 : if (!ws.page_break_columns().empty())
3091 : : {
3092 [ # # ]:UBC 0 : write_start_element(xmlns, "colBreaks");
3093 : :
3094 [ # # # ]: 0 : write_attribute("count", ws.page_break_columns().size());
3095 [ # # # ]: 0 : write_attribute("manualBreakCount", ws.page_break_columns().size());
3096 : :
3097 [ # # # ]: 0 : for (auto break_id : ws.page_break_columns())
3098 : : {
3099 [ # # ]: 0 : write_start_element(xmlns, "brk");
3100 [ # # ]: 0 : write_attribute("id", break_id.index);
3101 [ # # ]: 0 : write_attribute("max", 1048575);
3102 [ # # ]: 0 : write_attribute("man", 1);
3103 [ # # ]: 0 : write_end_element(xmlns, "brk");
3104 : : }
3105 : :
3106 [ # # ]: 0 : write_end_element(xmlns, "colBreaks");
3107 : : }
3108 : :
3109 [ + + ]:CBC 53 : if (!worksheet_rels.empty())
3110 : : {
3111 [ + + ]: 46 : for (const auto &child_rel : worksheet_rels)
3112 : : {
3113 [ + + + ]: 35 : if (child_rel.type() == xlnt::relationship_type::vml_drawing)
3114 : : {
3115 [ + + ]: 8 : write_start_element(xmlns, "legacyDrawing");
3116 [ + + + + : 24 : write_attribute(xml::qname(xmlns_r, "id"), child_rel.id());
+ ]
3117 [ + + ]: 16 : write_end_element(xmlns, "legacyDrawing");
3118 : : }
3119 [ + + + ]: 27 : else if (child_rel.type() == xlnt::relationship_type::drawings)
3120 : : {
3121 [ + + ]: 2 : write_start_element(xmlns, "drawing");
3122 [ + + + + : 6 : write_attribute(xml::qname(xmlns_r, "id"), child_rel.id());
+ ]
3123 [ + + ]: 4 : write_end_element(xmlns, "drawing");
3124 : : }
3125 : : }
3126 : : }
3127 : :
3128 [ + + ]: 53 : if (ws.d_->extension_list_.is_set())
3129 : : {
3130 [ + + ]: 2 : ws.d_->extension_list_.get().serialize(*current_part_serializer_, xmlns);
3131 : : }
3132 : :
3133 [ + + ]: 53 : write_end_element(xmlns, "worksheet");
3134 : :
3135 [ + + ]: 53 : if (!worksheet_rels.empty())
3136 : : {
3137 [ + ]: 11 : write_relationships(worksheet_rels, worksheet_part);
3138 : :
3139 [ + + ]: 46 : for (const auto &child_rel : worksheet_rels)
3140 : : {
3141 [ + + + ]: 36 : if (child_rel.target_mode() == target_mode::external) continue;
3142 : :
3143 : : // todo: this is ugly
3144 [ + + + + ]: 19 : path archive_path(worksheet_part.parent().append(child_rel.target().path()));
3145 [ + ]: 19 : auto split_part_path = archive_path.split();
3146 : 19 : auto part_path_iter = split_part_path.begin();
3147 : :
3148 [ + + ]: 106 : while (part_path_iter != split_part_path.end())
3149 : : {
3150 [ + + + ]: 87 : if (*part_path_iter == "..")
3151 : : {
3152 [ + ]: 19 : part_path_iter = split_part_path.erase(part_path_iter - 1, part_path_iter + 1);
3153 : 19 : continue;
3154 : : }
3155 : :
3156 : 68 : ++part_path_iter;
3157 : : }
3158 : :
3159 [ + + + ]: 38 : archive_path = std::accumulate(split_part_path.begin(), split_part_path.end(), path(""),
3160 : 68 : [](const path &a, const std::string &b) { return a.append(b); });
3161 : :
3162 [ + + + ]: 19 : if (child_rel.type() == relationship_type::printer_settings)
3163 : : {
3164 [ + ]: 1 : write_binary(archive_path);
3165 : 1 : continue;
3166 : : }
3167 : :
3168 [ + ]: 18 : begin_part(archive_path);
3169 : :
3170 [ + + + ]: 18 : if (child_rel.type() == relationship_type::comments)
3171 : : {
3172 [ + + ]: 8 : write_comments(child_rel, ws, cells_with_comments);
3173 : : }
3174 [ + + + ]: 10 : else if (child_rel.type() == relationship_type::vml_drawing)
3175 : : {
3176 [ + + ]: 8 : write_vml_drawings(child_rel, ws, cells_with_comments);
3177 : : }
3178 [ + + - ]: 2 : else if (child_rel.type() == relationship_type::drawings)
3179 : : {
3180 [ + + ]: 2 : write_drawings(child_rel, ws);
3181 : : }
3182 [ + + + + ]: 20 : }
3183 : : }
3184 : 53 : }
3185 : :
3186 : : // Sheet Relationship Target Parts
3187 : :
3188 : 8 : void xlsx_producer::write_comments(const relationship & /*rel*/, worksheet ws, const std::vector<cell_reference> &cells)
3189 : : {
3190 [ + + + - : 10 : static const auto &xmlns = constants::ns("spreadsheetml");
+ + - - ]
3191 : :
3192 [ + + ]: 16 : write_start_element(xmlns, "comments");
3193 [ + + ]: 8 : write_namespace(xmlns, "");
3194 : :
3195 [ + - ]: 8 : if (!cells.empty())
3196 : : {
3197 : 8 : std::unordered_map<std::string, std::size_t> authors;
3198 : :
3199 [ + + ]: 24 : for (auto cell_ref : cells)
3200 : : {
3201 [ + ]: 16 : auto cell = ws.cell(cell_ref);
3202 [ + + ]: 16 : auto author = cell.comment().author();
3203 : :
3204 [ + + + ]: 16 : if (authors.find(author) == authors.end())
3205 : : {
3206 : 8 : auto author_index = authors.size();
3207 [ + ]: 8 : authors[author] = author_index;
3208 : : }
3209 : 16 : }
3210 : :
3211 [ + + ]: 8 : write_start_element(xmlns, "authors");
3212 : :
3213 [ + + ]: 16 : for (const auto &author : authors)
3214 : : {
3215 [ + + ]: 8 : write_start_element(xmlns, "author");
3216 [ + + ]: 8 : write_characters(author.first);
3217 [ + + ]: 16 : write_end_element(xmlns, "author");
3218 : : }
3219 : :
3220 [ + + ]: 16 : write_end_element(xmlns, "authors");
3221 [ + + ]: 8 : write_start_element(xmlns, "commentList");
3222 : :
3223 [ + + ]: 24 : for (const auto &cell_ref : cells)
3224 : : {
3225 [ + + ]: 16 : write_start_element(xmlns, "comment");
3226 : :
3227 [ + ]: 16 : auto cell = ws.cell(cell_ref);
3228 [ + ]: 16 : auto cell_comment = cell.comment();
3229 : :
3230 [ + + + ]: 48 : write_attribute("ref", cell_ref.to_string());
3231 [ + + ]: 16 : auto author_id = authors.at(cell_comment.author());
3232 [ + + ]: 32 : write_attribute("authorId", author_id);
3233 : :
3234 [ + + ]: 16 : write_start_element(xmlns, "text");
3235 [ + + ]: 16 : write_rich_text(xmlns, cell_comment.text());
3236 [ + + ]: 32 : write_end_element(xmlns, "text");
3237 : :
3238 [ + + ]: 16 : write_end_element(xmlns, "comment");
3239 : 16 : }
3240 : :
3241 [ + + ]: 8 : write_end_element(xmlns, "commentList");
3242 : 8 : }
3243 : :
3244 [ + + ]: 8 : write_end_element(xmlns, "comments");
3245 : 8 : }
3246 : :
3247 : 8 : void xlsx_producer::write_vml_drawings(const relationship &rel, worksheet ws, const std::vector<cell_reference> &cells)
3248 : : {
3249 [ + + + - : 11 : static const auto &xmlns_mv = std::string("http://macVmlSchemaUri");
+ - - ]
3250 [ + + + - : 11 : static const auto &xmlns_o = std::string("urn:schemas-microsoft-com:office:office");
+ - - ]
3251 [ + + + - : 11 : static const auto &xmlns_v = std::string("urn:schemas-microsoft-com:vml");
+ - - ]
3252 [ + + + - : 11 : static const auto &xmlns_x = std::string("urn:schemas-microsoft-com:office:excel");
+ - - ]
3253 : :
3254 [ + + ]: 16 : write_start_element("xml");
3255 [ + + ]: 16 : write_namespace(xmlns_v, "v");
3256 [ + + ]: 16 : write_namespace(xmlns_o, "o");
3257 [ + + ]: 16 : write_namespace(xmlns_x, "x");
3258 [ + + ]: 16 : write_namespace(xmlns_mv, "mv");
3259 : :
3260 [ + + ]: 16 : write_start_element(xmlns_o, "shapelayout");
3261 [ + + + ]: 16 : write_attribute(xml::qname(xmlns_v, "ext"), "edit");
3262 [ + + ]: 16 : write_start_element(xmlns_o, "idmap");
3263 [ + + + ]: 8 : write_attribute(xml::qname(xmlns_v, "ext"), "edit");
3264 : :
3265 [ + + + ]: 8 : auto filename = rel.target().path().split_extension().first;
3266 : 8 : auto index_pos = filename.size() - 1;
3267 : :
3268 [ + - + + : 16 : while (filename[index_pos] >= '0' && filename[index_pos] <= '9')
+ + ]
3269 : : {
3270 : 8 : index_pos--;
3271 : : }
3272 : :
3273 : 8 : size_t file_index = 0;
3274 [ + + ]: 8 : detail::parse(filename.substr(index_pos + 1), file_index);
3275 : :
3276 [ + + ]: 24 : write_attribute("data", file_index);
3277 [ + + ]: 16 : write_end_element(xmlns_o, "idmap");
3278 [ + + ]: 16 : write_end_element(xmlns_o, "shapelayout");
3279 : :
3280 [ + + ]: 16 : write_start_element(xmlns_v, "shapetype");
3281 [ + + ]: 16 : write_attribute("id", "_x0000_t202");
3282 [ + + ]: 16 : write_attribute("coordsize", "21600,21600");
3283 [ + + + ]: 16 : write_attribute(xml::qname(xmlns_o, "spt"), "202");
3284 [ + + ]: 16 : write_attribute("path", "m0,0l0,21600,21600,21600,21600,0xe");
3285 [ + + ]: 16 : write_start_element(xmlns_v, "stroke");
3286 [ + + ]: 16 : write_attribute("joinstyle", "miter");
3287 [ + + ]: 16 : write_end_element(xmlns_v, "stroke");
3288 [ + + ]: 16 : write_start_element(xmlns_v, "path");
3289 [ + + ]: 16 : write_attribute("gradientshapeok", "t");
3290 [ + + + ]: 16 : write_attribute(xml::qname(xmlns_o, "connecttype"), "rect");
3291 [ + + ]: 16 : write_end_element(xmlns_v, "path");
3292 [ + + ]: 8 : write_end_element(xmlns_v, "shapetype");
3293 : :
3294 : 8 : std::size_t comment_index = 0;
3295 : :
3296 [ + + ]: 24 : for (const auto &cell_ref : cells)
3297 : : {
3298 [ + + ]: 16 : auto comment = ws.cell(cell_ref).comment();
3299 : 16 : auto shape_id = 1024 * file_index + 1 + comment_index * 2;
3300 : :
3301 [ + + ]: 16 : write_start_element(xmlns_v, "shape");
3302 [ + + + + ]: 48 : write_attribute("id", "_x0000_s" + std::to_string(shape_id));
3303 [ + + ]: 16 : write_attribute("type", "#_x0000_t202");
3304 : :
3305 : 16 : std::vector<std::pair<std::string, std::string>> style;
3306 : :
3307 [ + + ]: 16 : style.push_back({"position", "absolute"});
3308 [ + + + + ]: 16 : style.push_back({"margin-left", std::to_string(comment.left()) + "pt"});
3309 [ + + + + ]: 16 : style.push_back({"margin-top", std::to_string(comment.top()) + "pt"});
3310 [ + + + + ]: 16 : style.push_back({"width", std::to_string(comment.width()) + "pt"});
3311 [ + + + + ]: 16 : style.push_back({"height", std::to_string(comment.height()) + "pt"});
3312 [ + + + ]: 16 : style.push_back({"z-index", std::to_string(comment_index + 1)});
3313 [ + - + + : 16 : style.push_back({"visibility", comment.visible() ? "visible" : "hidden"});
+ ]
3314 : :
3315 : 16 : std::string style_string;
3316 : :
3317 [ + + + ]: 128 : for (auto part : style)
3318 : : {
3319 [ + ]: 112 : style_string.append(part.first);
3320 [ + ]: 112 : style_string.append(":");
3321 [ + ]: 112 : style_string.append(part.second);
3322 [ + ]: 112 : style_string.append(";");
3323 : 112 : }
3324 : :
3325 [ + + + ]: 48 : write_attribute("style", style_string);
3326 [ + + ]: 32 : write_attribute("fillcolor", "#fbf6d6");
3327 [ + + ]: 32 : write_attribute("strokecolor", "#edeaa1");
3328 : :
3329 [ + + ]: 32 : write_start_element(xmlns_v, "fill");
3330 [ + + ]: 32 : write_attribute("color2", "#fbfe82");
3331 [ + + ]: 32 : write_attribute("angle", -180);
3332 [ + + ]: 32 : write_attribute("type", "gradient");
3333 [ + + ]: 32 : write_start_element(xmlns_o, "fill");
3334 [ + + + ]: 32 : write_attribute(xml::qname(xmlns_v, "ext"), "view");
3335 [ + + ]: 32 : write_attribute("type", "gradientUnscaled");
3336 [ + + ]: 32 : write_end_element(xmlns_o, "fill");
3337 [ + + ]: 32 : write_end_element(xmlns_v, "fill");
3338 : :
3339 [ + + ]: 32 : write_start_element(xmlns_v, "shadow");
3340 [ + + ]: 32 : write_attribute("on", "t");
3341 [ + + ]: 32 : write_attribute("obscured", "t");
3342 [ + + ]: 32 : write_end_element(xmlns_v, "shadow");
3343 : :
3344 [ + + ]: 32 : write_start_element(xmlns_v, "path");
3345 [ + + + ]: 32 : write_attribute(xml::qname(xmlns_o, "connecttype"), "none");
3346 [ + + ]: 32 : write_end_element(xmlns_v, "path");
3347 : :
3348 [ + + ]: 32 : write_start_element(xmlns_v, "textbox");
3349 [ + + ]: 32 : write_attribute("style", "mso-direction-alt:auto");
3350 [ + + ]: 32 : write_start_element("div");
3351 [ + + ]: 16 : write_attribute("style", "text-align:left");
3352 [ + ]: 16 : write_characters("");
3353 [ + + ]: 32 : write_end_element("div");
3354 [ + + ]: 32 : write_end_element(xmlns_v, "textbox");
3355 : :
3356 [ + + ]: 32 : write_start_element(xmlns_x, "ClientData");
3357 [ + + ]: 32 : write_attribute("ObjectType", "Note");
3358 [ + + ]: 32 : write_start_element(xmlns_x, "MoveWithCells");
3359 [ + + ]: 32 : write_end_element(xmlns_x, "MoveWithCells");
3360 [ + + ]: 32 : write_start_element(xmlns_x, "SizeWithCells");
3361 [ + + ]: 32 : write_end_element(xmlns_x, "SizeWithCells");
3362 [ + + ]: 16 : write_start_element(xmlns_x, "Anchor");
3363 [ + + + + ]: 16 : write_characters("1, 15, 0, " + std::to_string(2 + comment_index * 4) + ", 2, 54, 4, 14");
3364 [ + + ]: 32 : write_end_element(xmlns_x, "Anchor");
3365 [ + + ]: 16 : write_start_element(xmlns_x, "AutoFill");
3366 [ + ]: 16 : write_characters("False");
3367 [ + + ]: 32 : write_end_element(xmlns_x, "AutoFill");
3368 [ + + ]: 16 : write_start_element(xmlns_x, "Row");
3369 [ + + ]: 16 : write_characters(cell_ref.row() - 1);
3370 [ + + ]: 32 : write_end_element(xmlns_x, "Row");
3371 [ + + ]: 16 : write_start_element(xmlns_x, "Column");
3372 [ + + ]: 16 : write_characters(cell_ref.column_index() - 1);
3373 [ + + ]: 32 : write_end_element(xmlns_x, "Column");
3374 [ + + ]: 32 : write_end_element(xmlns_x, "ClientData");
3375 : :
3376 [ + + ]: 16 : write_end_element(xmlns_v, "shape");
3377 : :
3378 : 16 : ++comment_index;
3379 : 16 : }
3380 : :
3381 [ + + ]: 8 : write_end_element("xml");
3382 : 8 : }
3383 : :
3384 : 2 : void xlsx_producer::write_drawings(const relationship &drawing_rel, worksheet ws)
3385 : : {
3386 [ + + + + ]: 4 : const auto workbook_rel = source_.manifest().relationship(path("/"), relationship_type::office_document);
3387 [ + ]: 2 : const auto worksheet_rel = ws.referring_relationship();
3388 [ + + + + : 12 : const auto drawing_part = source_.manifest().canonicalize({workbook_rel, worksheet_rel, drawing_rel});
+ - - ]
3389 [ + + ]: 2 : const auto drawing_rels = source_.manifest().relationships(drawing_part);
3390 : :
3391 [ + - ]: 2 : if (ws.d_->drawing_.is_set())
3392 : : {
3393 [ + + ]: 2 : ws.d_->drawing_.get().serialize(*current_part_serializer_);
3394 : : }
3395 : :
3396 [ + + ]: 2 : if (!drawing_rels.empty())
3397 : : {
3398 [ + ]: 1 : write_relationships(drawing_rels, drawing_part);
3399 : :
3400 [ + + + ]: 2 : for (auto rel : drawing_rels)
3401 : : {
3402 [ + + - ]: 1 : if (rel.type() == relationship_type::image)
3403 : : {
3404 [ + + + + : 6 : const auto image_path = source_.manifest().canonicalize({workbook_rel, worksheet_rel, rel});
+ - - ]
3405 [ + - + ]: 1 : if (image_path.string().find("cid:") != std::string::npos)
3406 : : {
3407 : : // skip cid attachments
3408 :UBC 0 : continue;
3409 : : }
3410 [ + ]:CBC 1 : write_image(image_path);
3411 [ + - ]: 1 : }
3412 [ + - ]: 1 : }
3413 : : }
3414 [ + + + + : 5 : }
+ + - - -
- - - -
- ]
3415 : :
3416 : : // Other Parts
3417 : :
3418 :UBC 0 : void xlsx_producer::write_custom_property()
3419 : : {
3420 : 0 : }
3421 : :
3422 : 0 : void xlsx_producer::write_unknown_parts()
3423 : : {
3424 : 0 : }
3425 : :
3426 : 0 : void xlsx_producer::write_unknown_relationships()
3427 : : {
3428 : 0 : }
3429 : :
3430 :CBC 32 : void xlsx_producer::write_image(const path &image_path)
3431 : : {
3432 : 32 : end_part();
3433 : :
3434 [ + + + ]: 32 : vector_istreambuf buffer(source_.d_->images_.at(image_path.string()));
3435 [ + ]: 32 : auto image_streambuf = archive_->open(image_path);
3436 [ + + ]: 32 : std::ostream(image_streambuf.get()) << &buffer;
3437 : 32 : }
3438 : :
3439 : 2 : void xlsx_producer::write_binary(const path &binary_path)
3440 : : {
3441 : 2 : end_part();
3442 : :
3443 [ + + + ]: 2 : vector_istreambuf buffer(source_.d_->binaries_.at(binary_path.string()));
3444 [ + ]: 2 : auto image_streambuf = archive_->open(binary_path);
3445 [ + + ]: 2 : std::ostream(image_streambuf.get()) << &buffer;
3446 : 2 : }
3447 : :
3448 : 2244 : std::string xlsx_producer::write_bool(bool boolean) const
3449 : : {
3450 [ + + + ]: 4488 : return boolean ? "1" : "0";
3451 : : }
3452 : :
3453 : 101 : void xlsx_producer::write_relationships(const std::vector<xlnt::relationship> &relationships, const path &part)
3454 : : {
3455 [ + ]: 101 : path parent = part.parent();
3456 : :
3457 [ + + + ]: 101 : if (parent.is_absolute())
3458 : : {
3459 [ + + + ]: 44 : parent = path(parent.string().substr(1));
3460 : : }
3461 : :
3462 [ + + + + : 101 : path rels_path(parent.append("_rels").append(part.filename() + ".rels").string());
+ + + ]
3463 [ + ]: 101 : begin_part(rels_path);
3464 : :
3465 [ + + + ]: 202 : const auto xmlns = xlnt::constants::ns("relationships");
3466 : :
3467 [ + + ]: 202 : write_start_element(xmlns, "Relationships");
3468 [ + + ]: 101 : write_namespace(xmlns, "");
3469 : :
3470 [ + + ]: 468 : for (std::size_t i = 1; i <= relationships.size(); ++i)
3471 : : {
3472 [ + ]: 367 : auto rel_iter = std::find_if(relationships.begin(), relationships.end(),
3473 [ + + + ]: 918 : [&i](const relationship &r) { return r.id() == "rId" + std::to_string(i); });
3474 [ + ]: 367 : auto relationship = *rel_iter;
3475 : :
3476 [ + + ]: 367 : write_start_element(xmlns, "Relationship");
3477 : :
3478 [ + + + + ]: 1101 : write_attribute("Id", relationship.id());
3479 [ + + + ]: 734 : write_attribute("Type", relationship.type());
3480 [ + + + + : 1101 : write_attribute("Target", relationship.target().path().string());
+ + ]
3481 : :
3482 [ + + + ]: 367 : if (relationship.target_mode() == xlnt::target_mode::external)
3483 : : {
3484 [ + + ]: 32 : write_attribute("TargetMode", "External");
3485 : : }
3486 : :
3487 [ + + ]: 367 : write_end_element(xmlns, "Relationship");
3488 : 367 : }
3489 : :
3490 [ + + ]: 101 : write_end_element(xmlns, "Relationships");
3491 : 101 : }
3492 : :
3493 : 577 : void xlsx_producer::write_color(const xlnt::color &color)
3494 : : {
3495 [ + + ]: 577 : if (color.auto_())
3496 : : {
3497 [ + + + ]: 6 : write_attribute("auto", write_bool(true));
3498 : 2 : return;
3499 : : }
3500 [ + + + - ]: 575 : switch (color.type())
3501 : : {
3502 : 256 : case xlnt::color_type::theme:
3503 [ + + ]: 512 : write_attribute("theme", color.theme().index());
3504 : 256 : break;
3505 : :
3506 : 173 : case xlnt::color_type::indexed:
3507 [ + + ]: 346 : write_attribute("indexed", color.indexed().index());
3508 : 173 : break;
3509 : :
3510 : 146 : case xlnt::color_type::rgb:
3511 [ + + + + ]: 438 : write_attribute("rgb", color.rgb().hex_string());
3512 : 146 : break;
3513 : : }
3514 [ + + ]: 575 : if (color.has_tint())
3515 : : {
3516 [ + + + + ]: 240 : write_attribute("tint", xlnt::detail::serialise(color.tint()));
3517 : : }
3518 : : }
3519 : :
3520 : 24 : void xlsx_producer::write_start_element(const std::string &name)
3521 : : {
3522 : 24 : current_part_serializer_->start_element(name);
3523 : 24 : }
3524 : :
3525 : 20024 : void xlsx_producer::write_start_element(const std::string &ns, const std::string &name)
3526 : : {
3527 : 20024 : current_part_serializer_->start_element(ns, name);
3528 : 20024 : }
3529 : :
3530 : 24 : void xlsx_producer::write_end_element(const std::string &name)
3531 : : {
3532 : 24 : current_part_serializer_->end_element(name);
3533 : 24 : }
3534 : :
3535 : 20024 : void xlsx_producer::write_end_element(const std::string &ns, const std::string &name)
3536 : : {
3537 : 20024 : current_part_serializer_->end_element(ns, name);
3538 : 20024 : }
3539 : :
3540 : 1032 : void xlsx_producer::write_namespace(const std::string &ns, const std::string &prefix)
3541 : : {
3542 : 1032 : current_part_serializer_->namespace_decl(ns, prefix);
3543 : 1032 : }
3544 : :
3545 : : } // namespace detail
3546 : : } // namespace xlnt
|