differential code coverage report with master
Current view: top level - source/packaging - manifest.cpp (source / functions) Coverage Total Hit UBC CBC
Current: coverage.info Lines: 84.0 % 156 131 25 131
Current Date: 2025-12-15 23:01:28 Functions: 85.2 % 27 23 4 23
Baseline: coverage_master.info Branches: 84.6 % 175 148 54 296
Baseline Date: 2025-12-15 23:01:27

             Branch data    TLA  Line data    Source code
       1                 :                : // Copyright (c) 2014-2022 Thomas Fussell
       2                 :                : // Copyright (c) 2010-2015 openpyxl
       3                 :                : // Copyright (c) 2024-2025 xlnt-community
       4                 :                : //
       5                 :                : // Permission is hereby granted, free of charge, to any person obtaining a copy
       6                 :                : // of this software and associated documentation files (the "Software"), to deal
       7                 :                : // in the Software without restriction, including without limitation the rights
       8                 :                : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9                 :                : // copies of the Software, and to permit persons to whom the Software is
      10                 :                : // furnished to do so, subject to the following conditions:
      11                 :                : //
      12                 :                : // The above copyright notice and this permission notice shall be included in
      13                 :                : // all copies or substantial portions of the Software.
      14                 :                : //
      15                 :                : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16                 :                : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17                 :                : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18                 :                : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19                 :                : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20                 :                : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21                 :                : // THE SOFTWARE
      22                 :                : //
      23                 :                : // @license: http://www.opensource.org/licenses/mit-license.php
      24                 :                : // @author: see AUTHORS file
      25                 :                : 
      26                 :                : #include <algorithm>
      27                 :                : #include <unordered_set>
      28                 :                : 
      29                 :                : #include <xlnt/packaging/manifest.hpp>
      30                 :                : #include <xlnt/utils/exceptions.hpp>
      31                 :                : #include <detail/serialization/parsers.hpp>
      32                 :                : 
      33                 :                : namespace xlnt {
      34                 :                : 
      35                 :UBC           0 : void manifest::clear()
      36                 :                : {
      37                 :              0 :     default_content_types_.clear();
      38                 :              0 :     override_content_types_.clear();
      39                 :              0 :     relationships_.clear();
      40                 :              0 : }
      41                 :                : 
      42                 :CBC        2499 : path manifest::canonicalize(const std::vector<xlnt::relationship> &rels) const
      43                 :                : {
      44            [ + ]:           2499 :     xlnt::path relative;
      45                 :                : 
      46         [ +  + ]:           5558 :     for (const auto& component : rels)
      47                 :                :     {
      48      [ +  +  + ]:           3059 :         if (component == rels.back())
      49                 :                :         {
      50      [ +  +  + ]:           2499 :             relative = relative.append(component.target().path());
      51                 :                :         }
      52                 :                :         else
      53                 :                :         {
      54   [ +  +  +  + ]:            560 :             relative = relative.append(component.target().path().parent());
      55                 :                :         }
      56                 :                :     }
      57                 :                : 
      58                 :           2499 :     std::vector<std::string> absolute_parts;
      59                 :                : 
      60      [ +  +  + ]:           7900 :     for (const auto &component : relative.split())
      61                 :                :     {
      62      [ +  -  + ]:           5401 :         if (component == ".") continue;
      63                 :                : 
      64      [ +  +  + ]:           5401 :         if (component == "..")
      65                 :                :         {
      66         [ +  + ]:             45 :             if (absolute_parts.empty())
      67                 :                :             {
      68                 :                : #ifdef THROW_ON_INVALID_XML
      69                 :                :                 auto relativestr = relative.string();
      70                 :                :                 throw invalid_file("invalid relation: " + relativestr);
      71                 :                : #endif
      72                 :                :             }
      73                 :                :             else
      74                 :                :             {
      75                 :             42 :                 absolute_parts.pop_back();
      76                 :                :             }
      77                 :                : 
      78                 :             45 :             continue;
      79                 :                :         }
      80                 :                : 
      81            [ + ]:           5356 :         absolute_parts.push_back(component);
      82                 :           2499 :     }
      83                 :                : 
      84            [ + ]:           2499 :     xlnt::path result;
      85                 :                : 
      86         [ +  + ]:           7813 :     for (const auto &component : absolute_parts)
      87                 :                :     {
      88            [ + ]:           5314 :         result = result.append(component);
      89                 :                :     }
      90                 :                : 
      91                 :           2499 :     return result;
      92                 :           2499 : }
      93                 :                : 
      94                 :           8761 : bool manifest::has_relationship(const path &path, relationship_type type) const
      95                 :                : {
      96            [ + ]:           8761 :     auto rels = relationships_.find(path);
      97         [ +  + ]:           8761 :     if (rels == relationships_.end())
      98                 :                :     {
      99                 :            752 :         return false;
     100                 :                :     }
     101            [ + ]:          21091 :     return rels->second.end() != std::find_if(rels->second.begin(), rels->second.end(), [type](const std::pair<std::string, xlnt::relationship> &rel) { return rel.second.type() == type; });
     102                 :                : }
     103                 :                : 
     104                 :UBC           0 : bool manifest::has_relationship(const path &path, const std::string &rel_id) const
     105                 :                : {
     106            [ # ]:              0 :     auto rels = relationships_.find(path);
     107         [ #  # ]:              0 :     if (rels == relationships_.end())
     108                 :                :     {
     109                 :              0 :         return false;
     110                 :                :     }
     111            [ # ]:              0 :     return rels->second.find(rel_id) != rels->second.end();
     112                 :                : }
     113                 :                : 
     114                 :CBC        3137 : relationship manifest::relationship(const path &part, relationship_type type) const
     115                 :                : {
     116   [ +  -  +  - ]:           3137 :     if (relationships_.find(part) == relationships_.end()) throw key_not_found();
     117                 :                : 
     118      [ +  +  - ]:          10266 :     for (const auto &rel : relationships_.at(part))
     119                 :                :     {
     120   [ +  +  +  + ]:          10266 :         if (rel.second.type() == type) return rel.second;
     121                 :                :     }
     122                 :                : 
     123            [ # ]:UBC           0 :     throw key_not_found();
     124                 :                : }
     125                 :                : 
     126                 :CBC         268 : std::vector<xlnt::relationship> manifest::relationships(const path &part, relationship_type type) const
     127                 :                : {
     128                 :            268 :     std::vector<xlnt::relationship> matches;
     129                 :                : 
     130      [ +  +  + ]:            268 :     if (has_relationship(part, type))
     131                 :                :     {
     132      [ +  +  + ]:            751 :         for (const auto &rel : relationships_.at(part))
     133                 :                :         {
     134      [ +  +  + ]:            598 :             if (rel.second.type() == type)
     135                 :                :             {
     136            [ + ]:            247 :                 matches.push_back(rel.second);
     137                 :                :             }
     138                 :                :         }
     139                 :                :     }
     140                 :                : 
     141                 :            268 :     return matches;
     142                 :UBC           0 : }
     143                 :                : 
     144                 :CBC         331 : std::string manifest::content_type(const path &part) const
     145                 :                : {
     146      [ +  +  + ]:            331 :     auto absolute = part.resolve(path("/"));
     147                 :                : 
     148      [ +  +  + ]:            331 :     if (has_override_type(absolute))
     149                 :                :     {
     150            [ + ]:            251 :         return override_type(absolute);
     151                 :                :     }
     152                 :                : 
     153   [ +  +  +  - ]:             80 :     if (has_default_type(part.extension()))
     154                 :                :     {
     155         [ +  + ]:             80 :         return default_type(part.extension());
     156                 :                :     }
     157                 :                : 
     158            [ # ]:UBC           0 :     throw key_not_found();
     159                 :CBC         331 : }
     160                 :                : 
     161                 :           2343 : void manifest::register_override_type(const path &part, const std::string &content_type)
     162                 :                : {
     163                 :           2343 :     override_content_types_[part] = content_type;
     164                 :           2343 : }
     165                 :                : 
     166                 :             10 : void manifest::unregister_override_type(const path &part)
     167                 :                : {
     168                 :             10 :     override_content_types_.erase(part);
     169                 :             10 : }
     170                 :                : 
     171                 :             44 : std::vector<path> manifest::parts_with_overriden_types() const
     172                 :                : {
     173                 :             44 :     std::vector<path> overriden;
     174                 :                : 
     175         [ +  + ]:            357 :     for (const auto &part : override_content_types_)
     176                 :                :     {
     177            [ + ]:            313 :         overriden.push_back(part.first);
     178                 :                :     }
     179                 :                : 
     180                 :             44 :     return overriden;
     181                 :UBC           0 : }
     182                 :                : 
     183                 :CBC         844 : std::vector<relationship> manifest::relationships(const path &part) const
     184                 :                : {
     185      [ +  +  + ]:            844 :     if (relationships_.find(part) == relationships_.end())
     186                 :                :     {
     187                 :            504 :         return {};
     188                 :                :     }
     189                 :                : 
     190                 :            340 :     std::vector<xlnt::relationship> relationships;
     191                 :                : 
     192      [ +  +  + ]:           1594 :     for (const auto &rel : relationships_.at(part))
     193                 :                :     {
     194            [ + ]:           1254 :         relationships.push_back(rel.second);
     195                 :                :     }
     196                 :                : 
     197                 :            340 :     return relationships;
     198                 :            340 : }
     199                 :                : 
     200                 :            284 : relationship manifest::relationship(const path &part, const std::string &rel_id) const
     201                 :                : {
     202      [ +  -  + ]:            284 :     if (relationships_.find(part) == relationships_.end())
     203                 :                :     {
     204            [ # ]:UBC           0 :         throw key_not_found();
     205                 :                :     }
     206                 :                : 
     207      [ +  +  - ]:CBC        1080 :     for (const auto &rel : relationships_.at(part))
     208                 :                :     {
     209      [ +  +  + ]:           1080 :         if (rel.second.id() == rel_id)
     210                 :                :         {
     211            [ + ]:            284 :             return rel.second;
     212                 :                :         }
     213                 :                :     }
     214                 :                : 
     215            [ # ]:UBC           0 :     throw key_not_found();
     216                 :                : }
     217                 :                : 
     218                 :CBC          22 : std::vector<path> manifest::parts() const
     219                 :                : {
     220                 :             22 :     std::unordered_set<path> parts;
     221                 :                : 
     222         [ +  + ]:             74 :     for (const auto &part_rels : relationships_)
     223                 :                :     {
     224            [ + ]:             52 :         parts.insert(part_rels.first);
     225                 :                : 
     226         [ +  + ]:            254 :         for (const auto &rel : part_rels.second)
     227                 :                :         {
     228      [ +  +  + ]:            202 :             if (rel.second.target_mode() == target_mode::internal)
     229                 :                :             {
     230      [ +  +  + ]:            186 :                 parts.insert(rel.second.target().path());
     231                 :                :             }
     232                 :                :         }
     233                 :                :     }
     234                 :                : 
     235            [ + ]:             44 :     return std::vector<path>(parts.begin(), parts.end());
     236                 :             22 : }
     237                 :                : 
     238                 :           1900 : std::string manifest::register_relationship(const uri &source,
     239                 :                :     relationship_type type, const uri &target, target_mode mode)
     240                 :                : {
     241      [ +  +  + ]:           1900 :     xlnt::relationship rel(next_relationship_id(source.path()), type, source, target, mode);
     242            [ + ]:           3800 :     return register_relationship(rel);
     243                 :           1900 : }
     244                 :                : 
     245                 :           3177 : std::string manifest::register_relationship(const class relationship &rel)
     246                 :                : {
     247                 :           3177 :     relationships_[rel.source().path()][rel.id()] = rel;
     248                 :           3177 :     return rel.id();
     249                 :                : }
     250                 :                : 
     251                 :            215 : std::unordered_map<std::string, std::string> manifest::unregister_relationship(const uri &source, const std::string &rel_id)
     252                 :                : {
     253                 :                :     // This shouldn't happen, but just in case...
     254   [ +  +  +  -  :            215 :     if (rel_id.substr(0, 3) != "rId" || rel_id.size() < 4)
          -  +  +  -  -  
                +  -  - ]
     255                 :                :     {
     256            [ # ]:UBC           0 :         throw xlnt::invalid_parameter();
     257                 :                :     }
     258                 :                : 
     259                 :CBC         215 :     std::unordered_map<std::string, std::string> id_map;
     260                 :            215 :     size_t rel_index = 0;
     261         [ +  + ]:            215 :     detail::parse(rel_id.substr(3), rel_index);
     262         [ +  + ]:            215 :     auto &part_rels = relationships_.at(source.path());
     263                 :                : 
     264         [ +  + ]:            644 :     for (auto i = rel_index; i <= part_rels.size() + 1; ++i)
     265                 :                :     {
     266         [ +  + ]:            429 :         auto old_id = "rId" + std::to_string(i);
     267                 :                : 
     268                 :                :         // Don't re-add the relationship to be deleted
     269         [ +  + ]:            429 :         if (i > rel_index)
     270                 :                :         {
     271                 :                :             // Shift all relationships with IDs greater than the deleted one
     272                 :                :             // down by one (e.g. rId7->rId6).
     273         [ +  + ]:            278 :             auto new_id = "rId" + std::to_string(i - 1);
     274            [ + ]:            278 :             const auto &old_rel = part_rels.at(old_id);
     275            [ + ]:            278 :             register_relationship(xlnt::relationship(new_id, old_rel.type(),
     276   [ +  +  +  +  :            278 :                 old_rel.source(), old_rel.target(), old_rel.target_mode()));
                      + ]
     277         [ +  + ]:            278 :             id_map[old_id] = new_id;
     278                 :            278 :         }
     279                 :                : 
     280            [ + ]:            429 :         part_rels.erase(old_id);
     281                 :            429 :     }
     282                 :                : 
     283                 :            215 :     return id_map;
     284                 :UBC           0 : }
     285                 :                : 
     286                 :CBC          81 : bool manifest::has_default_type(const std::string &extension) const
     287                 :                : {
     288            [ + ]:             81 :     return default_content_types_.find(extension) != default_content_types_.end();
     289                 :                : }
     290                 :                : 
     291                 :             44 : std::vector<std::string> manifest::extensions_with_default_types() const
     292                 :                : {
     293                 :             44 :     std::vector<std::string> extensions;
     294                 :                : 
     295         [ +  + ]:            174 :     for (const auto &extension_type_pair : default_content_types_)
     296                 :                :     {
     297            [ + ]:            130 :         extensions.push_back(extension_type_pair.first);
     298                 :                :     }
     299                 :                : 
     300                 :             44 :     return extensions;
     301                 :UBC           0 : }
     302                 :                : 
     303                 :CBC         211 : std::string manifest::default_type(const std::string &extension) const
     304                 :                : {
     305      [ +  +  + ]:            211 :     if (default_content_types_.find(extension) == default_content_types_.end())
     306                 :                :     {
     307            [ + ]:              1 :         throw key_not_found();
     308                 :                :     }
     309                 :                : 
     310                 :            210 :     return default_content_types_.at(extension);
     311                 :                : }
     312                 :                : 
     313                 :           1014 : void manifest::register_default_type(const std::string &extension, const std::string &content_type)
     314                 :                : {
     315                 :           1014 :     default_content_types_[extension] = content_type;
     316                 :           1014 : }
     317                 :                : 
     318                 :UBC           0 : void manifest::unregister_default_type(const std::string &extension)
     319                 :                : {
     320                 :              0 :     default_content_types_.erase(extension);
     321                 :              0 : }
     322                 :                : 
     323                 :CBC        1900 : std::string manifest::next_relationship_id(const path &part) const
     324                 :                : {
     325   [ +  +  +  + ]:           2932 :     if (relationships_.find(part) == relationships_.end()) return "rId1";
     326                 :                : 
     327                 :           1384 :     std::size_t index = 1;
     328                 :           1384 :     const auto &part_rels = relationships_.at(part);
     329                 :                : 
     330   [ +  +  +  +  :           4018 :     while (part_rels.find("rId" + std::to_string(index)) != part_rels.end())
                      + ]
     331                 :                :     {
     332                 :           2634 :         ++index;
     333                 :                :     }
     334                 :                : 
     335         [ +  + ]:           1384 :     return "rId" + std::to_string(index);
     336                 :                : }
     337                 :                : 
     338                 :            899 : bool manifest::has_override_type(const xlnt::path &part) const
     339                 :                : {
     340            [ + ]:            899 :     return override_content_types_.find(part) != override_content_types_.end();
     341                 :                : }
     342                 :                : 
     343                 :            564 : std::string manifest::override_type(const xlnt::path &part) const
     344                 :                : {
     345         [ -  + ]:            564 :     if (!has_override_type(part))
     346                 :                :     {
     347            [ # ]:UBC           0 :         throw key_not_found();
     348                 :                :     }
     349                 :                : 
     350                 :CBC         564 :     return override_content_types_.at(part);
     351                 :                : }
     352                 :                : 
     353                 :             14 : bool manifest::operator==(const manifest &other) const
     354                 :                : {
     355                 :             14 :     return default_content_types_ == other.default_content_types_
     356         [ +  - ]:             14 :         && override_content_types_ == other.override_content_types_
     357   [ +  -  +  - ]:             28 :         && relationships_ == other.relationships_;
     358                 :                : }
     359                 :                : 
     360                 :UBC           0 : bool manifest::operator!=(const manifest &other) const
     361                 :                : {
     362                 :              0 :     return !(*this == other);
     363                 :                : }
     364                 :                : 
     365                 :                : } // namespace xlnt
        

Generated by: LCOV version 2.3.1-beta