Branch data TLA Line data Source code
1 : : // Copyright (C) 2016-2022 Thomas Fussell
2 : : // Copyright (C) 2002-2007 Ariya Hidayat (ariya@kde.org).
3 : : // Copyright (c) 2024-2025 xlnt-community
4 : : //
5 : : // Redistribution and use in source and binary forms, with or without
6 : : // modification, are permitted provided that the following conditions
7 : : // are met:
8 : : //
9 : : // 1. Redistributions of source code must retain the above copyright
10 : : // notice, this list of conditions and the following disclaimer.
11 : : // 2. Redistributions in binary form must reproduce the above copyright
12 : : // notice, this list of conditions and the following disclaimer in the
13 : : // documentation and/or other materials provided with the distribution.
14 : : //
15 : : // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 : : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 : : // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 : : // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 : : // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 : : // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 : : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 : : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 : : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 : : // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 : :
26 : : #include <algorithm>
27 : : #include <array>
28 : : #include <cstring>
29 : : #include <iostream>
30 : : #include <locale>
31 : : #include <string>
32 : : #include <vector>
33 : :
34 : : #include <xlnt/utils/exceptions.hpp>
35 : : #include <detail/binary.hpp>
36 : : #include <detail/cryptography/compound_document.hpp>
37 : : #include <detail/unicode.hpp>
38 : :
39 : : namespace {
40 : :
41 : : using namespace xlnt::detail;
42 : :
43 :CBC 8 : int compare_keys(const std::string &left, const std::string &right)
44 : : {
45 : 16 : auto to_lower = [](std::string s) {
46 [ + + + - ]: 16 : static const auto locale = std::locale();
47 : 16 : std::use_facet<std::ctype<char>>(locale).tolower(&s[0], &s[0] + s.size());
48 : :
49 : 16 : return s;
50 : : };
51 : :
52 [ + + + + ]: 8 : return to_lower(left).compare(to_lower(right));
53 : : }
54 : :
55 : 12 : std::vector<std::string> split_path(const std::string &path)
56 : : {
57 : 12 : auto split = std::vector<std::string>();
58 : 12 : auto current = path.find('/');
59 : 12 : auto prev = std::size_t(0);
60 : :
61 [ + + ]: 24 : while (current != std::string::npos)
62 : : {
63 [ + + ]: 12 : split.push_back(path.substr(prev, current - prev));
64 : 12 : prev = current + 1;
65 : 12 : current = path.find('/', prev);
66 : : }
67 : :
68 [ + + ]: 12 : split.push_back(path.substr(prev));
69 : :
70 : 12 : return split;
71 :UBC 0 : }
72 : :
73 :CBC 178 : std::string join_path(const std::vector<std::string> &path)
74 : : {
75 : 178 : auto joined = std::string();
76 : :
77 [ + + + ]: 262 : for (auto part : path)
78 : : {
79 [ + ]: 84 : joined.append(part);
80 [ + ]: 84 : joined.push_back('/');
81 : 84 : }
82 : :
83 : 178 : return joined;
84 :UBC 0 : }
85 : :
86 : : const sector_id FreeSector = -1;
87 : : const sector_id EndOfChain = -2;
88 : : const sector_id SATSector = -3;
89 : : //const sector_id MSATSector = -4;
90 : :
91 : : const directory_id End = -1;
92 : :
93 : : } // namespace
94 : :
95 : : namespace xlnt {
96 : : namespace detail {
97 : :
98 : : /// <summary>
99 : : /// Allows a std::vector to be read through a std::istream.
100 : : /// </summary>
101 : : class compound_document_istreambuf : public std::streambuf
102 : : {
103 : : using int_type = std::streambuf::int_type;
104 : :
105 : : public:
106 :CBC 42 : compound_document_istreambuf(const compound_document_entry &entry, compound_document &document)
107 : 84 : : entry_(entry),
108 : 42 : document_(document),
109 : 42 : sector_writer_(current_sector_),
110 : 42 : position_(0)
111 : : {
112 : 42 : }
113 : :
114 : : compound_document_istreambuf(const compound_document_istreambuf &) = delete;
115 : : compound_document_istreambuf &operator=(const compound_document_istreambuf &) = delete;
116 : :
117 : : ~compound_document_istreambuf() override;
118 : :
119 : : private:
120 : 584 : std::streamsize xsgetn(char *c, std::streamsize count) override
121 : : {
122 : 584 : auto bytes_read = std::streamsize(0);
123 : :
124 [ + + + ]: 584 : const auto sector_chain = short_stream() ? document_.ssat_ : document_.sat_;
125 [ + ]: 584 : const auto chain = document_.follow_chain(entry_.start, sector_chain);
126 [ + + ]: 584 : const auto sector_size = short_stream() ? document_.short_sector_size() : document_.sector_size();
127 : 584 : auto current_sector = chain[position_ / sector_size];
128 : 584 : auto remaining = std::min(std::size_t(entry_.size) - position_, std::size_t(count));
129 : :
130 [ + + ]: 3378 : while (remaining)
131 : : {
132 [ + + + + : 2794 : if (current_sector_.empty() || chain[position_ / sector_size] != current_sector)
+ + ]
133 : : {
134 : 2249 : current_sector = chain[position_ / sector_size];
135 : 2249 : sector_writer_.reset();
136 [ + + ]: 2249 : if (short_stream())
137 : : {
138 [ + ]: 159 : document_.read_short_sector(current_sector, sector_writer_);
139 : : }
140 : : else
141 : : {
142 [ + ]: 2090 : document_.read_sector(current_sector, sector_writer_);
143 : : }
144 : : }
145 : :
146 : 5588 : const auto available = std::min(entry_.size - position_,
147 : 2794 : sector_size - position_ % sector_size);
148 : 2794 : const auto to_read = std::min(available, std::size_t(remaining));
149 : :
150 : 2794 : auto start = current_sector_.begin() + static_cast<std::ptrdiff_t>(position_ % sector_size);
151 : 2794 : auto end = start + static_cast<std::ptrdiff_t>(to_read);
152 : :
153 [ + + ]: 1076712 : for (auto i = start; i < end; ++i)
154 : : {
155 : 1073918 : *(c++) = static_cast<char>(*i);
156 : : }
157 : :
158 : 2794 : remaining -= to_read;
159 : 2794 : position_ += to_read;
160 : 2794 : bytes_read += to_read;
161 : : }
162 : :
163 [ + + + + : 584 : if (position_ < entry_.size && chain[position_ / sector_size] != current_sector)
+ + ]
164 : : {
165 : 15 : current_sector = chain[position_ / sector_size];
166 : 15 : sector_writer_.reset();
167 [ + - ]: 15 : if (short_stream())
168 : : {
169 [ + ]: 15 : document_.read_short_sector(current_sector, sector_writer_);
170 : : }
171 : : else
172 : : {
173 [ # ]:UBC 0 : document_.read_sector(current_sector, sector_writer_);
174 : : }
175 : : }
176 : :
177 :CBC 584 : return bytes_read;
178 : 584 : }
179 : :
180 : 3432 : bool short_stream()
181 : : {
182 : 3432 : return entry_.size < document_.header_.threshold;
183 : : }
184 : :
185 :UBC 0 : int_type underflow() override
186 : : {
187 [ # # ]: 0 : if (position_ >= entry_.size)
188 : : {
189 : 0 : return traits_type::eof();
190 : : }
191 : :
192 : 0 : auto old_position = position_;
193 : 0 : auto result = '\0';
194 [ # ]: 0 : xsgetn(&result, 1);
195 : 0 : position_ = old_position;
196 : :
197 : 0 : return result;
198 : : }
199 : :
200 : 0 : int_type uflow() override
201 : : {
202 : 0 : auto result = underflow();
203 : 0 : ++position_;
204 : :
205 : 0 : return result;
206 : : }
207 : :
208 : 0 : std::streamsize showmanyc() override
209 : : {
210 [ # # ]: 0 : if (position_ == entry_.size)
211 : : {
212 : 0 : return static_cast<std::streamsize>(-1);
213 : : }
214 : :
215 : 0 : return static_cast<std::streamsize>(entry_.size - position_);
216 : : }
217 : :
218 :CBC 30 : std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode) override
219 : : {
220 [ - + ]: 30 : if (way == std::ios_base::beg)
221 : : {
222 :UBC 0 : position_ = 0;
223 : : }
224 [ - + ]:CBC 30 : else if (way == std::ios_base::end)
225 : : {
226 :UBC 0 : position_ = entry_.size;
227 : : }
228 : :
229 [ - + ]:CBC 30 : if (off < 0)
230 : : {
231 [ # # ]:UBC 0 : if (static_cast<std::size_t>(-off) > position_)
232 : : {
233 : 0 : position_ = 0;
234 : 0 : return static_cast<std::ptrdiff_t>(-1);
235 : : }
236 : : else
237 : : {
238 : 0 : position_ -= static_cast<std::size_t>(-off);
239 : : }
240 : : }
241 [ - + ]:CBC 30 : else if (off > 0)
242 : : {
243 [ # # ]:UBC 0 : if (static_cast<std::size_t>(off) + position_ > entry_.size)
244 : : {
245 : 0 : position_ = entry_.size;
246 : 0 : return static_cast<std::ptrdiff_t>(-1);
247 : : }
248 : : else
249 : : {
250 : 0 : position_ += static_cast<std::size_t>(off);
251 : : }
252 : : }
253 : :
254 :CBC 30 : return static_cast<std::ptrdiff_t>(position_);
255 : : }
256 : :
257 :UBC 0 : std::streampos seekpos(std::streampos sp, std::ios_base::openmode) override
258 : : {
259 [ # # ]: 0 : if (sp < 0)
260 : : {
261 : 0 : position_ = 0;
262 : : }
263 [ # # ]: 0 : else if (static_cast<std::size_t>(sp) > entry_.size)
264 : : {
265 : 0 : position_ = entry_.size;
266 : : }
267 : : else
268 : : {
269 : 0 : position_ = static_cast<std::size_t>(sp);
270 : : }
271 : :
272 : 0 : return static_cast<std::ptrdiff_t>(position_);
273 : : }
274 : :
275 : : private:
276 : : const compound_document_entry &entry_;
277 : : compound_document &document_;
278 : : std::vector<byte> current_sector_;
279 : : binary_writer<byte> sector_writer_;
280 : : std::size_t position_;
281 : : };
282 : :
283 :CBC 84 : compound_document_istreambuf::~compound_document_istreambuf()
284 : : {
285 : 84 : }
286 : :
287 : : /// <summary>
288 : : /// Allows a std::vector to be written through a std::ostream.
289 : : /// </summary>
290 : : class compound_document_ostreambuf : public std::streambuf
291 : : {
292 : : using int_type = std::streambuf::int_type;
293 : :
294 : : public:
295 : 8 : compound_document_ostreambuf(compound_document_entry &entry, compound_document &document)
296 : 16 : : entry_(entry),
297 : 8 : document_(document),
298 [ + ]: 8 : current_sector_(document.header_.threshold),
299 : 8 : sector_reader_(current_sector_),
300 : 16 : position_(0)
301 : : {
302 : 8 : setp(reinterpret_cast<char *>(current_sector_.data()),
303 : 8 : reinterpret_cast<char *>(current_sector_.data() + current_sector_.size()));
304 : 8 : }
305 : :
306 : : compound_document_ostreambuf(const compound_document_ostreambuf &) = delete;
307 : : compound_document_ostreambuf &operator=(const compound_document_ostreambuf &) = delete;
308 : :
309 : : ~compound_document_ostreambuf() override;
310 : :
311 : : private:
312 : 986 : int sync() override
313 : : {
314 : 986 : auto written = static_cast<std::size_t>(pptr() - pbase());
315 : :
316 [ + + ]: 986 : if (written == std::size_t(0))
317 : : {
318 : 4 : return 0;
319 : : }
320 : :
321 : 982 : sector_reader_.reset();
322 : :
323 [ + + ]: 982 : if (short_stream())
324 : : {
325 [ + + ]: 8 : if (position_ + written >= document_.header_.threshold)
326 : : {
327 : 4 : convert_to_long_stream();
328 : : }
329 : : else
330 : : {
331 [ + - ]: 4 : if (entry_.start < 0)
332 : : {
333 : 4 : auto num_sectors = (position_ + written + document_.short_sector_size() - 1) / document_.short_sector_size();
334 [ + ]: 4 : chain_ = document_.allocate_short_sectors(num_sectors);
335 : 4 : entry_.start = chain_.front();
336 : : }
337 : :
338 [ + + ]: 80 : for (auto link : chain_)
339 : : {
340 [ + ]: 76 : document_.write_short_sector(sector_reader_, link);
341 : 76 : sector_reader_.offset(sector_reader_.offset() + document_.short_sector_size());
342 : : }
343 : : }
344 : : }
345 : : else
346 : : {
347 : 974 : const auto sector_index = position_ / document_.sector_size();
348 : 974 : document_.write_sector(sector_reader_, chain_[sector_index]);
349 : : }
350 : :
351 : 982 : position_ += written;
352 : 982 : entry_.size = std::max(entry_.size, static_cast<std::uint32_t>(position_));
353 : 982 : document_.write_directory();
354 : :
355 [ + ]: 982 : std::fill(current_sector_.begin(), current_sector_.end(), byte(0));
356 : 982 : setp(reinterpret_cast<char *>(current_sector_.data()),
357 : 982 : reinterpret_cast<char *>(current_sector_.data() + current_sector_.size()));
358 : :
359 : 982 : return 0;
360 : : }
361 : :
362 : 1956 : bool short_stream()
363 : : {
364 : 1956 : return entry_.size < document_.header_.threshold;
365 : : }
366 : :
367 : 974 : int_type overflow(int_type c = traits_type::eof()) override
368 : : {
369 : 974 : sync();
370 : :
371 [ - + ]: 974 : if (short_stream())
372 : : {
373 [ # ]:UBC 0 : auto next_sector = document_.allocate_short_sector();
374 : 0 : document_.ssat_[static_cast<std::size_t>(chain_.back())] = next_sector;
375 [ # ]: 0 : chain_.push_back(next_sector);
376 [ # ]: 0 : document_.write_ssat();
377 : : }
378 : : else
379 : : {
380 [ + ]:CBC 974 : auto next_sector = document_.allocate_sector();
381 : 974 : document_.sat_[static_cast<std::size_t>(chain_.back())] = next_sector;
382 [ + ]: 974 : chain_.push_back(next_sector);
383 [ + ]: 974 : document_.write_sat();
384 : : }
385 : :
386 : 974 : auto value = static_cast<std::uint8_t>(c);
387 : :
388 [ + - ]: 974 : if (c != traits_type::eof())
389 : : {
390 : 974 : current_sector_[position_ % current_sector_.size()] = value;
391 : : }
392 : :
393 : 974 : pbump(1);
394 : :
395 : 974 : return traits_type::to_int_type(static_cast<char>(value));
396 : : }
397 : :
398 : 4 : void convert_to_long_stream()
399 : : {
400 : 4 : sector_reader_.reset();
401 : :
402 : 4 : auto num_sectors = current_sector_.size() / document_.sector_size();
403 [ + ]: 4 : auto new_chain = document_.allocate_sectors(num_sectors);
404 : :
405 [ + + ]: 36 : for (auto link : new_chain)
406 : : {
407 [ + ]: 32 : document_.write_sector(sector_reader_, link);
408 : 32 : sector_reader_.offset(sector_reader_.offset() + document_.short_sector_size());
409 : : }
410 : :
411 [ + ]: 4 : current_sector_.resize(document_.sector_size(), 0);
412 [ + ]: 4 : std::fill(current_sector_.begin(), current_sector_.end(), byte(0));
413 : :
414 [ + - ]: 4 : if (entry_.start < 0)
415 : : {
416 : : // TODO: deallocate short sectors here
417 [ - + ]: 4 : if (document_.header_.num_short_sectors == 0)
418 : : {
419 :UBC 0 : document_.entries_[0].start = EndOfChain;
420 : : }
421 : : }
422 : :
423 [ + ]:CBC 4 : chain_ = new_chain;
424 : 4 : entry_.start = chain_.front();
425 [ + ]: 4 : document_.write_directory();
426 : 4 : }
427 : :
428 :UBC 0 : std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode) override
429 : : {
430 [ # # ]: 0 : if (way == std::ios_base::beg)
431 : : {
432 : 0 : position_ = 0;
433 : : }
434 [ # # ]: 0 : else if (way == std::ios_base::end)
435 : : {
436 : 0 : position_ = entry_.size;
437 : : }
438 : :
439 [ # # ]: 0 : if (off < 0)
440 : : {
441 [ # # ]: 0 : if (static_cast<std::size_t>(-off) > position_)
442 : : {
443 : 0 : position_ = 0;
444 : 0 : return static_cast<std::ptrdiff_t>(-1);
445 : : }
446 : : else
447 : : {
448 : 0 : position_ -= static_cast<std::size_t>(-off);
449 : : }
450 : : }
451 [ # # ]: 0 : else if (off > 0)
452 : : {
453 [ # # ]: 0 : if (static_cast<std::size_t>(off) + position_ > entry_.size)
454 : : {
455 : 0 : position_ = entry_.size;
456 : 0 : return static_cast<std::ptrdiff_t>(-1);
457 : : }
458 : : else
459 : : {
460 : 0 : position_ += static_cast<std::size_t>(off);
461 : : }
462 : : }
463 : :
464 : 0 : return static_cast<std::ptrdiff_t>(position_);
465 : : }
466 : :
467 : 0 : std::streampos seekpos(std::streampos sp, std::ios_base::openmode) override
468 : : {
469 [ # # ]: 0 : if (sp < 0)
470 : : {
471 : 0 : position_ = 0;
472 : : }
473 [ # # ]: 0 : else if (static_cast<std::size_t>(sp) > entry_.size)
474 : : {
475 : 0 : position_ = entry_.size;
476 : : }
477 : : else
478 : : {
479 : 0 : position_ = static_cast<std::size_t>(sp);
480 : : }
481 : :
482 : 0 : return static_cast<std::ptrdiff_t>(position_);
483 : : }
484 : :
485 : : private:
486 : : compound_document_entry &entry_;
487 : : compound_document &document_;
488 : : std::vector<byte> current_sector_;
489 : : binary_reader<byte> sector_reader_;
490 : : std::size_t position_;
491 : : sector_chain chain_;
492 : : };
493 : :
494 :CBC 16 : compound_document_ostreambuf::~compound_document_ostreambuf()
495 : : {
496 : 8 : sync();
497 : 16 : }
498 : :
499 : 4 : compound_document::compound_document(std::ostream &out)
500 : 4 : : out_(&out),
501 [ + ]: 4 : stream_in_(nullptr),
502 [ + ]: 8 : stream_out_(nullptr)
503 : : {
504 [ + ]: 4 : header_.msat.fill(FreeSector);
505 [ + ]: 4 : write_header();
506 [ + + ]: 4 : insert_entry("/Root Entry", compound_document_entry::entry_type::RootStorage);
507 : 4 : }
508 : :
509 : 21 : compound_document::compound_document(std::istream &in)
510 : 21 : : in_(&in),
511 [ + ]: 21 : stream_in_(nullptr),
512 [ + ]: 42 : stream_out_(nullptr)
513 : : {
514 [ + ]: 21 : read_header();
515 [ + ]: 21 : read_msat();
516 [ + ]: 21 : read_sat();
517 [ + ]: 21 : read_ssat();
518 [ + ]: 21 : read_directory();
519 : 21 : }
520 : :
521 : 25 : compound_document::~compound_document()
522 : : {
523 : 25 : close();
524 : 25 : }
525 : :
526 : 25 : void compound_document::close()
527 : : {
528 : 25 : stream_out_buffer_.reset(nullptr);
529 : 25 : }
530 : :
531 : 41284 : std::size_t compound_document::sector_size()
532 : : {
533 : 41284 : return static_cast<std::size_t>(1) << header_.sector_size_power;
534 : : }
535 : :
536 : 1138 : std::size_t compound_document::short_sector_size()
537 : : {
538 : 1138 : return static_cast<std::size_t>(1) << header_.short_sector_size_power;
539 : : }
540 : :
541 : 42 : std::istream &compound_document::open_read_stream(const std::string &name)
542 : : {
543 [ - + ]: 42 : if (!contains_entry(name, compound_document_entry::entry_type::UserStream))
544 : : {
545 [ # # ]:UBC 0 : throw xlnt::exception("not found");
546 : : }
547 : :
548 :CBC 42 : const auto entry_id = find_entry(name, compound_document_entry::entry_type::UserStream);
549 : 42 : const auto &entry = entries_.at(static_cast<std::size_t>(entry_id));
550 : :
551 [ + - - ]: 42 : stream_in_buffer_.reset(new compound_document_istreambuf(entry, *this));
552 : 42 : stream_in_.rdbuf(stream_in_buffer_.get());
553 : :
554 : 42 : return stream_in_;
555 : : }
556 : :
557 : 8 : std::ostream &compound_document::open_write_stream(const std::string &name)
558 : : {
559 : 8 : auto entry_id = contains_entry(name, compound_document_entry::entry_type::UserStream)
560 [ - + ]: 8 : ? find_entry(name, compound_document_entry::entry_type::UserStream)
561 : 8 : : insert_entry(name, compound_document_entry::entry_type::UserStream);
562 : 8 : auto &entry = entries_.at(static_cast<std::size_t>(entry_id));
563 : :
564 [ + - - ]: 8 : stream_out_buffer_.reset(new compound_document_ostreambuf(entry, *this));
565 : 8 : stream_out_.rdbuf(stream_out_buffer_.get());
566 : :
567 : 8 : return stream_out_;
568 : : }
569 : :
570 : : template <typename T>
571 : 10579 : void compound_document::write_sector(binary_reader<T> &reader, sector_id id)
572 : : {
573 [ + ]: 10579 : out_->seekp(static_cast<std::ptrdiff_t>(sector_data_start() + sector_size() * static_cast<std::size_t>(id)));
574 [ + ]: 10579 : out_->write(reinterpret_cast<const char *>(reader.data() + reader.offset()),
575 [ + ]: 10579 : static_cast<std::ptrdiff_t>(std::min(sector_size(), reader.bytes() - reader.offset())));
576 : 10579 : }
577 : :
578 : : template <typename T>
579 : 76 : void compound_document::write_short_sector(binary_reader<T> &reader, sector_id id)
580 : : {
581 [ + ]: 76 : auto chain = follow_chain(entries_[0].start, sat_);
582 : 76 : auto sector_id = chain[static_cast<std::size_t>(id) / (sector_size() / short_sector_size())];
583 : 76 : auto sector_offset = static_cast<std::size_t>(id) % (sector_size() / short_sector_size()) * short_sector_size();
584 [ + ]: 76 : out_->seekp(static_cast<std::ptrdiff_t>(sector_data_start() + sector_size() * static_cast<std::size_t>(sector_id) + sector_offset));
585 [ + ]: 76 : out_->write(reinterpret_cast<const char *>(reader.data() + reader.offset()),
586 [ + ]: 76 : static_cast<std::ptrdiff_t>(std::min(short_sector_size(), reader.bytes() - reader.offset())));
587 : 76 : }
588 : :
589 : : template <typename T>
590 : 2687 : void compound_document::read_sector(sector_id id, binary_writer<T> &writer)
591 : : {
592 [ + ]: 2687 : in_->seekg(static_cast<std::ptrdiff_t>(sector_data_start() + sector_size() * static_cast<std::size_t>(id)));
593 [ + ]: 2687 : std::vector<byte> sector(sector_size(), 0);
594 [ + ]: 2687 : in_->read(reinterpret_cast<char *>(sector.data()), static_cast<std::ptrdiff_t>(sector_size()));
595 [ + ]: 2687 : writer.append(sector);
596 : 2687 : }
597 : :
598 : : template <typename T>
599 : : void compound_document::read_sector_chain(sector_id start, binary_writer<T> &writer)
600 : : {
601 : : for (auto link : follow_chain(start, sat_))
602 : : {
603 : : read_sector(link, writer);
604 : : }
605 : : }
606 : :
607 : : template <typename T>
608 : : void compound_document::read_sector_chain(sector_id start, binary_writer<T> &writer, sector_id offset, std::size_t count)
609 : : {
610 : : auto chain = follow_chain(start, sat_);
611 : :
612 : : for (auto i = std::size_t(0); i < count; ++i)
613 : : {
614 : : read_sector(chain[offset + i], writer);
615 : : }
616 : : }
617 : :
618 : : template <typename T>
619 : 174 : void compound_document::read_short_sector(sector_id id, binary_writer<T> &writer)
620 : : {
621 [ + ]: 174 : const auto container_chain = follow_chain(entries_[0].start, sat_);
622 : 174 : auto container = std::vector<byte>();
623 : 174 : auto container_writer = binary_writer<byte>(container);
624 : :
625 [ + + ]: 702 : for (auto sector : container_chain)
626 : : {
627 [ + ]: 528 : read_sector(sector, container_writer);
628 : : }
629 : :
630 : 174 : auto container_reader = binary_reader<byte>(container);
631 : 174 : container_reader.offset(static_cast<std::size_t>(id) * short_sector_size());
632 : :
633 [ + ]: 174 : writer.append(container_reader, short_sector_size());
634 : 174 : }
635 : :
636 : : template <typename T>
637 : : void compound_document::read_short_sector_chain(sector_id start, binary_writer<T> &writer)
638 : : {
639 : : for (auto link : follow_chain(start, ssat_))
640 : : {
641 : : read_short_sector(link, writer);
642 : : }
643 : : }
644 : :
645 : : template <typename T>
646 : : void compound_document::read_short_sector_chain(sector_id start, binary_writer<T> &writer, sector_id offset, std::size_t count)
647 : : {
648 : : auto chain = follow_chain(start, ssat_);
649 : :
650 : : for (auto i = std::size_t(0); i < count; ++i)
651 : : {
652 : : read_short_sector(chain[offset + i], writer);
653 : : }
654 : : }
655 : :
656 : 1026 : sector_id compound_document::allocate_sector()
657 : : {
658 : 1026 : const auto sectors_per_sector = sector_size() / sizeof(sector_id);
659 [ + ]: 1026 : auto next_free_iter = std::find(sat_.begin(), sat_.end(), FreeSector);
660 : :
661 [ + + ]: 1026 : if (next_free_iter == sat_.end())
662 : : {
663 : 11 : auto next_msat_index = header_.num_msat_sectors;
664 : 11 : auto new_sat_sector_id = sector_id(sat_.size());
665 : :
666 [ + ]: 11 : msat_.push_back(new_sat_sector_id);
667 [ + ]: 11 : write_msat();
668 : :
669 : 11 : header_.msat[msat_.size() - 1] = new_sat_sector_id;
670 : 11 : ++header_.num_msat_sectors;
671 [ + ]: 11 : write_header();
672 : :
673 [ + ]: 11 : sat_.resize(sat_.size() + sectors_per_sector, FreeSector);
674 : 11 : sat_[static_cast<std::size_t>(new_sat_sector_id)] = SATSector;
675 : :
676 : 11 : auto sat_reader = binary_reader<sector_id>(sat_);
677 : 11 : sat_reader.offset(next_msat_index * sectors_per_sector);
678 [ + ]: 11 : write_sector(sat_reader, new_sat_sector_id);
679 : :
680 [ + ]: 11 : next_free_iter = std::find(sat_.begin(), sat_.end(), FreeSector);
681 : 11 : }
682 : :
683 : 1026 : auto next_free = sector_id(next_free_iter - sat_.begin());
684 : 1026 : sat_[static_cast<std::size_t>(next_free)] = EndOfChain;
685 : :
686 [ + ]: 1026 : write_sat();
687 : :
688 [ + ]: 1026 : auto empty_sector = std::vector<byte>(sector_size());
689 : 1026 : auto empty_sector_reader = binary_reader<byte>(empty_sector);
690 [ + ]: 1026 : write_sector(empty_sector_reader, next_free);
691 : :
692 : 1026 : return next_free;
693 : 1026 : }
694 : :
695 : 4 : sector_chain compound_document::allocate_sectors(std::size_t count)
696 : : {
697 [ - + ]: 4 : if (count == std::size_t(0)) return {};
698 : :
699 : 4 : auto chain = sector_chain();
700 [ + ]: 4 : auto current = allocate_sector();
701 : :
702 [ + + ]: 32 : for (auto i = std::size_t(1); i < count; ++i)
703 : : {
704 [ + ]: 28 : chain.push_back(current);
705 [ + ]: 28 : auto next = allocate_sector();
706 : 28 : sat_[static_cast<std::size_t>(current)] = next;
707 : 28 : current = next;
708 : : }
709 : :
710 [ + ]: 4 : chain.push_back(current);
711 [ + ]: 4 : write_sat();
712 : :
713 : 4 : return chain;
714 : 4 : }
715 : :
716 : 5200 : sector_chain compound_document::follow_chain(sector_id start, const sector_chain &table)
717 : : {
718 : 5200 : auto chain = sector_chain();
719 : 5200 : auto current = start;
720 : :
721 [ + + ]: 247196 : while (current >= 0)
722 : : {
723 [ + ]: 241996 : chain.push_back(current);
724 : 241996 : current = table[static_cast<std::size_t>(current)];
725 : : }
726 : :
727 : 5200 : return chain;
728 :UBC 0 : }
729 : :
730 :CBC 4 : sector_chain compound_document::allocate_short_sectors(std::size_t count)
731 : : {
732 [ - + ]: 4 : if (count == std::size_t(0)) return {};
733 : :
734 : 4 : auto chain = sector_chain();
735 [ + ]: 4 : auto current = allocate_short_sector();
736 : :
737 [ + + ]: 76 : for (auto i = std::size_t(1); i < count; ++i)
738 : : {
739 [ + ]: 72 : chain.push_back(current);
740 [ + ]: 72 : auto next = allocate_short_sector();
741 : 72 : ssat_[static_cast<std::size_t>(current)] = next;
742 : 72 : current = next;
743 : : }
744 : :
745 [ + ]: 4 : chain.push_back(current);
746 [ + ]: 4 : write_ssat();
747 : :
748 : 4 : return chain;
749 : 4 : }
750 : :
751 : 76 : sector_id compound_document::allocate_short_sector()
752 : : {
753 : 76 : const auto sectors_per_sector = sector_size() / sizeof(sector_id);
754 [ + ]: 76 : auto next_free_iter = std::find(ssat_.begin(), ssat_.end(), FreeSector);
755 : :
756 [ + + ]: 76 : if (next_free_iter == ssat_.end())
757 : : {
758 [ + ]: 4 : auto new_ssat_sector_id = allocate_sector();
759 : :
760 [ + - ]: 4 : if (header_.ssat_start < 0)
761 : : {
762 : 4 : header_.ssat_start = new_ssat_sector_id;
763 : : }
764 : : else
765 : : {
766 [ # ]:UBC 0 : auto ssat_chain = follow_chain(header_.ssat_start, sat_);
767 : 0 : sat_[static_cast<std::size_t>(ssat_chain.back())] = new_ssat_sector_id;
768 [ # ]: 0 : write_sat();
769 : 0 : }
770 : :
771 [ + ]:CBC 4 : write_header();
772 : :
773 : 4 : auto old_size = ssat_.size();
774 [ + ]: 4 : ssat_.resize(old_size + sectors_per_sector, FreeSector);
775 : :
776 : 4 : auto ssat_reader = binary_reader<sector_id>(ssat_);
777 : 4 : ssat_reader.offset(old_size / sectors_per_sector);
778 [ + ]: 4 : write_sector(ssat_reader, new_ssat_sector_id);
779 : :
780 [ + ]: 4 : next_free_iter = std::find(ssat_.begin(), ssat_.end(), FreeSector);
781 : 4 : }
782 : :
783 : 76 : ++header_.num_short_sectors;
784 [ + ]: 76 : write_header();
785 : :
786 : 76 : auto next_free = sector_id(next_free_iter - ssat_.begin());
787 : 76 : ssat_[static_cast<std::size_t>(next_free)] = EndOfChain;
788 : :
789 [ + ]: 76 : write_ssat();
790 : :
791 : 76 : const auto short_sectors_per_sector = sector_size() / short_sector_size();
792 : 76 : const auto required_container_sectors = static_cast<std::size_t>(next_free) / short_sectors_per_sector + std::size_t(1);
793 : :
794 [ + - ]: 76 : if (required_container_sectors > 0)
795 : : {
796 [ + + ]: 76 : if (entries_[0].start < 0)
797 : : {
798 [ + ]: 4 : entries_[0].start = allocate_sector();
799 [ + ]: 4 : write_entry(0);
800 : : }
801 : :
802 [ + ]: 76 : auto container_chain = follow_chain(entries_[0].start, sat_);
803 : :
804 [ + + ]: 76 : if (required_container_sectors > container_chain.size())
805 : : {
806 [ + ]: 8 : sat_[static_cast<std::size_t>(container_chain.back())] = allocate_sector();
807 [ + ]: 8 : write_sat();
808 : : }
809 : 76 : }
810 : :
811 : 76 : return next_free;
812 : : }
813 : :
814 : 12 : directory_id compound_document::next_empty_entry()
815 : : {
816 : 12 : auto entry_id = directory_id(0);
817 : :
818 [ + + ]: 24 : for (; entry_id < directory_id(entries_.size()); ++entry_id)
819 : : {
820 : 20 : auto &entry = entries_[static_cast<std::size_t>(entry_id)];
821 : :
822 [ + + ]: 20 : if (entry.type == compound_document_entry::entry_type::Empty)
823 : : {
824 : 8 : return entry_id;
825 : : }
826 : : }
827 : :
828 : : // entry_id is now equal to entries_.size()
829 : :
830 [ + - ]: 4 : if (header_.directory_start < 0)
831 : : {
832 : 4 : header_.directory_start = allocate_sector();
833 : : }
834 : : else
835 : : {
836 [ # ]:UBC 0 : auto directory_chain = follow_chain(header_.directory_start, sat_);
837 [ # ]: 0 : sat_[static_cast<std::size_t>(directory_chain.back())] = allocate_sector();
838 [ # ]: 0 : write_sat();
839 : 0 : }
840 : :
841 :CBC 4 : const auto entries_per_sector = sector_size()
842 : 4 : / sizeof(compound_document_entry);
843 : :
844 [ + + ]: 20 : for (auto i = std::size_t(0); i < entries_per_sector; ++i)
845 : : {
846 : 16 : auto empty_entry = compound_document_entry();
847 : 16 : empty_entry.type = compound_document_entry::entry_type::Empty;
848 [ + ]: 16 : entries_.push_back(empty_entry);
849 [ + ]: 16 : write_entry(entry_id + directory_id(i));
850 : : }
851 : :
852 : 4 : return entry_id;
853 : : }
854 : :
855 : 12 : directory_id compound_document::insert_entry(
856 : : const std::string &name,
857 : : compound_document_entry::entry_type type)
858 : : {
859 [ + ]: 12 : auto entry_id = next_empty_entry();
860 : 12 : auto &entry = entries_[static_cast<std::size_t>(entry_id)];
861 : :
862 : 12 : auto parent_id = directory_id(0);
863 [ + ]: 12 : auto split = split_path(name);
864 [ + ]: 12 : auto filename = split.back();
865 : 12 : split.pop_back();
866 : :
867 [ - + ]: 12 : if (split.size() > 1)
868 : : {
869 [ # # ]:UBC 0 : parent_id = find_entry(join_path(split), compound_document_entry::entry_type::UserStorage);
870 : :
871 [ # # ]: 0 : if (parent_id < 0)
872 : : {
873 [ # # ]: 0 : throw xlnt::exception("bad path");
874 : : }
875 : :
876 [ # ]: 0 : parent_storage_[entry_id] = parent_id;
877 : : }
878 : :
879 [ + ]:CBC 12 : entry.name(filename);
880 : 12 : entry.type = type;
881 : :
882 [ + ]: 12 : tree_insert(entry_id, parent_id);
883 [ + ]: 12 : write_directory();
884 : :
885 : 12 : return entry_id;
886 : 12 : }
887 : :
888 : 17510 : std::size_t compound_document::sector_data_start()
889 : : {
890 : 17510 : return sizeof(compound_document_header);
891 : : }
892 : :
893 : 50 : bool compound_document::contains_entry(const std::string &path,
894 : : compound_document_entry::entry_type type)
895 : : {
896 : 50 : return find_entry(path, type) >= 0;
897 : : }
898 : :
899 : 92 : directory_id compound_document::find_entry(const std::string &name,
900 : : compound_document_entry::entry_type type)
901 : : {
902 : 92 : if (type == compound_document_entry::entry_type::RootStorage
903 [ - + - - : 92 : && (name == "/" || name == "/Root Entry")) return 0;
- - - + ]
904 : :
905 : 92 : auto entry_id = directory_id(0);
906 : :
907 [ + + ]: 346 : for (auto &entry : entries_)
908 : : {
909 [ + + + + : 338 : if (entry.type == type && tree_path(entry_id) == name)
+ + + + +
- - ]
910 : : {
911 : 84 : return entry_id;
912 : : }
913 : :
914 : 254 : ++entry_id;
915 : : }
916 : :
917 : 8 : return End;
918 : : }
919 : :
920 :UBC 0 : void compound_document::print_directory()
921 : : {
922 : 0 : auto entry_id = directory_id(0);
923 : :
924 [ # # ]: 0 : for (auto &entry : entries_)
925 : : {
926 [ # # ]: 0 : if (entry.type == compound_document_entry::entry_type::UserStream)
927 : : {
928 [ # # # ]: 0 : std::cout << tree_path(entry_id) << std::endl;
929 : : }
930 : :
931 : 0 : ++entry_id;
932 : : }
933 : 0 : }
934 : :
935 :CBC 998 : void compound_document::write_directory()
936 : : {
937 [ + + ]: 4990 : for (auto entry_id = std::size_t(0); entry_id < entries_.size(); ++entry_id)
938 : : {
939 : 3992 : write_entry(directory_id(entry_id));
940 : : }
941 : 998 : }
942 : :
943 : 21 : void compound_document::read_directory()
944 : : {
945 : 21 : const auto entries_per_sector = sector_size() / sizeof(compound_document_entry);
946 [ + ]: 21 : const auto num_entries = follow_chain(header_.directory_start, sat_).size() * entries_per_sector;
947 : :
948 [ + + ]: 177 : for (auto entry_id = std::size_t(0); entry_id < num_entries; ++entry_id)
949 : : {
950 [ + ]: 156 : entries_.push_back(compound_document_entry());
951 [ + ]: 156 : read_entry(directory_id(entry_id));
952 : : }
953 : :
954 : 21 : auto stack = std::vector<directory_id>();
955 : 21 : auto storage_siblings = std::vector<directory_id>();
956 : 21 : auto stream_siblings = std::vector<directory_id>();
957 : :
958 : 21 : auto directory_stack = std::vector<directory_id>();
959 [ + ]: 21 : directory_stack.push_back(directory_id(0));
960 : :
961 [ + + ]: 78 : while (!directory_stack.empty())
962 : : {
963 : 57 : auto current_storage_id = directory_stack.back();
964 : 57 : directory_stack.pop_back();
965 : :
966 [ - + ]: 57 : if (tree_child(current_storage_id) < 0) continue;
967 : :
968 : 57 : auto storage_stack = std::vector<directory_id>();
969 : 57 : auto storage_root_id = tree_child(current_storage_id);
970 [ + ]: 57 : parent_[storage_root_id] = End;
971 [ + ]: 57 : storage_stack.push_back(storage_root_id);
972 : :
973 [ + + ]: 171 : while (!storage_stack.empty())
974 : : {
975 : 114 : auto current_entry_id = storage_stack.back();
976 : 114 : auto current_entry = entries_[static_cast<std::size_t>(current_entry_id)];
977 : 114 : storage_stack.pop_back();
978 : :
979 [ + ]: 114 : parent_storage_[current_entry_id] = current_storage_id;
980 : :
981 [ + + ]: 114 : if (current_entry.type == compound_document_entry::entry_type::UserStorage)
982 : : {
983 [ + ]: 36 : directory_stack.push_back(current_entry_id);
984 : : }
985 : :
986 [ + + ]: 114 : if (tree_left(current_entry_id) >= 0)
987 : : {
988 [ + ]: 18 : storage_stack.push_back(tree_left(current_entry_id));
989 [ + ]: 18 : tree_parent(tree_left(current_entry_id)) = current_entry_id;
990 : : }
991 : :
992 [ + + ]: 114 : if (tree_right(current_entry_id) >= 0)
993 : : {
994 [ + ]: 39 : storage_stack.push_back(tree_right(current_entry_id));
995 [ + ]: 39 : tree_parent(tree_right(current_entry_id)) = current_entry_id;
996 : : }
997 : : }
998 : 57 : }
999 : 21 : }
1000 : :
1001 : 12 : void compound_document::tree_insert(directory_id new_id, directory_id storage_id)
1002 : : {
1003 : : using entry_color = compound_document_entry::entry_color;
1004 : :
1005 : 12 : parent_storage_[new_id] = storage_id;
1006 : :
1007 : 12 : tree_left(new_id) = End;
1008 : 12 : tree_right(new_id) = End;
1009 : :
1010 [ + + ]: 12 : if (tree_root(new_id) == End)
1011 : : {
1012 [ + + ]: 8 : if (new_id != 0)
1013 : : {
1014 : 4 : tree_root(new_id) = new_id;
1015 : : }
1016 : :
1017 : 8 : tree_color(new_id) = entry_color::Black;
1018 : 8 : tree_parent(new_id) = End;
1019 : :
1020 : 8 : return;
1021 : : }
1022 : :
1023 : : // normal tree insert
1024 : : // (will probably unbalance the tree, fix after)
1025 : 4 : auto x = tree_root(new_id);
1026 : 4 : auto y = End;
1027 : :
1028 [ + + ]: 8 : while (x >= 0)
1029 : : {
1030 : 4 : y = x;
1031 : :
1032 [ + + + - : 4 : if (compare_keys(tree_key(new_id), tree_key(x)) > 0)
+ ]
1033 : : {
1034 :UBC 0 : x = tree_right(x);
1035 : : }
1036 : : else
1037 : : {
1038 :CBC 4 : x = tree_left(x);
1039 : : }
1040 : : }
1041 : :
1042 : 4 : tree_parent(new_id) = y;
1043 : :
1044 [ + + + - : 4 : if (compare_keys(tree_key(new_id), tree_key(y)) > 0)
+ ]
1045 : : {
1046 :UBC 0 : tree_right(y) = new_id;
1047 : : }
1048 : : else
1049 : : {
1050 :CBC 4 : tree_left(y) = new_id;
1051 : : }
1052 : :
1053 : 4 : tree_insert_fixup(new_id);
1054 : : }
1055 : :
1056 : 178 : std::string compound_document::tree_path(directory_id id)
1057 : : {
1058 [ + ]: 178 : auto storage_id = parent_storage_[id];
1059 : 178 : auto result = std::vector<std::string>();
1060 : :
1061 [ + + ]: 262 : while (storage_id > 0)
1062 : : {
1063 [ + ]: 84 : storage_id = parent_storage_[storage_id];
1064 [ + + ]: 84 : result.push_back(entries_[static_cast<std::size_t>(storage_id)].name());
1065 : : }
1066 : :
1067 [ + + + + ]: 356 : return "/" + join_path(result) + entries_[static_cast<std::size_t>(id)].name();
1068 : 178 : }
1069 : :
1070 :UBC 0 : void compound_document::tree_rotate_left(directory_id x)
1071 : : {
1072 : 0 : auto y = tree_right(x);
1073 : :
1074 : : // turn y's left subtree into x's right subtree
1075 : 0 : tree_right(x) = tree_left(y);
1076 : :
1077 [ # # ]: 0 : if (tree_left(y) != End)
1078 : : {
1079 : 0 : tree_parent(tree_left(y)) = x;
1080 : : }
1081 : :
1082 : : // link x's parent to y
1083 : 0 : tree_parent(y) = tree_parent(x);
1084 : :
1085 [ # # ]: 0 : if (tree_parent(x) == End)
1086 : : {
1087 : 0 : tree_root(x) = y;
1088 : : }
1089 [ # # ]: 0 : else if (x == tree_left(tree_parent(x)))
1090 : : {
1091 : 0 : tree_left(tree_parent(x)) = y;
1092 : : }
1093 : : else
1094 : : {
1095 : 0 : tree_right(tree_parent(x)) = y;
1096 : : }
1097 : :
1098 : : // put x on y's left
1099 : 0 : tree_left(y) = x;
1100 : 0 : tree_parent(x) = y;
1101 : 0 : }
1102 : :
1103 : 0 : void compound_document::tree_rotate_right(directory_id y)
1104 : : {
1105 : 0 : auto x = tree_left(y);
1106 : :
1107 : : // turn x's right subtree into y's left subtree
1108 : 0 : tree_left(y) = tree_right(x);
1109 : :
1110 [ # # ]: 0 : if (tree_right(x) != End)
1111 : : {
1112 : 0 : tree_parent(tree_right(x)) = y;
1113 : : }
1114 : :
1115 : : // link y's parent to x
1116 : 0 : tree_parent(x) = tree_parent(y);
1117 : :
1118 [ # # ]: 0 : if (tree_parent(y) == End)
1119 : : {
1120 : 0 : tree_root(y) = x;
1121 : : }
1122 [ # # ]: 0 : else if (y == tree_left(tree_parent(y)))
1123 : : {
1124 : 0 : tree_left(tree_parent(y)) = x;
1125 : : }
1126 : : else
1127 : : {
1128 : 0 : tree_right(tree_parent(y)) = x;
1129 : : }
1130 : :
1131 : : // put y on x's right
1132 : 0 : tree_right(x) = y;
1133 : 0 : tree_parent(y) = x;
1134 : 0 : }
1135 : :
1136 :CBC 4 : void compound_document::tree_insert_fixup(directory_id x)
1137 : : {
1138 : : using entry_color = compound_document_entry::entry_color;
1139 : :
1140 : 4 : tree_color(x) = entry_color::Red;
1141 : :
1142 [ + - - + : 4 : while (x != tree_root(x) && tree_color(tree_parent(x)) == entry_color::Red)
- + ]
1143 : : {
1144 [ # # ]:UBC 0 : if (tree_parent(x) == tree_left(tree_parent(tree_parent(x))))
1145 : : {
1146 : 0 : auto y = tree_right(tree_parent(tree_parent(x)));
1147 : :
1148 [ # # # # : 0 : if (y >= 0 && tree_color(y) == entry_color::Red)
# # ]
1149 : : {
1150 : : // case 1
1151 : 0 : tree_color(tree_parent(x)) = entry_color::Black;
1152 : 0 : tree_color(y) = entry_color::Black;
1153 : 0 : tree_color(tree_parent(tree_parent(x))) = entry_color::Red;
1154 : 0 : x = tree_parent(tree_parent(x));
1155 : : }
1156 : : else
1157 : : {
1158 [ # # ]: 0 : if (x == tree_right(tree_parent(x)))
1159 : : {
1160 : : // case 2
1161 : 0 : x = tree_parent(x);
1162 : 0 : tree_rotate_left(x);
1163 : : }
1164 : :
1165 : : // case 3
1166 : 0 : tree_color(tree_parent(x)) = entry_color::Black;
1167 : 0 : tree_color(tree_parent(tree_parent(x))) = entry_color::Red;
1168 : 0 : tree_rotate_right(tree_parent(tree_parent(x)));
1169 : : }
1170 : : }
1171 : : else // same as above with left and right switched
1172 : : {
1173 : 0 : auto y = tree_left(tree_parent(tree_parent(x)));
1174 : :
1175 [ # # # # : 0 : if (y >= 0 && tree_color(y) == entry_color::Red)
# # ]
1176 : : {
1177 : : //case 1
1178 : 0 : tree_color(tree_parent(x)) = entry_color::Black;
1179 : 0 : tree_color(y) = entry_color::Black;
1180 : 0 : tree_color(tree_parent(tree_parent(x))) = entry_color::Red;
1181 : 0 : x = tree_parent(tree_parent(x));
1182 : : }
1183 : : else
1184 : : {
1185 [ # # ]: 0 : if (x == tree_left(tree_parent(x)))
1186 : : {
1187 : : // case 2
1188 : 0 : x = tree_parent(x);
1189 : 0 : tree_rotate_right(x);
1190 : : }
1191 : :
1192 : : // case 3
1193 : 0 : tree_color(tree_parent(x)) = entry_color::Black;
1194 : 0 : tree_color(tree_parent(tree_parent(x))) = entry_color::Red;
1195 : 0 : tree_rotate_left(tree_parent(tree_parent(x)));
1196 : : }
1197 : : }
1198 : : }
1199 : :
1200 :CBC 4 : tree_color(tree_root(x)) = entry_color::Black;
1201 : 4 : }
1202 : :
1203 : 170 : directory_id &compound_document::tree_left(directory_id id)
1204 : : {
1205 : 170 : return entries_[static_cast<std::size_t>(id)].prev;
1206 : : }
1207 : :
1208 : 204 : directory_id &compound_document::tree_right(directory_id id)
1209 : : {
1210 : 204 : return entries_[static_cast<std::size_t>(id)].next;
1211 : : }
1212 : :
1213 : 73 : directory_id &compound_document::tree_parent(directory_id id)
1214 : : {
1215 : 73 : return parent_[id];
1216 : : }
1217 : :
1218 : 28 : directory_id &compound_document::tree_root(directory_id id)
1219 : : {
1220 : 28 : return tree_child(parent_storage_[id]);
1221 : : }
1222 : :
1223 : 142 : directory_id &compound_document::tree_child(directory_id id)
1224 : : {
1225 : 142 : return entries_[static_cast<std::size_t>(id)].child;
1226 : : }
1227 : :
1228 : 16 : std::string compound_document::tree_key(directory_id id)
1229 : : {
1230 : 16 : return entries_[static_cast<std::size_t>(id)].name();
1231 : : }
1232 : :
1233 : 20 : compound_document_entry::entry_color &compound_document::tree_color(directory_id id)
1234 : : {
1235 : 20 : return entries_[static_cast<std::size_t>(id)].color;
1236 : : }
1237 : :
1238 : 21 : void compound_document::read_header()
1239 : : {
1240 : 21 : in_->seekg(0, std::ios::beg);
1241 : 21 : in_->read(reinterpret_cast<char *>(&header_), sizeof(compound_document_header));
1242 : 21 : }
1243 : :
1244 : 21 : void compound_document::read_msat()
1245 : : {
1246 : 21 : msat_.clear();
1247 : :
1248 : 21 : auto msat_sector = header_.extra_msat_start;
1249 : 21 : auto msat_writer = binary_writer<sector_id>(msat_);
1250 : :
1251 [ + + ]: 69 : for (auto i = std::uint32_t(0); i < header_.num_msat_sectors; ++i)
1252 : : {
1253 [ + - ]: 48 : if (i < std::uint32_t(109))
1254 : : {
1255 [ + ]: 48 : msat_writer.write(header_.msat[i]);
1256 : : }
1257 : : else
1258 : : {
1259 [ # ]:UBC 0 : read_sector(msat_sector, msat_writer);
1260 : :
1261 : 0 : msat_sector = msat_.back();
1262 : 0 : msat_.pop_back();
1263 : : }
1264 : : }
1265 :CBC 21 : }
1266 : :
1267 : 21 : void compound_document::read_sat()
1268 : : {
1269 : 21 : sat_.clear();
1270 : 21 : auto sat_writer = binary_writer<sector_id>(sat_);
1271 : :
1272 [ + + ]: 69 : for (auto msat_sector : msat_)
1273 : : {
1274 [ + ]: 48 : read_sector(msat_sector, sat_writer);
1275 : : }
1276 : 21 : }
1277 : :
1278 : 21 : void compound_document::read_ssat()
1279 : : {
1280 : 21 : ssat_.clear();
1281 : 21 : auto ssat_writer = binary_writer<sector_id>(ssat_);
1282 : :
1283 [ + + + ]: 42 : for (auto ssat_sector : follow_chain(header_.ssat_start, sat_))
1284 : : {
1285 [ + ]: 21 : read_sector(ssat_sector, ssat_writer);
1286 : 21 : }
1287 : 21 : }
1288 : :
1289 : 156 : void compound_document::read_entry(directory_id id)
1290 : : {
1291 [ + ]: 156 : const auto directory_chain = follow_chain(header_.directory_start, sat_);
1292 : 156 : const auto entries_per_sector = sector_size() / sizeof(compound_document_entry);
1293 : 156 : const auto directory_sector = directory_chain[static_cast<std::size_t>(id) / entries_per_sector];
1294 : 156 : const auto offset = sector_size() * static_cast<std::size_t>(directory_sector)
1295 : 156 : + ((static_cast<std::size_t>(id) % entries_per_sector) * sizeof(compound_document_entry));
1296 : :
1297 [ + ]: 156 : in_->seekg(static_cast<std::ptrdiff_t>(sector_data_start() + offset), std::ios::beg);
1298 [ + ]: 156 : in_->read(reinterpret_cast<char *>(&entries_[static_cast<std::size_t>(id)]), sizeof(compound_document_entry));
1299 : 156 : }
1300 : :
1301 : 95 : void compound_document::write_header()
1302 : : {
1303 : 95 : out_->seekp(0, std::ios::beg);
1304 : 95 : out_->write(reinterpret_cast<char *>(&header_), sizeof(compound_document_header));
1305 : 95 : }
1306 : :
1307 : 11 : void compound_document::write_msat()
1308 : : {
1309 : 11 : auto msat_sector = header_.extra_msat_start;
1310 : :
1311 [ + + ]: 39 : for (auto i = std::uint32_t(0); i < header_.num_msat_sectors; ++i)
1312 : : {
1313 [ + - ]: 28 : if (i < std::uint32_t(109))
1314 : : {
1315 : 28 : header_.msat[i] = msat_[i];
1316 : : }
1317 : : else
1318 : : {
1319 :UBC 0 : auto sector = std::vector<sector_id>();
1320 : 0 : auto sector_writer = binary_writer<sector_id>(sector);
1321 : :
1322 [ # ]: 0 : read_sector(msat_sector, sector_writer);
1323 : :
1324 : 0 : msat_sector = sector.back();
1325 : 0 : sector.pop_back();
1326 : :
1327 [ # # ]: 0 : std::copy(sector.begin(), sector.end(), std::back_inserter(msat_));
1328 : 0 : }
1329 : : }
1330 :CBC 11 : }
1331 : :
1332 : 2012 : void compound_document::write_sat()
1333 : : {
1334 : 2012 : auto sector_reader = binary_reader<sector_id>(sat_);
1335 : :
1336 [ + + ]: 10464 : for (auto sat_sector : msat_)
1337 : : {
1338 [ + ]: 8452 : write_sector(sector_reader, sat_sector);
1339 : : }
1340 : 2012 : }
1341 : :
1342 : 80 : void compound_document::write_ssat()
1343 : : {
1344 : 80 : auto sector_reader = binary_reader<sector_id>(ssat_);
1345 : :
1346 [ + + + ]: 160 : for (auto ssat_sector : follow_chain(header_.ssat_start, sat_))
1347 : : {
1348 [ + ]: 80 : write_sector(sector_reader, ssat_sector);
1349 : 80 : }
1350 : 80 : }
1351 : :
1352 : 4012 : void compound_document::write_entry(directory_id id)
1353 : : {
1354 [ + ]: 4012 : const auto directory_chain = follow_chain(header_.directory_start, sat_);
1355 : 4012 : const auto entries_per_sector = sector_size() / sizeof(compound_document_entry);
1356 : 4012 : const auto directory_sector = directory_chain[static_cast<std::size_t>(id) / entries_per_sector];
1357 : 4012 : const auto offset = sector_data_start() + sector_size() * static_cast<std::size_t>(directory_sector)
1358 : 4012 : + ((static_cast<std::size_t>(id) % entries_per_sector) * sizeof(compound_document_entry));
1359 : :
1360 [ + ]: 4012 : out_->seekp(static_cast<std::ptrdiff_t>(offset), std::ios::beg);
1361 [ + ]: 4012 : out_->write(reinterpret_cast<char *>(&entries_[static_cast<std::size_t>(id)]), sizeof(compound_document_entry));
1362 : 4012 : }
1363 : :
1364 : : } // namespace detail
1365 : : } // namespace xlnt
|