CMake/Source/CPack/WiX/cmWIXSourceWriter.cxx
Nils Gladitz 7b390f75e8 CPackWiX: add CPack component support
Creates a hierarchy of WiX features from CPack components and component groups.
Switch to the FeatureTree UI in case components have been defined.
Handles the component REQUIRE and HIDDEN options
and the component group EXPANDED option.
2013-11-26 22:15:57 +01:00

218 lines
4.5 KiB
C++

/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2012 Kitware, Inc.
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmWIXSourceWriter.h"
#include <CPack/cmCPackGenerator.h>
#include <windows.h>
cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger,
const std::string& filename,
bool isIncludeFile):
Logger(logger),
file(filename.c_str()),
state(DEFAULT),
sourceFilename(filename)
{
WriteXMLDeclaration();
if(isIncludeFile)
{
BeginElement("Include");
}
else
{
BeginElement("Wix");
}
AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi");
}
cmWIXSourceWriter::~cmWIXSourceWriter()
{
if(elements.size() > 1)
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
elements.size() - 1 << " WiX elements were still open when closing '" <<
sourceFilename << "'" << std::endl);
return;
}
EndElement(elements.back());
}
void cmWIXSourceWriter::BeginElement(const std::string& name)
{
if(state == BEGIN)
{
file << ">";
}
file << "\n";
Indent(elements.size());
file << "<" << name;
elements.push_back(name);
state = BEGIN;
}
void cmWIXSourceWriter::EndElement(std::string const& name)
{
if(elements.empty())
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
"can not end WiX element with no open elements in '" <<
sourceFilename << "'" << std::endl);
return;
}
if(elements.back() != name)
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
"WiX element <" << elements.back() <<
"> can not be closed by </" << name << "> in '" <<
sourceFilename << "'" << std::endl);
return;
}
if(state == DEFAULT)
{
file << "\n";
Indent(elements.size()-1);
file << "</" << elements.back() << ">";
}
else
{
file << "/>";
}
elements.pop_back();
state = DEFAULT;
}
void cmWIXSourceWriter::AddProcessingInstruction(
const std::string& target, const std::string& content)
{
if(state == BEGIN)
{
file << ">";
}
file << "\n";
Indent(elements.size());
file << "<?" << target << " " << content << "?>";
state = DEFAULT;
}
void cmWIXSourceWriter::AddAttribute(
const std::string& key, const std::string& value)
{
std::string utf8 = WindowsCodepageToUtf8(value);
file << " " << key << "=\"" << EscapeAttributeValue(utf8) << '"';
}
void cmWIXSourceWriter::AddAttributeUnlessEmpty(
const std::string& key, const std::string& value)
{
if(value.size())
{
AddAttribute(key, value);
}
}
std::string cmWIXSourceWriter::WindowsCodepageToUtf8(const std::string& value)
{
if(value.empty())
{
return std::string();
}
int characterCount = MultiByteToWideChar(
CP_ACP, 0, value.c_str(), static_cast<int>(value.size()), 0, 0);
if(characterCount == 0)
{
return std::string();
}
std::vector<wchar_t> utf16(characterCount);
MultiByteToWideChar(
CP_ACP, 0, value.c_str(), static_cast<int>(value.size()),
&utf16[0], static_cast<int>(utf16.size()));
int utf8ByteCount = WideCharToMultiByte(
CP_UTF8, 0, &utf16[0], static_cast<int>(utf16.size()), 0, 0, 0, 0);
if(utf8ByteCount == 0)
{
return std::string();
}
std::vector<char> utf8(utf8ByteCount);
WideCharToMultiByte(CP_UTF8, 0, &utf16[0], static_cast<int>(utf16.size()),
&utf8[0], static_cast<int>(utf8.size()), 0, 0);
return std::string(&utf8[0], utf8.size());
}
void cmWIXSourceWriter::WriteXMLDeclaration()
{
file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
}
void cmWIXSourceWriter::Indent(size_t count)
{
for(size_t i = 0; i < count; ++i)
{
file << " ";
}
}
std::string cmWIXSourceWriter::EscapeAttributeValue(
const std::string& value)
{
std::string result;
result.reserve(value.size());
char c = 0;
for(size_t i = 0 ; i < value.size(); ++i)
{
c = value[i];
switch(c)
{
case '<':
result += "&lt;";
break;
case '>':
result += "&gt;";
break;
case '&':
result +="&amp;";
break;
case '"':
result += "&quot;";
break;
default:
result += c;
break;
}
}
return result;
}