blob: 751f7dc3a36be33205c50d7d441aaad2943fa8e3 [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 "cmWIXRichTextFormatWriter.h"
#include "cmVersion.h"
cmWIXRichTextFormatWriter::cmWIXRichTextFormatWriter(
std::string const& filename)
: File(filename.c_str(), std::ios::binary)
{
StartGroup();
WriteHeader();
WriteDocumentPrefix();
}
cmWIXRichTextFormatWriter::~cmWIXRichTextFormatWriter()
{
EndGroup();
/* I haven't seen this in the RTF spec but
* wordpad terminates its RTF like this */
File << "\r\n";
File.put(0);
}
void cmWIXRichTextFormatWriter::AddText(std::string const& text)
{
using rtf_byte_t = unsigned char;
for (size_t i = 0; i < text.size(); ++i) {
rtf_byte_t c = rtf_byte_t(text[i]);
switch (c) {
case '\\':
File << "\\\\";
break;
case '{':
File << "\\{";
break;
case '}':
File << "\\}";
break;
case '\n':
File << "\\par\r\n";
break;
case '\r':
continue;
default: {
if (c <= 0x7F) {
File << c;
} else {
if (c <= 0xC0) {
EmitInvalidCodepoint(c);
} else if (c < 0xE0 && i + 1 < text.size()) {
EmitUnicodeCodepoint((text[i + 1] & 0x3F) | ((c & 0x1F) << 6));
i += 1;
} else if (c < 0xF0 && i + 2 < text.size()) {
EmitUnicodeCodepoint((text[i + 2] & 0x3F) |
((text[i + 1] & 0x3F) << 6) |
((c & 0xF) << 12));
i += 2;
} else if (c < 0xF8 && i + 3 < text.size()) {
EmitUnicodeCodepoint(
(text[i + 3] & 0x3F) | ((text[i + 2] & 0x3F) << 6) |
((text[i + 1] & 0x3F) << 12) | ((c & 0x7) << 18));
i += 3;
} else {
EmitInvalidCodepoint(c);
}
}
} break;
}
}
}
void cmWIXRichTextFormatWriter::WriteHeader()
{
ControlWord("rtf1");
ControlWord("ansi");
ControlWord("ansicpg1252");
ControlWord("deff0");
ControlWord("deflang1031");
WriteFontTable();
WriteColorTable();
WriteGenerator();
}
void cmWIXRichTextFormatWriter::WriteFontTable()
{
StartGroup();
ControlWord("fonttbl");
StartGroup();
ControlWord("f0");
ControlWord("fswiss");
ControlWord("fcharset0 Arial;");
EndGroup();
EndGroup();
}
void cmWIXRichTextFormatWriter::WriteColorTable()
{
StartGroup();
ControlWord("colortbl ;");
ControlWord("red255");
ControlWord("green0");
ControlWord("blue0;");
ControlWord("red0");
ControlWord("green255");
ControlWord("blue0;");
ControlWord("red0");
ControlWord("green0");
ControlWord("blue255;");
EndGroup();
}
void cmWIXRichTextFormatWriter::WriteGenerator()
{
StartGroup();
NewControlWord("generator");
File << " CPack WiX Generator (" << cmVersion::GetCMakeVersion() << ");";
EndGroup();
}
void cmWIXRichTextFormatWriter::WriteDocumentPrefix()
{
ControlWord("viewkind4");
ControlWord("uc1");
ControlWord("pard");
ControlWord("f0");
ControlWord("fs20");
}
void cmWIXRichTextFormatWriter::ControlWord(std::string const& keyword)
{
File << "\\" << keyword;
}
void cmWIXRichTextFormatWriter::NewControlWord(std::string const& keyword)
{
File << "\\*\\" << keyword;
}
void cmWIXRichTextFormatWriter::StartGroup()
{
File.put('{');
}
void cmWIXRichTextFormatWriter::EndGroup()
{
File.put('}');
}
void cmWIXRichTextFormatWriter::EmitUnicodeCodepoint(int c)
{
// Do not emit byte order mark (BOM)
if (c == 0xFEFF) {
return;
} else if (c <= 0xFFFF) {
EmitUnicodeSurrogate(c);
} else {
c -= 0x10000;
EmitUnicodeSurrogate(((c >> 10) & 0x3FF) + 0xD800);
EmitUnicodeSurrogate((c & 0x3FF) + 0xDC00);
}
}
void cmWIXRichTextFormatWriter::EmitUnicodeSurrogate(int c)
{
ControlWord("u");
if (c <= 32767) {
File << c;
} else {
File << (c - 65536);
}
File << "?";
}
void cmWIXRichTextFormatWriter::EmitInvalidCodepoint(int c)
{
ControlWord("cf1 ");
File << "[INVALID-BYTE-" << int(c) << "]";
ControlWord("cf0 ");
}