CMake/Source/CPack/WiX/cmWIXSourceWriter.cxx

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;
}