cmWIXSourceWriter.cxx 4.5 KB

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