cmWIXSourceWriter.cxx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmWIXSourceWriter.h"
  4. #include <windows.h>
  5. #include "cmCPackGenerator.h"
  6. #include "cmCryptoHash.h"
  7. #include "cmUuid.h"
  8. cmWIXSourceWriter::cmWIXSourceWriter(unsigned long wixVersion,
  9. cmCPackLog* logger,
  10. std::string const& filename,
  11. GuidType componentGuidType,
  12. RootElementType rootElementType)
  13. : WixVersion(wixVersion)
  14. , Logger(logger)
  15. , File(filename.c_str())
  16. , State(DEFAULT)
  17. , SourceFilename(filename)
  18. , ComponentGuidType(componentGuidType)
  19. {
  20. WriteXMLDeclaration();
  21. if (rootElementType == INCLUDE_ELEMENT_ROOT) {
  22. BeginElement("Include");
  23. } else {
  24. BeginElement("Wix");
  25. }
  26. if (this->WixVersion >= 4) {
  27. AddAttribute("xmlns", "http://wixtoolset.org/schemas/v4/wxs");
  28. } else {
  29. AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi");
  30. }
  31. }
  32. cmWIXSourceWriter::~cmWIXSourceWriter()
  33. {
  34. if (Elements.size() > 1) {
  35. cmCPackLogger(cmCPackLog::LOG_ERROR,
  36. Elements.size() - 1
  37. << " WiX elements were still open when closing '"
  38. << SourceFilename << '\'' << std::endl);
  39. return;
  40. }
  41. EndElement(Elements.back());
  42. }
  43. void cmWIXSourceWriter::BeginElement_StandardDirectory()
  44. {
  45. if (this->WixVersion >= 4) {
  46. BeginElement("StandardDirectory");
  47. } else {
  48. BeginElement("Directory");
  49. }
  50. }
  51. void cmWIXSourceWriter::EndElement_StandardDirectory()
  52. {
  53. if (this->WixVersion >= 4) {
  54. EndElement("StandardDirectory");
  55. } else {
  56. EndElement("Directory");
  57. }
  58. }
  59. void cmWIXSourceWriter::BeginElement(std::string const& name)
  60. {
  61. if (State == BEGIN) {
  62. File << '>';
  63. }
  64. File << '\n';
  65. Indent(Elements.size());
  66. File << '<' << name;
  67. Elements.push_back(name);
  68. State = BEGIN;
  69. }
  70. void cmWIXSourceWriter::EndElement(std::string const& name)
  71. {
  72. if (Elements.empty()) {
  73. cmCPackLogger(cmCPackLog::LOG_ERROR,
  74. "can not end WiX element with no open elements in '"
  75. << SourceFilename << '\'' << std::endl);
  76. return;
  77. }
  78. if (Elements.back() != name) {
  79. cmCPackLogger(cmCPackLog::LOG_ERROR,
  80. "WiX element <"
  81. << Elements.back() << "> can not be closed by </" << name
  82. << "> in '" << SourceFilename << '\'' << std::endl);
  83. return;
  84. }
  85. if (State == DEFAULT) {
  86. File << '\n';
  87. Indent(Elements.size() - 1);
  88. File << "</" << Elements.back() << '>';
  89. } else {
  90. File << "/>";
  91. }
  92. Elements.pop_back();
  93. State = DEFAULT;
  94. }
  95. void cmWIXSourceWriter::AddTextNode(std::string const& text)
  96. {
  97. if (State == BEGIN) {
  98. File << '>';
  99. }
  100. if (Elements.empty()) {
  101. cmCPackLogger(cmCPackLog::LOG_ERROR,
  102. "can not add text without open WiX element in '"
  103. << SourceFilename << '\'' << std::endl);
  104. return;
  105. }
  106. File << cmWIXSourceWriter::EscapeAttributeValue(text);
  107. State = DEFAULT;
  108. }
  109. void cmWIXSourceWriter::AddProcessingInstruction(std::string const& target,
  110. std::string const& content)
  111. {
  112. if (State == BEGIN) {
  113. File << '>';
  114. }
  115. File << '\n';
  116. Indent(Elements.size());
  117. File << "<?" << target << ' ' << content << "?>";
  118. State = DEFAULT;
  119. }
  120. void cmWIXSourceWriter::AddAttribute(std::string const& key,
  121. std::string const& value)
  122. {
  123. File << ' ' << key << "=\"" << EscapeAttributeValue(value) << '"';
  124. }
  125. void cmWIXSourceWriter::AddAttributeUnlessEmpty(std::string const& key,
  126. std::string const& value)
  127. {
  128. if (!value.empty()) {
  129. AddAttribute(key, value);
  130. }
  131. }
  132. std::string cmWIXSourceWriter::CreateGuidFromComponentId(
  133. std::string const& componentId)
  134. {
  135. std::string guid = "*";
  136. if (this->ComponentGuidType == CMAKE_GENERATED_GUID) {
  137. cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
  138. std::string md5 = hasher.HashString(componentId);
  139. cmUuid uuid;
  140. std::vector<unsigned char> ns;
  141. guid = uuid.FromMd5(ns, md5);
  142. }
  143. return guid;
  144. }
  145. void cmWIXSourceWriter::WriteXMLDeclaration()
  146. {
  147. File << R"(<?xml version="1.0" encoding="UTF-8"?>)" << std::endl;
  148. }
  149. void cmWIXSourceWriter::Indent(size_t count)
  150. {
  151. for (size_t i = 0; i < count; ++i) {
  152. File << " ";
  153. }
  154. }
  155. std::string cmWIXSourceWriter::EscapeAttributeValue(std::string const& value)
  156. {
  157. std::string result;
  158. result.reserve(value.size());
  159. for (char c : value) {
  160. switch (c) {
  161. case '<':
  162. result += "&lt;";
  163. break;
  164. case '>':
  165. result += "&gt;";
  166. break;
  167. case '&':
  168. result += "&amp;";
  169. break;
  170. case '"':
  171. result += "&quot;";
  172. break;
  173. default:
  174. result += c;
  175. break;
  176. }
  177. }
  178. return result;
  179. }