cmWIXSourceWriter.cxx 5.7 KB

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