cmWIXSourceWriter.cxx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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 "cmStandardIncludes.h"
  11. #include "cmWIXSourceWriter.h"
  12. #include <CPack/cmCPackGenerator.h>
  13. #include <windows.h>
  14. cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger,
  15. std::string const& filename,
  16. bool isIncludeFile):
  17. Logger(logger),
  18. File(filename.c_str()),
  19. State(DEFAULT),
  20. SourceFilename(filename)
  21. {
  22. WriteXMLDeclaration();
  23. if(isIncludeFile)
  24. {
  25. BeginElement("Include");
  26. }
  27. else
  28. {
  29. BeginElement("Wix");
  30. }
  31. AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi");
  32. }
  33. cmWIXSourceWriter::~cmWIXSourceWriter()
  34. {
  35. if(Elements.size() > 1)
  36. {
  37. cmCPackLogger(cmCPackLog::LOG_ERROR,
  38. Elements.size() - 1 << " WiX elements were still open when closing '" <<
  39. SourceFilename << "'" << std::endl);
  40. return;
  41. }
  42. EndElement(Elements.back());
  43. }
  44. void cmWIXSourceWriter::BeginElement(std::string const& name)
  45. {
  46. if(State == BEGIN)
  47. {
  48. File << ">";
  49. }
  50. File << "\n";
  51. Indent(Elements.size());
  52. File << "<" << name;
  53. Elements.push_back(name);
  54. State = BEGIN;
  55. }
  56. void cmWIXSourceWriter::EndElement(std::string const& name)
  57. {
  58. if(Elements.empty())
  59. {
  60. cmCPackLogger(cmCPackLog::LOG_ERROR,
  61. "can not end WiX element with no open elements in '" <<
  62. SourceFilename << "'" << std::endl);
  63. return;
  64. }
  65. if(Elements.back() != name)
  66. {
  67. cmCPackLogger(cmCPackLog::LOG_ERROR,
  68. "WiX element <" << Elements.back() <<
  69. "> can not be closed by </" << name << "> in '" <<
  70. SourceFilename << "'" << std::endl);
  71. return;
  72. }
  73. if(State == DEFAULT)
  74. {
  75. File << "\n";
  76. Indent(Elements.size()-1);
  77. File << "</" << Elements.back() << ">";
  78. }
  79. else
  80. {
  81. File << "/>";
  82. }
  83. Elements.pop_back();
  84. State = DEFAULT;
  85. }
  86. void cmWIXSourceWriter::AddProcessingInstruction(
  87. std::string const& target, std::string const& content)
  88. {
  89. if(State == BEGIN)
  90. {
  91. File << ">";
  92. }
  93. File << "\n";
  94. Indent(Elements.size());
  95. File << "<?" << target << " " << content << "?>";
  96. State = DEFAULT;
  97. }
  98. void cmWIXSourceWriter::AddAttribute(
  99. std::string const& key, std::string const& value)
  100. {
  101. std::string utf8 = CMakeEncodingToUtf8(value);
  102. File << " " << key << "=\"" << EscapeAttributeValue(utf8) << '"';
  103. }
  104. void cmWIXSourceWriter::AddAttributeUnlessEmpty(
  105. std::string const& key, std::string const& value)
  106. {
  107. if(!value.empty())
  108. {
  109. AddAttribute(key, value);
  110. }
  111. }
  112. std::string cmWIXSourceWriter::CMakeEncodingToUtf8(std::string const& value)
  113. {
  114. #ifdef CMAKE_ENCODING_UTF8
  115. return value;
  116. #else
  117. if(value.empty())
  118. {
  119. return std::string();
  120. }
  121. int characterCount = MultiByteToWideChar(
  122. CP_ACP, 0, value.c_str(), static_cast<int>(value.size()), 0, 0);
  123. if(characterCount == 0)
  124. {
  125. return std::string();
  126. }
  127. std::vector<wchar_t> utf16(characterCount);
  128. MultiByteToWideChar(
  129. 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. {
  135. return std::string();
  136. }
  137. std::vector<char> utf8(utf8ByteCount);
  138. WideCharToMultiByte(CP_UTF8, 0, &utf16[0], static_cast<int>(utf16.size()),
  139. &utf8[0], static_cast<int>(utf8.size()), 0, 0);
  140. return std::string(&utf8[0], utf8.size());
  141. #endif
  142. }
  143. void cmWIXSourceWriter::WriteXMLDeclaration()
  144. {
  145. File << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
  146. }
  147. void cmWIXSourceWriter::Indent(size_t count)
  148. {
  149. for(size_t i = 0; i < count; ++i)
  150. {
  151. File << " ";
  152. }
  153. }
  154. std::string cmWIXSourceWriter::EscapeAttributeValue(
  155. std::string const& value)
  156. {
  157. std::string result;
  158. result.reserve(value.size());
  159. char c = 0;
  160. for(size_t i = 0 ; i < value.size(); ++i)
  161. {
  162. c = value[i];
  163. switch(c)
  164. {
  165. case '<':
  166. result += "&lt;";
  167. break;
  168. case '>':
  169. result += "&gt;";
  170. break;
  171. case '&':
  172. result +="&amp;";
  173. break;
  174. case '"':
  175. result += "&quot;";
  176. break;
  177. default:
  178. result += c;
  179. break;
  180. }
  181. }
  182. return result;
  183. }