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
|