manifest.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // Copyright (c) 2014-2021 Thomas Fussell
  2. // Copyright (c) 2010-2015 openpyxl
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE
  21. //
  22. // @license: http://www.opensource.org/licenses/mit-license.php
  23. // @author: see AUTHORS file
  24. #include <algorithm>
  25. #include <unordered_set>
  26. #include <xlnt/packaging/manifest.hpp>
  27. #include <xlnt/utils/exceptions.hpp>
  28. namespace xlnt {
  29. void manifest::clear()
  30. {
  31. default_content_types_.clear();
  32. override_content_types_.clear();
  33. relationships_.clear();
  34. }
  35. path manifest::canonicalize(const std::vector<xlnt::relationship> &rels) const
  36. {
  37. xlnt::path relative;
  38. for (auto component : rels)
  39. {
  40. if (component == rels.back())
  41. {
  42. relative = relative.append(component.target().path());
  43. }
  44. else
  45. {
  46. relative = relative.append(component.target().path().parent());
  47. }
  48. }
  49. std::vector<std::string> absolute_parts;
  50. for (const auto &component : relative.split())
  51. {
  52. if (component == ".") continue;
  53. if (component == "..")
  54. {
  55. absolute_parts.pop_back();
  56. continue;
  57. }
  58. absolute_parts.push_back(component);
  59. }
  60. xlnt::path result;
  61. for (const auto &component : absolute_parts)
  62. {
  63. result = result.append(component);
  64. }
  65. return result;
  66. }
  67. bool manifest::has_relationship(const path &path, relationship_type type) const
  68. {
  69. auto rels = relationships_.find(path);
  70. if (rels == relationships_.end())
  71. {
  72. return false;
  73. }
  74. 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; });
  75. }
  76. bool manifest::has_relationship(const path &path, const std::string &rel_id) const
  77. {
  78. auto rels = relationships_.find(path);
  79. if (rels == relationships_.end())
  80. {
  81. return false;
  82. }
  83. return rels->second.find(rel_id) != rels->second.end();
  84. }
  85. relationship manifest::relationship(const path &part, relationship_type type) const
  86. {
  87. if (relationships_.find(part) == relationships_.end()) throw key_not_found();
  88. for (const auto &rel : relationships_.at(part))
  89. {
  90. if (rel.second.type() == type) return rel.second;
  91. }
  92. throw key_not_found();
  93. }
  94. std::vector<xlnt::relationship> manifest::relationships(const path &part, relationship_type type) const
  95. {
  96. std::vector<xlnt::relationship> matches;
  97. if (has_relationship(part, type))
  98. {
  99. for (const auto &rel : relationships_.at(part))
  100. {
  101. if (rel.second.type() == type)
  102. {
  103. matches.push_back(rel.second);
  104. }
  105. }
  106. }
  107. return matches;
  108. }
  109. std::string manifest::content_type(const path &part) const
  110. {
  111. auto absolute = part.resolve(path("/"));
  112. if (has_override_type(absolute))
  113. {
  114. return override_type(absolute);
  115. }
  116. if (has_default_type(part.extension()))
  117. {
  118. return default_type(part.extension());
  119. }
  120. throw key_not_found();
  121. }
  122. void manifest::register_override_type(const path &part, const std::string &content_type)
  123. {
  124. override_content_types_[part] = content_type;
  125. }
  126. void manifest::unregister_override_type(const path &part)
  127. {
  128. override_content_types_.erase(part);
  129. }
  130. std::vector<path> manifest::parts_with_overriden_types() const
  131. {
  132. std::vector<path> overriden;
  133. for (const auto &part : override_content_types_)
  134. {
  135. overriden.push_back(part.first);
  136. }
  137. return overriden;
  138. }
  139. std::vector<relationship> manifest::relationships(const path &part) const
  140. {
  141. if (relationships_.find(part) == relationships_.end())
  142. {
  143. return {};
  144. }
  145. std::vector<xlnt::relationship> relationships;
  146. for (const auto &rel : relationships_.at(part))
  147. {
  148. relationships.push_back(rel.second);
  149. }
  150. return relationships;
  151. }
  152. relationship manifest::relationship(const path &part, const std::string &rel_id) const
  153. {
  154. if (relationships_.find(part) == relationships_.end())
  155. {
  156. throw key_not_found();
  157. }
  158. for (const auto &rel : relationships_.at(part))
  159. {
  160. if (rel.second.id() == rel_id)
  161. {
  162. return rel.second;
  163. }
  164. }
  165. throw key_not_found();
  166. }
  167. std::vector<path> manifest::parts() const
  168. {
  169. std::unordered_set<path> parts;
  170. for (const auto &part_rels : relationships_)
  171. {
  172. parts.insert(part_rels.first);
  173. for (const auto &rel : part_rels.second)
  174. {
  175. if (rel.second.target_mode() == target_mode::internal)
  176. {
  177. parts.insert(rel.second.target().path());
  178. }
  179. }
  180. }
  181. return std::vector<path>(parts.begin(), parts.end());
  182. }
  183. std::string manifest::register_relationship(const uri &source,
  184. relationship_type type, const uri &target, target_mode mode)
  185. {
  186. xlnt::relationship rel(next_relationship_id(source.path()), type, source, target, mode);
  187. return register_relationship(rel);
  188. }
  189. std::string manifest::register_relationship(const class relationship &rel)
  190. {
  191. relationships_[rel.source().path()][rel.id()] = rel;
  192. return rel.id();
  193. }
  194. std::unordered_map<std::string, std::string> manifest::unregister_relationship(const uri &source, const std::string &rel_id)
  195. {
  196. // This shouldn't happen, but just in case...
  197. if (rel_id.substr(0, 3) != "rId" || rel_id.size() < 4)
  198. {
  199. throw xlnt::invalid_parameter();
  200. }
  201. std::unordered_map<std::string, std::string> id_map;
  202. auto rel_index = static_cast<std::size_t>(std::stoull(rel_id.substr(3)));
  203. auto &part_rels = relationships_.at(source.path());
  204. for (auto i = rel_index; i <= part_rels.size() + 1; ++i)
  205. {
  206. auto old_id = "rId" + std::to_string(i);
  207. // Don't re-add the relationship to be deleted
  208. if (i > rel_index)
  209. {
  210. // Shift all relationships with IDs greater than the deleted one
  211. // down by one (e.g. rId7->rId6).
  212. auto new_id = "rId" + std::to_string(i - 1);
  213. const auto &old_rel = part_rels.at(old_id);
  214. register_relationship(xlnt::relationship(new_id, old_rel.type(),
  215. old_rel.source(), old_rel.target(), old_rel.target_mode()));
  216. id_map[old_id] = new_id;
  217. }
  218. part_rels.erase(old_id);
  219. }
  220. return id_map;
  221. }
  222. bool manifest::has_default_type(const std::string &extension) const
  223. {
  224. return default_content_types_.find(extension) != default_content_types_.end();
  225. }
  226. std::vector<std::string> manifest::extensions_with_default_types() const
  227. {
  228. std::vector<std::string> extensions;
  229. for (const auto &extension_type_pair : default_content_types_)
  230. {
  231. extensions.push_back(extension_type_pair.first);
  232. }
  233. return extensions;
  234. }
  235. std::string manifest::default_type(const std::string &extension) const
  236. {
  237. if (default_content_types_.find(extension) == default_content_types_.end())
  238. {
  239. throw key_not_found();
  240. }
  241. return default_content_types_.at(extension);
  242. }
  243. void manifest::register_default_type(const std::string &extension, const std::string &content_type)
  244. {
  245. default_content_types_[extension] = content_type;
  246. }
  247. void manifest::unregister_default_type(const std::string &extension)
  248. {
  249. default_content_types_.erase(extension);
  250. }
  251. std::string manifest::next_relationship_id(const path &part) const
  252. {
  253. if (relationships_.find(part) == relationships_.end()) return "rId1";
  254. std::size_t index = 1;
  255. const auto &part_rels = relationships_.at(part);
  256. while (part_rels.find("rId" + std::to_string(index)) != part_rels.end())
  257. {
  258. ++index;
  259. }
  260. return "rId" + std::to_string(index);
  261. }
  262. bool manifest::has_override_type(const xlnt::path &part) const
  263. {
  264. return override_content_types_.find(part) != override_content_types_.end();
  265. }
  266. std::string manifest::override_type(const xlnt::path &part) const
  267. {
  268. if (!has_override_type(part))
  269. {
  270. throw key_not_found();
  271. }
  272. return override_content_types_.at(part);
  273. }
  274. bool manifest::operator==(const manifest &other) const
  275. {
  276. return default_content_types_ == other.default_content_types_
  277. && override_content_types_ == other.override_content_types_
  278. && relationships_ == other.relationships_;
  279. }
  280. } // namespace xlnt