differential code coverage report with master
Current view: top level - source/detail/cryptography - compound_document.cpp (source / functions) Coverage Total Hit UBC CBC
Current: coverage.info Lines: 76.6 % 640 490 150 490
Current Date: 2025-12-15 23:01:28 Functions: 87.5 % 72 63 9 63
Baseline: coverage_master.info Branches: 68.2 % 400 273 254 546
Baseline Date: 2025-12-15 23:01:27

             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
        

Generated by: LCOV version 2.3.1-beta