blob: 6adf80bac212a31bf8307fa622a11c95ec240b4f [file] [log] [blame]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmWIXSourceWriter.h"
#include "cmCPackGenerator.h"
#include "cmUuid.h"
#include <windows.h>
cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger,
std::string const& filename,
GuidType componentGuidType,
RootElementType rootElementType)
: Logger(logger)
, File(filename.c_str())
, State(DEFAULT)
, SourceFilename(filename)
, ComponentGuidType(componentGuidType)
{
WriteXMLDeclaration();
if (rootElementType == INCLUDE_ELEMENT_ROOT) {
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(std::string const& 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::AddTextNode(std::string const& text)
{
if (State == BEGIN) {
File << ">";
}
if (Elements.empty()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"can not add text without open WiX element in '"
<< SourceFilename << "'" << std::endl);
return;
}
File << this->EscapeAttributeValue(text);
State = DEFAULT;
}
void cmWIXSourceWriter::AddProcessingInstruction(std::string const& target,
std::string const& content)
{
if (State == BEGIN) {
File << ">";
}
File << "\n";
Indent(Elements.size());
File << "<?" << target << " " << content << "?>";
State = DEFAULT;
}
void cmWIXSourceWriter::AddAttribute(std::string const& key,
std::string const& value)
{
File << " " << key << "=\"" << EscapeAttributeValue(value) << '"';
}
void cmWIXSourceWriter::AddAttributeUnlessEmpty(std::string const& key,
std::string const& value)
{
if (!value.empty()) {
AddAttribute(key, value);
}
}
std::string cmWIXSourceWriter::CreateGuidFromComponentId(
std::string const& componentId)
{
std::string guid = "*";
if (this->ComponentGuidType == CMAKE_GENERATED_GUID) {
std::string md5 = cmSystemTools::ComputeStringMD5(componentId);
cmUuid uuid;
std::vector<unsigned char> ns;
guid = uuid.FromMd5(ns, md5);
}
return guid;
}
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(std::string const& value)
{
std::string result;
result.reserve(value.size());
for (char c : value) {
switch (c) {
case '<':
result += "&lt;";
break;
case '>':
result += "&gt;";
break;
case '&':
result += "&amp;";
break;
case '"':
result += "&quot;";
break;
default:
result += c;
break;
}
}
return result;
}