209 lines
4.3 KiB
C++
209 lines
4.3 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) << '"';
|
|
}
|
|
|
|
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 += "<";
|
|
break;
|
|
case '>':
|
|
result += ">";
|
|
break;
|
|
case '&':
|
|
result +="&";
|
|
break;
|
|
case '"':
|
|
result += """;
|
|
break;
|
|
default:
|
|
result += c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|