summaryrefslogtreecommitdiffstats
path: root/writerfilter/source/rtftok
diff options
context:
space:
mode:
Diffstat (limited to 'writerfilter/source/rtftok')
-rw-r--r--writerfilter/source/rtftok/README12
-rw-r--r--writerfilter/source/rtftok/rtfcharsets.cxx64
-rw-r--r--writerfilter/source/rtftok/rtfcharsets.hxx37
-rw-r--r--writerfilter/source/rtftok/rtfcontrolwords.cxx1900
-rw-r--r--writerfilter/source/rtftok/rtfcontrolwords.hxx2049
-rw-r--r--writerfilter/source/rtftok/rtfdispatchdestination.cxx684
-rw-r--r--writerfilter/source/rtftok/rtfdispatchflag.cxx1258
-rw-r--r--writerfilter/source/rtftok/rtfdispatchsymbol.cxx442
-rw-r--r--writerfilter/source/rtftok/rtfdispatchvalue.cxx1832
-rw-r--r--writerfilter/source/rtftok/rtfdocumentfactory.cxx28
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.cxx3992
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.hxx994
-rw-r--r--writerfilter/source/rtftok/rtffly.hxx138
-rw-r--r--writerfilter/source/rtftok/rtflistener.hxx69
-rw-r--r--writerfilter/source/rtftok/rtflookahead.cxx101
-rw-r--r--writerfilter/source/rtftok/rtflookahead.hxx57
-rw-r--r--writerfilter/source/rtftok/rtfreferenceproperties.cxx40
-rw-r--r--writerfilter/source/rtftok/rtfreferenceproperties.hxx33
-rw-r--r--writerfilter/source/rtftok/rtfreferencetable.cxx29
-rw-r--r--writerfilter/source/rtftok/rtfreferencetable.hxx32
-rw-r--r--writerfilter/source/rtftok/rtfsdrimport.cxx1182
-rw-r--r--writerfilter/source/rtftok/rtfsdrimport.hxx103
-rw-r--r--writerfilter/source/rtftok/rtfskipdestination.cxx42
-rw-r--r--writerfilter/source/rtftok/rtfskipdestination.hxx33
-rw-r--r--writerfilter/source/rtftok/rtfsprm.cxx476
-rw-r--r--writerfilter/source/rtftok/rtfsprm.hxx101
-rw-r--r--writerfilter/source/rtftok/rtftokenizer.cxx329
-rw-r--r--writerfilter/source/rtftok/rtftokenizer.hxx72
-rw-r--r--writerfilter/source/rtftok/rtfvalue.cxx222
-rw-r--r--writerfilter/source/rtftok/rtfvalue.hxx85
30 files changed, 16436 insertions, 0 deletions
diff --git a/writerfilter/source/rtftok/README b/writerfilter/source/rtftok/README
new file mode 100644
index 000000000..4adbb7563
--- /dev/null
+++ b/writerfilter/source/rtftok/README
@@ -0,0 +1,12 @@
+= Writerfilter-based RTF tokenizer
+
+== Mathematics
+
+At the time of writing, all control words understood by SmOoxmlImport are
+imported. To view the current status:
+
+----
+grep M_TOKEN starmath/source/ooxmlimport.cxx |sed 's/.*\(M_TOKEN(\) /\1/;s/ ).*/)/'|sort -u > ~/math-import-list
+grep '[^_]M_TOKEN' writerfilter/source/rtftok/rtfdocumentimpl.cxx |sed 's/.*\(M_TOKEN(\)/\1/;s/).*/)/'|sort -u > ~/wf-export-list
+diff -u ~/math-import-list ~/wf-export-list |grep ^-M_TOKEN
+----
diff --git a/writerfilter/source/rtftok/rtfcharsets.cxx b/writerfilter/source/rtftok/rtfcharsets.cxx
new file mode 100644
index 000000000..14d27b5f2
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcharsets.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfcharsets.hxx"
+#include <array>
+#include <rtl/textenc.h>
+
+namespace writerfilter::rtftok
+{
+// See RTF spec v1.9.1, page 19
+RTFEncoding const aRTFEncodings[] = {
+ // charset codepage Windows / Mac name
+ { 0, 1252 }, // ANSI
+ { 1, 0 }, // Default
+ { 2, 42 }, // Symbol
+ { 77, 10000 }, // Mac Roman
+ { 78, 10001 }, // Mac Shift Jis
+ { 79, 10003 }, // Mac Hangul
+ { 80, 10008 }, // Mac GB2312
+ { 81, 10002 }, // Mac Big5
+ { 83, 10005 }, // Mac Herbrew
+ { 84, 10004 }, // Mac Arabic
+ { 85, 10006 }, // Mac Greek
+ { 86, 10081 }, // Mac Turkish
+ { 87, 10021 }, // Mac Thai
+ { 88, 10029 }, // Mac East Europe
+ { 89, 10007 }, // Mac Russian
+ { 128, 932 }, // Shift JIS
+ { 129, 949 }, // Hangul
+ { 130, 1361 }, // Johab
+ { 134, 936 }, // GB2312
+ { 136, 950 }, // Big5
+ { 161, 1253 }, // Greek
+ { 162, 1254 }, // Turkish
+ { 163, 1258 }, // Vietnamese
+ { 177, 1255 }, // Herbrew
+ { 178, 1256 }, // Arabic
+ { 186, 1257 }, // Baltic
+ { 204, 1251 }, // Russian
+ { 222, 874 }, // Thai
+ { 238, 1250 }, // Eastern European
+ { 254, 437 }, // PC 437
+ { 255, 850 }, // OEM
+};
+
+int nRTFEncodings = std::size(aRTFEncodings);
+
+RTFFontNameSuffix const aRTFFontNameSuffixes[] = {
+ { "Baltic", RTL_TEXTENCODING_MS_1257 }, { "CE", RTL_TEXTENCODING_MS_1250 },
+ { "Cyr", RTL_TEXTENCODING_MS_1251 }, { "Greek", RTL_TEXTENCODING_MS_1253 },
+ { "Tur", RTL_TEXTENCODING_MS_1254 }, { "(Hebrew)", RTL_TEXTENCODING_MS_1255 },
+ { "(Arabic)", RTL_TEXTENCODING_MS_1256 }, { "(Vietnamese)", RTL_TEXTENCODING_MS_1258 },
+ { "", RTL_TEXTENCODING_DONTKNOW } // End of array
+};
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcharsets.hxx b/writerfilter/source/rtftok/rtfcharsets.hxx
new file mode 100644
index 000000000..826dea271
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcharsets.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+/// RTF legacy charsets
+struct RTFEncoding
+{
+ int charset;
+ int codepage;
+};
+extern RTFEncoding const aRTFEncodings[];
+extern int nRTFEncodings;
+
+/// Font name can contain special suffixes used
+/// to determine encoding for given font table entry
+/// For example "Arial CE" is "Arial" with CP1250 encoding
+/// List of these suffixes is not official and detected in a empirical
+/// way thus may be inexact and incomplete.
+struct RTFFontNameSuffix
+{
+ const char* suffix;
+ int codepage;
+};
+extern RTFFontNameSuffix const aRTFFontNameSuffixes[];
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcontrolwords.cxx b/writerfilter/source/rtftok/rtfcontrolwords.cxx
new file mode 100644
index 000000000..3f5a0827b
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcontrolwords.cxx
@@ -0,0 +1,1900 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfcontrolwords.hxx"
+#include <oox/token/namespaces.hxx>
+
+namespace writerfilter::rtftok
+{
+RTFSymbol const aRTFControlWords[] = {
+ // sKeyword nControlType nIndex
+ { "'", RTFControlType::SYMBOL, RTFKeyword::HEXCHAR, 0 },
+ { "-", RTFControlType::SYMBOL, RTFKeyword::OPTHYPH, 0 },
+ { "*", RTFControlType::SYMBOL, RTFKeyword::IGNORE, 0 },
+ { ":", RTFControlType::SYMBOL, RTFKeyword::SUBENTRY, 0 },
+ { "\\", RTFControlType::SYMBOL, RTFKeyword::BACKSLASH, 0 },
+ { "\n", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "\r", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "\r\n", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "_", RTFControlType::SYMBOL, RTFKeyword::NOBRKHYPH, 0 },
+ { "{", RTFControlType::SYMBOL, RTFKeyword::LBRACE, 0 },
+ { "|", RTFControlType::SYMBOL, RTFKeyword::FORMULA, 0 },
+ { "}", RTFControlType::SYMBOL, RTFKeyword::RBRACE, 0 },
+ { "~", RTFControlType::SYMBOL, RTFKeyword::NOBREAK, 0 },
+ { "ab", RTFControlType::TOGGLE, RTFKeyword::AB, 1 },
+ { "absh", RTFControlType::VALUE, RTFKeyword::ABSH, 0 },
+ { "abslock", RTFControlType::FLAG, RTFKeyword::ABSLOCK, 0 },
+ { "absnoovrlp", RTFControlType::TOGGLE, RTFKeyword::ABSNOOVRLP, 1 },
+ { "absw", RTFControlType::VALUE, RTFKeyword::ABSW, 0 },
+ { "acaps", RTFControlType::TOGGLE, RTFKeyword::ACAPS, 1 },
+ { "acccircle", RTFControlType::TOGGLE, RTFKeyword::ACCCIRCLE, 1 },
+ { "acccomma", RTFControlType::TOGGLE, RTFKeyword::ACCCOMMA, 1 },
+ { "accdot", RTFControlType::TOGGLE, RTFKeyword::ACCDOT, 1 },
+ { "accnone", RTFControlType::TOGGLE, RTFKeyword::ACCNONE, 1 },
+ { "accunderdot", RTFControlType::TOGGLE, RTFKeyword::ACCUNDERDOT, 1 },
+ { "acf", RTFControlType::VALUE, RTFKeyword::ACF, 0 },
+ { "adeff", RTFControlType::VALUE, RTFKeyword::ADEFF, 0 },
+ { "additive", RTFControlType::FLAG, RTFKeyword::ADDITIVE, 0 },
+ { "adeflang", RTFControlType::VALUE, RTFKeyword::ADEFLANG, 0 },
+ { "adjustright", RTFControlType::FLAG, RTFKeyword::ADJUSTRIGHT, 0 },
+ { "adn", RTFControlType::VALUE, RTFKeyword::ADN, 6 },
+ { "aenddoc", RTFControlType::FLAG, RTFKeyword::AENDDOC, 0 },
+ { "aendnotes", RTFControlType::FLAG, RTFKeyword::AENDNOTES, 0 },
+ { "aexpnd", RTFControlType::VALUE, RTFKeyword::AEXPND, 0 },
+ { "af", RTFControlType::VALUE, RTFKeyword::AF, 0 },
+ { "afelev", RTFControlType::FLAG, RTFKeyword::AFELEV, 0 },
+ { "afs", RTFControlType::VALUE, RTFKeyword::AFS, 24 },
+ { "aftnbj", RTFControlType::FLAG, RTFKeyword::AFTNBJ, 0 },
+ { "aftncn", RTFControlType::DESTINATION, RTFKeyword::AFTNCN, 0 },
+ { "aftnnalc", RTFControlType::FLAG, RTFKeyword::AFTNNALC, 0 },
+ { "aftnnar", RTFControlType::FLAG, RTFKeyword::AFTNNAR, 0 },
+ { "aftnnauc", RTFControlType::FLAG, RTFKeyword::AFTNNAUC, 0 },
+ { "aftnnchi", RTFControlType::FLAG, RTFKeyword::AFTNNCHI, 0 },
+ { "aftnnchosung", RTFControlType::FLAG, RTFKeyword::AFTNNCHOSUNG, 0 },
+ { "aftnncnum", RTFControlType::FLAG, RTFKeyword::AFTNNCNUM, 0 },
+ { "aftnndbar", RTFControlType::FLAG, RTFKeyword::AFTNNDBAR, 0 },
+ { "aftnndbnum", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUM, 0 },
+ { "aftnndbnumd", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMD, 0 },
+ { "aftnndbnumk", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMK, 0 },
+ { "aftnndbnumt", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMT, 0 },
+ { "aftnnganada", RTFControlType::FLAG, RTFKeyword::AFTNNGANADA, 0 },
+ { "aftnngbnum", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUM, 0 },
+ { "aftnngbnumd", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUMD, 0 },
+ { "aftnngbnumk", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUMK, 0 },
+ { "aftnngbnuml", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUML, 0 },
+ { "aftnnrlc", RTFControlType::FLAG, RTFKeyword::AFTNNRLC, 0 },
+ { "aftnnruc", RTFControlType::FLAG, RTFKeyword::AFTNNRUC, 0 },
+ { "aftnnzodiac", RTFControlType::FLAG, RTFKeyword::AFTNNZODIAC, 0 },
+ { "aftnnzodiacd", RTFControlType::FLAG, RTFKeyword::AFTNNZODIACD, 0 },
+ { "aftnnzodiacl", RTFControlType::FLAG, RTFKeyword::AFTNNZODIACL, 0 },
+ { "aftnrestart", RTFControlType::FLAG, RTFKeyword::AFTNRESTART, 0 },
+ { "aftnrstcont", RTFControlType::FLAG, RTFKeyword::AFTNRSTCONT, 0 },
+ { "aftnsep", RTFControlType::DESTINATION, RTFKeyword::AFTNSEP, 0 },
+ { "aftnsepc", RTFControlType::DESTINATION, RTFKeyword::AFTNSEPC, 0 },
+ { "aftnstart", RTFControlType::VALUE, RTFKeyword::AFTNSTART, 1 },
+ { "aftntj", RTFControlType::FLAG, RTFKeyword::AFTNTJ, 0 },
+ { "ai", RTFControlType::TOGGLE, RTFKeyword::AI, 1 },
+ { "alang", RTFControlType::VALUE, RTFKeyword::ALANG, 0 },
+ { "allowfieldendsel", RTFControlType::FLAG, RTFKeyword::ALLOWFIELDENDSEL, 0 },
+ { "allprot", RTFControlType::FLAG, RTFKeyword::ALLPROT, 0 },
+ { "alntblind", RTFControlType::FLAG, RTFKeyword::ALNTBLIND, 0 },
+ { "alt", RTFControlType::FLAG, RTFKeyword::ALT, 0 },
+ { "animtext", RTFControlType::VALUE, RTFKeyword::ANIMTEXT, 0 },
+ { "annotation", RTFControlType::DESTINATION, RTFKeyword::ANNOTATION, 0 },
+ { "annotprot", RTFControlType::FLAG, RTFKeyword::ANNOTPROT, 0 },
+ { "ansi", RTFControlType::FLAG, RTFKeyword::ANSI, 0 },
+ { "ansicpg", RTFControlType::VALUE, RTFKeyword::ANSICPG, 0 },
+ { "aoutl", RTFControlType::TOGGLE, RTFKeyword::AOUTL, 1 },
+ { "ApplyBrkRules", RTFControlType::FLAG, RTFKeyword::APPLYBRKRULES, 0 },
+ { "ascaps", RTFControlType::TOGGLE, RTFKeyword::ASCAPS, 1 },
+ { "ashad", RTFControlType::TOGGLE, RTFKeyword::ASHAD, 1 },
+ { "asianbrkrule", RTFControlType::FLAG, RTFKeyword::ASIANBRKRULE, 0 },
+ { "aspalpha", RTFControlType::TOGGLE, RTFKeyword::ASPALPHA, 1 },
+ { "aspnum", RTFControlType::TOGGLE, RTFKeyword::ASPNUM, 1 },
+ { "astrike", RTFControlType::TOGGLE, RTFKeyword::ASTRIKE, 1 },
+ { "atnauthor", RTFControlType::DESTINATION, RTFKeyword::ATNAUTHOR, 0 },
+ { "atndate", RTFControlType::DESTINATION, RTFKeyword::ATNDATE, 0 },
+ { "atnicn", RTFControlType::DESTINATION, RTFKeyword::ATNICN, 0 },
+ { "atnid", RTFControlType::DESTINATION, RTFKeyword::ATNID, 0 },
+ { "atnparent", RTFControlType::DESTINATION, RTFKeyword::ATNPARENT, 0 },
+ { "atnref", RTFControlType::DESTINATION, RTFKeyword::ATNREF, 0 },
+ { "atntime", RTFControlType::DESTINATION, RTFKeyword::ATNTIME, 0 },
+ { "atrfend", RTFControlType::DESTINATION, RTFKeyword::ATRFEND, 0 },
+ { "atrfstart", RTFControlType::DESTINATION, RTFKeyword::ATRFSTART, 0 },
+ { "aul", RTFControlType::TOGGLE, RTFKeyword::AUL, 1 },
+ { "auld", RTFControlType::TOGGLE, RTFKeyword::AULD, 1 },
+ { "auldb", RTFControlType::TOGGLE, RTFKeyword::AULDB, 1 },
+ { "aulnone", RTFControlType::TOGGLE, RTFKeyword::AULNONE, 1 },
+ { "aulw", RTFControlType::TOGGLE, RTFKeyword::AULW, 1 },
+ { "aup", RTFControlType::VALUE, RTFKeyword::AUP, 6 },
+ { "author", RTFControlType::DESTINATION, RTFKeyword::AUTHOR, 0 },
+ { "autofmtoverride", RTFControlType::FLAG, RTFKeyword::AUTOFMTOVERRIDE, 0 },
+ { "b", RTFControlType::TOGGLE, RTFKeyword::B, 1 },
+ { "background", RTFControlType::DESTINATION, RTFKeyword::BACKGROUND, 0 },
+ { "bdbfhdr", RTFControlType::FLAG, RTFKeyword::BDBFHDR, 0 },
+ { "bdrrlswsix", RTFControlType::FLAG, RTFKeyword::BDRRLSWSIX, 0 },
+ { "bgbdiag", RTFControlType::FLAG, RTFKeyword::BGBDIAG, 0 },
+ { "bgcross", RTFControlType::FLAG, RTFKeyword::BGCROSS, 0 },
+ { "bgdcross", RTFControlType::FLAG, RTFKeyword::BGDCROSS, 0 },
+ { "bgdkbdiag", RTFControlType::FLAG, RTFKeyword::BGDKBDIAG, 0 },
+ { "bgdkcross", RTFControlType::FLAG, RTFKeyword::BGDKCROSS, 0 },
+ { "bgdkdcross", RTFControlType::FLAG, RTFKeyword::BGDKDCROSS, 0 },
+ { "bgdkfdiag", RTFControlType::FLAG, RTFKeyword::BGDKFDIAG, 0 },
+ { "bgdkhoriz", RTFControlType::FLAG, RTFKeyword::BGDKHORIZ, 0 },
+ { "bgdkvert", RTFControlType::FLAG, RTFKeyword::BGDKVERT, 0 },
+ { "bgfdiag", RTFControlType::FLAG, RTFKeyword::BGFDIAG, 0 },
+ { "bghoriz", RTFControlType::FLAG, RTFKeyword::BGHORIZ, 0 },
+ { "bgvert", RTFControlType::FLAG, RTFKeyword::BGVERT, 0 },
+ { "bin", RTFControlType::VALUE, RTFKeyword::BIN, 0 },
+ { "binfsxn", RTFControlType::VALUE, RTFKeyword::BINFSXN, 0 },
+ { "binsxn", RTFControlType::VALUE, RTFKeyword::BINSXN, 0 },
+ { "bkmkcolf", RTFControlType::VALUE, RTFKeyword::BKMKCOLF, 0 },
+ { "bkmkcoll", RTFControlType::VALUE, RTFKeyword::BKMKCOLL, 0 },
+ { "bkmkend", RTFControlType::DESTINATION, RTFKeyword::BKMKEND, 0 },
+ { "bkmkpub", RTFControlType::FLAG, RTFKeyword::BKMKPUB, 0 },
+ { "bkmkstart", RTFControlType::DESTINATION, RTFKeyword::BKMKSTART, 0 },
+ { "bliptag", RTFControlType::VALUE, RTFKeyword::BLIPTAG, 0 },
+ { "blipuid", RTFControlType::DESTINATION, RTFKeyword::BLIPUID, 0 },
+ { "blipupi", RTFControlType::VALUE, RTFKeyword::BLIPUPI, 0 },
+ { "blue", RTFControlType::VALUE, RTFKeyword::BLUE, 0 },
+ { "bookfold", RTFControlType::FLAG, RTFKeyword::BOOKFOLD, 0 },
+ { "bookfoldrev", RTFControlType::FLAG, RTFKeyword::BOOKFOLDREV, 0 },
+ { "bookfoldsheets", RTFControlType::VALUE, RTFKeyword::BOOKFOLDSHEETS, 0 },
+ { "box", RTFControlType::FLAG, RTFKeyword::BOX, 0 },
+ { "brdrart", RTFControlType::VALUE, RTFKeyword::BRDRART, 0 },
+ { "brdrb", RTFControlType::FLAG, RTFKeyword::BRDRB, 0 },
+ { "brdrbar", RTFControlType::FLAG, RTFKeyword::BRDRBAR, 0 },
+ { "brdrbtw", RTFControlType::FLAG, RTFKeyword::BRDRBTW, 0 },
+ { "brdrcf", RTFControlType::VALUE, RTFKeyword::BRDRCF, 0 },
+ { "brdrdash", RTFControlType::FLAG, RTFKeyword::BRDRDASH, 0 },
+ { "brdrdashd", RTFControlType::FLAG, RTFKeyword::BRDRDASHD, 0 },
+ { "brdrdashdd", RTFControlType::FLAG, RTFKeyword::BRDRDASHDD, 0 },
+ { "brdrdashdotstr", RTFControlType::FLAG, RTFKeyword::BRDRDASHDOTSTR, 0 },
+ { "brdrdashsm", RTFControlType::FLAG, RTFKeyword::BRDRDASHSM, 0 },
+ { "brdrdb", RTFControlType::FLAG, RTFKeyword::BRDRDB, 0 },
+ { "brdrdot", RTFControlType::FLAG, RTFKeyword::BRDRDOT, 0 },
+ { "brdremboss", RTFControlType::FLAG, RTFKeyword::BRDREMBOSS, 0 },
+ { "brdrengrave", RTFControlType::FLAG, RTFKeyword::BRDRENGRAVE, 0 },
+ { "brdrframe", RTFControlType::FLAG, RTFKeyword::BRDRFRAME, 0 },
+ { "brdrhair", RTFControlType::FLAG, RTFKeyword::BRDRHAIR, 0 },
+ { "brdrinset", RTFControlType::FLAG, RTFKeyword::BRDRINSET, 0 },
+ { "brdrl", RTFControlType::FLAG, RTFKeyword::BRDRL, 0 },
+ { "brdrnil", RTFControlType::FLAG, RTFKeyword::BRDRNIL, 0 },
+ { "brdrnone", RTFControlType::FLAG, RTFKeyword::BRDRNONE, 0 },
+ { "brdroutset", RTFControlType::FLAG, RTFKeyword::BRDROUTSET, 0 },
+ { "brdrr", RTFControlType::FLAG, RTFKeyword::BRDRR, 0 },
+ { "brdrs", RTFControlType::FLAG, RTFKeyword::BRDRS, 0 },
+ { "brdrsh", RTFControlType::FLAG, RTFKeyword::BRDRSH, 0 },
+ { "brdrt", RTFControlType::FLAG, RTFKeyword::BRDRT, 0 },
+ { "brdrtbl", RTFControlType::FLAG, RTFKeyword::BRDRTBL, 0 },
+ { "brdrth", RTFControlType::FLAG, RTFKeyword::BRDRTH, 0 },
+ { "brdrthtnlg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNLG, 0 },
+ { "brdrthtnmg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNMG, 0 },
+ { "brdrthtnsg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNSG, 0 },
+ { "brdrtnthlg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHLG, 0 },
+ { "brdrtnthmg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHMG, 0 },
+ { "brdrtnthsg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHSG, 0 },
+ { "brdrtnthtnlg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNLG, 0 },
+ { "brdrtnthtnmg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNMG, 0 },
+ { "brdrtnthtnsg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNSG, 0 },
+ { "brdrtriple", RTFControlType::FLAG, RTFKeyword::BRDRTRIPLE, 0 },
+ { "brdrw", RTFControlType::VALUE, RTFKeyword::BRDRW, 0 },
+ { "brdrwavy", RTFControlType::FLAG, RTFKeyword::BRDRWAVY, 0 },
+ { "brdrwavydb", RTFControlType::FLAG, RTFKeyword::BRDRWAVYDB, 0 },
+ { "brkfrm", RTFControlType::FLAG, RTFKeyword::BRKFRM, 0 },
+ { "brsp", RTFControlType::VALUE, RTFKeyword::BRSP, 0 },
+ { "bullet", RTFControlType::SYMBOL, RTFKeyword::BULLET, 0 },
+ { "buptim", RTFControlType::DESTINATION, RTFKeyword::BUPTIM, 0 },
+ { "bxe", RTFControlType::FLAG, RTFKeyword::BXE, 0 },
+ { "caccentfive", RTFControlType::FLAG, RTFKeyword::CACCENTFIVE, 0 },
+ { "caccentfour", RTFControlType::FLAG, RTFKeyword::CACCENTFOUR, 0 },
+ { "caccentone", RTFControlType::FLAG, RTFKeyword::CACCENTONE, 0 },
+ { "caccentsix", RTFControlType::FLAG, RTFKeyword::CACCENTSIX, 0 },
+ { "caccentthree", RTFControlType::FLAG, RTFKeyword::CACCENTTHREE, 0 },
+ { "caccenttwo", RTFControlType::FLAG, RTFKeyword::CACCENTTWO, 0 },
+ { "cachedcolbal", RTFControlType::FLAG, RTFKeyword::CACHEDCOLBAL, 0 },
+ { "caps", RTFControlType::TOGGLE, RTFKeyword::CAPS, 1 },
+ { "category", RTFControlType::DESTINATION, RTFKeyword::CATEGORY, 0 },
+ { "cb", RTFControlType::VALUE, RTFKeyword::CB, 0 },
+ { "cbackgroundone", RTFControlType::FLAG, RTFKeyword::CBACKGROUNDONE, 0 },
+ { "cbackgroundtwo", RTFControlType::FLAG, RTFKeyword::CBACKGROUNDTWO, 0 },
+ { "cbpat", RTFControlType::VALUE, RTFKeyword::CBPAT, 0 },
+ { "cchs", RTFControlType::VALUE, RTFKeyword::CCHS, 0 },
+ { "cell", RTFControlType::SYMBOL, RTFKeyword::CELL, 0 },
+ { "cellx", RTFControlType::VALUE, RTFKeyword::CELLX, 0 },
+ { "cf", RTFControlType::VALUE, RTFKeyword::CF, 0 },
+ { "cfollowedhyperlink", RTFControlType::FLAG, RTFKeyword::CFOLLOWEDHYPERLINK, 0 },
+ { "cfpat", RTFControlType::VALUE, RTFKeyword::CFPAT, 0 },
+ { "cgrid", RTFControlType::VALUE, RTFKeyword::CGRID, 0 },
+ { "charrsid", RTFControlType::VALUE, RTFKeyword::CHARRSID, 0 },
+ { "charscalex", RTFControlType::VALUE, RTFKeyword::CHARSCALEX, 100 },
+ { "chatn", RTFControlType::SYMBOL, RTFKeyword::CHATN, 0 },
+ { "chbgbdiag", RTFControlType::FLAG, RTFKeyword::CHBGBDIAG, 0 },
+ { "chbgcross", RTFControlType::FLAG, RTFKeyword::CHBGCROSS, 0 },
+ { "chbgdcross", RTFControlType::FLAG, RTFKeyword::CHBGDCROSS, 0 },
+ { "chbgdkbdiag", RTFControlType::FLAG, RTFKeyword::CHBGDKBDIAG, 0 },
+ { "chbgdkcross", RTFControlType::FLAG, RTFKeyword::CHBGDKCROSS, 0 },
+ { "chbgdkdcross", RTFControlType::FLAG, RTFKeyword::CHBGDKDCROSS, 0 },
+ { "chbgdkfdiag", RTFControlType::FLAG, RTFKeyword::CHBGDKFDIAG, 0 },
+ { "chbgdkhoriz", RTFControlType::FLAG, RTFKeyword::CHBGDKHORIZ, 0 },
+ { "chbgdkvert", RTFControlType::FLAG, RTFKeyword::CHBGDKVERT, 0 },
+ { "chbgfdiag", RTFControlType::FLAG, RTFKeyword::CHBGFDIAG, 0 },
+ { "chbghoriz", RTFControlType::FLAG, RTFKeyword::CHBGHORIZ, 0 },
+ { "chbgvert", RTFControlType::FLAG, RTFKeyword::CHBGVERT, 0 },
+ { "chbrdr", RTFControlType::FLAG, RTFKeyword::CHBRDR, 0 },
+ { "chcbpat", RTFControlType::VALUE, RTFKeyword::CHCBPAT, 0 },
+ { "chcfpat", RTFControlType::VALUE, RTFKeyword::CHCFPAT, 0 },
+ { "chdate", RTFControlType::SYMBOL, RTFKeyword::CHDATE, 0 },
+ { "chdpa", RTFControlType::SYMBOL, RTFKeyword::CHDPA, 0 },
+ { "chdpl", RTFControlType::SYMBOL, RTFKeyword::CHDPL, 0 },
+ { "chftn", RTFControlType::SYMBOL, RTFKeyword::CHFTN, 0 },
+ { "chftnsep", RTFControlType::SYMBOL, RTFKeyword::CHFTNSEP, 0 },
+ { "chftnsepc", RTFControlType::SYMBOL, RTFKeyword::CHFTNSEPC, 0 },
+ { "chpgn", RTFControlType::SYMBOL, RTFKeyword::CHPGN, 0 },
+ { "chhres", RTFControlType::VALUE, RTFKeyword::CHHRES, 0 },
+ { "chshdng", RTFControlType::VALUE, RTFKeyword::CHSHDNG, 0 },
+ { "chtime", RTFControlType::SYMBOL, RTFKeyword::CHTIME, 0 },
+ { "chyperlink", RTFControlType::FLAG, RTFKeyword::CHYPERLINK, 0 },
+ { "clbgbdiag", RTFControlType::FLAG, RTFKeyword::CLBGBDIAG, 0 },
+ { "clbgcross", RTFControlType::FLAG, RTFKeyword::CLBGCROSS, 0 },
+ { "clbgdcross", RTFControlType::FLAG, RTFKeyword::CLBGDCROSS, 0 },
+ { "clbgdkbdiag", RTFControlType::FLAG, RTFKeyword::CLBGDKBDIAG, 0 },
+ { "clbgdkcross", RTFControlType::FLAG, RTFKeyword::CLBGDKCROSS, 0 },
+ { "clbgdkdcross", RTFControlType::FLAG, RTFKeyword::CLBGDKDCROSS, 0 },
+ { "clbgdkfdiag", RTFControlType::FLAG, RTFKeyword::CLBGDKFDIAG, 0 },
+ { "clbgdkhor", RTFControlType::FLAG, RTFKeyword::CLBGDKHOR, 0 },
+ { "clbgdkvert", RTFControlType::FLAG, RTFKeyword::CLBGDKVERT, 0 },
+ { "clbgfdiag", RTFControlType::FLAG, RTFKeyword::CLBGFDIAG, 0 },
+ { "clbghoriz", RTFControlType::FLAG, RTFKeyword::CLBGHORIZ, 0 },
+ { "clbgvert", RTFControlType::FLAG, RTFKeyword::CLBGVERT, 0 },
+ { "clbrdrb", RTFControlType::FLAG, RTFKeyword::CLBRDRB, 0 },
+ { "clbrdrl", RTFControlType::FLAG, RTFKeyword::CLBRDRL, 0 },
+ { "clbrdrr", RTFControlType::FLAG, RTFKeyword::CLBRDRR, 0 },
+ { "clbrdrt", RTFControlType::FLAG, RTFKeyword::CLBRDRT, 0 },
+ { "clcbpat", RTFControlType::VALUE, RTFKeyword::CLCBPAT, 0 },
+ { "clcbpatraw", RTFControlType::VALUE, RTFKeyword::CLCBPATRAW, 0 },
+ { "clcfpat", RTFControlType::VALUE, RTFKeyword::CLCFPAT, 0 },
+ { "clcfpatraw", RTFControlType::VALUE, RTFKeyword::CLCFPATRAW, 0 },
+ { "cldel", RTFControlType::FLAG, RTFKeyword::CLDEL, 0 },
+ { "cldelauth", RTFControlType::VALUE, RTFKeyword::CLDELAUTH, 0 },
+ { "cldeldttm", RTFControlType::VALUE, RTFKeyword::CLDELDTTM, 0 },
+ { "cldgll", RTFControlType::FLAG, RTFKeyword::CLDGLL, 0 },
+ { "cldglu", RTFControlType::FLAG, RTFKeyword::CLDGLU, 0 },
+ { "clFitText", RTFControlType::FLAG, RTFKeyword::CLFITTEXT, 0 },
+ { "clftsWidth", RTFControlType::VALUE, RTFKeyword::CLFTSWIDTH, 0 },
+ { "clhidemark", RTFControlType::FLAG, RTFKeyword::CLHIDEMARK, 0 },
+ { "clins", RTFControlType::FLAG, RTFKeyword::CLINS, 0 },
+ { "clinsauth", RTFControlType::VALUE, RTFKeyword::CLINSAUTH, 0 },
+ { "clinsdttm", RTFControlType::VALUE, RTFKeyword::CLINSDTTM, 0 },
+ { "clmgf", RTFControlType::FLAG, RTFKeyword::CLMGF, 0 },
+ { "clmrg", RTFControlType::FLAG, RTFKeyword::CLMRG, 0 },
+ { "clmrgd", RTFControlType::FLAG, RTFKeyword::CLMRGD, 0 },
+ { "clmrgdauth", RTFControlType::VALUE, RTFKeyword::CLMRGDAUTH, 0 },
+ { "clmrgddttm", RTFControlType::VALUE, RTFKeyword::CLMRGDDTTM, 0 },
+ { "clmrgdr", RTFControlType::FLAG, RTFKeyword::CLMRGDR, 0 },
+ { "clNoWrap", RTFControlType::FLAG, RTFKeyword::CLNOWRAP, 0 },
+ { "clpadb", RTFControlType::VALUE, RTFKeyword::CLPADB, 0 },
+ { "clpadfb", RTFControlType::VALUE, RTFKeyword::CLPADFB, 0 },
+ { "clpadfl", RTFControlType::VALUE, RTFKeyword::CLPADFL, 0 },
+ { "clpadfr", RTFControlType::VALUE, RTFKeyword::CLPADFR, 0 },
+ { "clpadft", RTFControlType::VALUE, RTFKeyword::CLPADFT, 0 },
+ { "clpadl", RTFControlType::VALUE, RTFKeyword::CLPADL, 0 },
+ { "clpadr", RTFControlType::VALUE, RTFKeyword::CLPADR, 0 },
+ { "clpadt", RTFControlType::VALUE, RTFKeyword::CLPADT, 0 },
+ { "clspb", RTFControlType::VALUE, RTFKeyword::CLSPB, 0 },
+ { "clspfb", RTFControlType::VALUE, RTFKeyword::CLSPFB, 0 },
+ { "clspfl", RTFControlType::VALUE, RTFKeyword::CLSPFL, 0 },
+ { "clspfr", RTFControlType::VALUE, RTFKeyword::CLSPFR, 0 },
+ { "clspft", RTFControlType::VALUE, RTFKeyword::CLSPFT, 0 },
+ { "clspl", RTFControlType::VALUE, RTFKeyword::CLSPL, 0 },
+ { "clspr", RTFControlType::VALUE, RTFKeyword::CLSPR, 0 },
+ { "clspt", RTFControlType::VALUE, RTFKeyword::CLSPT, 0 },
+ { "clshdng", RTFControlType::VALUE, RTFKeyword::CLSHDNG, 0 },
+ { "clshdngraw", RTFControlType::VALUE, RTFKeyword::CLSHDNGRAW, 0 },
+ { "clshdrawnil", RTFControlType::FLAG, RTFKeyword::CLSHDRAWNIL, 0 },
+ { "clsplit", RTFControlType::FLAG, RTFKeyword::CLSPLIT, 0 },
+ { "clsplitr", RTFControlType::FLAG, RTFKeyword::CLSPLITR, 0 },
+ { "cltxbtlr", RTFControlType::FLAG, RTFKeyword::CLTXBTLR, 0 },
+ { "cltxlrtb", RTFControlType::FLAG, RTFKeyword::CLTXLRTB, 0 },
+ { "cltxlrtbv", RTFControlType::FLAG, RTFKeyword::CLTXLRTBV, 0 },
+ { "cltxtbrl", RTFControlType::FLAG, RTFKeyword::CLTXTBRL, 0 },
+ { "cltxtbrlv", RTFControlType::FLAG, RTFKeyword::CLTXTBRLV, 0 },
+ { "clvertalb", RTFControlType::FLAG, RTFKeyword::CLVERTALB, 0 },
+ { "clvertalc", RTFControlType::FLAG, RTFKeyword::CLVERTALC, 0 },
+ { "clvertalt", RTFControlType::FLAG, RTFKeyword::CLVERTALT, 0 },
+ { "clvmgf", RTFControlType::FLAG, RTFKeyword::CLVMGF, 0 },
+ { "clvmrg", RTFControlType::FLAG, RTFKeyword::CLVMRG, 0 },
+ { "clwWidth", RTFControlType::VALUE, RTFKeyword::CLWWIDTH, 0 },
+ { "cmaindarkone", RTFControlType::FLAG, RTFKeyword::CMAINDARKONE, 0 },
+ { "cmaindarktwo", RTFControlType::FLAG, RTFKeyword::CMAINDARKTWO, 0 },
+ { "cmainlightone", RTFControlType::FLAG, RTFKeyword::CMAINLIGHTONE, 0 },
+ { "cmainlighttwo", RTFControlType::FLAG, RTFKeyword::CMAINLIGHTTWO, 0 },
+ { "collapsed", RTFControlType::FLAG, RTFKeyword::COLLAPSED, 0 },
+ { "colno", RTFControlType::VALUE, RTFKeyword::COLNO, 0 },
+ { "colorschememapping", RTFControlType::DESTINATION, RTFKeyword::COLORSCHEMEMAPPING, 0 },
+ { "colortbl", RTFControlType::DESTINATION, RTFKeyword::COLORTBL, 0 },
+ { "cols", RTFControlType::VALUE, RTFKeyword::COLS, 1 },
+ { "colsr", RTFControlType::VALUE, RTFKeyword::COLSR, 0 },
+ { "colsx", RTFControlType::VALUE, RTFKeyword::COLSX, 720 },
+ { "column", RTFControlType::SYMBOL, RTFKeyword::COLUMN, 0 },
+ { "colw", RTFControlType::VALUE, RTFKeyword::COLW, 0 },
+ { "comment", RTFControlType::DESTINATION, RTFKeyword::COMMENT, 0 },
+ { "company", RTFControlType::DESTINATION, RTFKeyword::COMPANY, 0 },
+ { "contextualspace", RTFControlType::FLAG, RTFKeyword::CONTEXTUALSPACE, 0 },
+ { "cpg", RTFControlType::VALUE, RTFKeyword::CPG, 0 },
+ { "crauth", RTFControlType::VALUE, RTFKeyword::CRAUTH, 0 },
+ { "crdate", RTFControlType::VALUE, RTFKeyword::CRDATE, 0 },
+ { "creatim", RTFControlType::DESTINATION, RTFKeyword::CREATIM, 0 },
+ { "cs", RTFControlType::VALUE, RTFKeyword::CS, 0 },
+ { "cshade", RTFControlType::VALUE, RTFKeyword::CSHADE, 0 },
+ { "ctextone", RTFControlType::FLAG, RTFKeyword::CTEXTONE, 0 },
+ { "ctexttwo", RTFControlType::FLAG, RTFKeyword::CTEXTTWO, 0 },
+ { "ctint", RTFControlType::VALUE, RTFKeyword::CTINT, 0 },
+ { "ctrl", RTFControlType::FLAG, RTFKeyword::CTRL, 0 },
+ { "cts", RTFControlType::VALUE, RTFKeyword::CTS, 0 },
+ { "cufi", RTFControlType::VALUE, RTFKeyword::CUFI, 0 },
+ { "culi", RTFControlType::VALUE, RTFKeyword::CULI, 0 },
+ { "curi", RTFControlType::VALUE, RTFKeyword::CURI, 0 },
+ { "cvmme", RTFControlType::FLAG, RTFKeyword::CVMME, 0 },
+ { "datafield", RTFControlType::DESTINATION, RTFKeyword::DATAFIELD, 0 },
+ { "datastore", RTFControlType::DESTINATION, RTFKeyword::DATASTORE, 0 },
+ { "date", RTFControlType::FLAG, RTFKeyword::DATE, 0 },
+ { "dbch", RTFControlType::FLAG, RTFKeyword::DBCH, 0 },
+ { "defchp", RTFControlType::DESTINATION, RTFKeyword::DEFCHP, 0 },
+ { "deff", RTFControlType::VALUE, RTFKeyword::DEFF, 0 },
+ { "defformat", RTFControlType::FLAG, RTFKeyword::DEFFORMAT, 0 },
+ { "deflang", RTFControlType::VALUE, RTFKeyword::DEFLANG, 0 },
+ { "deflangfe", RTFControlType::VALUE, RTFKeyword::DEFLANGFE, 0 },
+ { "defpap", RTFControlType::DESTINATION, RTFKeyword::DEFPAP, 0 },
+ { "defshp", RTFControlType::FLAG, RTFKeyword::DEFSHP, 0 },
+ { "deftab", RTFControlType::VALUE, RTFKeyword::DEFTAB, 720 },
+ { "deleted", RTFControlType::TOGGLE, RTFKeyword::DELETED, 1 },
+ { "delrsid", RTFControlType::VALUE, RTFKeyword::DELRSID, 0 },
+ { "dfrauth", RTFControlType::VALUE, RTFKeyword::DFRAUTH, 0 },
+ { "dfrdate", RTFControlType::VALUE, RTFKeyword::DFRDATE, 0 },
+ { "dfrmtxtx", RTFControlType::VALUE, RTFKeyword::DFRMTXTX, 0 },
+ { "dfrmtxty", RTFControlType::VALUE, RTFKeyword::DFRMTXTY, 0 },
+ { "dfrstart", RTFControlType::VALUE, RTFKeyword::DFRSTART, 0 },
+ { "dfrstop", RTFControlType::VALUE, RTFKeyword::DFRSTOP, 0 },
+ { "dfrxst", RTFControlType::VALUE, RTFKeyword::DFRXST, 0 },
+ { "dghorigin", RTFControlType::VALUE, RTFKeyword::DGHORIGIN, 1701 },
+ { "dghshow", RTFControlType::VALUE, RTFKeyword::DGHSHOW, 3 },
+ { "dghspace", RTFControlType::VALUE, RTFKeyword::DGHSPACE, 120 },
+ { "dgmargin", RTFControlType::FLAG, RTFKeyword::DGMARGIN, 0 },
+ { "dgsnap", RTFControlType::FLAG, RTFKeyword::DGSNAP, 0 },
+ { "dgvorigin", RTFControlType::VALUE, RTFKeyword::DGVORIGIN, 1984 },
+ { "dgvshow", RTFControlType::VALUE, RTFKeyword::DGVSHOW, 0 },
+ { "dgvspace", RTFControlType::VALUE, RTFKeyword::DGVSPACE, 120 },
+ { "dibitmap", RTFControlType::VALUE, RTFKeyword::DIBITMAP, 0 },
+ { "disabled", RTFControlType::TOGGLE, RTFKeyword::DISABLED, 1 },
+ { "dn", RTFControlType::VALUE, RTFKeyword::DN, 6 },
+ { "dntblnsbdb", RTFControlType::FLAG, RTFKeyword::DNTBLNSBDB, 0 },
+ { "do", RTFControlType::DESTINATION, RTFKeyword::DO, 0 },
+ { "dobxcolumn", RTFControlType::FLAG, RTFKeyword::DOBXCOLUMN, 0 },
+ { "dobxmargin", RTFControlType::FLAG, RTFKeyword::DOBXMARGIN, 0 },
+ { "dobxpage", RTFControlType::FLAG, RTFKeyword::DOBXPAGE, 0 },
+ { "dobymargin", RTFControlType::FLAG, RTFKeyword::DOBYMARGIN, 0 },
+ { "dobypage", RTFControlType::FLAG, RTFKeyword::DOBYPAGE, 0 },
+ { "dobypara", RTFControlType::FLAG, RTFKeyword::DOBYPARA, 0 },
+ { "doccomm", RTFControlType::DESTINATION, RTFKeyword::DOCCOMM, 0 },
+ { "doctemp", RTFControlType::FLAG, RTFKeyword::DOCTEMP, 0 },
+ { "doctype", RTFControlType::VALUE, RTFKeyword::DOCTYPE, 0 },
+ { "docvar", RTFControlType::DESTINATION, RTFKeyword::DOCVAR, 0 },
+ { "dodhgt", RTFControlType::VALUE, RTFKeyword::DODHGT, 0 },
+ { "dolock", RTFControlType::FLAG, RTFKeyword::DOLOCK, 0 },
+ { "donotembedlingdata", RTFControlType::VALUE, RTFKeyword::DONOTEMBEDLINGDATA, 0 },
+ { "donotembedsysfont", RTFControlType::VALUE, RTFKeyword::DONOTEMBEDSYSFONT, 0 },
+ { "donotshowcomments", RTFControlType::FLAG, RTFKeyword::DONOTSHOWCOMMENTS, 0 },
+ { "donotshowinsdel", RTFControlType::FLAG, RTFKeyword::DONOTSHOWINSDEL, 0 },
+ { "donotshowmarkup", RTFControlType::FLAG, RTFKeyword::DONOTSHOWMARKUP, 0 },
+ { "donotshowprops", RTFControlType::FLAG, RTFKeyword::DONOTSHOWPROPS, 0 },
+ { "dpaendhol", RTFControlType::FLAG, RTFKeyword::DPAENDHOL, 0 },
+ { "dpaendl", RTFControlType::VALUE, RTFKeyword::DPAENDL, 0 },
+ { "dpaendsol", RTFControlType::FLAG, RTFKeyword::DPAENDSOL, 0 },
+ { "dpaendw", RTFControlType::VALUE, RTFKeyword::DPAENDW, 0 },
+ { "dparc", RTFControlType::FLAG, RTFKeyword::DPARC, 0 },
+ { "dparcflipx", RTFControlType::FLAG, RTFKeyword::DPARCFLIPX, 0 },
+ { "dparcflipy", RTFControlType::FLAG, RTFKeyword::DPARCFLIPY, 0 },
+ { "dpastarthol", RTFControlType::FLAG, RTFKeyword::DPASTARTHOL, 0 },
+ { "dpastartl", RTFControlType::VALUE, RTFKeyword::DPASTARTL, 0 },
+ { "dpastartsol", RTFControlType::FLAG, RTFKeyword::DPASTARTSOL, 0 },
+ { "dpastartw", RTFControlType::VALUE, RTFKeyword::DPASTARTW, 0 },
+ { "dpcallout", RTFControlType::FLAG, RTFKeyword::DPCALLOUT, 0 },
+ { "dpcoa", RTFControlType::VALUE, RTFKeyword::DPCOA, 0 },
+ { "dpcoaccent", RTFControlType::FLAG, RTFKeyword::DPCOACCENT, 0 },
+ { "dpcobestfit", RTFControlType::FLAG, RTFKeyword::DPCOBESTFIT, 0 },
+ { "dpcoborder", RTFControlType::FLAG, RTFKeyword::DPCOBORDER, 0 },
+ { "dpcodabs", RTFControlType::FLAG, RTFKeyword::DPCODABS, 0 },
+ { "dpcodbottom", RTFControlType::FLAG, RTFKeyword::DPCODBOTTOM, 0 },
+ { "dpcodcenter", RTFControlType::FLAG, RTFKeyword::DPCODCENTER, 0 },
+ { "dpcodescent", RTFControlType::VALUE, RTFKeyword::DPCODESCENT, 0 },
+ { "dpcodtop", RTFControlType::FLAG, RTFKeyword::DPCODTOP, 0 },
+ { "dpcolength", RTFControlType::VALUE, RTFKeyword::DPCOLENGTH, 0 },
+ { "dpcominusx", RTFControlType::FLAG, RTFKeyword::DPCOMINUSX, 0 },
+ { "dpcominusy", RTFControlType::FLAG, RTFKeyword::DPCOMINUSY, 0 },
+ { "dpcooffset", RTFControlType::VALUE, RTFKeyword::DPCOOFFSET, 0 },
+ { "dpcosmarta", RTFControlType::FLAG, RTFKeyword::DPCOSMARTA, 0 },
+ { "dpcotdouble", RTFControlType::FLAG, RTFKeyword::DPCOTDOUBLE, 0 },
+ { "dpcotright", RTFControlType::FLAG, RTFKeyword::DPCOTRIGHT, 0 },
+ { "dpcotsingle", RTFControlType::FLAG, RTFKeyword::DPCOTSINGLE, 0 },
+ { "dpcottriple", RTFControlType::FLAG, RTFKeyword::DPCOTTRIPLE, 0 },
+ { "dpcount", RTFControlType::VALUE, RTFKeyword::DPCOUNT, 0 },
+ { "dpellipse", RTFControlType::FLAG, RTFKeyword::DPELLIPSE, 0 },
+ { "dpendgroup", RTFControlType::FLAG, RTFKeyword::DPENDGROUP, 0 },
+ { "dpfillbgcb", RTFControlType::VALUE, RTFKeyword::DPFILLBGCB, 0 },
+ { "dpfillbgcg", RTFControlType::VALUE, RTFKeyword::DPFILLBGCG, 0 },
+ { "dpfillbgcr", RTFControlType::VALUE, RTFKeyword::DPFILLBGCR, 0 },
+ { "dpfillbggray", RTFControlType::VALUE, RTFKeyword::DPFILLBGGRAY, 0 },
+ { "dpfillbgpal", RTFControlType::FLAG, RTFKeyword::DPFILLBGPAL, 0 },
+ { "dpfillfgcb", RTFControlType::VALUE, RTFKeyword::DPFILLFGCB, 0 },
+ { "dpfillfgcg", RTFControlType::VALUE, RTFKeyword::DPFILLFGCG, 0 },
+ { "dpfillfgcr", RTFControlType::VALUE, RTFKeyword::DPFILLFGCR, 0 },
+ { "dpfillfggray", RTFControlType::VALUE, RTFKeyword::DPFILLFGGRAY, 0 },
+ { "dpfillfgpal", RTFControlType::FLAG, RTFKeyword::DPFILLFGPAL, 0 },
+ { "dpfillpat", RTFControlType::VALUE, RTFKeyword::DPFILLPAT, 0 },
+ { "dpgroup", RTFControlType::FLAG, RTFKeyword::DPGROUP, 0 },
+ { "dpline", RTFControlType::FLAG, RTFKeyword::DPLINE, 0 },
+ { "dplinecob", RTFControlType::VALUE, RTFKeyword::DPLINECOB, 0 },
+ { "dplinecog", RTFControlType::VALUE, RTFKeyword::DPLINECOG, 0 },
+ { "dplinecor", RTFControlType::VALUE, RTFKeyword::DPLINECOR, 0 },
+ { "dplinedado", RTFControlType::FLAG, RTFKeyword::DPLINEDADO, 0 },
+ { "dplinedadodo", RTFControlType::FLAG, RTFKeyword::DPLINEDADODO, 0 },
+ { "dplinedash", RTFControlType::FLAG, RTFKeyword::DPLINEDASH, 0 },
+ { "dplinedot", RTFControlType::FLAG, RTFKeyword::DPLINEDOT, 0 },
+ { "dplinegray", RTFControlType::VALUE, RTFKeyword::DPLINEGRAY, 0 },
+ { "dplinehollow", RTFControlType::FLAG, RTFKeyword::DPLINEHOLLOW, 0 },
+ { "dplinepal", RTFControlType::FLAG, RTFKeyword::DPLINEPAL, 0 },
+ { "dplinesolid", RTFControlType::FLAG, RTFKeyword::DPLINESOLID, 0 },
+ { "dplinew", RTFControlType::VALUE, RTFKeyword::DPLINEW, 0 },
+ { "dppolycount", RTFControlType::VALUE, RTFKeyword::DPPOLYCOUNT, 0 },
+ { "dppolygon", RTFControlType::FLAG, RTFKeyword::DPPOLYGON, 0 },
+ { "dppolyline", RTFControlType::FLAG, RTFKeyword::DPPOLYLINE, 0 },
+ { "dpptx", RTFControlType::VALUE, RTFKeyword::DPPTX, 0 },
+ { "dppty", RTFControlType::VALUE, RTFKeyword::DPPTY, 0 },
+ { "dprect", RTFControlType::FLAG, RTFKeyword::DPRECT, 0 },
+ { "dproundr", RTFControlType::FLAG, RTFKeyword::DPROUNDR, 0 },
+ { "dpshadow", RTFControlType::FLAG, RTFKeyword::DPSHADOW, 0 },
+ { "dpshadx", RTFControlType::VALUE, RTFKeyword::DPSHADX, 0 },
+ { "dpshady", RTFControlType::VALUE, RTFKeyword::DPSHADY, 0 },
+ { "dptxbtlr", RTFControlType::FLAG, RTFKeyword::DPTXBTLR, 0 },
+ { "dptxbx", RTFControlType::FLAG, RTFKeyword::DPTXBX, 0 },
+ { "dptxbxmar", RTFControlType::VALUE, RTFKeyword::DPTXBXMAR, 0 },
+ { "dptxbxtext", RTFControlType::DESTINATION, RTFKeyword::DPTXBXTEXT, 0 },
+ { "dptxlrtb", RTFControlType::FLAG, RTFKeyword::DPTXLRTB, 0 },
+ { "dptxlrtbv", RTFControlType::FLAG, RTFKeyword::DPTXLRTBV, 0 },
+ { "dptxtbrl", RTFControlType::FLAG, RTFKeyword::DPTXTBRL, 0 },
+ { "dptxtbrlv", RTFControlType::FLAG, RTFKeyword::DPTXTBRLV, 0 },
+ { "dpx", RTFControlType::VALUE, RTFKeyword::DPX, 0 },
+ { "dpxsize", RTFControlType::VALUE, RTFKeyword::DPXSIZE, 0 },
+ { "dpy", RTFControlType::VALUE, RTFKeyword::DPY, 0 },
+ { "dpysize", RTFControlType::VALUE, RTFKeyword::DPYSIZE, 0 },
+ { "dropcapli", RTFControlType::VALUE, RTFKeyword::DROPCAPLI, 0 },
+ { "dropcapt", RTFControlType::VALUE, RTFKeyword::DROPCAPT, 0 },
+ { "ds", RTFControlType::VALUE, RTFKeyword::DS, 0 },
+ { "dxfrtext", RTFControlType::VALUE, RTFKeyword::DXFRTEXT, 0 },
+ { "dy", RTFControlType::VALUE, RTFKeyword::DY, 0 },
+ { "ebcend", RTFControlType::DESTINATION, RTFKeyword::EBCEND, 0 },
+ { "ebcstart", RTFControlType::DESTINATION, RTFKeyword::EBCSTART, 0 },
+ { "edmins", RTFControlType::VALUE, RTFKeyword::EDMINS, 0 },
+ { "embo", RTFControlType::TOGGLE, RTFKeyword::EMBO, 1 },
+ { "emdash", RTFControlType::SYMBOL, RTFKeyword::EMDASH, 0 },
+ { "emfblip", RTFControlType::FLAG, RTFKeyword::EMFBLIP, 0 },
+ { "emspace", RTFControlType::SYMBOL, RTFKeyword::EMSPACE, 0 },
+ { "endash", RTFControlType::SYMBOL, RTFKeyword::ENDASH, 0 },
+ { "enddoc", RTFControlType::FLAG, RTFKeyword::ENDDOC, 0 },
+ { "endnhere", RTFControlType::FLAG, RTFKeyword::ENDNHERE, 0 },
+ { "endnotes", RTFControlType::FLAG, RTFKeyword::ENDNOTES, 0 },
+ { "enforceprot", RTFControlType::VALUE, RTFKeyword::ENFORCEPROT, 0 },
+ { "enspace", RTFControlType::SYMBOL, RTFKeyword::ENSPACE, 0 },
+ { "expnd", RTFControlType::VALUE, RTFKeyword::EXPND, 0 },
+ { "expndtw", RTFControlType::VALUE, RTFKeyword::EXPNDTW, 0 },
+ { "expshrtn", RTFControlType::FLAG, RTFKeyword::EXPSHRTN, 0 },
+ { "f", RTFControlType::VALUE, RTFKeyword::F, 0 },
+ { "faauto", RTFControlType::FLAG, RTFKeyword::FAAUTO, 0 },
+ { "facenter", RTFControlType::FLAG, RTFKeyword::FACENTER, 0 },
+ { "facingp", RTFControlType::TOGGLE, RTFKeyword::FACINGP, 1 },
+ { "factoidname", RTFControlType::DESTINATION, RTFKeyword::FACTOIDNAME, 0 },
+ { "fafixed", RTFControlType::FLAG, RTFKeyword::FAFIXED, 0 },
+ { "fahang", RTFControlType::FLAG, RTFKeyword::FAHANG, 0 },
+ { "falt", RTFControlType::DESTINATION, RTFKeyword::FALT, 0 },
+ { "faroman", RTFControlType::FLAG, RTFKeyword::FAROMAN, 0 },
+ { "favar", RTFControlType::FLAG, RTFKeyword::FAVAR, 0 },
+ { "fbias", RTFControlType::VALUE, RTFKeyword::FBIAS, 0 },
+ { "fbidi", RTFControlType::FLAG, RTFKeyword::FBIDI, 0 },
+ { "fbidis", RTFControlType::FLAG, RTFKeyword::FBIDIS, 0 },
+ { "fbimajor", RTFControlType::FLAG, RTFKeyword::FBIMAJOR, 0 },
+ { "fbiminor", RTFControlType::FLAG, RTFKeyword::FBIMINOR, 0 },
+ { "fchars", RTFControlType::DESTINATION, RTFKeyword::FCHARS, 0 },
+ { "fcharset", RTFControlType::VALUE, RTFKeyword::FCHARSET, 0 },
+ { "fcs", RTFControlType::VALUE, RTFKeyword::FCS, 0 },
+ { "fdbmajor", RTFControlType::FLAG, RTFKeyword::FDBMAJOR, 0 },
+ { "fdbminor", RTFControlType::FLAG, RTFKeyword::FDBMINOR, 0 },
+ { "fdecor", RTFControlType::FLAG, RTFKeyword::FDECOR, 0 },
+ { "felnbrelev", RTFControlType::FLAG, RTFKeyword::FELNBRELEV, 0 },
+ { "fet", RTFControlType::VALUE, RTFKeyword::FET, 0 },
+ { "fetch", RTFControlType::FLAG, RTFKeyword::FETCH, 0 },
+ { "ffdefres", RTFControlType::VALUE, RTFKeyword::FFDEFRES, 0 },
+ { "ffdeftext", RTFControlType::DESTINATION, RTFKeyword::FFDEFTEXT, 0 },
+ { "ffentrymcr", RTFControlType::DESTINATION, RTFKeyword::FFENTRYMCR, 0 },
+ { "ffexitmcr", RTFControlType::DESTINATION, RTFKeyword::FFEXITMCR, 0 },
+ { "ffformat", RTFControlType::DESTINATION, RTFKeyword::FFFORMAT, 0 },
+ { "ffhaslistbox", RTFControlType::VALUE, RTFKeyword::FFHASLISTBOX, 0 },
+ { "ffhelptext", RTFControlType::DESTINATION, RTFKeyword::FFHELPTEXT, 0 },
+ { "ffhps", RTFControlType::VALUE, RTFKeyword::FFHPS, 0 },
+ { "ffl", RTFControlType::DESTINATION, RTFKeyword::FFL, 0 },
+ { "ffmaxlen", RTFControlType::VALUE, RTFKeyword::FFMAXLEN, 0 },
+ { "ffname", RTFControlType::DESTINATION, RTFKeyword::FFNAME, 0 },
+ { "ffownhelp", RTFControlType::VALUE, RTFKeyword::FFOWNHELP, 0 },
+ { "ffownstat", RTFControlType::VALUE, RTFKeyword::FFOWNSTAT, 0 },
+ { "ffprot", RTFControlType::VALUE, RTFKeyword::FFPROT, 0 },
+ { "ffrecalc", RTFControlType::VALUE, RTFKeyword::FFRECALC, 0 },
+ { "ffres", RTFControlType::VALUE, RTFKeyword::FFRES, 0 },
+ { "ffsize", RTFControlType::VALUE, RTFKeyword::FFSIZE, 0 },
+ { "ffstattext", RTFControlType::DESTINATION, RTFKeyword::FFSTATTEXT, 0 },
+ { "fftype", RTFControlType::VALUE, RTFKeyword::FFTYPE, 0 },
+ { "fftypetxt", RTFControlType::VALUE, RTFKeyword::FFTYPETXT, 0 },
+ { "fhimajor", RTFControlType::FLAG, RTFKeyword::FHIMAJOR, 0 },
+ { "fhiminor", RTFControlType::FLAG, RTFKeyword::FHIMINOR, 0 },
+ { "fi", RTFControlType::VALUE, RTFKeyword::FI, 0 },
+ { "fid", RTFControlType::VALUE, RTFKeyword::FID, 0 },
+ { "field", RTFControlType::DESTINATION, RTFKeyword::FIELD, 0 },
+ { "file", RTFControlType::DESTINATION, RTFKeyword::FILE, 0 },
+ { "filetbl", RTFControlType::DESTINATION, RTFKeyword::FILETBL, 0 },
+ { "fittext", RTFControlType::VALUE, RTFKeyword::FITTEXT, 0 },
+ { "fjgothic", RTFControlType::FLAG, RTFKeyword::FJGOTHIC, 0 },
+ { "fjminchou", RTFControlType::FLAG, RTFKeyword::FJMINCHOU, 0 },
+ { "fldalt", RTFControlType::FLAG, RTFKeyword::FLDALT, 0 },
+ { "flddirty", RTFControlType::FLAG, RTFKeyword::FLDDIRTY, 0 },
+ { "fldedit", RTFControlType::FLAG, RTFKeyword::FLDEDIT, 0 },
+ { "fldinst", RTFControlType::DESTINATION, RTFKeyword::FLDINST, 0 },
+ { "fldlock", RTFControlType::FLAG, RTFKeyword::FLDLOCK, 0 },
+ { "fldpriv", RTFControlType::FLAG, RTFKeyword::FLDPRIV, 0 },
+ { "fldrslt", RTFControlType::DESTINATION, RTFKeyword::FLDRSLT, 0 },
+ { "fldtype", RTFControlType::DESTINATION, RTFKeyword::FLDTYPE, 0 },
+ { "flomajor", RTFControlType::FLAG, RTFKeyword::FLOMAJOR, 0 },
+ { "flominor", RTFControlType::FLAG, RTFKeyword::FLOMINOR, 0 },
+ { "fmodern", RTFControlType::FLAG, RTFKeyword::FMODERN, 0 },
+ { "fn", RTFControlType::VALUE, RTFKeyword::FN, 0 },
+ { "fname", RTFControlType::DESTINATION, RTFKeyword::FNAME, 0 },
+ { "fnetwork", RTFControlType::FLAG, RTFKeyword::FNETWORK, 0 },
+ { "fnil", RTFControlType::FLAG, RTFKeyword::FNIL, 0 },
+ { "fnonfilesys", RTFControlType::FLAG, RTFKeyword::FNONFILESYS, 0 },
+ { "fontemb", RTFControlType::DESTINATION, RTFKeyword::FONTEMB, 0 },
+ { "fontfile", RTFControlType::DESTINATION, RTFKeyword::FONTFILE, 0 },
+ { "fonttbl", RTFControlType::DESTINATION, RTFKeyword::FONTTBL, 0 },
+ { "footer", RTFControlType::DESTINATION, RTFKeyword::FOOTER, 0 },
+ { "footerf", RTFControlType::DESTINATION, RTFKeyword::FOOTERF, 0 },
+ { "footerl", RTFControlType::DESTINATION, RTFKeyword::FOOTERL, 0 },
+ { "footerr", RTFControlType::DESTINATION, RTFKeyword::FOOTERR, 0 },
+ { "footery", RTFControlType::VALUE, RTFKeyword::FOOTERY, 720 },
+ { "footnote", RTFControlType::DESTINATION, RTFKeyword::FOOTNOTE, 0 },
+ { "forceupgrade", RTFControlType::FLAG, RTFKeyword::FORCEUPGRADE, 0 },
+ { "formdisp", RTFControlType::FLAG, RTFKeyword::FORMDISP, 0 },
+ { "formfield", RTFControlType::DESTINATION, RTFKeyword::FORMFIELD, 0 },
+ { "formprot", RTFControlType::FLAG, RTFKeyword::FORMPROT, 0 },
+ { "formshade", RTFControlType::FLAG, RTFKeyword::FORMSHADE, 0 },
+ { "fosnum", RTFControlType::VALUE, RTFKeyword::FOSNUM, 0 },
+ { "fprq", RTFControlType::VALUE, RTFKeyword::FPRQ, 0 },
+ { "fracwidth", RTFControlType::FLAG, RTFKeyword::FRACWIDTH, 0 },
+ { "frelative", RTFControlType::VALUE, RTFKeyword::FRELATIVE, 0 },
+ { "frmtxbtlr", RTFControlType::FLAG, RTFKeyword::FRMTXBTLR, 0 },
+ { "frmtxlrtb", RTFControlType::FLAG, RTFKeyword::FRMTXLRTB, 0 },
+ { "frmtxlrtbv", RTFControlType::FLAG, RTFKeyword::FRMTXLRTBV, 0 },
+ { "frmtxtbrl", RTFControlType::FLAG, RTFKeyword::FRMTXTBRL, 0 },
+ { "frmtxtbrlv", RTFControlType::FLAG, RTFKeyword::FRMTXTBRLV, 0 },
+ { "froman", RTFControlType::FLAG, RTFKeyword::FROMAN, 0 },
+ { "fromhtml", RTFControlType::VALUE, RTFKeyword::FROMHTML, 0 },
+ { "fromtext", RTFControlType::FLAG, RTFKeyword::FROMTEXT, 0 },
+ { "fs", RTFControlType::VALUE, RTFKeyword::FS, 24 },
+ { "fscript", RTFControlType::FLAG, RTFKeyword::FSCRIPT, 0 },
+ { "fswiss", RTFControlType::FLAG, RTFKeyword::FSWISS, 0 },
+ { "ftech", RTFControlType::FLAG, RTFKeyword::FTECH, 0 },
+ { "ftnalt", RTFControlType::FLAG, RTFKeyword::FTNALT, 0 },
+ { "ftnbj", RTFControlType::FLAG, RTFKeyword::FTNBJ, 0 },
+ { "ftncn", RTFControlType::DESTINATION, RTFKeyword::FTNCN, 0 },
+ { "ftnil", RTFControlType::FLAG, RTFKeyword::FTNIL, 0 },
+ { "ftnlytwnine", RTFControlType::FLAG, RTFKeyword::FTNLYTWNINE, 0 },
+ { "ftnnalc", RTFControlType::FLAG, RTFKeyword::FTNNALC, 0 },
+ { "ftnnar", RTFControlType::FLAG, RTFKeyword::FTNNAR, 0 },
+ { "ftnnauc", RTFControlType::FLAG, RTFKeyword::FTNNAUC, 0 },
+ { "ftnnchi", RTFControlType::FLAG, RTFKeyword::FTNNCHI, 0 },
+ { "ftnnchosung", RTFControlType::FLAG, RTFKeyword::FTNNCHOSUNG, 0 },
+ { "ftnncnum", RTFControlType::FLAG, RTFKeyword::FTNNCNUM, 0 },
+ { "ftnndbar", RTFControlType::FLAG, RTFKeyword::FTNNDBAR, 0 },
+ { "ftnndbnum", RTFControlType::FLAG, RTFKeyword::FTNNDBNUM, 0 },
+ { "ftnndbnumd", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMD, 0 },
+ { "ftnndbnumk", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMK, 0 },
+ { "ftnndbnumt", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMT, 0 },
+ { "ftnnganada", RTFControlType::FLAG, RTFKeyword::FTNNGANADA, 0 },
+ { "ftnngbnum", RTFControlType::FLAG, RTFKeyword::FTNNGBNUM, 0 },
+ { "ftnngbnumd", RTFControlType::FLAG, RTFKeyword::FTNNGBNUMD, 0 },
+ { "ftnngbnumk", RTFControlType::FLAG, RTFKeyword::FTNNGBNUMK, 0 },
+ { "ftnngbnuml", RTFControlType::FLAG, RTFKeyword::FTNNGBNUML, 0 },
+ { "ftnnrlc", RTFControlType::FLAG, RTFKeyword::FTNNRLC, 0 },
+ { "ftnnruc", RTFControlType::FLAG, RTFKeyword::FTNNRUC, 0 },
+ { "ftnnzodiac", RTFControlType::FLAG, RTFKeyword::FTNNZODIAC, 0 },
+ { "ftnnzodiacd", RTFControlType::FLAG, RTFKeyword::FTNNZODIACD, 0 },
+ { "ftnnzodiacl", RTFControlType::FLAG, RTFKeyword::FTNNZODIACL, 0 },
+ { "ftnrestart", RTFControlType::FLAG, RTFKeyword::FTNRESTART, 0 },
+ { "ftnrstcont", RTFControlType::FLAG, RTFKeyword::FTNRSTCONT, 0 },
+ { "ftnrstpg", RTFControlType::FLAG, RTFKeyword::FTNRSTPG, 0 },
+ { "ftnsep", RTFControlType::DESTINATION, RTFKeyword::FTNSEP, 0 },
+ { "ftnsepc", RTFControlType::DESTINATION, RTFKeyword::FTNSEPC, 0 },
+ { "ftnstart", RTFControlType::VALUE, RTFKeyword::FTNSTART, 1 },
+ { "ftntj", RTFControlType::FLAG, RTFKeyword::FTNTJ, 0 },
+ { "fttruetype", RTFControlType::FLAG, RTFKeyword::FTTRUETYPE, 0 },
+ { "fvaliddos", RTFControlType::FLAG, RTFKeyword::FVALIDDOS, 0 },
+ { "fvalidhpfs", RTFControlType::FLAG, RTFKeyword::FVALIDHPFS, 0 },
+ { "fvalidmac", RTFControlType::FLAG, RTFKeyword::FVALIDMAC, 0 },
+ { "fvalidntfs", RTFControlType::FLAG, RTFKeyword::FVALIDNTFS, 0 },
+ { "g", RTFControlType::DESTINATION, RTFKeyword::G, 0 },
+ { "gcw", RTFControlType::VALUE, RTFKeyword::GCW, 0 },
+ { "generator", RTFControlType::DESTINATION, RTFKeyword::GENERATOR, 0 },
+ { "green", RTFControlType::VALUE, RTFKeyword::GREEN, 0 },
+ { "grfdocevents", RTFControlType::VALUE, RTFKeyword::GRFDOCEVENTS, 0 },
+ { "gridtbl", RTFControlType::DESTINATION, RTFKeyword::GRIDTBL, 0 },
+ { "gutter", RTFControlType::VALUE, RTFKeyword::GUTTER, 0 },
+ { "gutterprl", RTFControlType::FLAG, RTFKeyword::GUTTERPRL, 0 },
+ { "guttersxn", RTFControlType::VALUE, RTFKeyword::GUTTERSXN, 0 },
+ { "header", RTFControlType::DESTINATION, RTFKeyword::HEADER, 0 },
+ { "headerf", RTFControlType::DESTINATION, RTFKeyword::HEADERF, 0 },
+ { "headerl", RTFControlType::DESTINATION, RTFKeyword::HEADERL, 0 },
+ { "headerr", RTFControlType::DESTINATION, RTFKeyword::HEADERR, 0 },
+ { "headery", RTFControlType::VALUE, RTFKeyword::HEADERY, 720 },
+ { "hich", RTFControlType::FLAG, RTFKeyword::HICH, 0 },
+ { "highlight", RTFControlType::VALUE, RTFKeyword::HIGHLIGHT, 0 },
+ { "hl", RTFControlType::DESTINATION, RTFKeyword::HL, 0 },
+ { "hlfr", RTFControlType::DESTINATION, RTFKeyword::HLFR, 0 },
+ { "hlinkbase", RTFControlType::DESTINATION, RTFKeyword::HLINKBASE, 0 },
+ { "hlloc", RTFControlType::DESTINATION, RTFKeyword::HLLOC, 0 },
+ { "hlsrc", RTFControlType::DESTINATION, RTFKeyword::HLSRC, 0 },
+ { "horzdoc", RTFControlType::FLAG, RTFKeyword::HORZDOC, 0 },
+ { "horzsect", RTFControlType::FLAG, RTFKeyword::HORZSECT, 0 },
+ { "horzvert", RTFControlType::VALUE, RTFKeyword::HORZVERT, 0 },
+ { "hr", RTFControlType::VALUE, RTFKeyword::HR, 0 },
+ { "hres", RTFControlType::VALUE, RTFKeyword::HRES, 0 },
+ { "hrule", RTFControlType::FLAG, RTFKeyword::HRULE, 0 },
+ { "hsv", RTFControlType::DESTINATION, RTFKeyword::HSV, 0 },
+ { "htmautsp", RTFControlType::FLAG, RTFKeyword::HTMAUTSP, 0 },
+ { "htmlbase", RTFControlType::FLAG, RTFKeyword::HTMLBASE, 0 },
+ { "htmlrtf", RTFControlType::TOGGLE, RTFKeyword::HTMLRTF, 1 },
+ { "htmltag", RTFControlType::DESTINATION, RTFKeyword::HTMLTAG, 0 },
+ { "hwelev", RTFControlType::FLAG, RTFKeyword::HWELEV, 0 },
+ { "hyphauto", RTFControlType::TOGGLE, RTFKeyword::HYPHAUTO, 1 },
+ { "hyphcaps", RTFControlType::TOGGLE, RTFKeyword::HYPHCAPS, 1 },
+ { "hyphconsec", RTFControlType::VALUE, RTFKeyword::HYPHCONSEC, 0 },
+ { "hyphhotz", RTFControlType::VALUE, RTFKeyword::HYPHHOTZ, 0 },
+ { "hyphpar", RTFControlType::TOGGLE, RTFKeyword::HYPHPAR, 1 },
+ { "i", RTFControlType::TOGGLE, RTFKeyword::I, 1 },
+ { "id", RTFControlType::VALUE, RTFKeyword::ID, 0 },
+ { "ignoremixedcontent", RTFControlType::VALUE, RTFKeyword::IGNOREMIXEDCONTENT, 0 },
+ { "ilfomacatclnup", RTFControlType::VALUE, RTFKeyword::ILFOMACATCLNUP, 0 },
+ { "ilvl", RTFControlType::VALUE, RTFKeyword::ILVL, 0 },
+ { "impr", RTFControlType::TOGGLE, RTFKeyword::IMPR, 1 },
+ { "indmirror", RTFControlType::FLAG, RTFKeyword::INDMIRROR, 0 },
+ { "indrlsweleven", RTFControlType::FLAG, RTFKeyword::INDRLSWELEVEN, 0 },
+ { "info", RTFControlType::DESTINATION, RTFKeyword::INFO, 0 },
+ { "insrsid", RTFControlType::VALUE, RTFKeyword::INSRSID, 0 },
+ { "intbl", RTFControlType::FLAG, RTFKeyword::INTBL, 0 },
+ { "ipgp", RTFControlType::VALUE, RTFKeyword::IPGP, 0 },
+ { "irowband", RTFControlType::VALUE, RTFKeyword::IROWBAND, 0 },
+ { "irow", RTFControlType::VALUE, RTFKeyword::IROW, 0 },
+ { "itap", RTFControlType::VALUE, RTFKeyword::ITAP, 1 },
+ { "ixe", RTFControlType::FLAG, RTFKeyword::IXE, 0 },
+ { "jcompress", RTFControlType::FLAG, RTFKeyword::JCOMPRESS, 0 },
+ { "jexpand", RTFControlType::FLAG, RTFKeyword::JEXPAND, 0 },
+ { "jis", RTFControlType::FLAG, RTFKeyword::JIS, 0 },
+ { "jpegblip", RTFControlType::FLAG, RTFKeyword::JPEGBLIP, 0 },
+ { "jsksu", RTFControlType::FLAG, RTFKeyword::JSKSU, 0 },
+ { "keep", RTFControlType::FLAG, RTFKeyword::KEEP, 0 },
+ { "keepn", RTFControlType::FLAG, RTFKeyword::KEEPN, 0 },
+ { "kerning", RTFControlType::VALUE, RTFKeyword::KERNING, 0 },
+ { "keycode", RTFControlType::DESTINATION, RTFKeyword::KEYCODE, 0 },
+ { "keywords", RTFControlType::DESTINATION, RTFKeyword::KEYWORDS, 0 },
+ { "krnprsnet", RTFControlType::FLAG, RTFKeyword::KRNPRSNET, 0 },
+ { "ksulang", RTFControlType::VALUE, RTFKeyword::KSULANG, 0 },
+ { "jclisttab", RTFControlType::FLAG, RTFKeyword::JCLISTTAB, 0 },
+ { "landscape", RTFControlType::FLAG, RTFKeyword::LANDSCAPE, 0 },
+ { "lang", RTFControlType::VALUE, RTFKeyword::LANG, 0 },
+ { "langfe", RTFControlType::VALUE, RTFKeyword::LANGFE, 0 },
+ { "langfenp", RTFControlType::VALUE, RTFKeyword::LANGFENP, 0 },
+ { "langnp", RTFControlType::VALUE, RTFKeyword::LANGNP, 0 },
+ { "lastrow", RTFControlType::FLAG, RTFKeyword::LASTROW, 0 },
+ { "latentstyles", RTFControlType::DESTINATION, RTFKeyword::LATENTSTYLES, 0 },
+ { "lbr", RTFControlType::VALUE, RTFKeyword::LBR, 0 },
+ { "lchars", RTFControlType::DESTINATION, RTFKeyword::LCHARS, 0 },
+ { "ldblquote", RTFControlType::SYMBOL, RTFKeyword::LDBLQUOTE, 0 },
+ { "level", RTFControlType::VALUE, RTFKeyword::LEVEL, 0 },
+ { "levelfollow", RTFControlType::VALUE, RTFKeyword::LEVELFOLLOW, 0 },
+ { "levelindent", RTFControlType::VALUE, RTFKeyword::LEVELINDENT, 0 },
+ { "leveljc", RTFControlType::VALUE, RTFKeyword::LEVELJC, 0 },
+ { "leveljcn", RTFControlType::VALUE, RTFKeyword::LEVELJCN, 0 },
+ { "levellegal", RTFControlType::VALUE, RTFKeyword::LEVELLEGAL, 0 },
+ { "levelnfc", RTFControlType::VALUE, RTFKeyword::LEVELNFC, 0 },
+ { "levelnfcn", RTFControlType::VALUE, RTFKeyword::LEVELNFCN, 0 },
+ { "levelnorestart", RTFControlType::VALUE, RTFKeyword::LEVELNORESTART, 0 },
+ { "levelnumbers", RTFControlType::DESTINATION, RTFKeyword::LEVELNUMBERS, 0 },
+ { "levelold", RTFControlType::VALUE, RTFKeyword::LEVELOLD, 0 },
+ { "levelpicture", RTFControlType::VALUE, RTFKeyword::LEVELPICTURE, 0 },
+ { "levelpicturenosize", RTFControlType::FLAG, RTFKeyword::LEVELPICTURENOSIZE, 0 },
+ { "levelprev", RTFControlType::VALUE, RTFKeyword::LEVELPREV, 0 },
+ { "levelprevspace", RTFControlType::VALUE, RTFKeyword::LEVELPREVSPACE, 0 },
+ { "levelspace", RTFControlType::VALUE, RTFKeyword::LEVELSPACE, 0 },
+ { "levelstartat", RTFControlType::VALUE, RTFKeyword::LEVELSTARTAT, 0 },
+ { "leveltemplateid", RTFControlType::VALUE, RTFKeyword::LEVELTEMPLATEID, 0 },
+ { "leveltext", RTFControlType::DESTINATION, RTFKeyword::LEVELTEXT, 0 },
+ { "lfolevel", RTFControlType::DESTINATION, RTFKeyword::LFOLEVEL, 0 },
+ { "li", RTFControlType::VALUE, RTFKeyword::LI, 0 },
+ { "line", RTFControlType::SYMBOL, RTFKeyword::LINE, 0 },
+ { "linebetcol", RTFControlType::FLAG, RTFKeyword::LINEBETCOL, 0 },
+ { "linecont", RTFControlType::FLAG, RTFKeyword::LINECONT, 0 },
+ { "linemod", RTFControlType::VALUE, RTFKeyword::LINEMOD, 1 },
+ { "lineppage", RTFControlType::FLAG, RTFKeyword::LINEPPAGE, 0 },
+ { "linerestart", RTFControlType::FLAG, RTFKeyword::LINERESTART, 0 },
+ { "linestart", RTFControlType::VALUE, RTFKeyword::LINESTART, 1 },
+ { "linestarts", RTFControlType::VALUE, RTFKeyword::LINESTARTS, 1 },
+ { "linex", RTFControlType::VALUE, RTFKeyword::LINEX, 360 },
+ { "linkself", RTFControlType::FLAG, RTFKeyword::LINKSELF, 0 },
+ { "linkstyles", RTFControlType::FLAG, RTFKeyword::LINKSTYLES, 0 },
+ { "linkval", RTFControlType::DESTINATION, RTFKeyword::LINKVAL, 0 },
+ { "lin", RTFControlType::VALUE, RTFKeyword::LIN, 0 },
+ { "lisa", RTFControlType::VALUE, RTFKeyword::LISA, 0 },
+ { "lisb", RTFControlType::VALUE, RTFKeyword::LISB, 0 },
+ { "list", RTFControlType::DESTINATION, RTFKeyword::LIST, 0 },
+ { "listhybrid", RTFControlType::FLAG, RTFKeyword::LISTHYBRID, 0 },
+ { "listid", RTFControlType::VALUE, RTFKeyword::LISTID, 0 },
+ { "listlevel", RTFControlType::DESTINATION, RTFKeyword::LISTLEVEL, 0 },
+ { "listname", RTFControlType::DESTINATION, RTFKeyword::LISTNAME, 0 },
+ { "listoverride", RTFControlType::DESTINATION, RTFKeyword::LISTOVERRIDE, 0 },
+ { "listoverridecount", RTFControlType::VALUE, RTFKeyword::LISTOVERRIDECOUNT, 0 },
+ { "listoverrideformat", RTFControlType::VALUE, RTFKeyword::LISTOVERRIDEFORMAT, 0 },
+ { "listoverridestartat", RTFControlType::FLAG, RTFKeyword::LISTOVERRIDESTARTAT, 0 },
+ { "listoverridetable", RTFControlType::DESTINATION, RTFKeyword::LISTOVERRIDETABLE, 0 },
+ { "listpicture", RTFControlType::DESTINATION, RTFKeyword::LISTPICTURE, 0 },
+ { "listrestarthdn", RTFControlType::VALUE, RTFKeyword::LISTRESTARTHDN, 0 },
+ { "listsimple", RTFControlType::VALUE, RTFKeyword::LISTSIMPLE, 0 },
+ { "liststyleid", RTFControlType::VALUE, RTFKeyword::LISTSTYLEID, 0 },
+ { "liststylename", RTFControlType::DESTINATION, RTFKeyword::LISTSTYLENAME, 0 },
+ { "listtable", RTFControlType::DESTINATION, RTFKeyword::LISTTABLE, 0 },
+ { "listtemplateid", RTFControlType::VALUE, RTFKeyword::LISTTEMPLATEID, 0 },
+ { "listtext", RTFControlType::DESTINATION, RTFKeyword::LISTTEXT, 0 },
+ { "lnbrkrule", RTFControlType::FLAG, RTFKeyword::LNBRKRULE, 0 },
+ { "lndscpsxn", RTFControlType::FLAG, RTFKeyword::LNDSCPSXN, 0 },
+ { "lnongrid", RTFControlType::FLAG, RTFKeyword::LNONGRID, 0 },
+ { "loch", RTFControlType::FLAG, RTFKeyword::LOCH, 0 },
+ { "lquote", RTFControlType::SYMBOL, RTFKeyword::LQUOTE, 0 },
+ { "ls", RTFControlType::VALUE, RTFKeyword::LS, 0 },
+ { "lsdlocked", RTFControlType::VALUE, RTFKeyword::LSDLOCKED, 0 },
+ { "lsdlockeddef", RTFControlType::VALUE, RTFKeyword::LSDLOCKEDDEF, 0 },
+ { "lsdlockedexcept", RTFControlType::DESTINATION, RTFKeyword::LSDLOCKEDEXCEPT, 0 },
+ { "lsdpriority", RTFControlType::VALUE, RTFKeyword::LSDPRIORITY, 0 },
+ { "lsdprioritydef", RTFControlType::VALUE, RTFKeyword::LSDPRIORITYDEF, 0 },
+ { "lsdqformat", RTFControlType::VALUE, RTFKeyword::LSDQFORMAT, 0 },
+ { "lsdqformatdef", RTFControlType::VALUE, RTFKeyword::LSDQFORMATDEF, 0 },
+ { "lsdsemihidden", RTFControlType::VALUE, RTFKeyword::LSDSEMIHIDDEN, 0 },
+ { "lsdsemihiddendef", RTFControlType::VALUE, RTFKeyword::LSDSEMIHIDDENDEF, 0 },
+ { "lsdstimax", RTFControlType::VALUE, RTFKeyword::LSDSTIMAX, 0 },
+ { "lsdunhideused", RTFControlType::VALUE, RTFKeyword::LSDUNHIDEUSED, 0 },
+ { "lsdunhideuseddef", RTFControlType::VALUE, RTFKeyword::LSDUNHIDEUSEDDEF, 0 },
+ { "ltrch", RTFControlType::FLAG, RTFKeyword::LTRCH, 0 },
+ { "ltrdoc", RTFControlType::FLAG, RTFKeyword::LTRDOC, 0 },
+ { "ltrmark", RTFControlType::SYMBOL, RTFKeyword::LTRMARK, 0 },
+ { "ltrpar", RTFControlType::FLAG, RTFKeyword::LTRPAR, 0 },
+ { "ltrrow", RTFControlType::FLAG, RTFKeyword::LTRROW, 0 },
+ { "ltrsect", RTFControlType::FLAG, RTFKeyword::LTRSECT, 0 },
+ { "lvltentative", RTFControlType::FLAG, RTFKeyword::LVLTENTATIVE, 0 },
+ { "lytcalctblwd", RTFControlType::FLAG, RTFKeyword::LYTCALCTBLWD, 0 },
+ { "lytexcttp", RTFControlType::FLAG, RTFKeyword::LYTEXCTTP, 0 },
+ { "lytprtmet", RTFControlType::FLAG, RTFKeyword::LYTPRTMET, 0 },
+ { "lyttblrtgr", RTFControlType::FLAG, RTFKeyword::LYTTBLRTGR, 0 },
+ { "mac", RTFControlType::FLAG, RTFKeyword::MAC, 0 },
+ { "macc", RTFControlType::DESTINATION, RTFKeyword::MACC, 0 },
+ { "maccPr", RTFControlType::DESTINATION, RTFKeyword::MACCPR, 0 },
+ { "macpict", RTFControlType::FLAG, RTFKeyword::MACPICT, 0 },
+ { "mailmerge", RTFControlType::DESTINATION, RTFKeyword::MAILMERGE, 0 },
+ { "makebackup", RTFControlType::FLAG, RTFKeyword::MAKEBACKUP, 0 },
+ { "maln", RTFControlType::DESTINATION, RTFKeyword::MALN, 0 },
+ { "malnScr", RTFControlType::DESTINATION, RTFKeyword::MALNSCR, 0 },
+ { "manager", RTFControlType::DESTINATION, RTFKeyword::MANAGER, 0 },
+ { "margb", RTFControlType::VALUE, RTFKeyword::MARGB, 1440 },
+ { "margbsxn", RTFControlType::VALUE, RTFKeyword::MARGBSXN, 0 },
+ { "margl", RTFControlType::VALUE, RTFKeyword::MARGL, 1800 },
+ { "marglsxn", RTFControlType::VALUE, RTFKeyword::MARGLSXN, 0 },
+ { "margmirror", RTFControlType::FLAG, RTFKeyword::MARGMIRROR, 0 },
+ { "margmirsxn", RTFControlType::FLAG, RTFKeyword::MARGMIRSXN, 0 },
+ { "margPr", RTFControlType::DESTINATION, RTFKeyword::MARGPR, 0 },
+ { "margr", RTFControlType::VALUE, RTFKeyword::MARGR, 1800 },
+ { "margrsxn", RTFControlType::VALUE, RTFKeyword::MARGRSXN, 0 },
+ { "margSz", RTFControlType::VALUE, RTFKeyword::MARGSZ, 0 },
+ { "margt", RTFControlType::VALUE, RTFKeyword::MARGT, 1440 },
+ { "margtsxn", RTFControlType::VALUE, RTFKeyword::MARGTSXN, 0 },
+ { "mbar", RTFControlType::DESTINATION, RTFKeyword::MBAR, 0 },
+ { "mbarPr", RTFControlType::DESTINATION, RTFKeyword::MBARPR, 0 },
+ { "mbaseJc", RTFControlType::DESTINATION, RTFKeyword::MBASEJC, 0 },
+ { "mbegChr", RTFControlType::DESTINATION, RTFKeyword::MBEGCHR, 0 },
+ { "mborderBox", RTFControlType::DESTINATION, RTFKeyword::MBORDERBOX, 0 },
+ { "mborderBoxPr", RTFControlType::DESTINATION, RTFKeyword::MBORDERBOXPR, 0 },
+ { "mbox", RTFControlType::DESTINATION, RTFKeyword::MBOX, 0 },
+ { "mboxPr", RTFControlType::DESTINATION, RTFKeyword::MBOXPR, 0 },
+ { "mbrk", RTFControlType::VALUE, RTFKeyword::MBRK, 0 },
+ { "mbrkBin", RTFControlType::VALUE, RTFKeyword::MBRKBIN, 0 },
+ { "mbrkBinSub", RTFControlType::VALUE, RTFKeyword::MBRKBINSUB, 0 },
+ { "mcGp", RTFControlType::VALUE, RTFKeyword::MCGP, 0 },
+ { "mcGpRule", RTFControlType::VALUE, RTFKeyword::MCGPRULE, 0 },
+ { "mchr", RTFControlType::DESTINATION, RTFKeyword::MCHR, 0 },
+ { "mcount", RTFControlType::DESTINATION, RTFKeyword::MCOUNT, 0 },
+ { "mcSp", RTFControlType::VALUE, RTFKeyword::MCSP, 0 },
+ { "mctrlPr", RTFControlType::DESTINATION, RTFKeyword::MCTRLPR, 0 },
+ { "md", RTFControlType::DESTINATION, RTFKeyword::MD, 0 },
+ { "mdefJc", RTFControlType::VALUE, RTFKeyword::MDEFJC, 0 },
+ { "mdeg", RTFControlType::DESTINATION, RTFKeyword::MDEG, 0 },
+ { "mdegHide", RTFControlType::DESTINATION, RTFKeyword::MDEGHIDE, 0 },
+ { "mden", RTFControlType::DESTINATION, RTFKeyword::MDEN, 0 },
+ { "mdiff", RTFControlType::DESTINATION, RTFKeyword::MDIFF, 0 },
+ { "mdiffSty", RTFControlType::VALUE, RTFKeyword::MDIFFSTY, 0 },
+ { "mdispdef", RTFControlType::VALUE, RTFKeyword::MDISPDEF, 1 },
+ { "mdPr", RTFControlType::DESTINATION, RTFKeyword::MDPR, 0 },
+ { "me", RTFControlType::DESTINATION, RTFKeyword::ME, 0 },
+ { "mendChr", RTFControlType::DESTINATION, RTFKeyword::MENDCHR, 0 },
+ { "meqArr", RTFControlType::DESTINATION, RTFKeyword::MEQARR, 0 },
+ { "meqArrPr", RTFControlType::DESTINATION, RTFKeyword::MEQARRPR, 0 },
+ { "mf", RTFControlType::DESTINATION, RTFKeyword::MF, 0 },
+ { "mfName", RTFControlType::DESTINATION, RTFKeyword::MFNAME, 0 },
+ { "mfPr", RTFControlType::DESTINATION, RTFKeyword::MFPR, 0 },
+ { "mfunc", RTFControlType::DESTINATION, RTFKeyword::MFUNC, 0 },
+ { "mfuncPr", RTFControlType::DESTINATION, RTFKeyword::MFUNCPR, 0 },
+ { "mgroupChr", RTFControlType::DESTINATION, RTFKeyword::MGROUPCHR, 0 },
+ { "mgroupChrPr", RTFControlType::DESTINATION, RTFKeyword::MGROUPCHRPR, 0 },
+ { "mgrow", RTFControlType::DESTINATION, RTFKeyword::MGROW, 0 },
+ { "mhideBot", RTFControlType::DESTINATION, RTFKeyword::MHIDEBOT, 0 },
+ { "mhideLeft", RTFControlType::DESTINATION, RTFKeyword::MHIDELEFT, 0 },
+ { "mhideRight", RTFControlType::DESTINATION, RTFKeyword::MHIDERIGHT, 0 },
+ { "mhideTop", RTFControlType::DESTINATION, RTFKeyword::MHIDETOP, 0 },
+ { "mhtmltag", RTFControlType::DESTINATION, RTFKeyword::MHTMLTAG, 0 },
+ { "min", RTFControlType::VALUE, RTFKeyword::MIN, 0 },
+ { "minterSp", RTFControlType::VALUE, RTFKeyword::MINTERSP, 0 },
+ { "mintLim", RTFControlType::VALUE, RTFKeyword::MINTLIM, 0 },
+ { "mintraSp", RTFControlType::VALUE, RTFKeyword::MINTRASP, 0 },
+ { "mjc", RTFControlType::VALUE, RTFKeyword::MJC, 0 },
+ { "mlim", RTFControlType::DESTINATION, RTFKeyword::MLIM, 0 },
+ { "mlimloc", RTFControlType::DESTINATION, RTFKeyword::MLIMLOC, 0 },
+ { "mlimLoc", RTFControlType::DESTINATION, RTFKeyword::MLIMLOC, 0 },
+ { "mlimlow", RTFControlType::DESTINATION, RTFKeyword::MLIMLOW, 0 },
+ { "mlimLow", RTFControlType::DESTINATION, RTFKeyword::MLIMLOW, 0 },
+ { "mlimlowPr", RTFControlType::DESTINATION, RTFKeyword::MLIMLOWPR, 0 },
+ { "mlimLowPr", RTFControlType::DESTINATION, RTFKeyword::MLIMLOWPR, 0 },
+ { "mlimupp", RTFControlType::DESTINATION, RTFKeyword::MLIMUPP, 0 },
+ { "mlimUpp", RTFControlType::DESTINATION, RTFKeyword::MLIMUPP, 0 },
+ { "mlimuppPr", RTFControlType::DESTINATION, RTFKeyword::MLIMUPPPR, 0 },
+ { "mlimUppPr", RTFControlType::DESTINATION, RTFKeyword::MLIMUPPPR, 0 },
+ { "mlit", RTFControlType::FLAG, RTFKeyword::MLIT, 0 },
+ { "mlMargin", RTFControlType::VALUE, RTFKeyword::MLMARGIN, 0 },
+ { "mm", RTFControlType::DESTINATION, RTFKeyword::MM, 0 },
+ { "mmaddfieldname", RTFControlType::DESTINATION, RTFKeyword::MMADDFIELDNAME, 0 },
+ { "mmath", RTFControlType::DESTINATION, RTFKeyword::MMATH, 0 },
+ { "mmathFont", RTFControlType::VALUE, RTFKeyword::MMATHFONT, 0 },
+ { "mmathPict", RTFControlType::DESTINATION, RTFKeyword::MMATHPICT, 0 },
+ { "mmathPr", RTFControlType::DESTINATION, RTFKeyword::MMATHPR, 0 },
+ { "mmattach", RTFControlType::FLAG, RTFKeyword::MMATTACH, 0 },
+ { "mmaxdist", RTFControlType::DESTINATION, RTFKeyword::MMAXDIST, 0 },
+ { "mmblanklines", RTFControlType::FLAG, RTFKeyword::MMBLANKLINES, 0 },
+ { "mmc", RTFControlType::DESTINATION, RTFKeyword::MMC, 0 },
+ { "mmcJc", RTFControlType::DESTINATION, RTFKeyword::MMCJC, 0 },
+ { "mmconnectstr", RTFControlType::DESTINATION, RTFKeyword::MMCONNECTSTR, 0 },
+ { "mmconnectstrdata", RTFControlType::DESTINATION, RTFKeyword::MMCONNECTSTRDATA, 0 },
+ { "mmcPr", RTFControlType::DESTINATION, RTFKeyword::MMCPR, 0 },
+ { "mmcs", RTFControlType::DESTINATION, RTFKeyword::MMCS, 0 },
+ { "mmdatasource", RTFControlType::DESTINATION, RTFKeyword::MMDATASOURCE, 0 },
+ { "mmdatatypeaccess", RTFControlType::FLAG, RTFKeyword::MMDATATYPEACCESS, 0 },
+ { "mmdatatypeexcel", RTFControlType::FLAG, RTFKeyword::MMDATATYPEEXCEL, 0 },
+ { "mmdatatypefile", RTFControlType::FLAG, RTFKeyword::MMDATATYPEFILE, 0 },
+ { "mmdatatypeodbc", RTFControlType::FLAG, RTFKeyword::MMDATATYPEODBC, 0 },
+ { "mmdatatypeodso", RTFControlType::FLAG, RTFKeyword::MMDATATYPEODSO, 0 },
+ { "mmdatatypeqt", RTFControlType::FLAG, RTFKeyword::MMDATATYPEQT, 0 },
+ { "mmdefaultsql", RTFControlType::FLAG, RTFKeyword::MMDEFAULTSQL, 0 },
+ { "mmdestemail", RTFControlType::FLAG, RTFKeyword::MMDESTEMAIL, 0 },
+ { "mmdestfax", RTFControlType::FLAG, RTFKeyword::MMDESTFAX, 0 },
+ { "mmdestnewdoc", RTFControlType::FLAG, RTFKeyword::MMDESTNEWDOC, 0 },
+ { "mmdestprinter", RTFControlType::FLAG, RTFKeyword::MMDESTPRINTER, 0 },
+ { "mmerrors", RTFControlType::VALUE, RTFKeyword::MMERRORS, 0 },
+ { "mmfttypeaddress", RTFControlType::FLAG, RTFKeyword::MMFTTYPEADDRESS, 0 },
+ { "mmfttypebarcode", RTFControlType::FLAG, RTFKeyword::MMFTTYPEBARCODE, 0 },
+ { "mmfttypedbcolumn", RTFControlType::FLAG, RTFKeyword::MMFTTYPEDBCOLUMN, 0 },
+ { "mmfttypemapped", RTFControlType::FLAG, RTFKeyword::MMFTTYPEMAPPED, 0 },
+ { "mmfttypenull", RTFControlType::FLAG, RTFKeyword::MMFTTYPENULL, 0 },
+ { "mmfttypesalutation", RTFControlType::FLAG, RTFKeyword::MMFTTYPESALUTATION, 0 },
+ { "mmheadersource", RTFControlType::DESTINATION, RTFKeyword::MMHEADERSOURCE, 0 },
+ { "mmjdsotype", RTFControlType::VALUE, RTFKeyword::MMJDSOTYPE, 0 },
+ { "mmlinktoquery", RTFControlType::FLAG, RTFKeyword::MMLINKTOQUERY, 0 },
+ { "mmmailsubject", RTFControlType::DESTINATION, RTFKeyword::MMMAILSUBJECT, 0 },
+ { "mmmaintypecatalog", RTFControlType::FLAG, RTFKeyword::MMMAINTYPECATALOG, 0 },
+ { "mmmaintypeemail", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEEMAIL, 0 },
+ { "mmmaintypeenvelopes", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEENVELOPES, 0 },
+ { "mmmaintypefax", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEFAX, 0 },
+ { "mmmaintypelabels", RTFControlType::FLAG, RTFKeyword::MMMAINTYPELABELS, 0 },
+ { "mmmaintypeletters", RTFControlType::FLAG, RTFKeyword::MMMAINTYPELETTERS, 0 },
+ { "mmodso", RTFControlType::DESTINATION, RTFKeyword::MMODSO, 0 },
+ { "mmodsoactive", RTFControlType::VALUE, RTFKeyword::MMODSOACTIVE, 0 },
+ { "mmodsocoldelim", RTFControlType::VALUE, RTFKeyword::MMODSOCOLDELIM, 0 },
+ { "mmodsocolumn", RTFControlType::VALUE, RTFKeyword::MMODSOCOLUMN, 0 },
+ { "mmodsodynaddr", RTFControlType::VALUE, RTFKeyword::MMODSODYNADDR, 0 },
+ { "mmodsofhdr", RTFControlType::VALUE, RTFKeyword::MMODSOFHDR, 0 },
+ { "mmodsofilter", RTFControlType::DESTINATION, RTFKeyword::MMODSOFILTER, 0 },
+ { "mmodsofldmpdata", RTFControlType::DESTINATION, RTFKeyword::MMODSOFLDMPDATA, 0 },
+ { "mmodsofmcolumn", RTFControlType::VALUE, RTFKeyword::MMODSOFMCOLUMN, 0 },
+ { "mmodsohash", RTFControlType::VALUE, RTFKeyword::MMODSOHASH, 0 },
+ { "mmodsolid", RTFControlType::VALUE, RTFKeyword::MMODSOLID, 0 },
+ { "mmodsomappedname", RTFControlType::DESTINATION, RTFKeyword::MMODSOMAPPEDNAME, 0 },
+ { "mmodsoname", RTFControlType::DESTINATION, RTFKeyword::MMODSONAME, 0 },
+ { "mmodsorecipdata", RTFControlType::DESTINATION, RTFKeyword::MMODSORECIPDATA, 0 },
+ { "mmodsosort", RTFControlType::DESTINATION, RTFKeyword::MMODSOSORT, 0 },
+ { "mmodsosrc", RTFControlType::DESTINATION, RTFKeyword::MMODSOSRC, 0 },
+ { "mmodsotable", RTFControlType::DESTINATION, RTFKeyword::MMODSOTABLE, 0 },
+ { "mmodsoudl", RTFControlType::DESTINATION, RTFKeyword::MMODSOUDL, 0 },
+ { "mmodsoudldata", RTFControlType::DESTINATION, RTFKeyword::MMODSOUDLDATA, 0 },
+ { "mmodsouniquetag", RTFControlType::DESTINATION, RTFKeyword::MMODSOUNIQUETAG, 0 },
+ { "mmPr", RTFControlType::DESTINATION, RTFKeyword::MMPR, 0 },
+ { "mmquery", RTFControlType::DESTINATION, RTFKeyword::MMQUERY, 0 },
+ { "mmr", RTFControlType::DESTINATION, RTFKeyword::MMR, 0 },
+ { "mmreccur", RTFControlType::VALUE, RTFKeyword::MMRECCUR, 0 },
+ { "mmshowdata", RTFControlType::FLAG, RTFKeyword::MMSHOWDATA, 0 },
+ { "mnary", RTFControlType::DESTINATION, RTFKeyword::MNARY, 0 },
+ { "mnaryLim", RTFControlType::VALUE, RTFKeyword::MNARYLIM, 0 },
+ { "mnaryPr", RTFControlType::DESTINATION, RTFKeyword::MNARYPR, 0 },
+ { "mnoBreak", RTFControlType::DESTINATION, RTFKeyword::MNOBREAK, 0 },
+ { "mnor", RTFControlType::FLAG, RTFKeyword::MNOR, 0 },
+ { "mnum", RTFControlType::DESTINATION, RTFKeyword::MNUM, 0 },
+ { "mo", RTFControlType::VALUE, RTFKeyword::MO, 0 },
+ { "mobjDist", RTFControlType::DESTINATION, RTFKeyword::MOBJDIST, 0 },
+ { "moMath", RTFControlType::DESTINATION, RTFKeyword::MOMATH, 0 },
+ { "moMathPara", RTFControlType::DESTINATION, RTFKeyword::MOMATHPARA, 0 },
+ { "moMathParaPr", RTFControlType::DESTINATION, RTFKeyword::MOMATHPARAPR, 0 },
+ { "mopEmu", RTFControlType::DESTINATION, RTFKeyword::MOPEMU, 0 },
+ { "mphant", RTFControlType::DESTINATION, RTFKeyword::MPHANT, 0 },
+ { "mphantPr", RTFControlType::DESTINATION, RTFKeyword::MPHANTPR, 0 },
+ { "mplcHide", RTFControlType::DESTINATION, RTFKeyword::MPLCHIDE, 0 },
+ { "mpos", RTFControlType::DESTINATION, RTFKeyword::MPOS, 0 },
+ { "mpostSp", RTFControlType::VALUE, RTFKeyword::MPOSTSP, 0 },
+ { "mpreSp", RTFControlType::VALUE, RTFKeyword::MPRESP, 0 },
+ { "mr", RTFControlType::DESTINATION, RTFKeyword::MR, 0 },
+ { "mrad", RTFControlType::DESTINATION, RTFKeyword::MRAD, 0 },
+ { "mradPr", RTFControlType::DESTINATION, RTFKeyword::MRADPR, 0 },
+ { "mrMargin", RTFControlType::VALUE, RTFKeyword::MRMARGIN, 0 },
+ { "mrPr", RTFControlType::DESTINATION, RTFKeyword::MRPR, 0 },
+ { "mrSp", RTFControlType::VALUE, RTFKeyword::MRSP, 0 },
+ { "mrSpRule", RTFControlType::VALUE, RTFKeyword::MRSPRULE, 0 },
+ { "mscr", RTFControlType::VALUE, RTFKeyword::MSCR, 0 },
+ { "msepChr", RTFControlType::DESTINATION, RTFKeyword::MSEPCHR, 0 },
+ { "mshow", RTFControlType::DESTINATION, RTFKeyword::MSHOW, 0 },
+ { "mshp", RTFControlType::DESTINATION, RTFKeyword::MSHP, 0 },
+ { "msmallFrac", RTFControlType::VALUE, RTFKeyword::MSMALLFRAC, 0 },
+ { "msmcap", RTFControlType::FLAG, RTFKeyword::MSMCAP, 0 },
+ { "msPre", RTFControlType::DESTINATION, RTFKeyword::MSPRE, 0 },
+ { "msPrePr", RTFControlType::DESTINATION, RTFKeyword::MSPREPR, 0 },
+ { "msSub", RTFControlType::DESTINATION, RTFKeyword::MSSUB, 0 },
+ { "msSubPr", RTFControlType::DESTINATION, RTFKeyword::MSSUBPR, 0 },
+ { "msSubSup", RTFControlType::DESTINATION, RTFKeyword::MSSUBSUP, 0 },
+ { "msSubSupPr", RTFControlType::DESTINATION, RTFKeyword::MSSUBSUPPR, 0 },
+ { "msSup", RTFControlType::DESTINATION, RTFKeyword::MSSUP, 0 },
+ { "msSupPr", RTFControlType::DESTINATION, RTFKeyword::MSSUPPR, 0 },
+ { "mstrikeBLTR", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEBLTR, 0 },
+ { "mstrikeH", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEH, 0 },
+ { "mstrikeTLBR", RTFControlType::DESTINATION, RTFKeyword::MSTRIKETLBR, 0 },
+ { "mstrikeV", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEV, 0 },
+ { "msty", RTFControlType::VALUE, RTFKeyword::MSTY, 0 },
+ { "msub", RTFControlType::DESTINATION, RTFKeyword::MSUB, 0 },
+ { "msubHide", RTFControlType::DESTINATION, RTFKeyword::MSUBHIDE, 0 },
+ { "msup", RTFControlType::DESTINATION, RTFKeyword::MSUP, 0 },
+ { "msupHide", RTFControlType::DESTINATION, RTFKeyword::MSUPHIDE, 0 },
+ { "mtransp", RTFControlType::DESTINATION, RTFKeyword::MTRANSP, 0 },
+ { "mtype", RTFControlType::DESTINATION, RTFKeyword::MTYPE, 0 },
+ { "muser", RTFControlType::FLAG, RTFKeyword::MUSER, 0 },
+ { "mvauth", RTFControlType::VALUE, RTFKeyword::MVAUTH, 0 },
+ { "mvdate", RTFControlType::VALUE, RTFKeyword::MVDATE, 0 },
+ { "mvertJc", RTFControlType::DESTINATION, RTFKeyword::MVERTJC, 0 },
+ { "mvf", RTFControlType::FLAG, RTFKeyword::MVF, 0 },
+ { "mvfmf", RTFControlType::DESTINATION, RTFKeyword::MVFMF, 0 },
+ { "mvfml", RTFControlType::DESTINATION, RTFKeyword::MVFML, 0 },
+ { "mvt", RTFControlType::FLAG, RTFKeyword::MVT, 0 },
+ { "mvtof", RTFControlType::DESTINATION, RTFKeyword::MVTOF, 0 },
+ { "mvtol", RTFControlType::DESTINATION, RTFKeyword::MVTOL, 0 },
+ { "mwrapIndent", RTFControlType::VALUE, RTFKeyword::MWRAPINDENT, 1440 },
+ { "mwrapRight", RTFControlType::VALUE, RTFKeyword::MWRAPRIGHT, 0 },
+ { "mzeroAsc", RTFControlType::DESTINATION, RTFKeyword::MZEROASC, 0 },
+ { "mzeroDesc", RTFControlType::DESTINATION, RTFKeyword::MZERODESC, 0 },
+ { "mzeroWid", RTFControlType::DESTINATION, RTFKeyword::MZEROWID, 0 },
+ { "nestcell", RTFControlType::SYMBOL, RTFKeyword::NESTCELL, 0 },
+ { "nestrow", RTFControlType::SYMBOL, RTFKeyword::NESTROW, 0 },
+ { "nesttableprops", RTFControlType::DESTINATION, RTFKeyword::NESTTABLEPROPS, 0 },
+ { "newtblstyruls", RTFControlType::FLAG, RTFKeyword::NEWTBLSTYRULS, 0 },
+ { "nextfile", RTFControlType::DESTINATION, RTFKeyword::NEXTFILE, 0 },
+ { "noafcnsttbl", RTFControlType::FLAG, RTFKeyword::NOAFCNSTTBL, 0 },
+ { "nobrkwrptbl", RTFControlType::FLAG, RTFKeyword::NOBRKWRPTBL, 0 },
+ { "nocolbal", RTFControlType::FLAG, RTFKeyword::NOCOLBAL, 0 },
+ { "nocompatoptions", RTFControlType::FLAG, RTFKeyword::NOCOMPATOPTIONS, 0 },
+ { "nocwrap", RTFControlType::FLAG, RTFKeyword::NOCWRAP, 0 },
+ { "nocxsptable", RTFControlType::FLAG, RTFKeyword::NOCXSPTABLE, 0 },
+ { "noextrasprl", RTFControlType::FLAG, RTFKeyword::NOEXTRASPRL, 0 },
+ { "nofchars", RTFControlType::VALUE, RTFKeyword::NOFCHARS, 0 },
+ { "nofcharsws", RTFControlType::VALUE, RTFKeyword::NOFCHARSWS, 0 },
+ { "nofeaturethrottle", RTFControlType::FLAG, RTFKeyword::NOFEATURETHROTTLE, 0 },
+ { "nofpages", RTFControlType::VALUE, RTFKeyword::NOFPAGES, 0 },
+ { "nofwords", RTFControlType::VALUE, RTFKeyword::NOFWORDS, 0 },
+ { "nogrowautofit", RTFControlType::FLAG, RTFKeyword::NOGROWAUTOFIT, 0 },
+ { "noindnmbrts", RTFControlType::FLAG, RTFKeyword::NOINDNMBRTS, 0 },
+ { "nojkernpunct", RTFControlType::FLAG, RTFKeyword::NOJKERNPUNCT, 0 },
+ { "nolead", RTFControlType::FLAG, RTFKeyword::NOLEAD, 0 },
+ { "noline", RTFControlType::FLAG, RTFKeyword::NOLINE, 0 },
+ { "nolnhtadjtbl", RTFControlType::FLAG, RTFKeyword::NOLNHTADJTBL, 0 },
+ { "nonesttables", RTFControlType::DESTINATION, RTFKeyword::NONESTTABLES, 0 },
+ { "nonshppict", RTFControlType::FLAG, RTFKeyword::NONSHPPICT, 0 },
+ { "nooverflow", RTFControlType::FLAG, RTFKeyword::NOOVERFLOW, 0 },
+ { "noproof", RTFControlType::FLAG, RTFKeyword::NOPROOF, 0 },
+ { "noqfpromote", RTFControlType::FLAG, RTFKeyword::NOQFPROMOTE, 0 },
+ { "nosectexpand", RTFControlType::FLAG, RTFKeyword::NOSECTEXPAND, 0 },
+ { "nosnaplinegrid", RTFControlType::FLAG, RTFKeyword::NOSNAPLINEGRID, 0 },
+ { "nospaceforul", RTFControlType::FLAG, RTFKeyword::NOSPACEFORUL, 0 },
+ { "nosupersub", RTFControlType::FLAG, RTFKeyword::NOSUPERSUB, 0 },
+ { "notabind", RTFControlType::FLAG, RTFKeyword::NOTABIND, 0 },
+ { "notbrkcnstfrctbl", RTFControlType::FLAG, RTFKeyword::NOTBRKCNSTFRCTBL, 0 },
+ { "notcvasp", RTFControlType::FLAG, RTFKeyword::NOTCVASP, 0 },
+ { "notvatxbx", RTFControlType::FLAG, RTFKeyword::NOTVATXBX, 0 },
+ { "nouicompat", RTFControlType::FLAG, RTFKeyword::NOUICOMPAT, 0 },
+ { "noultrlspc", RTFControlType::FLAG, RTFKeyword::NOULTRLSPC, 0 },
+ { "nowidctlpar", RTFControlType::FLAG, RTFKeyword::NOWIDCTLPAR, 0 },
+ { "nowrap", RTFControlType::FLAG, RTFKeyword::NOWRAP, 0 },
+ { "nowwrap", RTFControlType::FLAG, RTFKeyword::NOWWRAP, 0 },
+ { "noxlattoyen", RTFControlType::FLAG, RTFKeyword::NOXLATTOYEN, 0 },
+ { "objalias", RTFControlType::DESTINATION, RTFKeyword::OBJALIAS, 0 },
+ { "objalign", RTFControlType::VALUE, RTFKeyword::OBJALIGN, 0 },
+ { "objattph", RTFControlType::FLAG, RTFKeyword::OBJATTPH, 0 },
+ { "objautlink", RTFControlType::FLAG, RTFKeyword::OBJAUTLINK, 0 },
+ { "objclass", RTFControlType::DESTINATION, RTFKeyword::OBJCLASS, 0 },
+ { "objcropb", RTFControlType::VALUE, RTFKeyword::OBJCROPB, 0 },
+ { "objcropl", RTFControlType::VALUE, RTFKeyword::OBJCROPL, 0 },
+ { "objcropr", RTFControlType::VALUE, RTFKeyword::OBJCROPR, 0 },
+ { "objcropt", RTFControlType::VALUE, RTFKeyword::OBJCROPT, 0 },
+ { "objdata", RTFControlType::DESTINATION, RTFKeyword::OBJDATA, 0 },
+ { "object", RTFControlType::DESTINATION, RTFKeyword::OBJECT, 0 },
+ { "objemb", RTFControlType::FLAG, RTFKeyword::OBJEMB, 0 },
+ { "objh", RTFControlType::VALUE, RTFKeyword::OBJH, 0 },
+ { "objhtml", RTFControlType::FLAG, RTFKeyword::OBJHTML, 0 },
+ { "objicemb", RTFControlType::FLAG, RTFKeyword::OBJICEMB, 0 },
+ { "objlink", RTFControlType::FLAG, RTFKeyword::OBJLINK, 0 },
+ { "objlock", RTFControlType::FLAG, RTFKeyword::OBJLOCK, 0 },
+ { "objname", RTFControlType::DESTINATION, RTFKeyword::OBJNAME, 0 },
+ { "objocx", RTFControlType::FLAG, RTFKeyword::OBJOCX, 0 },
+ { "objpub", RTFControlType::FLAG, RTFKeyword::OBJPUB, 0 },
+ { "objscalex", RTFControlType::VALUE, RTFKeyword::OBJSCALEX, 0 },
+ { "objscaley", RTFControlType::VALUE, RTFKeyword::OBJSCALEY, 0 },
+ { "objsect", RTFControlType::DESTINATION, RTFKeyword::OBJSECT, 0 },
+ { "objsetsize", RTFControlType::FLAG, RTFKeyword::OBJSETSIZE, 0 },
+ { "objsub", RTFControlType::FLAG, RTFKeyword::OBJSUB, 0 },
+ { "objtime", RTFControlType::DESTINATION, RTFKeyword::OBJTIME, 0 },
+ { "objtransy", RTFControlType::VALUE, RTFKeyword::OBJTRANSY, 0 },
+ { "objupdate", RTFControlType::FLAG, RTFKeyword::OBJUPDATE, 0 },
+ { "objw", RTFControlType::VALUE, RTFKeyword::OBJW, 0 },
+ { "ogutter", RTFControlType::VALUE, RTFKeyword::OGUTTER, 0 },
+ { "oldas", RTFControlType::FLAG, RTFKeyword::OLDAS, 0 },
+ { "oldcprops", RTFControlType::DESTINATION, RTFKeyword::OLDCPROPS, 0 },
+ { "oldlinewrap", RTFControlType::FLAG, RTFKeyword::OLDLINEWRAP, 0 },
+ { "oldpprops", RTFControlType::DESTINATION, RTFKeyword::OLDPPROPS, 0 },
+ { "oldsprops", RTFControlType::DESTINATION, RTFKeyword::OLDSPROPS, 0 },
+ { "oldtprops", RTFControlType::DESTINATION, RTFKeyword::OLDTPROPS, 0 },
+ { "oleclsid", RTFControlType::DESTINATION, RTFKeyword::OLECLSID, 0 },
+ { "operator", RTFControlType::DESTINATION, RTFKeyword::OPERATOR, 0 },
+ { "otblrul", RTFControlType::FLAG, RTFKeyword::OTBLRUL, 0 },
+ { "outl", RTFControlType::TOGGLE, RTFKeyword::OUTL, 1 },
+ { "outlinelevel", RTFControlType::VALUE, RTFKeyword::OUTLINELEVEL, 0 },
+ { "overlay", RTFControlType::FLAG, RTFKeyword::OVERLAY, 0 },
+ { "page", RTFControlType::SYMBOL, RTFKeyword::PAGE, 0 },
+ { "pagebb", RTFControlType::FLAG, RTFKeyword::PAGEBB, 0 },
+ { "panose", RTFControlType::DESTINATION, RTFKeyword::PANOSE, 0 },
+ { "paperh", RTFControlType::VALUE, RTFKeyword::PAPERH, 15840 },
+ { "paperw", RTFControlType::VALUE, RTFKeyword::PAPERW, 12240 },
+ { "par", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "pararsid", RTFControlType::VALUE, RTFKeyword::PARARSID, 0 },
+ { "pard", RTFControlType::FLAG, RTFKeyword::PARD, 0 },
+ { "password", RTFControlType::DESTINATION, RTFKeyword::PASSWORD, 0 },
+ { "passwordhash", RTFControlType::DESTINATION, RTFKeyword::PASSWORDHASH, 0 },
+ { "pc", RTFControlType::FLAG, RTFKeyword::PC, 0 },
+ { "pca", RTFControlType::FLAG, RTFKeyword::PCA, 0 },
+ { "pgbrdrb", RTFControlType::FLAG, RTFKeyword::PGBRDRB, 0 },
+ { "pgbrdrfoot", RTFControlType::FLAG, RTFKeyword::PGBRDRFOOT, 0 },
+ { "pgbrdrhead", RTFControlType::FLAG, RTFKeyword::PGBRDRHEAD, 0 },
+ { "pgbrdrl", RTFControlType::FLAG, RTFKeyword::PGBRDRL, 0 },
+ { "pgbrdropt", RTFControlType::VALUE, RTFKeyword::PGBRDROPT, 0 },
+ { "pgbrdrr", RTFControlType::FLAG, RTFKeyword::PGBRDRR, 0 },
+ { "pgbrdrsnap", RTFControlType::FLAG, RTFKeyword::PGBRDRSNAP, 0 },
+ { "pgbrdrt", RTFControlType::FLAG, RTFKeyword::PGBRDRT, 0 },
+ { "pghsxn", RTFControlType::VALUE, RTFKeyword::PGHSXN, 0 },
+ { "pgnbidia", RTFControlType::FLAG, RTFKeyword::PGNBIDIA, 0 },
+ { "pgnbidib", RTFControlType::FLAG, RTFKeyword::PGNBIDIB, 0 },
+ { "pgnchosung", RTFControlType::FLAG, RTFKeyword::PGNCHOSUNG, 0 },
+ { "pgncnum", RTFControlType::FLAG, RTFKeyword::PGNCNUM, 0 },
+ { "pgncont", RTFControlType::FLAG, RTFKeyword::PGNCONT, 0 },
+ { "pgndbnum", RTFControlType::FLAG, RTFKeyword::PGNDBNUM, 0 },
+ { "pgndbnumd", RTFControlType::FLAG, RTFKeyword::PGNDBNUMD, 0 },
+ { "pgndbnumk", RTFControlType::FLAG, RTFKeyword::PGNDBNUMK, 0 },
+ { "pgndbnumt", RTFControlType::FLAG, RTFKeyword::PGNDBNUMT, 0 },
+ { "pgndec", RTFControlType::FLAG, RTFKeyword::PGNDEC, 0 },
+ { "pgndecd", RTFControlType::FLAG, RTFKeyword::PGNDECD, 0 },
+ { "pgnganada", RTFControlType::FLAG, RTFKeyword::PGNGANADA, 0 },
+ { "pgngbnum", RTFControlType::FLAG, RTFKeyword::PGNGBNUM, 0 },
+ { "pgngbnumd", RTFControlType::FLAG, RTFKeyword::PGNGBNUMD, 0 },
+ { "pgngbnumk", RTFControlType::FLAG, RTFKeyword::PGNGBNUMK, 0 },
+ { "pgngbnuml", RTFControlType::FLAG, RTFKeyword::PGNGBNUML, 0 },
+ { "pgnhindia", RTFControlType::FLAG, RTFKeyword::PGNHINDIA, 0 },
+ { "pgnhindib", RTFControlType::FLAG, RTFKeyword::PGNHINDIB, 0 },
+ { "pgnhindic", RTFControlType::FLAG, RTFKeyword::PGNHINDIC, 0 },
+ { "pgnhindid", RTFControlType::FLAG, RTFKeyword::PGNHINDID, 0 },
+ { "pgnhn", RTFControlType::VALUE, RTFKeyword::PGNHN, 0 },
+ { "pgnhnsc", RTFControlType::FLAG, RTFKeyword::PGNHNSC, 0 },
+ { "pgnhnsh", RTFControlType::FLAG, RTFKeyword::PGNHNSH, 0 },
+ { "pgnhnsm", RTFControlType::FLAG, RTFKeyword::PGNHNSM, 0 },
+ { "pgnhnsn", RTFControlType::FLAG, RTFKeyword::PGNHNSN, 0 },
+ { "pgnhnsp", RTFControlType::FLAG, RTFKeyword::PGNHNSP, 0 },
+ { "pgnid", RTFControlType::FLAG, RTFKeyword::PGNID, 0 },
+ { "pgnlcltr", RTFControlType::FLAG, RTFKeyword::PGNLCLTR, 0 },
+ { "pgnlcrm", RTFControlType::FLAG, RTFKeyword::PGNLCRM, 0 },
+ { "pgnrestart", RTFControlType::FLAG, RTFKeyword::PGNRESTART, 0 },
+ { "pgnstart", RTFControlType::VALUE, RTFKeyword::PGNSTART, 1 },
+ { "pgnstarts", RTFControlType::VALUE, RTFKeyword::PGNSTARTS, 1 },
+ { "pgnthaia", RTFControlType::FLAG, RTFKeyword::PGNTHAIA, 0 },
+ { "pgnthaib", RTFControlType::FLAG, RTFKeyword::PGNTHAIB, 0 },
+ { "pgnthaic", RTFControlType::FLAG, RTFKeyword::PGNTHAIC, 0 },
+ { "pgnucltr", RTFControlType::FLAG, RTFKeyword::PGNUCLTR, 0 },
+ { "pgnucrm", RTFControlType::FLAG, RTFKeyword::PGNUCRM, 0 },
+ { "pgnvieta", RTFControlType::FLAG, RTFKeyword::PGNVIETA, 0 },
+ { "pgnx", RTFControlType::VALUE, RTFKeyword::PGNX, 720 },
+ { "pgny", RTFControlType::VALUE, RTFKeyword::PGNY, 720 },
+ { "pgnzodiac", RTFControlType::FLAG, RTFKeyword::PGNZODIAC, 0 },
+ { "pgnzodiacd", RTFControlType::FLAG, RTFKeyword::PGNZODIACD, 0 },
+ { "pgnzodiacl", RTFControlType::FLAG, RTFKeyword::PGNZODIACL, 0 },
+ { "pgp", RTFControlType::DESTINATION, RTFKeyword::PGP, 0 },
+ { "pgptbl", RTFControlType::DESTINATION, RTFKeyword::PGPTBL, 0 },
+ { "pgwsxn", RTFControlType::VALUE, RTFKeyword::PGWSXN, 0 },
+ { "phcol", RTFControlType::FLAG, RTFKeyword::PHCOL, 0 },
+ { "phmrg", RTFControlType::FLAG, RTFKeyword::PHMRG, 0 },
+ { "phpg", RTFControlType::FLAG, RTFKeyword::PHPG, 0 },
+ { "picbmp", RTFControlType::FLAG, RTFKeyword::PICBMP, 0 },
+ { "picbpp", RTFControlType::VALUE, RTFKeyword::PICBPP, 0 },
+ { "piccropb", RTFControlType::VALUE, RTFKeyword::PICCROPB, 0 },
+ { "piccropl", RTFControlType::VALUE, RTFKeyword::PICCROPL, 0 },
+ { "piccropr", RTFControlType::VALUE, RTFKeyword::PICCROPR, 0 },
+ { "piccropt", RTFControlType::VALUE, RTFKeyword::PICCROPT, 0 },
+ { "pich", RTFControlType::VALUE, RTFKeyword::PICH, 0 },
+ { "pichgoal", RTFControlType::VALUE, RTFKeyword::PICHGOAL, 0 },
+ { "pichGoal", RTFControlType::VALUE, RTFKeyword::PICHGOAL, 0 },
+ { "picprop", RTFControlType::DESTINATION, RTFKeyword::PICPROP, 0 },
+ { "picscaled", RTFControlType::FLAG, RTFKeyword::PICSCALED, 0 },
+ { "picscalex", RTFControlType::VALUE, RTFKeyword::PICSCALEX, 100 },
+ { "picscaley", RTFControlType::VALUE, RTFKeyword::PICSCALEY, 100 },
+ { "pict", RTFControlType::DESTINATION, RTFKeyword::PICT, 0 },
+ { "picw", RTFControlType::VALUE, RTFKeyword::PICW, 0 },
+ { "picwgoal", RTFControlType::VALUE, RTFKeyword::PICWGOAL, 0 },
+ { "picwGoal", RTFControlType::VALUE, RTFKeyword::PICWGOAL, 0 },
+ { "pindtabqc", RTFControlType::FLAG, RTFKeyword::PINDTABQC, 0 },
+ { "pindtabql", RTFControlType::FLAG, RTFKeyword::PINDTABQL, 0 },
+ { "pindtabqr", RTFControlType::FLAG, RTFKeyword::PINDTABQR, 0 },
+ { "plain", RTFControlType::FLAG, RTFKeyword::PLAIN, 0 },
+ { "pmartabqc", RTFControlType::FLAG, RTFKeyword::PMARTABQC, 0 },
+ { "pmartabql", RTFControlType::FLAG, RTFKeyword::PMARTABQL, 0 },
+ { "pmartabqr", RTFControlType::FLAG, RTFKeyword::PMARTABQR, 0 },
+ { "pmmetafile", RTFControlType::VALUE, RTFKeyword::PMMETAFILE, 0 },
+ { "pn", RTFControlType::DESTINATION, RTFKeyword::PN, 0 },
+ { "pnacross", RTFControlType::FLAG, RTFKeyword::PNACROSS, 0 },
+ { "pnaiu", RTFControlType::FLAG, RTFKeyword::PNAIU, 0 },
+ { "pnaiud", RTFControlType::FLAG, RTFKeyword::PNAIUD, 0 },
+ { "pnaiueo", RTFControlType::FLAG, RTFKeyword::PNAIUEO, 0 },
+ { "pnaiueod", RTFControlType::FLAG, RTFKeyword::PNAIUEOD, 0 },
+ { "pnb", RTFControlType::TOGGLE, RTFKeyword::PNB, 1 },
+ { "pnbidia", RTFControlType::FLAG, RTFKeyword::PNBIDIA, 0 },
+ { "pnbidib", RTFControlType::FLAG, RTFKeyword::PNBIDIB, 0 },
+ { "pncaps", RTFControlType::TOGGLE, RTFKeyword::PNCAPS, 1 },
+ { "pncard", RTFControlType::FLAG, RTFKeyword::PNCARD, 0 },
+ { "pncf", RTFControlType::VALUE, RTFKeyword::PNCF, 0 },
+ { "pnchosung", RTFControlType::FLAG, RTFKeyword::PNCHOSUNG, 0 },
+ { "pncnum", RTFControlType::FLAG, RTFKeyword::PNCNUM, 0 },
+ { "pndbnum", RTFControlType::FLAG, RTFKeyword::PNDBNUM, 0 },
+ { "pndbnumd", RTFControlType::FLAG, RTFKeyword::PNDBNUMD, 0 },
+ { "pndbnumk", RTFControlType::FLAG, RTFKeyword::PNDBNUMK, 0 },
+ { "pndbnuml", RTFControlType::FLAG, RTFKeyword::PNDBNUML, 0 },
+ { "pndbnumt", RTFControlType::FLAG, RTFKeyword::PNDBNUMT, 0 },
+ { "pndec", RTFControlType::FLAG, RTFKeyword::PNDEC, 0 },
+ { "pndecd", RTFControlType::FLAG, RTFKeyword::PNDECD, 0 },
+ { "pnf", RTFControlType::VALUE, RTFKeyword::PNF, 0 },
+ { "pnfs", RTFControlType::VALUE, RTFKeyword::PNFS, 0 },
+ { "pnganada", RTFControlType::FLAG, RTFKeyword::PNGANADA, 0 },
+ { "pngblip", RTFControlType::FLAG, RTFKeyword::PNGBLIP, 0 },
+ { "pngbnum", RTFControlType::FLAG, RTFKeyword::PNGBNUM, 0 },
+ { "pngbnumd", RTFControlType::FLAG, RTFKeyword::PNGBNUMD, 0 },
+ { "pngbnumk", RTFControlType::FLAG, RTFKeyword::PNGBNUMK, 0 },
+ { "pngbnuml", RTFControlType::FLAG, RTFKeyword::PNGBNUML, 0 },
+ { "pnhang", RTFControlType::FLAG, RTFKeyword::PNHANG, 0 },
+ { "pni", RTFControlType::TOGGLE, RTFKeyword::PNI, 1 },
+ { "pnindent", RTFControlType::VALUE, RTFKeyword::PNINDENT, 0 },
+ { "pniroha", RTFControlType::FLAG, RTFKeyword::PNIROHA, 0 },
+ { "pnirohad", RTFControlType::FLAG, RTFKeyword::PNIROHAD, 0 },
+ { "pnlcltr", RTFControlType::FLAG, RTFKeyword::PNLCLTR, 0 },
+ { "pnlcrm", RTFControlType::FLAG, RTFKeyword::PNLCRM, 0 },
+ { "pnlvl", RTFControlType::VALUE, RTFKeyword::PNLVL, 0 },
+ { "pnlvlblt", RTFControlType::FLAG, RTFKeyword::PNLVLBLT, 0 },
+ { "pnlvlbody", RTFControlType::FLAG, RTFKeyword::PNLVLBODY, 0 },
+ { "pnlvlcont", RTFControlType::FLAG, RTFKeyword::PNLVLCONT, 0 },
+ { "pnnumonce", RTFControlType::FLAG, RTFKeyword::PNNUMONCE, 0 },
+ { "pnord", RTFControlType::FLAG, RTFKeyword::PNORD, 0 },
+ { "pnordt", RTFControlType::FLAG, RTFKeyword::PNORDT, 0 },
+ { "pnprev", RTFControlType::FLAG, RTFKeyword::PNPREV, 0 },
+ { "pnqc", RTFControlType::FLAG, RTFKeyword::PNQC, 0 },
+ { "pnql", RTFControlType::FLAG, RTFKeyword::PNQL, 0 },
+ { "pnqr", RTFControlType::FLAG, RTFKeyword::PNQR, 0 },
+ { "pnrauth", RTFControlType::VALUE, RTFKeyword::PNRAUTH, 0 },
+ { "pnrdate", RTFControlType::VALUE, RTFKeyword::PNRDATE, 0 },
+ { "pnrestart", RTFControlType::FLAG, RTFKeyword::PNRESTART, 0 },
+ { "pnrnfc", RTFControlType::VALUE, RTFKeyword::PNRNFC, 0 },
+ { "pnrnot", RTFControlType::FLAG, RTFKeyword::PNRNOT, 0 },
+ { "pnrpnbr", RTFControlType::VALUE, RTFKeyword::PNRPNBR, 0 },
+ { "pnrrgb", RTFControlType::VALUE, RTFKeyword::PNRRGB, 0 },
+ { "pnrstart", RTFControlType::VALUE, RTFKeyword::PNRSTART, 0 },
+ { "pnrstop", RTFControlType::VALUE, RTFKeyword::PNRSTOP, 0 },
+ { "pnrxst", RTFControlType::VALUE, RTFKeyword::PNRXST, 0 },
+ { "pnscaps", RTFControlType::TOGGLE, RTFKeyword::PNSCAPS, 1 },
+ { "pnseclvl", RTFControlType::DESTINATION, RTFKeyword::PNSECLVL, 0 },
+ { "pnsp", RTFControlType::VALUE, RTFKeyword::PNSP, 0 },
+ { "pnstart", RTFControlType::VALUE, RTFKeyword::PNSTART, 0 },
+ { "pnstrike", RTFControlType::TOGGLE, RTFKeyword::PNSTRIKE, 1 },
+ { "pntext", RTFControlType::DESTINATION, RTFKeyword::PNTEXT, 0 },
+ { "pntxta", RTFControlType::DESTINATION, RTFKeyword::PNTXTA, 0 },
+ { "pntxtb", RTFControlType::DESTINATION, RTFKeyword::PNTXTB, 0 },
+ { "pnucltr", RTFControlType::FLAG, RTFKeyword::PNUCLTR, 0 },
+ { "pnucrm", RTFControlType::FLAG, RTFKeyword::PNUCRM, 0 },
+ { "pnul", RTFControlType::TOGGLE, RTFKeyword::PNUL, 1 },
+ { "pnuld", RTFControlType::FLAG, RTFKeyword::PNULD, 0 },
+ { "pnuldash", RTFControlType::FLAG, RTFKeyword::PNULDASH, 0 },
+ { "pnuldashd", RTFControlType::FLAG, RTFKeyword::PNULDASHD, 0 },
+ { "pnuldashdd", RTFControlType::FLAG, RTFKeyword::PNULDASHDD, 0 },
+ { "pnuldb", RTFControlType::FLAG, RTFKeyword::PNULDB, 0 },
+ { "pnulhair", RTFControlType::FLAG, RTFKeyword::PNULHAIR, 0 },
+ { "pnulnone", RTFControlType::FLAG, RTFKeyword::PNULNONE, 0 },
+ { "pnulth", RTFControlType::FLAG, RTFKeyword::PNULTH, 0 },
+ { "pnulw", RTFControlType::FLAG, RTFKeyword::PNULW, 0 },
+ { "pnulwave", RTFControlType::FLAG, RTFKeyword::PNULWAVE, 0 },
+ { "pnzodiac", RTFControlType::FLAG, RTFKeyword::PNZODIAC, 0 },
+ { "pnzodiacd", RTFControlType::FLAG, RTFKeyword::PNZODIACD, 0 },
+ { "pnzodiacl", RTFControlType::FLAG, RTFKeyword::PNZODIACL, 0 },
+ { "posnegx", RTFControlType::VALUE, RTFKeyword::POSNEGX, 0 },
+ { "posnegy", RTFControlType::VALUE, RTFKeyword::POSNEGY, 0 },
+ { "posx", RTFControlType::VALUE, RTFKeyword::POSX, 0 },
+ { "posxc", RTFControlType::FLAG, RTFKeyword::POSXC, 0 },
+ { "posxi", RTFControlType::FLAG, RTFKeyword::POSXI, 0 },
+ { "posxl", RTFControlType::FLAG, RTFKeyword::POSXL, 0 },
+ { "posxo", RTFControlType::FLAG, RTFKeyword::POSXO, 0 },
+ { "posxr", RTFControlType::FLAG, RTFKeyword::POSXR, 0 },
+ { "posy", RTFControlType::VALUE, RTFKeyword::POSY, 0 },
+ { "posyb", RTFControlType::FLAG, RTFKeyword::POSYB, 0 },
+ { "posyc", RTFControlType::FLAG, RTFKeyword::POSYC, 0 },
+ { "posyil", RTFControlType::FLAG, RTFKeyword::POSYIL, 0 },
+ { "posyin", RTFControlType::FLAG, RTFKeyword::POSYIN, 0 },
+ { "posyout", RTFControlType::FLAG, RTFKeyword::POSYOUT, 0 },
+ { "posyt", RTFControlType::FLAG, RTFKeyword::POSYT, 0 },
+ { "prauth", RTFControlType::VALUE, RTFKeyword::PRAUTH, 0 },
+ { "prcolbl", RTFControlType::FLAG, RTFKeyword::PRCOLBL, 0 },
+ { "prdate", RTFControlType::VALUE, RTFKeyword::PRDATE, 0 },
+ { "printdata", RTFControlType::FLAG, RTFKeyword::PRINTDATA, 0 },
+ { "printim", RTFControlType::DESTINATION, RTFKeyword::PRINTIM, 0 },
+ { "private", RTFControlType::DESTINATION, RTFKeyword::PRIVATE, 0 },
+ { "propname", RTFControlType::DESTINATION, RTFKeyword::PROPNAME, 0 },
+ { "proptype", RTFControlType::VALUE, RTFKeyword::PROPTYPE, 0 },
+ { "protect", RTFControlType::TOGGLE, RTFKeyword::PROTECT, 1 },
+ { "protend", RTFControlType::DESTINATION, RTFKeyword::PROTEND, 0 },
+ { "protlevel", RTFControlType::VALUE, RTFKeyword::PROTLEVEL, 0 },
+ { "protstart", RTFControlType::DESTINATION, RTFKeyword::PROTSTART, 0 },
+ { "protusertbl", RTFControlType::DESTINATION, RTFKeyword::PROTUSERTBL, 0 },
+ { "psover", RTFControlType::FLAG, RTFKeyword::PSOVER, 0 },
+ { "psz", RTFControlType::VALUE, RTFKeyword::PSZ, 0 },
+ { "ptabldot", RTFControlType::FLAG, RTFKeyword::PTABLDOT, 0 },
+ { "ptablmdot", RTFControlType::FLAG, RTFKeyword::PTABLMDOT, 0 },
+ { "ptablminus", RTFControlType::FLAG, RTFKeyword::PTABLMINUS, 0 },
+ { "ptablnone", RTFControlType::FLAG, RTFKeyword::PTABLNONE, 0 },
+ { "ptabluscore", RTFControlType::FLAG, RTFKeyword::PTABLUSCORE, 0 },
+ { "pubauto", RTFControlType::FLAG, RTFKeyword::PUBAUTO, 0 },
+ { "pvmrg", RTFControlType::FLAG, RTFKeyword::PVMRG, 0 },
+ { "pvpara", RTFControlType::FLAG, RTFKeyword::PVPARA, 0 },
+ { "pvpg", RTFControlType::FLAG, RTFKeyword::PVPG, 0 },
+ { "pwd", RTFControlType::VALUE, RTFKeyword::PWD, 0 },
+ { "pxe", RTFControlType::DESTINATION, RTFKeyword::PXE, 0 },
+ { "qc", RTFControlType::FLAG, RTFKeyword::QC, 0 },
+ { "qd", RTFControlType::FLAG, RTFKeyword::QD, 0 },
+ { "qj", RTFControlType::FLAG, RTFKeyword::QJ, 0 },
+ { "qk", RTFControlType::VALUE, RTFKeyword::QK, 0 },
+ { "ql", RTFControlType::FLAG, RTFKeyword::QL, 0 },
+ { "qmspace", RTFControlType::SYMBOL, RTFKeyword::QMSPACE, 0 },
+ { "qr", RTFControlType::FLAG, RTFKeyword::QR, 0 },
+ { "qt", RTFControlType::FLAG, RTFKeyword::QT, 0 },
+ { "rawclbgdkbdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKBDIAG, 0 },
+ { "rawclbgbdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGBDIAG, 0 },
+ { "rawclbgcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGCROSS, 0 },
+ { "rawclbgdcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDCROSS, 0 },
+ { "rawclbgdkcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKCROSS, 0 },
+ { "rawclbgdkdcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKDCROSS, 0 },
+ { "rawclbgdkfdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKFDIAG, 0 },
+ { "rawclbgdkhor", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKHOR, 0 },
+ { "rawclbgdkvert", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKVERT, 0 },
+ { "rawclbgfdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGFDIAG, 0 },
+ { "rawclbghoriz", RTFControlType::FLAG, RTFKeyword::RAWCLBGHORIZ, 0 },
+ { "rawclbgvert", RTFControlType::FLAG, RTFKeyword::RAWCLBGVERT, 0 },
+ { "rdblquote", RTFControlType::SYMBOL, RTFKeyword::RDBLQUOTE, 0 },
+ { "readonlyrecommended", RTFControlType::FLAG, RTFKeyword::READONLYRECOMMENDED, 0 },
+ { "readprot", RTFControlType::FLAG, RTFKeyword::READPROT, 0 },
+ { "red", RTFControlType::VALUE, RTFKeyword::RED, 0 },
+ { "relyonvml", RTFControlType::VALUE, RTFKeyword::RELYONVML, 0 },
+ { "remdttm", RTFControlType::FLAG, RTFKeyword::REMDTTM, 0 },
+ { "rempersonalinfo", RTFControlType::FLAG, RTFKeyword::REMPERSONALINFO, 0 },
+ { "result", RTFControlType::DESTINATION, RTFKeyword::RESULT, 0 },
+ { "revauth", RTFControlType::VALUE, RTFKeyword::REVAUTH, 0 },
+ { "revauthdel", RTFControlType::VALUE, RTFKeyword::REVAUTHDEL, 0 },
+ { "revbar", RTFControlType::VALUE, RTFKeyword::REVBAR, 3 },
+ { "revdttm", RTFControlType::VALUE, RTFKeyword::REVDTTM, 0 },
+ { "revdttmdel", RTFControlType::VALUE, RTFKeyword::REVDTTMDEL, 0 },
+ { "revised", RTFControlType::TOGGLE, RTFKeyword::REVISED, 1 },
+ { "revisions", RTFControlType::FLAG, RTFKeyword::REVISIONS, 0 },
+ { "revprop", RTFControlType::VALUE, RTFKeyword::REVPROP, 3 },
+ { "revprot", RTFControlType::FLAG, RTFKeyword::REVPROT, 0 },
+ { "revtbl", RTFControlType::DESTINATION, RTFKeyword::REVTBL, 0 },
+ { "revtim", RTFControlType::DESTINATION, RTFKeyword::REVTIM, 0 },
+ { "ri", RTFControlType::VALUE, RTFKeyword::RI, 0 },
+ { "rin", RTFControlType::VALUE, RTFKeyword::RIN, 0 },
+ { "row", RTFControlType::SYMBOL, RTFKeyword::ROW, 0 },
+ { "rquote", RTFControlType::SYMBOL, RTFKeyword::RQUOTE, 0 },
+ { "rsid", RTFControlType::VALUE, RTFKeyword::RSID, 0 },
+ { "rsidroot", RTFControlType::VALUE, RTFKeyword::RSIDROOT, 0 },
+ { "rsidtbl", RTFControlType::DESTINATION, RTFKeyword::RSIDTBL, 0 },
+ { "rsltbmp", RTFControlType::FLAG, RTFKeyword::RSLTBMP, 0 },
+ { "rslthtml", RTFControlType::FLAG, RTFKeyword::RSLTHTML, 0 },
+ { "rsltmerge", RTFControlType::FLAG, RTFKeyword::RSLTMERGE, 0 },
+ { "rsltpict", RTFControlType::FLAG, RTFKeyword::RSLTPICT, 0 },
+ { "rsltrtf", RTFControlType::FLAG, RTFKeyword::RSLTRTF, 0 },
+ { "rslttxt", RTFControlType::FLAG, RTFKeyword::RSLTTXT, 0 },
+ { "rtf", RTFControlType::DESTINATION, RTFKeyword::RTF, 0 },
+ { "rtlch", RTFControlType::FLAG, RTFKeyword::RTLCH, 0 },
+ { "rtldoc", RTFControlType::FLAG, RTFKeyword::RTLDOC, 0 },
+ { "rtlgutter", RTFControlType::FLAG, RTFKeyword::RTLGUTTER, 0 },
+ { "rtlmark", RTFControlType::SYMBOL, RTFKeyword::RTLMARK, 0 },
+ { "rtlpar", RTFControlType::FLAG, RTFKeyword::RTLPAR, 0 },
+ { "rtlrow", RTFControlType::FLAG, RTFKeyword::RTLROW, 0 },
+ { "rtlsect", RTFControlType::FLAG, RTFKeyword::RTLSECT, 0 },
+ { "rxe", RTFControlType::DESTINATION, RTFKeyword::RXE, 0 },
+ { "s", RTFControlType::VALUE, RTFKeyword::S, 0 },
+ { "sa", RTFControlType::VALUE, RTFKeyword::SA, 0 },
+ { "saauto", RTFControlType::TOGGLE, RTFKeyword::SAAUTO, 1 },
+ { "saftnnalc", RTFControlType::FLAG, RTFKeyword::SAFTNNALC, 0 },
+ { "saftnnar", RTFControlType::FLAG, RTFKeyword::SAFTNNAR, 0 },
+ { "saftnnauc", RTFControlType::FLAG, RTFKeyword::SAFTNNAUC, 0 },
+ { "saftnnchi", RTFControlType::FLAG, RTFKeyword::SAFTNNCHI, 0 },
+ { "saftnnchosung", RTFControlType::FLAG, RTFKeyword::SAFTNNCHOSUNG, 0 },
+ { "saftnncnum", RTFControlType::FLAG, RTFKeyword::SAFTNNCNUM, 0 },
+ { "saftnndbar", RTFControlType::FLAG, RTFKeyword::SAFTNNDBAR, 0 },
+ { "saftnndbnum", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUM, 0 },
+ { "saftnndbnumd", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMD, 0 },
+ { "saftnndbnumk", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMK, 0 },
+ { "saftnndbnumt", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMT, 0 },
+ { "saftnnganada", RTFControlType::FLAG, RTFKeyword::SAFTNNGANADA, 0 },
+ { "saftnngbnum", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUM, 0 },
+ { "saftnngbnumd", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUMD, 0 },
+ { "saftnngbnumk", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUMK, 0 },
+ { "saftnngbnuml", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUML, 0 },
+ { "saftnnrlc", RTFControlType::FLAG, RTFKeyword::SAFTNNRLC, 0 },
+ { "saftnnruc", RTFControlType::FLAG, RTFKeyword::SAFTNNRUC, 0 },
+ { "saftnnzodiac", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIAC, 0 },
+ { "saftnnzodiacd", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIACD, 0 },
+ { "saftnnzodiacl", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIACL, 0 },
+ { "saftnrestart", RTFControlType::FLAG, RTFKeyword::SAFTNRESTART, 0 },
+ { "saftnrstcont", RTFControlType::FLAG, RTFKeyword::SAFTNRSTCONT, 0 },
+ { "saftnstart", RTFControlType::VALUE, RTFKeyword::SAFTNSTART, 1 },
+ { "sautoupd", RTFControlType::FLAG, RTFKeyword::SAUTOUPD, 0 },
+ { "saveinvalidxml", RTFControlType::FLAG, RTFKeyword::SAVEINVALIDXML, 0 },
+ { "saveprevpict", RTFControlType::FLAG, RTFKeyword::SAVEPREVPICT, 0 },
+ { "sb", RTFControlType::VALUE, RTFKeyword::SB, 0 },
+ { "sbasedon", RTFControlType::VALUE, RTFKeyword::SBASEDON, 222 },
+ { "sbauto", RTFControlType::TOGGLE, RTFKeyword::SBAUTO, 1 },
+ { "sbkcol", RTFControlType::FLAG, RTFKeyword::SBKCOL, 0 },
+ { "sbkeven", RTFControlType::FLAG, RTFKeyword::SBKEVEN, 0 },
+ { "sbknone", RTFControlType::FLAG, RTFKeyword::SBKNONE, 0 },
+ { "sbkodd", RTFControlType::FLAG, RTFKeyword::SBKODD, 0 },
+ { "sbkpage", RTFControlType::FLAG, RTFKeyword::SBKPAGE, 0 },
+ { "sbys", RTFControlType::FLAG, RTFKeyword::SBYS, 0 },
+ { "scaps", RTFControlType::TOGGLE, RTFKeyword::SCAPS, 1 },
+ { "scompose", RTFControlType::FLAG, RTFKeyword::SCOMPOSE, 0 },
+ { "sec", RTFControlType::VALUE, RTFKeyword::SEC, 0 },
+ { "sect", RTFControlType::SYMBOL, RTFKeyword::SECT, 0 },
+ { "sectd", RTFControlType::FLAG, RTFKeyword::SECTD, 0 },
+ { "sectdefaultcl", RTFControlType::FLAG, RTFKeyword::SECTDEFAULTCL, 0 },
+ { "sectexpand", RTFControlType::VALUE, RTFKeyword::SECTEXPAND, 0 },
+ { "sectlinegrid", RTFControlType::VALUE, RTFKeyword::SECTLINEGRID, 0 },
+ { "sectnum", RTFControlType::SYMBOL, RTFKeyword::SECTNUM, 0 },
+ { "sectrsid", RTFControlType::VALUE, RTFKeyword::SECTRSID, 0 },
+ { "sectspecifycl", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYCL, 0 },
+ { "sectspecifygenN", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYGENN, 0 },
+ { "sectspecifyl", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYL, 0 },
+ { "sectunlocked", RTFControlType::FLAG, RTFKeyword::SECTUNLOCKED, 0 },
+ { "sftnbj", RTFControlType::FLAG, RTFKeyword::SFTNBJ, 0 },
+ { "sftnnalc", RTFControlType::FLAG, RTFKeyword::SFTNNALC, 0 },
+ { "sftnnar", RTFControlType::FLAG, RTFKeyword::SFTNNAR, 0 },
+ { "sftnnauc", RTFControlType::FLAG, RTFKeyword::SFTNNAUC, 0 },
+ { "sftnnchi", RTFControlType::FLAG, RTFKeyword::SFTNNCHI, 0 },
+ { "sftnnchosung", RTFControlType::FLAG, RTFKeyword::SFTNNCHOSUNG, 0 },
+ { "sftnncnum", RTFControlType::FLAG, RTFKeyword::SFTNNCNUM, 0 },
+ { "sftnndbar", RTFControlType::FLAG, RTFKeyword::SFTNNDBAR, 0 },
+ { "sftnndbnum", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUM, 0 },
+ { "sftnndbnumd", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMD, 0 },
+ { "sftnndbnumk", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMK, 0 },
+ { "sftnndbnumt", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMT, 0 },
+ { "sftnnganada", RTFControlType::FLAG, RTFKeyword::SFTNNGANADA, 0 },
+ { "sftnngbnum", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUM, 0 },
+ { "sftnngbnumd", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUMD, 0 },
+ { "sftnngbnumk", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUMK, 0 },
+ { "sftnngbnuml", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUML, 0 },
+ { "sftnnrlc", RTFControlType::FLAG, RTFKeyword::SFTNNRLC, 0 },
+ { "sftnnruc", RTFControlType::FLAG, RTFKeyword::SFTNNRUC, 0 },
+ { "sftnnzodiac", RTFControlType::FLAG, RTFKeyword::SFTNNZODIAC, 0 },
+ { "sftnnzodiacd", RTFControlType::FLAG, RTFKeyword::SFTNNZODIACD, 0 },
+ { "sftnnzodiacl", RTFControlType::FLAG, RTFKeyword::SFTNNZODIACL, 0 },
+ { "sftnrestart", RTFControlType::FLAG, RTFKeyword::SFTNRESTART, 0 },
+ { "sftnrstcont", RTFControlType::FLAG, RTFKeyword::SFTNRSTCONT, 0 },
+ { "sftnrstpg", RTFControlType::FLAG, RTFKeyword::SFTNRSTPG, 0 },
+ { "sftnstart", RTFControlType::VALUE, RTFKeyword::SFTNSTART, 1 },
+ { "sftntj", RTFControlType::FLAG, RTFKeyword::SFTNTJ, 0 },
+ { "shad", RTFControlType::TOGGLE, RTFKeyword::SHAD, 1 },
+ { "shading", RTFControlType::VALUE, RTFKeyword::SHADING, 0 },
+ { "shidden", RTFControlType::FLAG, RTFKeyword::SHIDDEN, 0 },
+ { "shift", RTFControlType::FLAG, RTFKeyword::SHIFT, 0 },
+ { "showplaceholdtext", RTFControlType::VALUE, RTFKeyword::SHOWPLACEHOLDTEXT, 0 },
+ { "showxmlerrors", RTFControlType::VALUE, RTFKeyword::SHOWXMLERRORS, 0 },
+ { "shp", RTFControlType::DESTINATION, RTFKeyword::SHP, 0 },
+ { "shpbottom", RTFControlType::VALUE, RTFKeyword::SHPBOTTOM, 0 },
+ { "shpbxcolumn", RTFControlType::FLAG, RTFKeyword::SHPBXCOLUMN, 0 },
+ { "shpbxignore", RTFControlType::FLAG, RTFKeyword::SHPBXIGNORE, 0 },
+ { "shpbxmargin", RTFControlType::FLAG, RTFKeyword::SHPBXMARGIN, 0 },
+ { "shpbxpage", RTFControlType::FLAG, RTFKeyword::SHPBXPAGE, 0 },
+ { "shpbyignore", RTFControlType::FLAG, RTFKeyword::SHPBYIGNORE, 0 },
+ { "shpbymargin", RTFControlType::FLAG, RTFKeyword::SHPBYMARGIN, 0 },
+ { "shpbypage", RTFControlType::FLAG, RTFKeyword::SHPBYPAGE, 0 },
+ { "shpbypara", RTFControlType::FLAG, RTFKeyword::SHPBYPARA, 0 },
+ { "shpfblwtxt", RTFControlType::VALUE, RTFKeyword::SHPFBLWTXT, 0 },
+ { "shpfhdr", RTFControlType::VALUE, RTFKeyword::SHPFHDR, 0 },
+ { "shpgrp", RTFControlType::DESTINATION, RTFKeyword::SHPGRP, 0 },
+ { "shpinst", RTFControlType::DESTINATION, RTFKeyword::SHPINST, 0 },
+ { "shpleft", RTFControlType::VALUE, RTFKeyword::SHPLEFT, 0 },
+ { "shplid", RTFControlType::VALUE, RTFKeyword::SHPLID, 0 },
+ { "shplockanchor", RTFControlType::FLAG, RTFKeyword::SHPLOCKANCHOR, 0 },
+ { "shppict", RTFControlType::DESTINATION, RTFKeyword::SHPPICT, 0 },
+ { "shpright", RTFControlType::VALUE, RTFKeyword::SHPRIGHT, 0 },
+ { "shprslt", RTFControlType::DESTINATION, RTFKeyword::SHPRSLT, 0 },
+ { "shptop", RTFControlType::VALUE, RTFKeyword::SHPTOP, 0 },
+ { "shptxt", RTFControlType::DESTINATION, RTFKeyword::SHPTXT, 0 },
+ { "shpwrk", RTFControlType::VALUE, RTFKeyword::SHPWRK, 0 },
+ { "shpwr", RTFControlType::VALUE, RTFKeyword::SHPWR, 0 },
+ { "shpz", RTFControlType::VALUE, RTFKeyword::SHPZ, 0 },
+ { "sl", RTFControlType::VALUE, RTFKeyword::SL, 0 },
+ { "slink", RTFControlType::VALUE, RTFKeyword::SLINK, 0 },
+ { "slmult", RTFControlType::VALUE, RTFKeyword::SLMULT, 0 },
+ { "slocked", RTFControlType::FLAG, RTFKeyword::SLOCKED, 0 },
+ { "sn", RTFControlType::DESTINATION, RTFKeyword::SN, 0 },
+ { "snaptogridincell", RTFControlType::FLAG, RTFKeyword::SNAPTOGRIDINCELL, 0 },
+ { "snext", RTFControlType::VALUE, RTFKeyword::SNEXT, 0 },
+ { "softcol", RTFControlType::FLAG, RTFKeyword::SOFTCOL, 0 },
+ { "softlheight", RTFControlType::VALUE, RTFKeyword::SOFTLHEIGHT, 0 },
+ { "softline", RTFControlType::FLAG, RTFKeyword::SOFTLINE, 0 },
+ { "softpage", RTFControlType::FLAG, RTFKeyword::SOFTPAGE, 0 },
+ { "sp", RTFControlType::DESTINATION, RTFKeyword::SP, 0 },
+ { "spersonal", RTFControlType::FLAG, RTFKeyword::SPERSONAL, 0 },
+ { "spltpgpar", RTFControlType::FLAG, RTFKeyword::SPLTPGPAR, 0 },
+ { "splytwnine", RTFControlType::FLAG, RTFKeyword::SPLYTWNINE, 0 },
+ { "spriority", RTFControlType::VALUE, RTFKeyword::SPRIORITY, 0 },
+ { "sprsbsp", RTFControlType::FLAG, RTFKeyword::SPRSBSP, 0 },
+ { "sprslnsp", RTFControlType::FLAG, RTFKeyword::SPRSLNSP, 0 },
+ { "sprsspbf", RTFControlType::FLAG, RTFKeyword::SPRSSPBF, 0 },
+ { "sprstsm", RTFControlType::FLAG, RTFKeyword::SPRSTSM, 0 },
+ { "sprstsp", RTFControlType::FLAG, RTFKeyword::SPRSTSP, 0 },
+ { "spv", RTFControlType::FLAG, RTFKeyword::SPV, 0 },
+ { "sqformat", RTFControlType::FLAG, RTFKeyword::SQFORMAT, 0 },
+ { "srauth", RTFControlType::VALUE, RTFKeyword::SRAUTH, 0 },
+ { "srdate", RTFControlType::VALUE, RTFKeyword::SRDATE, 0 },
+ { "sreply", RTFControlType::FLAG, RTFKeyword::SREPLY, 0 },
+ { "ssemihidden", RTFControlType::VALUE, RTFKeyword::SSEMIHIDDEN, 0 },
+ { "staticval", RTFControlType::DESTINATION, RTFKeyword::STATICVAL, 0 },
+ { "stextflow", RTFControlType::VALUE, RTFKeyword::STEXTFLOW, 0 },
+ { "strike", RTFControlType::TOGGLE, RTFKeyword::STRIKE, 1 },
+ { "striked", RTFControlType::TOGGLE, RTFKeyword::STRIKED, 1 },
+ { "stshfbi", RTFControlType::VALUE, RTFKeyword::STSHFBI, 0 },
+ { "stshfdbch", RTFControlType::VALUE, RTFKeyword::STSHFDBCH, 0 },
+ { "stshfhich", RTFControlType::VALUE, RTFKeyword::STSHFHICH, 0 },
+ { "stshfloch", RTFControlType::VALUE, RTFKeyword::STSHFLOCH, 0 },
+ { "stylelock", RTFControlType::FLAG, RTFKeyword::STYLELOCK, 0 },
+ { "stylelockbackcomp", RTFControlType::FLAG, RTFKeyword::STYLELOCKBACKCOMP, 0 },
+ { "stylelockenforced", RTFControlType::FLAG, RTFKeyword::STYLELOCKENFORCED, 0 },
+ { "stylelockqfset", RTFControlType::FLAG, RTFKeyword::STYLELOCKQFSET, 0 },
+ { "stylelocktheme", RTFControlType::FLAG, RTFKeyword::STYLELOCKTHEME, 0 },
+ { "stylesheet", RTFControlType::DESTINATION, RTFKeyword::STYLESHEET, 0 },
+ { "stylesortmethod", RTFControlType::VALUE, RTFKeyword::STYLESORTMETHOD, 1 },
+ { "styrsid", RTFControlType::VALUE, RTFKeyword::STYRSID, 0 },
+ { "sub", RTFControlType::FLAG, RTFKeyword::SUB, 0 },
+ { "subdocument", RTFControlType::VALUE, RTFKeyword::SUBDOCUMENT, 0 },
+ { "subfontbysize", RTFControlType::FLAG, RTFKeyword::SUBFONTBYSIZE, 0 },
+ { "subject", RTFControlType::DESTINATION, RTFKeyword::SUBJECT, 0 },
+ { "sunhideused", RTFControlType::VALUE, RTFKeyword::SUNHIDEUSED, 0 },
+ { "super", RTFControlType::FLAG, RTFKeyword::SUPER, 0 },
+ { "sv", RTFControlType::DESTINATION, RTFKeyword::SV, 0 },
+ { "svb", RTFControlType::DESTINATION, RTFKeyword::SVB, 0 },
+ { "swpbdr", RTFControlType::FLAG, RTFKeyword::SWPBDR, 0 },
+ { "tab", RTFControlType::SYMBOL, RTFKeyword::TAB, 0 },
+ { "tabsnoovrlp", RTFControlType::FLAG, RTFKeyword::TABSNOOVRLP, 0 },
+ { "taprtl", RTFControlType::FLAG, RTFKeyword::TAPRTL, 0 },
+ { "tb", RTFControlType::VALUE, RTFKeyword::TB, 0 },
+ { "tblind", RTFControlType::VALUE, RTFKeyword::TBLIND, 0 },
+ { "tblindtype", RTFControlType::VALUE, RTFKeyword::TBLINDTYPE, 0 },
+ { "tbllkbestfit", RTFControlType::FLAG, RTFKeyword::TBLLKBESTFIT, 0 },
+ { "tbllkborder", RTFControlType::FLAG, RTFKeyword::TBLLKBORDER, 0 },
+ { "tbllkcolor", RTFControlType::FLAG, RTFKeyword::TBLLKCOLOR, 0 },
+ { "tbllkfont", RTFControlType::FLAG, RTFKeyword::TBLLKFONT, 0 },
+ { "tbllkhdrcols", RTFControlType::FLAG, RTFKeyword::TBLLKHDRCOLS, 0 },
+ { "tbllkhdrrows", RTFControlType::FLAG, RTFKeyword::TBLLKHDRROWS, 0 },
+ { "tbllklastcol", RTFControlType::FLAG, RTFKeyword::TBLLKLASTCOL, 0 },
+ { "tbllklastrow", RTFControlType::FLAG, RTFKeyword::TBLLKLASTROW, 0 },
+ { "tbllknocolband", RTFControlType::FLAG, RTFKeyword::TBLLKNOCOLBAND, 0 },
+ { "tbllknorowband", RTFControlType::FLAG, RTFKeyword::TBLLKNOROWBAND, 0 },
+ { "tbllkshading", RTFControlType::FLAG, RTFKeyword::TBLLKSHADING, 0 },
+ { "tblrsid", RTFControlType::VALUE, RTFKeyword::TBLRSID, 0 },
+ { "tc", RTFControlType::DESTINATION, RTFKeyword::TC, 0 },
+ { "tcelld", RTFControlType::FLAG, RTFKeyword::TCELLD, 0 },
+ { "tcf", RTFControlType::VALUE, RTFKeyword::TCF, 67 },
+ { "tcl", RTFControlType::VALUE, RTFKeyword::TCL, 0 },
+ { "tcn", RTFControlType::FLAG, RTFKeyword::TCN, 0 },
+ { "tdfrmtxtBottom", RTFControlType::VALUE, RTFKeyword::TDFRMTXTBOTTOM, 0 },
+ { "tdfrmtxtLeft", RTFControlType::VALUE, RTFKeyword::TDFRMTXTLEFT, 0 },
+ { "tdfrmtxtRight", RTFControlType::VALUE, RTFKeyword::TDFRMTXTRIGHT, 0 },
+ { "tdfrmtxtTop", RTFControlType::VALUE, RTFKeyword::TDFRMTXTTOP, 0 },
+ { "template", RTFControlType::DESTINATION, RTFKeyword::TEMPLATE, 0 },
+ { "themedata", RTFControlType::DESTINATION, RTFKeyword::THEMEDATA, 0 },
+ { "themelang", RTFControlType::VALUE, RTFKeyword::THEMELANG, 0 },
+ { "themelangcs", RTFControlType::VALUE, RTFKeyword::THEMELANGCS, 0 },
+ { "themelangfe", RTFControlType::VALUE, RTFKeyword::THEMELANGFE, 0 },
+ { "time", RTFControlType::FLAG, RTFKeyword::TIME, 0 },
+ { "title", RTFControlType::DESTINATION, RTFKeyword::TITLE, 0 },
+ { "titlepg", RTFControlType::FLAG, RTFKeyword::TITLEPG, 0 },
+ { "tldot", RTFControlType::FLAG, RTFKeyword::TLDOT, 0 },
+ { "tleq", RTFControlType::FLAG, RTFKeyword::TLEQ, 0 },
+ { "tlhyph", RTFControlType::FLAG, RTFKeyword::TLHYPH, 0 },
+ { "tlmdot", RTFControlType::FLAG, RTFKeyword::TLMDOT, 0 },
+ { "tlth", RTFControlType::FLAG, RTFKeyword::TLTH, 0 },
+ { "tlul", RTFControlType::FLAG, RTFKeyword::TLUL, 0 },
+ { "toplinepunct", RTFControlType::FLAG, RTFKeyword::TOPLINEPUNCT, 0 },
+ { "tphcol", RTFControlType::FLAG, RTFKeyword::TPHCOL, 0 },
+ { "tphmrg", RTFControlType::FLAG, RTFKeyword::TPHMRG, 0 },
+ { "tphpg", RTFControlType::FLAG, RTFKeyword::TPHPG, 0 },
+ { "tposnegx", RTFControlType::VALUE, RTFKeyword::TPOSNEGX, 0 },
+ { "tposnegy", RTFControlType::VALUE, RTFKeyword::TPOSNEGY, 0 },
+ { "tposxc", RTFControlType::FLAG, RTFKeyword::TPOSXC, 0 },
+ { "tposxi", RTFControlType::FLAG, RTFKeyword::TPOSXI, 0 },
+ { "tposxl", RTFControlType::FLAG, RTFKeyword::TPOSXL, 0 },
+ { "tposx", RTFControlType::VALUE, RTFKeyword::TPOSX, 0 },
+ { "tposxo", RTFControlType::FLAG, RTFKeyword::TPOSXO, 0 },
+ { "tposxr", RTFControlType::FLAG, RTFKeyword::TPOSXR, 0 },
+ { "tposy", RTFControlType::VALUE, RTFKeyword::TPOSY, 0 },
+ { "tposyb", RTFControlType::FLAG, RTFKeyword::TPOSYB, 0 },
+ { "tposyc", RTFControlType::FLAG, RTFKeyword::TPOSYC, 0 },
+ { "tposyil", RTFControlType::FLAG, RTFKeyword::TPOSYIL, 0 },
+ { "tposyin", RTFControlType::FLAG, RTFKeyword::TPOSYIN, 0 },
+ { "tposyout", RTFControlType::FLAG, RTFKeyword::TPOSYOUT, 0 },
+ { "tposyt", RTFControlType::FLAG, RTFKeyword::TPOSYT, 0 },
+ { "tpvmrg", RTFControlType::FLAG, RTFKeyword::TPVMRG, 0 },
+ { "tpvpara", RTFControlType::FLAG, RTFKeyword::TPVPARA, 0 },
+ { "tpvpg", RTFControlType::FLAG, RTFKeyword::TPVPG, 0 },
+ { "tqc", RTFControlType::FLAG, RTFKeyword::TQC, 0 },
+ { "tqdec", RTFControlType::FLAG, RTFKeyword::TQDEC, 0 },
+ { "tqr", RTFControlType::FLAG, RTFKeyword::TQR, 0 },
+ { "trackformatting", RTFControlType::VALUE, RTFKeyword::TRACKFORMATTING, 0 },
+ { "trackmoves", RTFControlType::VALUE, RTFKeyword::TRACKMOVES, 0 },
+ { "transmf", RTFControlType::FLAG, RTFKeyword::TRANSMF, 0 },
+ { "trauth", RTFControlType::VALUE, RTFKeyword::TRAUTH, 0 },
+ { "trautofit", RTFControlType::TOGGLE, RTFKeyword::TRAUTOFIT, 1 },
+ { "trbgbdiag", RTFControlType::FLAG, RTFKeyword::TRBGBDIAG, 0 },
+ { "trbgcross", RTFControlType::FLAG, RTFKeyword::TRBGCROSS, 0 },
+ { "trbgdcross", RTFControlType::FLAG, RTFKeyword::TRBGDCROSS, 0 },
+ { "trbgdkbdiag", RTFControlType::FLAG, RTFKeyword::TRBGDKBDIAG, 0 },
+ { "trbgdkcross", RTFControlType::FLAG, RTFKeyword::TRBGDKCROSS, 0 },
+ { "trbgdkdcross", RTFControlType::FLAG, RTFKeyword::TRBGDKDCROSS, 0 },
+ { "trbgdkfdiag", RTFControlType::FLAG, RTFKeyword::TRBGDKFDIAG, 0 },
+ { "trbgdkhor", RTFControlType::FLAG, RTFKeyword::TRBGDKHOR, 0 },
+ { "trbgdkvert", RTFControlType::FLAG, RTFKeyword::TRBGDKVERT, 0 },
+ { "trbgfdiag", RTFControlType::FLAG, RTFKeyword::TRBGFDIAG, 0 },
+ { "trbghoriz", RTFControlType::FLAG, RTFKeyword::TRBGHORIZ, 0 },
+ { "trbgvert", RTFControlType::FLAG, RTFKeyword::TRBGVERT, 0 },
+ { "trbrdrb", RTFControlType::FLAG, RTFKeyword::TRBRDRB, 0 },
+ { "trbrdrh", RTFControlType::FLAG, RTFKeyword::TRBRDRH, 0 },
+ { "trbrdrl", RTFControlType::FLAG, RTFKeyword::TRBRDRL, 0 },
+ { "trbrdrr", RTFControlType::FLAG, RTFKeyword::TRBRDRR, 0 },
+ { "trbrdrt", RTFControlType::FLAG, RTFKeyword::TRBRDRT, 0 },
+ { "trbrdrv", RTFControlType::FLAG, RTFKeyword::TRBRDRV, 0 },
+ { "trcbpat", RTFControlType::VALUE, RTFKeyword::TRCBPAT, 0 },
+ { "trcfpat", RTFControlType::VALUE, RTFKeyword::TRCFPAT, 0 },
+ { "trdate", RTFControlType::VALUE, RTFKeyword::TRDATE, 0 },
+ { "trftsWidthA", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTHA, 0 },
+ { "trftsWidthB", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTHB, 0 },
+ { "trftsWidth", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTH, 0 },
+ { "trgaph", RTFControlType::VALUE, RTFKeyword::TRGAPH, 0 },
+ { "trhdr", RTFControlType::FLAG, RTFKeyword::TRHDR, 0 },
+ { "trkeep", RTFControlType::FLAG, RTFKeyword::TRKEEP, 0 },
+ { "trkeepfollow", RTFControlType::FLAG, RTFKeyword::TRKEEPFOLLOW, 0 },
+ { "trleft", RTFControlType::VALUE, RTFKeyword::TRLEFT, 0 },
+ { "trowd", RTFControlType::FLAG, RTFKeyword::TROWD, 0 },
+ { "trpaddb", RTFControlType::VALUE, RTFKeyword::TRPADDB, 0 },
+ { "trpaddfb", RTFControlType::VALUE, RTFKeyword::TRPADDFB, 0 },
+ { "trpaddfl", RTFControlType::VALUE, RTFKeyword::TRPADDFL, 0 },
+ { "trpaddfr", RTFControlType::VALUE, RTFKeyword::TRPADDFR, 0 },
+ { "trpaddft", RTFControlType::VALUE, RTFKeyword::TRPADDFT, 0 },
+ { "trpaddl", RTFControlType::VALUE, RTFKeyword::TRPADDL, 0 },
+ { "trpaddr", RTFControlType::VALUE, RTFKeyword::TRPADDR, 0 },
+ { "trpaddt", RTFControlType::VALUE, RTFKeyword::TRPADDT, 0 },
+ { "trpadob", RTFControlType::VALUE, RTFKeyword::TRPADOB, 0 },
+ { "trpadofb", RTFControlType::VALUE, RTFKeyword::TRPADOFB, 0 },
+ { "trpadofl", RTFControlType::VALUE, RTFKeyword::TRPADOFL, 0 },
+ { "trpadofr", RTFControlType::VALUE, RTFKeyword::TRPADOFR, 0 },
+ { "trpadoft", RTFControlType::VALUE, RTFKeyword::TRPADOFT, 0 },
+ { "trpadol", RTFControlType::VALUE, RTFKeyword::TRPADOL, 0 },
+ { "trpador", RTFControlType::VALUE, RTFKeyword::TRPADOR, 0 },
+ { "trpadot", RTFControlType::VALUE, RTFKeyword::TRPADOT, 0 },
+ { "trpat", RTFControlType::VALUE, RTFKeyword::TRPAT, 0 },
+ { "trqc", RTFControlType::FLAG, RTFKeyword::TRQC, 0 },
+ { "trql", RTFControlType::FLAG, RTFKeyword::TRQL, 0 },
+ { "trqr", RTFControlType::FLAG, RTFKeyword::TRQR, 0 },
+ { "trrh", RTFControlType::VALUE, RTFKeyword::TRRH, 0 },
+ { "trshdng", RTFControlType::VALUE, RTFKeyword::TRSHDNG, 0 },
+ { "trspdb", RTFControlType::VALUE, RTFKeyword::TRSPDB, 0 },
+ { "trspdfb", RTFControlType::VALUE, RTFKeyword::TRSPDFB, 0 },
+ { "trspdfl", RTFControlType::VALUE, RTFKeyword::TRSPDFL, 0 },
+ { "trspdfr", RTFControlType::VALUE, RTFKeyword::TRSPDFR, 0 },
+ { "trspdft", RTFControlType::VALUE, RTFKeyword::TRSPDFT, 0 },
+ { "trspdl", RTFControlType::VALUE, RTFKeyword::TRSPDL, 0 },
+ { "trspdr", RTFControlType::VALUE, RTFKeyword::TRSPDR, 0 },
+ { "trspdt", RTFControlType::VALUE, RTFKeyword::TRSPDT, 0 },
+ { "trspob", RTFControlType::VALUE, RTFKeyword::TRSPOB, 0 },
+ { "trspofb", RTFControlType::VALUE, RTFKeyword::TRSPOFB, 0 },
+ { "trspofl", RTFControlType::VALUE, RTFKeyword::TRSPOFL, 0 },
+ { "trspofr", RTFControlType::VALUE, RTFKeyword::TRSPOFR, 0 },
+ { "trspoft", RTFControlType::VALUE, RTFKeyword::TRSPOFT, 0 },
+ { "trspol", RTFControlType::VALUE, RTFKeyword::TRSPOL, 0 },
+ { "trspor", RTFControlType::VALUE, RTFKeyword::TRSPOR, 0 },
+ { "trspot", RTFControlType::VALUE, RTFKeyword::TRSPOT, 0 },
+ { "truncatefontheight", RTFControlType::FLAG, RTFKeyword::TRUNCATEFONTHEIGHT, 0 },
+ { "truncex", RTFControlType::FLAG, RTFKeyword::TRUNCEX, 0 },
+ { "trwWidthA", RTFControlType::VALUE, RTFKeyword::TRWWIDTHA, 0 },
+ { "trwWidthB", RTFControlType::VALUE, RTFKeyword::TRWWIDTHB, 0 },
+ { "trwWidth", RTFControlType::VALUE, RTFKeyword::TRWWIDTH, 0 },
+ { "ts", RTFControlType::VALUE, RTFKeyword::TS, 0 },
+ { "tsbgbdiag", RTFControlType::FLAG, RTFKeyword::TSBGBDIAG, 0 },
+ { "tsbgcross", RTFControlType::FLAG, RTFKeyword::TSBGCROSS, 0 },
+ { "tsbgdcross", RTFControlType::FLAG, RTFKeyword::TSBGDCROSS, 0 },
+ { "tsbgdkbdiag", RTFControlType::FLAG, RTFKeyword::TSBGDKBDIAG, 0 },
+ { "tsbgdkcross", RTFControlType::FLAG, RTFKeyword::TSBGDKCROSS, 0 },
+ { "tsbgdkdcross", RTFControlType::FLAG, RTFKeyword::TSBGDKDCROSS, 0 },
+ { "tsbgdkfdiag", RTFControlType::FLAG, RTFKeyword::TSBGDKFDIAG, 0 },
+ { "tsbgdkhor", RTFControlType::FLAG, RTFKeyword::TSBGDKHOR, 0 },
+ { "tsbgdkvert", RTFControlType::FLAG, RTFKeyword::TSBGDKVERT, 0 },
+ { "tsbgfdiag", RTFControlType::FLAG, RTFKeyword::TSBGFDIAG, 0 },
+ { "tsbghoriz", RTFControlType::FLAG, RTFKeyword::TSBGHORIZ, 0 },
+ { "tsbgvert", RTFControlType::FLAG, RTFKeyword::TSBGVERT, 0 },
+ { "tsbrdrb", RTFControlType::FLAG, RTFKeyword::TSBRDRB, 0 },
+ { "tsbrdrdgl", RTFControlType::FLAG, RTFKeyword::TSBRDRDGL, 0 },
+ { "tsbrdrdgr", RTFControlType::FLAG, RTFKeyword::TSBRDRDGR, 0 },
+ { "tsbrdrh", RTFControlType::FLAG, RTFKeyword::TSBRDRH, 0 },
+ { "tsbrdrl", RTFControlType::FLAG, RTFKeyword::TSBRDRL, 0 },
+ { "tsbrdrr", RTFControlType::FLAG, RTFKeyword::TSBRDRR, 0 },
+ { "tsbrdrt", RTFControlType::FLAG, RTFKeyword::TSBRDRT, 0 },
+ { "tsbrdrv", RTFControlType::FLAG, RTFKeyword::TSBRDRV, 0 },
+ { "tscbandhorzeven", RTFControlType::FLAG, RTFKeyword::TSCBANDHORZEVEN, 0 },
+ { "tscbandhorzodd", RTFControlType::FLAG, RTFKeyword::TSCBANDHORZODD, 0 },
+ { "tscbandsh", RTFControlType::VALUE, RTFKeyword::TSCBANDSH, 0 },
+ { "tscbandsv", RTFControlType::VALUE, RTFKeyword::TSCBANDSV, 0 },
+ { "tscbandverteven", RTFControlType::FLAG, RTFKeyword::TSCBANDVERTEVEN, 0 },
+ { "tscbandvertodd", RTFControlType::FLAG, RTFKeyword::TSCBANDVERTODD, 0 },
+ { "tscellcbpat", RTFControlType::VALUE, RTFKeyword::TSCELLCBPAT, 0 },
+ { "tscellcfpat", RTFControlType::VALUE, RTFKeyword::TSCELLCFPAT, 0 },
+ { "tscellpaddb", RTFControlType::VALUE, RTFKeyword::TSCELLPADDB, 0 },
+ { "tscellpaddfb", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFB, 0 },
+ { "tscellpaddfl", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFL, 0 },
+ { "tscellpaddfr", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFR, 0 },
+ { "tscellpaddft", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFT, 0 },
+ { "tscellpaddl", RTFControlType::VALUE, RTFKeyword::TSCELLPADDL, 0 },
+ { "tscellpaddr", RTFControlType::VALUE, RTFKeyword::TSCELLPADDR, 0 },
+ { "tscellpaddt", RTFControlType::VALUE, RTFKeyword::TSCELLPADDT, 0 },
+ { "tscellpct", RTFControlType::VALUE, RTFKeyword::TSCELLPCT, 0 },
+ { "tscellwidth", RTFControlType::VALUE, RTFKeyword::TSCELLWIDTH, 0 },
+ { "tscellwidthfts", RTFControlType::VALUE, RTFKeyword::TSCELLWIDTHFTS, 0 },
+ { "tscfirstcol", RTFControlType::FLAG, RTFKeyword::TSCFIRSTCOL, 0 },
+ { "tscfirstrow", RTFControlType::FLAG, RTFKeyword::TSCFIRSTROW, 0 },
+ { "tsclastcol", RTFControlType::FLAG, RTFKeyword::TSCLASTCOL, 0 },
+ { "tsclastrow", RTFControlType::FLAG, RTFKeyword::TSCLASTROW, 0 },
+ { "tscnecell", RTFControlType::FLAG, RTFKeyword::TSCNECELL, 0 },
+ { "tscnwcell", RTFControlType::FLAG, RTFKeyword::TSCNWCELL, 0 },
+ { "tscsecell", RTFControlType::FLAG, RTFKeyword::TSCSECELL, 0 },
+ { "tscswcell", RTFControlType::FLAG, RTFKeyword::TSCSWCELL, 0 },
+ { "tsd", RTFControlType::FLAG, RTFKeyword::TSD, 0 },
+ { "tsnowrap", RTFControlType::FLAG, RTFKeyword::TSNOWRAP, 0 },
+ { "tsrowd", RTFControlType::FLAG, RTFKeyword::TSROWD, 0 },
+ { "tsvertalb", RTFControlType::FLAG, RTFKeyword::TSVERTALB, 0 },
+ { "tsvertalc", RTFControlType::FLAG, RTFKeyword::TSVERTALC, 0 },
+ { "tsvertalt", RTFControlType::FLAG, RTFKeyword::TSVERTALT, 0 },
+ { "twoinone", RTFControlType::VALUE, RTFKeyword::TWOINONE, 0 },
+ { "twoonone", RTFControlType::FLAG, RTFKeyword::TWOONONE, 0 },
+ { "tx", RTFControlType::VALUE, RTFKeyword::TX, 0 },
+ { "txbxtwalways", RTFControlType::FLAG, RTFKeyword::TXBXTWALWAYS, 0 },
+ { "txbxtwfirst", RTFControlType::FLAG, RTFKeyword::TXBXTWFIRST, 0 },
+ { "txbxtwfirstlast", RTFControlType::FLAG, RTFKeyword::TXBXTWFIRSTLAST, 0 },
+ { "txbxtwlast", RTFControlType::FLAG, RTFKeyword::TXBXTWLAST, 0 },
+ { "txbxtwno", RTFControlType::FLAG, RTFKeyword::TXBXTWNO, 0 },
+ { "txe", RTFControlType::DESTINATION, RTFKeyword::TXE, 0 },
+ { "u", RTFControlType::VALUE, RTFKeyword::U, 0 },
+ { "uc", RTFControlType::VALUE, RTFKeyword::UC, 1 },
+ { "ud", RTFControlType::DESTINATION, RTFKeyword::UD, 0 },
+ { "ul", RTFControlType::TOGGLE, RTFKeyword::UL, 1 },
+ { "ulc", RTFControlType::VALUE, RTFKeyword::ULC, 0 },
+ { "uld", RTFControlType::FLAG, RTFKeyword::ULD, 0 },
+ { "uldash", RTFControlType::TOGGLE, RTFKeyword::ULDASH, 1 },
+ { "uldashd", RTFControlType::TOGGLE, RTFKeyword::ULDASHD, 1 },
+ { "uldashdd", RTFControlType::TOGGLE, RTFKeyword::ULDASHDD, 1 },
+ { "uldb", RTFControlType::TOGGLE, RTFKeyword::ULDB, 1 },
+ { "ulhair", RTFControlType::TOGGLE, RTFKeyword::ULHAIR, 1 },
+ { "ulhwave", RTFControlType::TOGGLE, RTFKeyword::ULHWAVE, 1 },
+ { "ulldash", RTFControlType::TOGGLE, RTFKeyword::ULLDASH, 1 },
+ { "ulnone", RTFControlType::FLAG, RTFKeyword::ULNONE, 0 },
+ { "ulth", RTFControlType::TOGGLE, RTFKeyword::ULTH, 1 },
+ { "ulthd", RTFControlType::TOGGLE, RTFKeyword::ULTHD, 1 },
+ { "ulthdash", RTFControlType::TOGGLE, RTFKeyword::ULTHDASH, 1 },
+ { "ulthdashd", RTFControlType::TOGGLE, RTFKeyword::ULTHDASHD, 1 },
+ { "ulthdashdd", RTFControlType::TOGGLE, RTFKeyword::ULTHDASHDD, 1 },
+ { "ulthldash", RTFControlType::TOGGLE, RTFKeyword::ULTHLDASH, 1 },
+ { "ululdbwave", RTFControlType::TOGGLE, RTFKeyword::ULULDBWAVE, 1 },
+ { "ulw", RTFControlType::FLAG, RTFKeyword::ULW, 0 },
+ { "ulwave", RTFControlType::TOGGLE, RTFKeyword::ULWAVE, 1 },
+ { "up", RTFControlType::VALUE, RTFKeyword::UP, 6 },
+ { "upr", RTFControlType::DESTINATION, RTFKeyword::UPR, 0 },
+ { "urtf", RTFControlType::VALUE, RTFKeyword::URTF, 0 },
+ { "useltbaln", RTFControlType::FLAG, RTFKeyword::USELTBALN, 0 },
+ { "usenormstyforlist", RTFControlType::FLAG, RTFKeyword::USENORMSTYFORLIST, 0 },
+ { "userprops", RTFControlType::DESTINATION, RTFKeyword::USERPROPS, 0 },
+ { "usexform", RTFControlType::FLAG, RTFKeyword::USEXFORM, 0 },
+ { "utinl", RTFControlType::FLAG, RTFKeyword::UTINL, 0 },
+ { "v", RTFControlType::TOGGLE, RTFKeyword::V, 1 },
+ { "validatexml", RTFControlType::VALUE, RTFKeyword::VALIDATEXML, 0 },
+ { "vern", RTFControlType::VALUE, RTFKeyword::VERN, 0 },
+ { "version", RTFControlType::VALUE, RTFKeyword::VERSION, 0 },
+ { "vertal", RTFControlType::FLAG, RTFKeyword::VERTAL, 0 },
+ { "vertalb", RTFControlType::FLAG, RTFKeyword::VERTALB, 0 },
+ { "vertalc", RTFControlType::FLAG, RTFKeyword::VERTALC, 0 },
+ { "vertalj", RTFControlType::FLAG, RTFKeyword::VERTALJ, 0 },
+ { "vertalt", RTFControlType::FLAG, RTFKeyword::VERTALT, 0 },
+ { "vertdoc", RTFControlType::FLAG, RTFKeyword::VERTDOC, 0 },
+ { "vertsect", RTFControlType::FLAG, RTFKeyword::VERTSECT, 0 },
+ { "viewbksp", RTFControlType::VALUE, RTFKeyword::VIEWBKSP, 0 },
+ { "viewkind", RTFControlType::VALUE, RTFKeyword::VIEWKIND, 0 },
+ { "viewnobound", RTFControlType::FLAG, RTFKeyword::VIEWNOBOUND, 0 },
+ { "viewscale", RTFControlType::VALUE, RTFKeyword::VIEWSCALE, 100 },
+ { "viewzk", RTFControlType::VALUE, RTFKeyword::VIEWZK, 0 },
+ { "wbitmap", RTFControlType::VALUE, RTFKeyword::WBITMAP, 0 },
+ { "wbmbitspixel", RTFControlType::VALUE, RTFKeyword::WBMBITSPIXEL, 1 },
+ { "wbmplanes", RTFControlType::VALUE, RTFKeyword::WBMPLANES, 0 },
+ { "wbmwidthbyte", RTFControlType::VALUE, RTFKeyword::WBMWIDTHBYTE, 0 },
+ { "webhidden", RTFControlType::FLAG, RTFKeyword::WEBHIDDEN, 0 },
+ { "wgrffmtfilter", RTFControlType::DESTINATION, RTFKeyword::WGRFFMTFILTER, 0 },
+ { "widctlpar", RTFControlType::FLAG, RTFKeyword::WIDCTLPAR, 0 },
+ { "widowctrl", RTFControlType::FLAG, RTFKeyword::WIDOWCTRL, 0 },
+ { "windowcaption", RTFControlType::DESTINATION, RTFKeyword::WINDOWCAPTION, 0 },
+ { "wmetafile", RTFControlType::VALUE, RTFKeyword::WMETAFILE, 1 },
+ { "wpeqn", RTFControlType::FLAG, RTFKeyword::WPEQN, 0 },
+ { "wpjst", RTFControlType::FLAG, RTFKeyword::WPJST, 0 },
+ { "wpsp", RTFControlType::FLAG, RTFKeyword::WPSP, 0 },
+ { "wraparound", RTFControlType::FLAG, RTFKeyword::WRAPAROUND, 0 },
+ { "wrapdefault", RTFControlType::FLAG, RTFKeyword::WRAPDEFAULT, 0 },
+ { "wrapthrough", RTFControlType::FLAG, RTFKeyword::WRAPTHROUGH, 0 },
+ { "wraptight", RTFControlType::FLAG, RTFKeyword::WRAPTIGHT, 0 },
+ { "wraptrsp", RTFControlType::FLAG, RTFKeyword::WRAPTRSP, 0 },
+ { "writereservation", RTFControlType::DESTINATION, RTFKeyword::WRITERESERVATION, 0 },
+ { "writereservhash", RTFControlType::DESTINATION, RTFKeyword::WRITERESERVHASH, 0 },
+ { "wrppunct", RTFControlType::FLAG, RTFKeyword::WRPPUNCT, 0 },
+ { "xe", RTFControlType::DESTINATION, RTFKeyword::XE, 0 },
+ { "xef", RTFControlType::VALUE, RTFKeyword::XEF, 0 },
+ { "xform", RTFControlType::DESTINATION, RTFKeyword::XFORM, 0 },
+ { "xmlattr", RTFControlType::FLAG, RTFKeyword::XMLATTR, 0 },
+ { "xmlattrname", RTFControlType::DESTINATION, RTFKeyword::XMLATTRNAME, 0 },
+ { "xmlattrns", RTFControlType::VALUE, RTFKeyword::XMLATTRNS, 0 },
+ { "xmlattrvalue", RTFControlType::DESTINATION, RTFKeyword::XMLATTRVALUE, 0 },
+ { "xmlclose", RTFControlType::DESTINATION, RTFKeyword::XMLCLOSE, 0 },
+ { "xmlname", RTFControlType::DESTINATION, RTFKeyword::XMLNAME, 0 },
+ { "xmlns", RTFControlType::VALUE, RTFKeyword::XMLNS, 0 },
+ { "xmlnstbl", RTFControlType::DESTINATION, RTFKeyword::XMLNSTBL, 0 },
+ { "xmlopen", RTFControlType::DESTINATION, RTFKeyword::XMLOPEN, 0 },
+ { "xmlsdttcell", RTFControlType::FLAG, RTFKeyword::XMLSDTTCELL, 0 },
+ { "xmlsdttpara", RTFControlType::FLAG, RTFKeyword::XMLSDTTPARA, 0 },
+ { "xmlsdttregular", RTFControlType::FLAG, RTFKeyword::XMLSDTTREGULAR, 0 },
+ { "xmlsdttrow", RTFControlType::FLAG, RTFKeyword::XMLSDTTROW, 0 },
+ { "xmlsdttunknown", RTFControlType::FLAG, RTFKeyword::XMLSDTTUNKNOWN, 0 },
+ { "yr", RTFControlType::VALUE, RTFKeyword::YR, 0 },
+ { "yts", RTFControlType::VALUE, RTFKeyword::YTS, 0 },
+ { "yxe", RTFControlType::FLAG, RTFKeyword::YXE, 0 },
+ { "zwbo", RTFControlType::SYMBOL, RTFKeyword::ZWBO, 0 },
+ { "zwj", RTFControlType::SYMBOL, RTFKeyword::ZWJ, 0 },
+ { "zwnbo", RTFControlType::SYMBOL, RTFKeyword::ZWNBO, 0 },
+ { "zwnj", RTFControlType::SYMBOL, RTFKeyword::ZWNJ, 0 },
+ { "flymaincnt", RTFControlType::DESTINATION, RTFKeyword::FLYMAINCNT, 0 },
+ { "flyvert", RTFControlType::VALUE, RTFKeyword::FLYVERT, 0 },
+ { "flyhorz", RTFControlType::VALUE, RTFKeyword::FLYHORZ, 0 },
+ { "flyanchor", RTFControlType::VALUE, RTFKeyword::FLYANCHOR, 0 },
+};
+const int nRTFControlWords = SAL_N_ELEMENTS(aRTFControlWords);
+
+RTFMathSymbol const aRTFMathControlWords[] = {
+ // eKeyword nToken eDestination
+ { RTFKeyword::MOMATH, M_TOKEN(oMath), Destination::MOMATH },
+ { RTFKeyword::MF, M_TOKEN(f), Destination::MF },
+ { RTFKeyword::MFPR, M_TOKEN(fPr), Destination::MFPR },
+ { RTFKeyword::MCTRLPR, M_TOKEN(ctrlPr), Destination::MCTRLPR },
+ { RTFKeyword::MNUM, M_TOKEN(num), Destination::MNUM },
+ { RTFKeyword::MDEN, M_TOKEN(den), Destination::MDEN },
+ { RTFKeyword::MACC, M_TOKEN(acc), Destination::MACC },
+ { RTFKeyword::MACCPR, M_TOKEN(accPr), Destination::MACCPR },
+ { RTFKeyword::MBAR, M_TOKEN(bar), Destination::MBAR },
+ { RTFKeyword::MBARPR, M_TOKEN(barPr), Destination::MBARPR },
+ { RTFKeyword::ME, M_TOKEN(e), Destination::ME },
+ { RTFKeyword::MD, M_TOKEN(d), Destination::MD },
+ { RTFKeyword::MDPR, M_TOKEN(dPr), Destination::MDPR },
+ { RTFKeyword::MFUNC, M_TOKEN(func), Destination::MFUNC },
+ { RTFKeyword::MFUNCPR, M_TOKEN(funcPr), Destination::MFUNCPR },
+ { RTFKeyword::MFNAME, M_TOKEN(fName), Destination::MFNAME },
+ { RTFKeyword::MLIMLOW, M_TOKEN(limLow), Destination::MLIMLOW },
+ { RTFKeyword::MLIMLOWPR, M_TOKEN(limLowPr), Destination::MLIMLOWPR },
+ { RTFKeyword::MLIM, M_TOKEN(lim), Destination::MLIM },
+ { RTFKeyword::MM, M_TOKEN(m), Destination::MM },
+ { RTFKeyword::MMPR, M_TOKEN(mPr), Destination::MMPR },
+ { RTFKeyword::MMR, M_TOKEN(mr), Destination::MMR },
+ { RTFKeyword::MNARY, M_TOKEN(nary), Destination::MNARY },
+ { RTFKeyword::MNARYPR, M_TOKEN(naryPr), Destination::MNARYPR },
+ { RTFKeyword::MSUB, M_TOKEN(sub), Destination::MSUB },
+ { RTFKeyword::MSUP, M_TOKEN(sup), Destination::MSUP },
+ { RTFKeyword::MLIMUPP, M_TOKEN(limUpp), Destination::MLIMUPP },
+ { RTFKeyword::MLIMUPPPR, M_TOKEN(limUppPr), Destination::MLIMUPPPR },
+ { RTFKeyword::MGROUPCHR, M_TOKEN(groupChr), Destination::MGROUPCHR },
+ { RTFKeyword::MGROUPCHRPR, M_TOKEN(groupChrPr), Destination::MGROUPCHRPR },
+ { RTFKeyword::MBORDERBOX, M_TOKEN(borderBox), Destination::MBORDERBOX },
+ { RTFKeyword::MBORDERBOXPR, M_TOKEN(borderBoxPr), Destination::MBORDERBOXPR },
+ { RTFKeyword::MRAD, M_TOKEN(rad), Destination::MRAD },
+ { RTFKeyword::MRADPR, M_TOKEN(radPr), Destination::MRADPR },
+ { RTFKeyword::MDEG, M_TOKEN(deg), Destination::MDEG },
+ { RTFKeyword::MSSUB, M_TOKEN(sSub), Destination::MSSUB },
+ { RTFKeyword::MSSUBPR, M_TOKEN(sSubPr), Destination::MSSUBPR },
+ { RTFKeyword::MSSUP, M_TOKEN(sSup), Destination::MSSUP },
+ { RTFKeyword::MSSUPPR, M_TOKEN(sSupPr), Destination::MSSUPPR },
+ { RTFKeyword::MSSUBSUP, M_TOKEN(sSubSup), Destination::MSSUBSUP },
+ { RTFKeyword::MSSUBSUPPR, M_TOKEN(sSubSupPr), Destination::MSSUBSUPPR },
+ { RTFKeyword::MSPRE, M_TOKEN(sPre), Destination::MSPRE },
+ { RTFKeyword::MSPREPR, M_TOKEN(sPrePr), Destination::MSPREPR },
+ { RTFKeyword::MBOX, M_TOKEN(box), Destination::MBOX },
+ { RTFKeyword::MEQARR, M_TOKEN(eqArr), Destination::MEQARR },
+};
+const int nRTFMathControlWords = SAL_N_ELEMENTS(aRTFMathControlWords);
+
+bool RTFMathSymbol::operator<(const RTFMathSymbol& rOther) const
+{
+ return m_eKeyword < rOther.m_eKeyword;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcontrolwords.hxx b/writerfilter/source/rtftok/rtfcontrolwords.hxx
new file mode 100644
index 000000000..c1480ffb0
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx
@@ -0,0 +1,2049 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+/**
+ * An RTF destination state is the last open destination control word.
+ *
+ * Note that this is not a 1:1 mapping between destination control
+ * words, e.g. RTF_PICT gets mapped to Destination::PICT or
+ * Destination::SHAPEPROPERTYVALUEPICT.
+ */
+enum class Destination
+{
+ NORMAL,
+ SKIP,
+ FONTTABLE,
+ FONTENTRY,
+ COLORTABLE,
+ STYLESHEET,
+ STYLEENTRY,
+ FIELD,
+ FIELDINSTRUCTION,
+ FIELDRESULT,
+ LISTTABLE,
+ LISTPICTURE,
+ LISTENTRY,
+ LISTNAME,
+ LISTOVERRIDETABLE,
+ LISTOVERRIDEENTRY,
+ LISTLEVEL,
+ LEVELTEXT,
+ LEVELNUMBERS,
+ SHPPICT,
+ PICT,
+ PICPROP,
+ SHAPEPROPERTY,
+ SHAPEPROPERTYNAME,
+ SHAPEPROPERTYVALUE,
+ SHAPE,
+ SHAPEINSTRUCTION,
+ SHAPEPROPERTYVALUEPICT,
+ NESTEDTABLEPROPERTIES,
+ FOOTNOTE,
+ BOOKMARKSTART,
+ BOOKMARKEND,
+ REVISIONTABLE,
+ REVISIONENTRY,
+ SHAPETEXT,
+ FORMFIELD,
+ FORMFIELDNAME,
+ FORMFIELDLIST,
+ DATAFIELD,
+ INFO,
+ CREATIONTIME,
+ REVISIONTIME,
+ PRINTTIME,
+ AUTHOR,
+ KEYWORDS,
+ OPERATOR,
+ COMPANY,
+ COMMENT,
+ OBJECT,
+ OBJDATA,
+ OBJCLASS,
+ RESULT,
+ ANNOTATIONDATE,
+ ANNOTATIONAUTHOR,
+ ANNOTATIONREFERENCE,
+ FALT,
+ FLYMAINCONTENT,
+ DRAWINGOBJECT,
+ PARAGRAPHNUMBERING,
+ PARAGRAPHNUMBERING_TEXTBEFORE,
+ PARAGRAPHNUMBERING_TEXTAFTER,
+ TITLE,
+ SUBJECT,
+ DOCCOMM,
+ ATNID,
+ ANNOTATIONREFERENCESTART,
+ ANNOTATIONREFERENCEEND,
+ MOMATH,
+ MR,
+ MF,
+ MFPR,
+ MCTRLPR,
+ MNUM,
+ MDEN,
+ MACC,
+ MACCPR,
+ MCHR,
+ MPOS,
+ MVERTJC,
+ MSTRIKEH,
+ MDEGHIDE,
+ ME,
+ MBAR,
+ MBARPR,
+ MD,
+ MDPR,
+ MBEGCHR,
+ MSEPCHR,
+ MENDCHR,
+ MFUNC,
+ MFUNCPR,
+ MFNAME,
+ MLIMLOW,
+ MLIMLOWPR,
+ MLIM,
+ MM,
+ MMPR,
+ MMR,
+ MNARY,
+ MNARYPR,
+ MSUB,
+ MSUP,
+ MSUBHIDE,
+ MSUPHIDE,
+ MLIMUPP,
+ MLIMUPPPR,
+ MGROUPCHR,
+ MGROUPCHRPR,
+ MBORDERBOX,
+ MBORDERBOXPR,
+ MRAD,
+ MRADPR,
+ MDEG,
+ MSSUB,
+ MSSUBPR,
+ MSSUP,
+ MSSUPPR,
+ MSSUBSUP,
+ MSSUBSUPPR,
+ MSPRE,
+ MSPREPR,
+ MTYPE,
+ MGROW,
+ MBOX,
+ MEQARR,
+ UPR,
+ LFOLEVEL,
+ BACKGROUND,
+ SHAPEGROUP,
+ FOOTNOTESEPARATOR,
+ INDEXENTRY,
+ TOCENTRY,
+ USERPROPS,
+ PROPNAME,
+ STATICVAL,
+ GENERATOR,
+ DOCVAR,
+};
+
+enum class RTFKeyword
+{
+ invalid = -1,
+ HEXCHAR,
+ OPTHYPH,
+ IGNORE,
+ SUBENTRY,
+ BACKSLASH,
+ NOBRKHYPH,
+ LBRACE,
+ FORMULA,
+ RBRACE,
+ NOBREAK,
+ AB,
+ ABSH,
+ ABSLOCK,
+ ABSNOOVRLP,
+ ABSW,
+ ACAPS,
+ ACCCIRCLE,
+ ACCCOMMA,
+ ACCDOT,
+ ACCNONE,
+ ACCUNDERDOT,
+ ACF,
+ ADEFF,
+ ADDITIVE,
+ ADEFLANG,
+ ADJUSTRIGHT,
+ ADN,
+ AENDDOC,
+ AENDNOTES,
+ AEXPND,
+ AF,
+ AFELEV,
+ AFS,
+ AFTNBJ,
+ AFTNCN,
+ AFTNNALC,
+ AFTNNAR,
+ AFTNNAUC,
+ AFTNNCHI,
+ AFTNNCHOSUNG,
+ AFTNNCNUM,
+ AFTNNDBAR,
+ AFTNNDBNUM,
+ AFTNNDBNUMD,
+ AFTNNDBNUMK,
+ AFTNNDBNUMT,
+ AFTNNGANADA,
+ AFTNNGBNUM,
+ AFTNNGBNUMD,
+ AFTNNGBNUMK,
+ AFTNNGBNUML,
+ AFTNNRLC,
+ AFTNNRUC,
+ AFTNNZODIAC,
+ AFTNNZODIACD,
+ AFTNNZODIACL,
+ AFTNRESTART,
+ AFTNRSTCONT,
+ AFTNSEP,
+ AFTNSEPC,
+ AFTNSTART,
+ AFTNTJ,
+ AI,
+ ALANG,
+ ALLOWFIELDENDSEL,
+ ALLPROT,
+ ALNTBLIND,
+ ALT,
+ ANIMTEXT,
+ ANNOTATION,
+ ANNOTPROT,
+ ANSI,
+ ANSICPG,
+ AOUTL,
+ APPLYBRKRULES,
+ ASCAPS,
+ ASHAD,
+ ASIANBRKRULE,
+ ASPALPHA,
+ ASPNUM,
+ ASTRIKE,
+ ATNAUTHOR,
+ ATNDATE,
+ ATNICN,
+ ATNID,
+ ATNPARENT,
+ ATNREF,
+ ATNTIME,
+ ATRFEND,
+ ATRFSTART,
+ AUL,
+ AULD,
+ AULDB,
+ AULNONE,
+ AULW,
+ AUP,
+ AUTHOR,
+ AUTOFMTOVERRIDE,
+ B,
+ BACKGROUND,
+ BDBFHDR,
+ BDRRLSWSIX,
+ BGBDIAG,
+ BGCROSS,
+ BGDCROSS,
+ BGDKBDIAG,
+ BGDKCROSS,
+ BGDKDCROSS,
+ BGDKFDIAG,
+ BGDKHORIZ,
+ BGDKVERT,
+ BGFDIAG,
+ BGHORIZ,
+ BGVERT,
+ BIN,
+ BINFSXN,
+ BINSXN,
+ BKMKCOLF,
+ BKMKCOLL,
+ BKMKEND,
+ BKMKPUB,
+ BKMKSTART,
+ BLIPTAG,
+ BLIPUID,
+ BLIPUPI,
+ BLUE,
+ BOOKFOLD,
+ BOOKFOLDREV,
+ BOOKFOLDSHEETS,
+ BOX,
+ BRDRART,
+ BRDRB,
+ BRDRBAR,
+ BRDRBTW,
+ BRDRCF,
+ BRDRDASH,
+ BRDRDASHD,
+ BRDRDASHDD,
+ BRDRDASHDOTSTR,
+ BRDRDASHSM,
+ BRDRDB,
+ BRDRDOT,
+ BRDREMBOSS,
+ BRDRENGRAVE,
+ BRDRFRAME,
+ BRDRHAIR,
+ BRDRINSET,
+ BRDRL,
+ BRDRNIL,
+ BRDRNONE,
+ BRDROUTSET,
+ BRDRR,
+ BRDRS,
+ BRDRSH,
+ BRDRT,
+ BRDRTBL,
+ BRDRTH,
+ BRDRTHTNLG,
+ BRDRTHTNMG,
+ BRDRTHTNSG,
+ BRDRTNTHLG,
+ BRDRTNTHMG,
+ BRDRTNTHSG,
+ BRDRTNTHTNLG,
+ BRDRTNTHTNMG,
+ BRDRTNTHTNSG,
+ BRDRTRIPLE,
+ BRDRW,
+ BRDRWAVY,
+ BRDRWAVYDB,
+ BRKFRM,
+ BRSP,
+ BULLET,
+ BUPTIM,
+ BXE,
+ CACCENTFIVE,
+ CACCENTFOUR,
+ CACCENTONE,
+ CACCENTSIX,
+ CACCENTTHREE,
+ CACCENTTWO,
+ CACHEDCOLBAL,
+ CAPS,
+ CATEGORY,
+ CB,
+ CBACKGROUNDONE,
+ CBACKGROUNDTWO,
+ CBPAT,
+ CCHS,
+ CELL,
+ CELLX,
+ CF,
+ CFOLLOWEDHYPERLINK,
+ CFPAT,
+ CGRID,
+ CHARRSID,
+ CHARSCALEX,
+ CHATN,
+ CHBGBDIAG,
+ CHBGCROSS,
+ CHBGDCROSS,
+ CHBGDKBDIAG,
+ CHBGDKCROSS,
+ CHBGDKDCROSS,
+ CHBGDKFDIAG,
+ CHBGDKHORIZ,
+ CHBGDKVERT,
+ CHBGFDIAG,
+ CHBGHORIZ,
+ CHBGVERT,
+ CHBRDR,
+ CHCBPAT,
+ CHCFPAT,
+ CHDATE,
+ CHDPA,
+ CHDPL,
+ CHFTN,
+ CHFTNSEP,
+ CHFTNSEPC,
+ CHPGN,
+ CHHRES,
+ CHSHDNG,
+ CHTIME,
+ CHYPERLINK,
+ CLBGBDIAG,
+ CLBGCROSS,
+ CLBGDCROSS,
+ CLBGDKBDIAG,
+ CLBGDKCROSS,
+ CLBGDKDCROSS,
+ CLBGDKFDIAG,
+ CLBGDKHOR,
+ CLBGDKVERT,
+ CLBGFDIAG,
+ CLBGHORIZ,
+ CLBGVERT,
+ CLBRDRB,
+ CLBRDRL,
+ CLBRDRR,
+ CLBRDRT,
+ CLCBPAT,
+ CLCBPATRAW,
+ CLCFPAT,
+ CLCFPATRAW,
+ CLDEL,
+ CLDELAUTH,
+ CLDELDTTM,
+ CLDGLL,
+ CLDGLU,
+ CLFITTEXT,
+ CLFTSWIDTH,
+ CLHIDEMARK,
+ CLINS,
+ CLINSAUTH,
+ CLINSDTTM,
+ CLMGF,
+ CLMRG,
+ CLMRGD,
+ CLMRGDAUTH,
+ CLMRGDDTTM,
+ CLMRGDR,
+ CLNOWRAP,
+ CLPADB,
+ CLPADFB,
+ CLPADFL,
+ CLPADFR,
+ CLPADFT,
+ CLPADL,
+ CLPADR,
+ CLPADT,
+ CLSPB,
+ CLSPFB,
+ CLSPFL,
+ CLSPFR,
+ CLSPFT,
+ CLSPL,
+ CLSPR,
+ CLSPT,
+ CLSHDNG,
+ CLSHDNGRAW,
+ CLSHDRAWNIL,
+ CLSPLIT,
+ CLSPLITR,
+ CLTXBTLR,
+ CLTXLRTB,
+ CLTXLRTBV,
+ CLTXTBRL,
+ CLTXTBRLV,
+ CLVERTALB,
+ CLVERTALC,
+ CLVERTALT,
+ CLVMGF,
+ CLVMRG,
+ CLWWIDTH,
+ CMAINDARKONE,
+ CMAINDARKTWO,
+ CMAINLIGHTONE,
+ CMAINLIGHTTWO,
+ COLLAPSED,
+ COLNO,
+ COLORSCHEMEMAPPING,
+ COLORTBL,
+ COLS,
+ COLSR,
+ COLSX,
+ COLUMN,
+ COLW,
+ COMMENT,
+ COMPANY,
+ CONTEXTUALSPACE,
+ CPG,
+ CRAUTH,
+ CRDATE,
+ CREATIM,
+ CS,
+ CSHADE,
+ CTEXTONE,
+ CTEXTTWO,
+ CTINT,
+ CTRL,
+ CTS,
+ CUFI,
+ CULI,
+ CURI,
+ CVMME,
+ DATAFIELD,
+ DATASTORE,
+ DATE,
+ DBCH,
+ DEFCHP,
+ DEFF,
+ DEFFORMAT,
+ DEFLANG,
+ DEFLANGFE,
+ DEFPAP,
+ DEFSHP,
+ DEFTAB,
+ DELETED,
+ DELRSID,
+ DFRAUTH,
+ DFRDATE,
+ DFRMTXTX,
+ DFRMTXTY,
+ DFRSTART,
+ DFRSTOP,
+ DFRXST,
+ DGHORIGIN,
+ DGHSHOW,
+ DGHSPACE,
+ DGMARGIN,
+ DGSNAP,
+ DGVORIGIN,
+ DGVSHOW,
+ DGVSPACE,
+ DIBITMAP,
+ DISABLED,
+ DN,
+ DNTBLNSBDB,
+ DO,
+ DOBXCOLUMN,
+ DOBXMARGIN,
+ DOBXPAGE,
+ DOBYMARGIN,
+ DOBYPAGE,
+ DOBYPARA,
+ DOCCOMM,
+ DOCTEMP,
+ DOCTYPE,
+ DOCVAR,
+ DODHGT,
+ DOLOCK,
+ DONOTEMBEDLINGDATA,
+ DONOTEMBEDSYSFONT,
+ DONOTSHOWCOMMENTS,
+ DONOTSHOWINSDEL,
+ DONOTSHOWMARKUP,
+ DONOTSHOWPROPS,
+ DPAENDHOL,
+ DPAENDL,
+ DPAENDSOL,
+ DPAENDW,
+ DPARC,
+ DPARCFLIPX,
+ DPARCFLIPY,
+ DPASTARTHOL,
+ DPASTARTL,
+ DPASTARTSOL,
+ DPASTARTW,
+ DPCALLOUT,
+ DPCOA,
+ DPCOACCENT,
+ DPCOBESTFIT,
+ DPCOBORDER,
+ DPCODABS,
+ DPCODBOTTOM,
+ DPCODCENTER,
+ DPCODESCENT,
+ DPCODTOP,
+ DPCOLENGTH,
+ DPCOMINUSX,
+ DPCOMINUSY,
+ DPCOOFFSET,
+ DPCOSMARTA,
+ DPCOTDOUBLE,
+ DPCOTRIGHT,
+ DPCOTSINGLE,
+ DPCOTTRIPLE,
+ DPCOUNT,
+ DPELLIPSE,
+ DPENDGROUP,
+ DPFILLBGCB,
+ DPFILLBGCG,
+ DPFILLBGCR,
+ DPFILLBGGRAY,
+ DPFILLBGPAL,
+ DPFILLFGCB,
+ DPFILLFGCG,
+ DPFILLFGCR,
+ DPFILLFGGRAY,
+ DPFILLFGPAL,
+ DPFILLPAT,
+ DPGROUP,
+ DPLINE,
+ DPLINECOB,
+ DPLINECOG,
+ DPLINECOR,
+ DPLINEDADO,
+ DPLINEDADODO,
+ DPLINEDASH,
+ DPLINEDOT,
+ DPLINEGRAY,
+ DPLINEHOLLOW,
+ DPLINEPAL,
+ DPLINESOLID,
+ DPLINEW,
+ DPPOLYCOUNT,
+ DPPOLYGON,
+ DPPOLYLINE,
+ DPPTX,
+ DPPTY,
+ DPRECT,
+ DPROUNDR,
+ DPSHADOW,
+ DPSHADX,
+ DPSHADY,
+ DPTXBTLR,
+ DPTXBX,
+ DPTXBXMAR,
+ DPTXBXTEXT,
+ DPTXLRTB,
+ DPTXLRTBV,
+ DPTXTBRL,
+ DPTXTBRLV,
+ DPX,
+ DPXSIZE,
+ DPY,
+ DPYSIZE,
+ DROPCAPLI,
+ DROPCAPT,
+ DS,
+ DXFRTEXT,
+ DY,
+ EBCEND,
+ EBCSTART,
+ EDMINS,
+ EMBO,
+ EMDASH,
+ EMFBLIP,
+ EMSPACE,
+ ENDASH,
+ ENDDOC,
+ ENDNHERE,
+ ENDNOTES,
+ ENFORCEPROT,
+ ENSPACE,
+ EXPND,
+ EXPNDTW,
+ EXPSHRTN,
+ F,
+ FAAUTO,
+ FACENTER,
+ FACINGP,
+ FACTOIDNAME,
+ FAFIXED,
+ FAHANG,
+ FALT,
+ FAROMAN,
+ FAVAR,
+ FBIAS,
+ FBIDI,
+ FBIDIS,
+ FBIMAJOR,
+ FBIMINOR,
+ FCHARS,
+ FCHARSET,
+ FCS,
+ FDBMAJOR,
+ FDBMINOR,
+ FDECOR,
+ FELNBRELEV,
+ FET,
+ FETCH,
+ FFDEFRES,
+ FFDEFTEXT,
+ FFENTRYMCR,
+ FFEXITMCR,
+ FFFORMAT,
+ FFHASLISTBOX,
+ FFHELPTEXT,
+ FFHPS,
+ FFL,
+ FFMAXLEN,
+ FFNAME,
+ FFOWNHELP,
+ FFOWNSTAT,
+ FFPROT,
+ FFRECALC,
+ FFRES,
+ FFSIZE,
+ FFSTATTEXT,
+ FFTYPE,
+ FFTYPETXT,
+ FHIMAJOR,
+ FHIMINOR,
+ FI,
+ FID,
+ FIELD,
+ FILE,
+ FILETBL,
+ FITTEXT,
+ FJGOTHIC,
+ FJMINCHOU,
+ FLDALT,
+ FLDDIRTY,
+ FLDEDIT,
+ FLDINST,
+ FLDLOCK,
+ FLDPRIV,
+ FLDRSLT,
+ FLDTYPE,
+ FLOMAJOR,
+ FLOMINOR,
+ FMODERN,
+ FN,
+ FNAME,
+ FNETWORK,
+ FNIL,
+ FNONFILESYS,
+ FONTEMB,
+ FONTFILE,
+ FONTTBL,
+ FOOTER,
+ FOOTERF,
+ FOOTERL,
+ FOOTERR,
+ FOOTERY,
+ FOOTNOTE,
+ FORCEUPGRADE,
+ FORMDISP,
+ FORMFIELD,
+ FORMPROT,
+ FORMSHADE,
+ FOSNUM,
+ FPRQ,
+ FRACWIDTH,
+ FRELATIVE,
+ FRMTXBTLR,
+ FRMTXLRTB,
+ FRMTXLRTBV,
+ FRMTXTBRL,
+ FRMTXTBRLV,
+ FROMAN,
+ FROMHTML,
+ FROMTEXT,
+ FS,
+ FSCRIPT,
+ FSWISS,
+ FTECH,
+ FTNALT,
+ FTNBJ,
+ FTNCN,
+ FTNIL,
+ FTNLYTWNINE,
+ FTNNALC,
+ FTNNAR,
+ FTNNAUC,
+ FTNNCHI,
+ FTNNCHOSUNG,
+ FTNNCNUM,
+ FTNNDBAR,
+ FTNNDBNUM,
+ FTNNDBNUMD,
+ FTNNDBNUMK,
+ FTNNDBNUMT,
+ FTNNGANADA,
+ FTNNGBNUM,
+ FTNNGBNUMD,
+ FTNNGBNUMK,
+ FTNNGBNUML,
+ FTNNRLC,
+ FTNNRUC,
+ FTNNZODIAC,
+ FTNNZODIACD,
+ FTNNZODIACL,
+ FTNRESTART,
+ FTNRSTCONT,
+ FTNRSTPG,
+ FTNSEP,
+ FTNSEPC,
+ FTNSTART,
+ FTNTJ,
+ FTTRUETYPE,
+ FVALIDDOS,
+ FVALIDHPFS,
+ FVALIDMAC,
+ FVALIDNTFS,
+ G,
+ GCW,
+ GENERATOR,
+ GREEN,
+ GRFDOCEVENTS,
+ GRIDTBL,
+ GUTTER,
+ GUTTERPRL,
+ GUTTERSXN,
+ HEADER,
+ HEADERF,
+ HEADERL,
+ HEADERR,
+ HEADERY,
+ HICH,
+ HIGHLIGHT,
+ HL,
+ HLFR,
+ HLINKBASE,
+ HLLOC,
+ HLSRC,
+ HORZDOC,
+ HORZSECT,
+ HORZVERT,
+ HR,
+ HRES,
+ HRULE,
+ HSV,
+ HTMAUTSP,
+ HTMLBASE,
+ HTMLRTF,
+ HTMLTAG,
+ HWELEV,
+ HYPHAUTO,
+ HYPHCAPS,
+ HYPHCONSEC,
+ HYPHHOTZ,
+ HYPHPAR,
+ I,
+ ID,
+ IGNOREMIXEDCONTENT,
+ ILFOMACATCLNUP,
+ ILVL,
+ IMPR,
+ INDMIRROR,
+ INDRLSWELEVEN,
+ INFO,
+ INSRSID,
+ INTBL,
+ IPGP,
+ IROWBAND,
+ IROW,
+ ITAP,
+ IXE,
+ JCOMPRESS,
+ JEXPAND,
+ JIS,
+ JPEGBLIP,
+ JSKSU,
+ KEEP,
+ KEEPN,
+ KERNING,
+ KEYCODE,
+ KEYWORDS,
+ KRNPRSNET,
+ KSULANG,
+ JCLISTTAB,
+ LANDSCAPE,
+ LANG,
+ LANGFE,
+ LANGFENP,
+ LANGNP,
+ LASTROW,
+ LATENTSTYLES,
+ LBR,
+ LCHARS,
+ LDBLQUOTE,
+ LEVEL,
+ LEVELFOLLOW,
+ LEVELINDENT,
+ LEVELJC,
+ LEVELJCN,
+ LEVELLEGAL,
+ LEVELNFC,
+ LEVELNFCN,
+ LEVELNORESTART,
+ LEVELNUMBERS,
+ LEVELOLD,
+ LEVELPICTURE,
+ LEVELPICTURENOSIZE,
+ LEVELPREV,
+ LEVELPREVSPACE,
+ LEVELSPACE,
+ LEVELSTARTAT,
+ LEVELTEMPLATEID,
+ LEVELTEXT,
+ LFOLEVEL,
+ LI,
+ LINE,
+ LINEBETCOL,
+ LINECONT,
+ LINEMOD,
+ LINEPPAGE,
+ LINERESTART,
+ LINESTART,
+ LINESTARTS,
+ LINEX,
+ LINKSELF,
+ LINKSTYLES,
+ LINKVAL,
+ LIN,
+ LISA,
+ LISB,
+ LIST,
+ LISTHYBRID,
+ LISTID,
+ LISTLEVEL,
+ LISTNAME,
+ LISTOVERRIDE,
+ LISTOVERRIDECOUNT,
+ LISTOVERRIDEFORMAT,
+ LISTOVERRIDESTARTAT,
+ LISTOVERRIDETABLE,
+ LISTPICTURE,
+ LISTRESTARTHDN,
+ LISTSIMPLE,
+ LISTSTYLEID,
+ LISTSTYLENAME,
+ LISTTABLE,
+ LISTTEMPLATEID,
+ LISTTEXT,
+ LNBRKRULE,
+ LNDSCPSXN,
+ LNONGRID,
+ LOCH,
+ LQUOTE,
+ LS,
+ LSDLOCKED,
+ LSDLOCKEDDEF,
+ LSDLOCKEDEXCEPT,
+ LSDPRIORITY,
+ LSDPRIORITYDEF,
+ LSDQFORMAT,
+ LSDQFORMATDEF,
+ LSDSEMIHIDDEN,
+ LSDSEMIHIDDENDEF,
+ LSDSTIMAX,
+ LSDUNHIDEUSED,
+ LSDUNHIDEUSEDDEF,
+ LTRCH,
+ LTRDOC,
+ LTRMARK,
+ LTRPAR,
+ LTRROW,
+ LTRSECT,
+ LVLTENTATIVE,
+ LYTCALCTBLWD,
+ LYTEXCTTP,
+ LYTPRTMET,
+ LYTTBLRTGR,
+ MAC,
+ MACC,
+ MACCPR,
+ MACPICT,
+ MAILMERGE,
+ MAKEBACKUP,
+ MALN,
+ MALNSCR,
+ MANAGER,
+ MARGB,
+ MARGBSXN,
+ MARGL,
+ MARGLSXN,
+ MARGMIRROR,
+ MARGMIRSXN,
+ MARGPR,
+ MARGR,
+ MARGRSXN,
+ MARGSZ,
+ MARGT,
+ MARGTSXN,
+ MBAR,
+ MBARPR,
+ MBASEJC,
+ MBEGCHR,
+ MBORDERBOX,
+ MBORDERBOXPR,
+ MBOX,
+ MBOXPR,
+ MBRK,
+ MBRKBIN,
+ MBRKBINSUB,
+ MCGP,
+ MCGPRULE,
+ MCHR,
+ MCOUNT,
+ MCSP,
+ MCTRLPR,
+ MD,
+ MDEFJC,
+ MDEG,
+ MDEGHIDE,
+ MDEN,
+ MDIFF,
+ MDIFFSTY,
+ MDISPDEF,
+ MDPR,
+ ME,
+ MENDCHR,
+ MEQARR,
+ MEQARRPR,
+ MF,
+ MFNAME,
+ MFPR,
+ MFUNC,
+ MFUNCPR,
+ MGROUPCHR,
+ MGROUPCHRPR,
+ MGROW,
+ MHIDEBOT,
+ MHIDELEFT,
+ MHIDERIGHT,
+ MHIDETOP,
+ MHTMLTAG,
+ MIN,
+ MINTERSP,
+ MINTLIM,
+ MINTRASP,
+ MJC,
+ MLIM,
+ MLIMLOC,
+ MLIMLOW,
+ MLIMLOWPR,
+ MLIMUPP,
+ MLIMUPPPR,
+ MLIT,
+ MLMARGIN,
+ MM,
+ MMADDFIELDNAME,
+ MMATH,
+ MMATHFONT,
+ MMATHPICT,
+ MMATHPR,
+ MMATTACH,
+ MMAXDIST,
+ MMBLANKLINES,
+ MMC,
+ MMCJC,
+ MMCONNECTSTR,
+ MMCONNECTSTRDATA,
+ MMCPR,
+ MMCS,
+ MMDATASOURCE,
+ MMDATATYPEACCESS,
+ MMDATATYPEEXCEL,
+ MMDATATYPEFILE,
+ MMDATATYPEODBC,
+ MMDATATYPEODSO,
+ MMDATATYPEQT,
+ MMDEFAULTSQL,
+ MMDESTEMAIL,
+ MMDESTFAX,
+ MMDESTNEWDOC,
+ MMDESTPRINTER,
+ MMERRORS,
+ MMFTTYPEADDRESS,
+ MMFTTYPEBARCODE,
+ MMFTTYPEDBCOLUMN,
+ MMFTTYPEMAPPED,
+ MMFTTYPENULL,
+ MMFTTYPESALUTATION,
+ MMHEADERSOURCE,
+ MMJDSOTYPE,
+ MMLINKTOQUERY,
+ MMMAILSUBJECT,
+ MMMAINTYPECATALOG,
+ MMMAINTYPEEMAIL,
+ MMMAINTYPEENVELOPES,
+ MMMAINTYPEFAX,
+ MMMAINTYPELABELS,
+ MMMAINTYPELETTERS,
+ MMODSO,
+ MMODSOACTIVE,
+ MMODSOCOLDELIM,
+ MMODSOCOLUMN,
+ MMODSODYNADDR,
+ MMODSOFHDR,
+ MMODSOFILTER,
+ MMODSOFLDMPDATA,
+ MMODSOFMCOLUMN,
+ MMODSOHASH,
+ MMODSOLID,
+ MMODSOMAPPEDNAME,
+ MMODSONAME,
+ MMODSORECIPDATA,
+ MMODSOSORT,
+ MMODSOSRC,
+ MMODSOTABLE,
+ MMODSOUDL,
+ MMODSOUDLDATA,
+ MMODSOUNIQUETAG,
+ MMPR,
+ MMQUERY,
+ MMR,
+ MMRECCUR,
+ MMSHOWDATA,
+ MNARY,
+ MNARYLIM,
+ MNARYPR,
+ MNOBREAK,
+ MNOR,
+ MNUM,
+ MO,
+ MOBJDIST,
+ MOMATH,
+ MOMATHPARA,
+ MOMATHPARAPR,
+ MOPEMU,
+ MPHANT,
+ MPHANTPR,
+ MPLCHIDE,
+ MPOS,
+ MPOSTSP,
+ MPRESP,
+ MR,
+ MRAD,
+ MRADPR,
+ MRMARGIN,
+ MRPR,
+ MRSP,
+ MRSPRULE,
+ MSCR,
+ MSEPCHR,
+ MSHOW,
+ MSHP,
+ MSMALLFRAC,
+ MSMCAP,
+ MSPRE,
+ MSPREPR,
+ MSSUB,
+ MSSUBPR,
+ MSSUBSUP,
+ MSSUBSUPPR,
+ MSSUP,
+ MSSUPPR,
+ MSTRIKEBLTR,
+ MSTRIKEH,
+ MSTRIKETLBR,
+ MSTRIKEV,
+ MSTY,
+ MSUB,
+ MSUBHIDE,
+ MSUP,
+ MSUPHIDE,
+ MTRANSP,
+ MTYPE,
+ MUSER,
+ MVAUTH,
+ MVDATE,
+ MVERTJC,
+ MVF,
+ MVFMF,
+ MVFML,
+ MVT,
+ MVTOF,
+ MVTOL,
+ MWRAPINDENT,
+ MWRAPRIGHT,
+ MZEROASC,
+ MZERODESC,
+ MZEROWID,
+ NESTCELL,
+ NESTROW,
+ NESTTABLEPROPS,
+ NEWTBLSTYRULS,
+ NEXTFILE,
+ NOAFCNSTTBL,
+ NOBRKWRPTBL,
+ NOCOLBAL,
+ NOCOMPATOPTIONS,
+ NOCWRAP,
+ NOCXSPTABLE,
+ NOEXTRASPRL,
+ NOFCHARS,
+ NOFCHARSWS,
+ NOFEATURETHROTTLE,
+ NOFPAGES,
+ NOFWORDS,
+ NOGROWAUTOFIT,
+ NOINDNMBRTS,
+ NOJKERNPUNCT,
+ NOLEAD,
+ NOLINE,
+ NOLNHTADJTBL,
+ NONESTTABLES,
+ NONSHPPICT,
+ NOOVERFLOW,
+ NOPROOF,
+ NOQFPROMOTE,
+ NOSECTEXPAND,
+ NOSNAPLINEGRID,
+ NOSPACEFORUL,
+ NOSUPERSUB,
+ NOTABIND,
+ NOTBRKCNSTFRCTBL,
+ NOTCVASP,
+ NOTVATXBX,
+ NOUICOMPAT,
+ NOULTRLSPC,
+ NOWIDCTLPAR,
+ NOWRAP,
+ NOWWRAP,
+ NOXLATTOYEN,
+ OBJALIAS,
+ OBJALIGN,
+ OBJATTPH,
+ OBJAUTLINK,
+ OBJCLASS,
+ OBJCROPB,
+ OBJCROPL,
+ OBJCROPR,
+ OBJCROPT,
+ OBJDATA,
+ OBJECT,
+ OBJEMB,
+ OBJH,
+ OBJHTML,
+ OBJICEMB,
+ OBJLINK,
+ OBJLOCK,
+ OBJNAME,
+ OBJOCX,
+ OBJPUB,
+ OBJSCALEX,
+ OBJSCALEY,
+ OBJSECT,
+ OBJSETSIZE,
+ OBJSUB,
+ OBJTIME,
+ OBJTRANSY,
+ OBJUPDATE,
+ OBJW,
+ OGUTTER,
+ OLDAS,
+ OLDCPROPS,
+ OLDLINEWRAP,
+ OLDPPROPS,
+ OLDSPROPS,
+ OLDTPROPS,
+ OLECLSID,
+ OPERATOR,
+ OTBLRUL,
+ OUTL,
+ OUTLINELEVEL,
+ OVERLAY,
+ PAGE,
+ PAGEBB,
+ PANOSE,
+ PAPERH,
+ PAPERW,
+ PAR,
+ PARARSID,
+ PARD,
+ PASSWORD,
+ PASSWORDHASH,
+ PC,
+ PCA,
+ PGBRDRB,
+ PGBRDRFOOT,
+ PGBRDRHEAD,
+ PGBRDRL,
+ PGBRDROPT,
+ PGBRDRR,
+ PGBRDRSNAP,
+ PGBRDRT,
+ PGHSXN,
+ PGNBIDIA,
+ PGNBIDIB,
+ PGNCHOSUNG,
+ PGNCNUM,
+ PGNCONT,
+ PGNDBNUM,
+ PGNDBNUMD,
+ PGNDBNUMK,
+ PGNDBNUMT,
+ PGNDEC,
+ PGNDECD,
+ PGNGANADA,
+ PGNGBNUM,
+ PGNGBNUMD,
+ PGNGBNUMK,
+ PGNGBNUML,
+ PGNHINDIA,
+ PGNHINDIB,
+ PGNHINDIC,
+ PGNHINDID,
+ PGNHN,
+ PGNHNSC,
+ PGNHNSH,
+ PGNHNSM,
+ PGNHNSN,
+ PGNHNSP,
+ PGNID,
+ PGNLCLTR,
+ PGNLCRM,
+ PGNRESTART,
+ PGNSTART,
+ PGNSTARTS,
+ PGNTHAIA,
+ PGNTHAIB,
+ PGNTHAIC,
+ PGNUCLTR,
+ PGNUCRM,
+ PGNVIETA,
+ PGNX,
+ PGNY,
+ PGNZODIAC,
+ PGNZODIACD,
+ PGNZODIACL,
+ PGP,
+ PGPTBL,
+ PGWSXN,
+ PHCOL,
+ PHMRG,
+ PHPG,
+ PICBMP,
+ PICBPP,
+ PICCROPB,
+ PICCROPL,
+ PICCROPR,
+ PICCROPT,
+ PICH,
+ PICHGOAL,
+ PICPROP,
+ PICSCALED,
+ PICSCALEX,
+ PICSCALEY,
+ PICT,
+ PICW,
+ PICWGOAL,
+ PINDTABQC,
+ PINDTABQL,
+ PINDTABQR,
+ PLAIN,
+ PMARTABQC,
+ PMARTABQL,
+ PMARTABQR,
+ PMMETAFILE,
+ PN,
+ PNACROSS,
+ PNAIU,
+ PNAIUD,
+ PNAIUEO,
+ PNAIUEOD,
+ PNB,
+ PNBIDIA,
+ PNBIDIB,
+ PNCAPS,
+ PNCARD,
+ PNCF,
+ PNCHOSUNG,
+ PNCNUM,
+ PNDBNUM,
+ PNDBNUMD,
+ PNDBNUMK,
+ PNDBNUML,
+ PNDBNUMT,
+ PNDEC,
+ PNDECD,
+ PNF,
+ PNFS,
+ PNGANADA,
+ PNGBLIP,
+ PNGBNUM,
+ PNGBNUMD,
+ PNGBNUMK,
+ PNGBNUML,
+ PNHANG,
+ PNI,
+ PNINDENT,
+ PNIROHA,
+ PNIROHAD,
+ PNLCLTR,
+ PNLCRM,
+ PNLVL,
+ PNLVLBLT,
+ PNLVLBODY,
+ PNLVLCONT,
+ PNNUMONCE,
+ PNORD,
+ PNORDT,
+ PNPREV,
+ PNQC,
+ PNQL,
+ PNQR,
+ PNRAUTH,
+ PNRDATE,
+ PNRESTART,
+ PNRNFC,
+ PNRNOT,
+ PNRPNBR,
+ PNRRGB,
+ PNRSTART,
+ PNRSTOP,
+ PNRXST,
+ PNSCAPS,
+ PNSECLVL,
+ PNSP,
+ PNSTART,
+ PNSTRIKE,
+ PNTEXT,
+ PNTXTA,
+ PNTXTB,
+ PNUCLTR,
+ PNUCRM,
+ PNUL,
+ PNULD,
+ PNULDASH,
+ PNULDASHD,
+ PNULDASHDD,
+ PNULDB,
+ PNULHAIR,
+ PNULNONE,
+ PNULTH,
+ PNULW,
+ PNULWAVE,
+ PNZODIAC,
+ PNZODIACD,
+ PNZODIACL,
+ POSNEGX,
+ POSNEGY,
+ POSX,
+ POSXC,
+ POSXI,
+ POSXL,
+ POSXO,
+ POSXR,
+ POSY,
+ POSYB,
+ POSYC,
+ POSYIL,
+ POSYIN,
+ POSYOUT,
+ POSYT,
+ PRAUTH,
+ PRCOLBL,
+ PRDATE,
+ PRINTDATA,
+ PRINTIM,
+ PRIVATE,
+ PROPNAME,
+ PROPTYPE,
+ PROTECT,
+ PROTEND,
+ PROTLEVEL,
+ PROTSTART,
+ PROTUSERTBL,
+ PSOVER,
+ PSZ,
+ PTABLDOT,
+ PTABLMDOT,
+ PTABLMINUS,
+ PTABLNONE,
+ PTABLUSCORE,
+ PUBAUTO,
+ PVMRG,
+ PVPARA,
+ PVPG,
+ PWD,
+ PXE,
+ QC,
+ QD,
+ QJ,
+ QK,
+ QL,
+ QMSPACE,
+ QR,
+ QT,
+ RAWCLBGDKBDIAG,
+ RAWCLBGBDIAG,
+ RAWCLBGCROSS,
+ RAWCLBGDCROSS,
+ RAWCLBGDKCROSS,
+ RAWCLBGDKDCROSS,
+ RAWCLBGDKFDIAG,
+ RAWCLBGDKHOR,
+ RAWCLBGDKVERT,
+ RAWCLBGFDIAG,
+ RAWCLBGHORIZ,
+ RAWCLBGVERT,
+ RDBLQUOTE,
+ READONLYRECOMMENDED,
+ READPROT,
+ RED,
+ RELYONVML,
+ REMDTTM,
+ REMPERSONALINFO,
+ RESULT,
+ REVAUTH,
+ REVAUTHDEL,
+ REVBAR,
+ REVDTTM,
+ REVDTTMDEL,
+ REVISED,
+ REVISIONS,
+ REVPROP,
+ REVPROT,
+ REVTBL,
+ REVTIM,
+ RI,
+ RIN,
+ ROW,
+ RQUOTE,
+ RSID,
+ RSIDROOT,
+ RSIDTBL,
+ RSLTBMP,
+ RSLTHTML,
+ RSLTMERGE,
+ RSLTPICT,
+ RSLTRTF,
+ RSLTTXT,
+ RTF,
+ RTLCH,
+ RTLDOC,
+ RTLGUTTER,
+ RTLMARK,
+ RTLPAR,
+ RTLROW,
+ RTLSECT,
+ RXE,
+ S,
+ SA,
+ SAAUTO,
+ SAFTNNALC,
+ SAFTNNAR,
+ SAFTNNAUC,
+ SAFTNNCHI,
+ SAFTNNCHOSUNG,
+ SAFTNNCNUM,
+ SAFTNNDBAR,
+ SAFTNNDBNUM,
+ SAFTNNDBNUMD,
+ SAFTNNDBNUMK,
+ SAFTNNDBNUMT,
+ SAFTNNGANADA,
+ SAFTNNGBNUM,
+ SAFTNNGBNUMD,
+ SAFTNNGBNUMK,
+ SAFTNNGBNUML,
+ SAFTNNRLC,
+ SAFTNNRUC,
+ SAFTNNZODIAC,
+ SAFTNNZODIACD,
+ SAFTNNZODIACL,
+ SAFTNRESTART,
+ SAFTNRSTCONT,
+ SAFTNSTART,
+ SAUTOUPD,
+ SAVEINVALIDXML,
+ SAVEPREVPICT,
+ SB,
+ SBASEDON,
+ SBAUTO,
+ SBKCOL,
+ SBKEVEN,
+ SBKNONE,
+ SBKODD,
+ SBKPAGE,
+ SBYS,
+ SCAPS,
+ SCOMPOSE,
+ SEC,
+ SECT,
+ SECTD,
+ SECTDEFAULTCL,
+ SECTEXPAND,
+ SECTLINEGRID,
+ SECTNUM,
+ SECTRSID,
+ SECTSPECIFYCL,
+ SECTSPECIFYGENN,
+ SECTSPECIFYL,
+ SECTUNLOCKED,
+ SFTNBJ,
+ SFTNNALC,
+ SFTNNAR,
+ SFTNNAUC,
+ SFTNNCHI,
+ SFTNNCHOSUNG,
+ SFTNNCNUM,
+ SFTNNDBAR,
+ SFTNNDBNUM,
+ SFTNNDBNUMD,
+ SFTNNDBNUMK,
+ SFTNNDBNUMT,
+ SFTNNGANADA,
+ SFTNNGBNUM,
+ SFTNNGBNUMD,
+ SFTNNGBNUMK,
+ SFTNNGBNUML,
+ SFTNNRLC,
+ SFTNNRUC,
+ SFTNNZODIAC,
+ SFTNNZODIACD,
+ SFTNNZODIACL,
+ SFTNRESTART,
+ SFTNRSTCONT,
+ SFTNRSTPG,
+ SFTNSTART,
+ SFTNTJ,
+ SHAD,
+ SHADING,
+ SHIDDEN,
+ SHIFT,
+ SHOWPLACEHOLDTEXT,
+ SHOWXMLERRORS,
+ SHP,
+ SHPBOTTOM,
+ SHPBXCOLUMN,
+ SHPBXIGNORE,
+ SHPBXMARGIN,
+ SHPBXPAGE,
+ SHPBYIGNORE,
+ SHPBYMARGIN,
+ SHPBYPAGE,
+ SHPBYPARA,
+ SHPFBLWTXT,
+ SHPFHDR,
+ SHPGRP,
+ SHPINST,
+ SHPLEFT,
+ SHPLID,
+ SHPLOCKANCHOR,
+ SHPPICT,
+ SHPRIGHT,
+ SHPRSLT,
+ SHPTOP,
+ SHPTXT,
+ SHPWRK,
+ SHPWR,
+ SHPZ,
+ SL,
+ SLINK,
+ SLMULT,
+ SLOCKED,
+ SN,
+ SNAPTOGRIDINCELL,
+ SNEXT,
+ SOFTCOL,
+ SOFTLHEIGHT,
+ SOFTLINE,
+ SOFTPAGE,
+ SP,
+ SPERSONAL,
+ SPLTPGPAR,
+ SPLYTWNINE,
+ SPRIORITY,
+ SPRSBSP,
+ SPRSLNSP,
+ SPRSSPBF,
+ SPRSTSM,
+ SPRSTSP,
+ SPV,
+ SQFORMAT,
+ SRAUTH,
+ SRDATE,
+ SREPLY,
+ SSEMIHIDDEN,
+ STATICVAL,
+ STEXTFLOW,
+ STRIKE,
+ STRIKED,
+ STSHFBI,
+ STSHFDBCH,
+ STSHFHICH,
+ STSHFLOCH,
+ STYLELOCK,
+ STYLELOCKBACKCOMP,
+ STYLELOCKENFORCED,
+ STYLELOCKQFSET,
+ STYLELOCKTHEME,
+ STYLESHEET,
+ STYLESORTMETHOD,
+ STYRSID,
+ SUB,
+ SUBDOCUMENT,
+ SUBFONTBYSIZE,
+ SUBJECT,
+ SUNHIDEUSED,
+ SUPER,
+ SV,
+ SVB,
+ SWPBDR,
+ TAB,
+ TABSNOOVRLP,
+ TAPRTL,
+ TB,
+ TBLIND,
+ TBLINDTYPE,
+ TBLLKBESTFIT,
+ TBLLKBORDER,
+ TBLLKCOLOR,
+ TBLLKFONT,
+ TBLLKHDRCOLS,
+ TBLLKHDRROWS,
+ TBLLKLASTCOL,
+ TBLLKLASTROW,
+ TBLLKNOCOLBAND,
+ TBLLKNOROWBAND,
+ TBLLKSHADING,
+ TBLRSID,
+ TC,
+ TCELLD,
+ TCF,
+ TCL,
+ TCN,
+ TDFRMTXTBOTTOM,
+ TDFRMTXTLEFT,
+ TDFRMTXTRIGHT,
+ TDFRMTXTTOP,
+ TEMPLATE,
+ THEMEDATA,
+ THEMELANG,
+ THEMELANGCS,
+ THEMELANGFE,
+ TIME,
+ TITLE,
+ TITLEPG,
+ TLDOT,
+ TLEQ,
+ TLHYPH,
+ TLMDOT,
+ TLTH,
+ TLUL,
+ TOPLINEPUNCT,
+ TPHCOL,
+ TPHMRG,
+ TPHPG,
+ TPOSNEGX,
+ TPOSNEGY,
+ TPOSXC,
+ TPOSXI,
+ TPOSXL,
+ TPOSX,
+ TPOSXO,
+ TPOSXR,
+ TPOSY,
+ TPOSYB,
+ TPOSYC,
+ TPOSYIL,
+ TPOSYIN,
+ TPOSYOUT,
+ TPOSYT,
+ TPVMRG,
+ TPVPARA,
+ TPVPG,
+ TQC,
+ TQDEC,
+ TQR,
+ TRACKFORMATTING,
+ TRACKMOVES,
+ TRANSMF,
+ TRAUTH,
+ TRAUTOFIT,
+ TRBGBDIAG,
+ TRBGCROSS,
+ TRBGDCROSS,
+ TRBGDKBDIAG,
+ TRBGDKCROSS,
+ TRBGDKDCROSS,
+ TRBGDKFDIAG,
+ TRBGDKHOR,
+ TRBGDKVERT,
+ TRBGFDIAG,
+ TRBGHORIZ,
+ TRBGVERT,
+ TRBRDRB,
+ TRBRDRH,
+ TRBRDRL,
+ TRBRDRR,
+ TRBRDRT,
+ TRBRDRV,
+ TRCBPAT,
+ TRCFPAT,
+ TRDATE,
+ TRFTSWIDTHA,
+ TRFTSWIDTHB,
+ TRFTSWIDTH,
+ TRGAPH,
+ TRHDR,
+ TRKEEP,
+ TRKEEPFOLLOW,
+ TRLEFT,
+ TROWD,
+ TRPADDB,
+ TRPADDFB,
+ TRPADDFL,
+ TRPADDFR,
+ TRPADDFT,
+ TRPADDL,
+ TRPADDR,
+ TRPADDT,
+ TRPADOB,
+ TRPADOFB,
+ TRPADOFL,
+ TRPADOFR,
+ TRPADOFT,
+ TRPADOL,
+ TRPADOR,
+ TRPADOT,
+ TRPAT,
+ TRQC,
+ TRQL,
+ TRQR,
+ TRRH,
+ TRSHDNG,
+ TRSPDB,
+ TRSPDFB,
+ TRSPDFL,
+ TRSPDFR,
+ TRSPDFT,
+ TRSPDL,
+ TRSPDR,
+ TRSPDT,
+ TRSPOB,
+ TRSPOFB,
+ TRSPOFL,
+ TRSPOFR,
+ TRSPOFT,
+ TRSPOL,
+ TRSPOR,
+ TRSPOT,
+ TRUNCATEFONTHEIGHT,
+ TRUNCEX,
+ TRWWIDTHA,
+ TRWWIDTHB,
+ TRWWIDTH,
+ TS,
+ TSBGBDIAG,
+ TSBGCROSS,
+ TSBGDCROSS,
+ TSBGDKBDIAG,
+ TSBGDKCROSS,
+ TSBGDKDCROSS,
+ TSBGDKFDIAG,
+ TSBGDKHOR,
+ TSBGDKVERT,
+ TSBGFDIAG,
+ TSBGHORIZ,
+ TSBGVERT,
+ TSBRDRB,
+ TSBRDRDGL,
+ TSBRDRDGR,
+ TSBRDRH,
+ TSBRDRL,
+ TSBRDRR,
+ TSBRDRT,
+ TSBRDRV,
+ TSCBANDHORZEVEN,
+ TSCBANDHORZODD,
+ TSCBANDSH,
+ TSCBANDSV,
+ TSCBANDVERTEVEN,
+ TSCBANDVERTODD,
+ TSCELLCBPAT,
+ TSCELLCFPAT,
+ TSCELLPADDB,
+ TSCELLPADDFB,
+ TSCELLPADDFL,
+ TSCELLPADDFR,
+ TSCELLPADDFT,
+ TSCELLPADDL,
+ TSCELLPADDR,
+ TSCELLPADDT,
+ TSCELLPCT,
+ TSCELLWIDTH,
+ TSCELLWIDTHFTS,
+ TSCFIRSTCOL,
+ TSCFIRSTROW,
+ TSCLASTCOL,
+ TSCLASTROW,
+ TSCNECELL,
+ TSCNWCELL,
+ TSCSECELL,
+ TSCSWCELL,
+ TSD,
+ TSNOWRAP,
+ TSROWD,
+ TSVERTALB,
+ TSVERTALC,
+ TSVERTALT,
+ TWOINONE,
+ TWOONONE,
+ TX,
+ TXBXTWALWAYS,
+ TXBXTWFIRST,
+ TXBXTWFIRSTLAST,
+ TXBXTWLAST,
+ TXBXTWNO,
+ TXE,
+ U,
+ UC,
+ UD,
+ UL,
+ ULC,
+ ULD,
+ ULDASH,
+ ULDASHD,
+ ULDASHDD,
+ ULDB,
+ ULHAIR,
+ ULHWAVE,
+ ULLDASH,
+ ULNONE,
+ ULTH,
+ ULTHD,
+ ULTHDASH,
+ ULTHDASHD,
+ ULTHDASHDD,
+ ULTHLDASH,
+ ULULDBWAVE,
+ ULW,
+ ULWAVE,
+ UP,
+ UPR,
+ URTF,
+ USELTBALN,
+ USENORMSTYFORLIST,
+ USERPROPS,
+ USEXFORM,
+ UTINL,
+ V,
+ VALIDATEXML,
+ VERN,
+ VERSION,
+ VERTAL,
+ VERTALB,
+ VERTALC,
+ VERTALJ,
+ VERTALT,
+ VERTDOC,
+ VERTSECT,
+ VIEWBKSP,
+ VIEWKIND,
+ VIEWNOBOUND,
+ VIEWSCALE,
+ VIEWZK,
+ WBITMAP,
+ WBMBITSPIXEL,
+ WBMPLANES,
+ WBMWIDTHBYTE,
+ WEBHIDDEN,
+ WGRFFMTFILTER,
+ WIDCTLPAR,
+ WIDOWCTRL,
+ WINDOWCAPTION,
+ WMETAFILE,
+ WPEQN,
+ WPJST,
+ WPSP,
+ WRAPAROUND,
+ WRAPDEFAULT,
+ WRAPTHROUGH,
+ WRAPTIGHT,
+ WRAPTRSP,
+ WRITERESERVATION,
+ WRITERESERVHASH,
+ WRPPUNCT,
+ XE,
+ XEF,
+ XFORM,
+ XMLATTR,
+ XMLATTRNAME,
+ XMLATTRNS,
+ XMLATTRVALUE,
+ XMLCLOSE,
+ XMLNAME,
+ XMLNS,
+ XMLNSTBL,
+ XMLOPEN,
+ XMLSDTTCELL,
+ XMLSDTTPARA,
+ XMLSDTTREGULAR,
+ XMLSDTTROW,
+ XMLSDTTUNKNOWN,
+ YR,
+ YTS,
+ YXE,
+ ZWBO,
+ ZWJ,
+ ZWNBO,
+ ZWNJ,
+ FLYMAINCNT,
+ FLYVERT,
+ FLYHORZ,
+ FLYANCHOR
+};
+const char* keywordToString(RTFKeyword nKeyword);
+
+/// Types of an RTF Control Word
+enum class RTFControlType
+{
+ FLAG, // eg \sbknone takes no parameter
+ DESTINATION, // eg \fonttbl, if ignored, the whole group should be skipped
+ SYMBOL, // eg \tab
+ TOGGLE, // eg \b (between on and off)
+ VALUE // eg \fs (requires parameter)
+};
+
+/// Represents an RTF Control Word
+class RTFSymbol
+{
+ const char* m_sKeyword;
+ RTFControlType m_eControlType;
+ RTFKeyword m_nIndex;
+
+ int m_nDefValue; ///< Most of the control words default to 0.
+
+public:
+ RTFSymbol(const char* sKeyword, RTFControlType nControlType, RTFKeyword nIndex, int nDefValue)
+ : m_sKeyword(sKeyword)
+ , m_eControlType(nControlType)
+ , m_nIndex(nIndex)
+ , m_nDefValue(nDefValue)
+ {
+ }
+
+ const char* GetKeyword() const { return m_sKeyword; }
+
+ RTFControlType GetControlType() const { return m_eControlType; }
+
+ RTFKeyword GetIndex() const { return m_nIndex; }
+
+ int GetDefValue() const { return m_nDefValue; }
+};
+
+extern RTFSymbol const aRTFControlWords[];
+extern const int nRTFControlWords;
+
+/// Represents an RTF Math Control Word
+class RTFMathSymbol
+{
+ RTFKeyword m_eKeyword;
+ int m_nToken; ///< This is the OOXML token equivalent.
+ Destination m_eDestination;
+
+public:
+ RTFMathSymbol(RTFKeyword eKeyword, int nToken = 0,
+ Destination eDestination = Destination::NORMAL)
+ : m_eKeyword(eKeyword)
+ , m_nToken(nToken)
+ , m_eDestination(eDestination)
+ {
+ }
+
+ int GetToken() const { return m_nToken; }
+
+ Destination GetDestination() const { return m_eDestination; }
+
+ bool operator<(const RTFMathSymbol& rOther) const;
+};
+
+extern RTFMathSymbol const aRTFMathControlWords[];
+extern const int nRTFMathControlWords;
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchdestination.cxx b/writerfilter/source/rtftok/rtfdispatchdestination.cxx
new file mode 100644
index 000000000..8789c3f85
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchdestination.cxx
@@ -0,0 +1,684 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/document/DocumentProperties.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <filter/msfilter/escherex.hxx>
+#include <rtl/character.hxx>
+#include <tools/stream.hxx>
+#include <sal/log.hxx>
+
+#include <dmapper/DomainMapperFactory.hxx>
+#include <ooxml/resourceids.hxx>
+
+#include "rtflookahead.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfsdrimport.hxx"
+#include "rtfskipdestination.hxx"
+#include "rtftokenizer.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ // special case \upr: ignore everything except nested \ud
+ if (Destination::UPR == m_aStates.top().getDestination() && RTFKeyword::UD != nKeyword)
+ {
+ m_aStates.top().setDestination(Destination::SKIP);
+ aSkip.setParsed(false);
+ }
+ else
+ switch (nKeyword)
+ {
+ case RTFKeyword::RTF:
+ break;
+ case RTFKeyword::FONTTBL:
+ m_aStates.top().setDestination(Destination::FONTTABLE);
+ break;
+ case RTFKeyword::COLORTBL:
+ m_aStates.top().setDestination(Destination::COLORTABLE);
+ break;
+ case RTFKeyword::STYLESHEET:
+ m_aStates.top().setDestination(Destination::STYLESHEET);
+ break;
+ case RTFKeyword::FIELD:
+ m_aStates.top().setDestination(Destination::FIELD);
+ m_aStates.top().setFieldLocked(false);
+ break;
+ case RTFKeyword::DOCVAR:
+ m_aStates.top().setDestination(Destination::DOCVAR);
+ break;
+ case RTFKeyword::FLDINST:
+ {
+ // Look for the field type
+ sal_uInt64 const nPos = Strm().Tell();
+ OStringBuffer aBuf;
+ char ch = 0;
+ bool bFoundCode = false;
+ bool bInKeyword = false;
+ while (!bFoundCode && ch != '}')
+ {
+ Strm().ReadChar(ch);
+ if ('\\' == ch)
+ bInKeyword = true;
+ if (!bInKeyword && rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
+ aBuf.append(ch);
+ else if (bInKeyword && rtl::isAsciiWhiteSpace(static_cast<unsigned char>(ch)))
+ bInKeyword = false;
+ if (!aBuf.isEmpty()
+ && !rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
+ bFoundCode = true;
+ }
+
+ if (std::string_view(aBuf) == "INCLUDEPICTURE")
+ {
+ // Extract the field argument of INCLUDEPICTURE: we handle that
+ // at a tokenizer level, as DOCX has no such field.
+ aBuf.append(ch);
+ while (true)
+ {
+ Strm().ReadChar(ch);
+ if (ch == '}')
+ break;
+ aBuf.append(ch);
+ }
+ OUString aFieldCommand = OStringToOUString(aBuf, RTL_TEXTENCODING_UTF8);
+ std::tuple<OUString, std::vector<OUString>, std::vector<OUString>> aResult
+ = writerfilter::dmapper::splitFieldCommand(aFieldCommand);
+ m_aPicturePath
+ = std::get<1>(aResult).empty() ? OUString() : std::get<1>(aResult).front();
+ }
+
+ Strm().Seek(nPos);
+
+ // Form data should be handled only for form fields if any
+ if (aBuf.toString().indexOf("FORM") != -1)
+ m_bFormField = true;
+
+ singleChar(cFieldStart);
+ m_aStates.top().setDestination(Destination::FIELDINSTRUCTION);
+ }
+ break;
+ case RTFKeyword::FLDRSLT:
+ m_aStates.top().setDestination(Destination::FIELDRESULT);
+ break;
+ case RTFKeyword::LISTTABLE:
+ m_aStates.top().setDestination(Destination::LISTTABLE);
+ break;
+ case RTFKeyword::LISTPICTURE:
+ m_aStates.top().setDestination(Destination::LISTPICTURE);
+ m_aStates.top().setInListpicture(true);
+ break;
+ case RTFKeyword::LIST:
+ m_aStates.top().setDestination(Destination::LISTENTRY);
+ break;
+ case RTFKeyword::LISTNAME:
+ m_aStates.top().setDestination(Destination::LISTNAME);
+ break;
+ case RTFKeyword::LFOLEVEL:
+ m_aStates.top().setDestination(Destination::LFOLEVEL);
+ m_aStates.top().getTableSprms().clear();
+ break;
+ case RTFKeyword::LISTOVERRIDETABLE:
+ m_aStates.top().setDestination(Destination::LISTOVERRIDETABLE);
+ break;
+ case RTFKeyword::LISTOVERRIDE:
+ m_aStates.top().setDestination(Destination::LISTOVERRIDEENTRY);
+ break;
+ case RTFKeyword::LISTLEVEL:
+ m_aStates.top().setDestination(Destination::LISTLEVEL);
+ ++m_nListLevel;
+ break;
+ case RTFKeyword::LEVELTEXT:
+ m_aStates.top().setDestination(Destination::LEVELTEXT);
+ break;
+ case RTFKeyword::LEVELNUMBERS:
+ m_aStates.top().setDestination(Destination::LEVELNUMBERS);
+ break;
+ case RTFKeyword::SHPPICT:
+ resetFrame();
+ m_aStates.top().setDestination(Destination::SHPPICT);
+ break;
+ case RTFKeyword::PICT:
+ if (m_aStates.top().getDestination() != Destination::SHAPEPROPERTYVALUE)
+ m_aStates.top().setDestination(Destination::PICT); // as character
+ else
+ m_aStates.top().setDestination(
+ Destination::SHAPEPROPERTYVALUEPICT); // anchored inside a shape
+ break;
+ case RTFKeyword::PICPROP:
+ m_aStates.top().setDestination(Destination::PICPROP);
+ break;
+ case RTFKeyword::SP:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTY);
+ break;
+ case RTFKeyword::SN:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTYNAME);
+ break;
+ case RTFKeyword::SV:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTYVALUE);
+ break;
+ case RTFKeyword::SHP:
+ m_bNeedCrOrig = m_bNeedCr;
+ m_aStates.top().setDestination(Destination::SHAPE);
+ m_aStates.top().setInShape(true);
+ break;
+ case RTFKeyword::SHPINST:
+ m_aStates.top().setDestination(Destination::SHAPEINSTRUCTION);
+ break;
+ case RTFKeyword::NESTTABLEPROPS:
+ // do not set any properties of outer table at nested table!
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+ m_aNestedTableCellsSprms.clear();
+ m_aNestedTableCellsAttributes.clear();
+ m_nNestedCells = 0;
+ m_aStates.top().setDestination(Destination::NESTEDTABLEPROPERTIES);
+ break;
+ case RTFKeyword::HEADER:
+ case RTFKeyword::FOOTER:
+ case RTFKeyword::HEADERL:
+ case RTFKeyword::HEADERR:
+ case RTFKeyword::HEADERF:
+ case RTFKeyword::FOOTERL:
+ case RTFKeyword::FOOTERR:
+ case RTFKeyword::FOOTERF:
+ if (!m_pSuperstream)
+ {
+ Id nId = 0;
+ std::size_t nPos = m_nGroupStartPos - 1;
+ switch (nKeyword)
+ {
+ case RTFKeyword::HEADER:
+ if (!m_hasRHeader)
+ {
+ nId = NS_ooxml::LN_headerr;
+ m_hasRHeader = true;
+ }
+ break;
+ case RTFKeyword::FOOTER:
+ if (!m_hasRFooter)
+ {
+ nId = NS_ooxml::LN_footerr;
+ m_hasRFooter = true;
+ }
+ break;
+ case RTFKeyword::HEADERL:
+ nId = NS_ooxml::LN_headerl;
+ break;
+ case RTFKeyword::HEADERR:
+ nId = NS_ooxml::LN_headerr;
+ break;
+ case RTFKeyword::HEADERF:
+ if (!m_hasFHeader)
+ {
+ nId = NS_ooxml::LN_headerf;
+ m_hasFHeader = true;
+ }
+ break;
+ case RTFKeyword::FOOTERL:
+ nId = NS_ooxml::LN_footerl;
+ break;
+ case RTFKeyword::FOOTERR:
+ nId = NS_ooxml::LN_footerr;
+ break;
+ case RTFKeyword::FOOTERF:
+ if (!m_hasFFooter)
+ {
+ nId = NS_ooxml::LN_footerf;
+ m_hasFFooter = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (nId != 0)
+ m_nHeaderFooterPositions.push(std::make_pair(nId, nPos));
+
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ break;
+ case RTFKeyword::FOOTNOTE:
+ checkFirstRun();
+ if (!m_pSuperstream)
+ {
+ Id nId = NS_ooxml::LN_footnote;
+
+ // Check if this is an endnote.
+ OStringBuffer aBuf;
+ char ch;
+ sal_uInt64 const nCurrent = Strm().Tell();
+ for (int i = 0; i < 7; ++i)
+ {
+ Strm().ReadChar(ch);
+ aBuf.append(ch);
+ }
+ Strm().Seek(nCurrent);
+ OString aKeyword = aBuf.makeStringAndClear();
+ if (aKeyword == "\\ftnalt")
+ nId = NS_ooxml::LN_endnote;
+
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ m_aStates.top().setCurrentBuffer(nullptr);
+ bool bCustomMark = false;
+ OUString aCustomMark;
+ for (auto const& elem : m_aSuperBuffer)
+ {
+ if (std::get<0>(elem) == BUFFER_UTEXT)
+ {
+ aCustomMark = std::get<1>(elem)->getString();
+ bCustomMark = true;
+ }
+ }
+ m_aSuperBuffer.clear();
+ m_aStates.top().setDestination(Destination::FOOTNOTE);
+ Mapper().startCharacterGroup();
+ runProps();
+ if (!m_aStates.top().getCurrentBuffer())
+ resolveSubstream(m_nGroupStartPos - 1, nId, aCustomMark);
+ else
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
+ aAttributes.set(Id(1), new RTFValue(nId));
+ aAttributes.set(Id(2), new RTFValue(aCustomMark));
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
+ }
+ if (bCustomMark)
+ {
+ m_aStates.top().getCharacterAttributes().clear();
+ m_aStates.top().getCharacterSprms().clear();
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows, pValue);
+ text(aCustomMark);
+ }
+ Mapper().endCharacterGroup();
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ break;
+ case RTFKeyword::BKMKSTART:
+ m_aStates.top().setDestination(Destination::BOOKMARKSTART);
+ break;
+ case RTFKeyword::BKMKEND:
+ m_aStates.top().setDestination(Destination::BOOKMARKEND);
+ break;
+ case RTFKeyword::XE:
+ m_aStates.top().setDestination(Destination::INDEXENTRY);
+ break;
+ case RTFKeyword::TC:
+ case RTFKeyword::TCN:
+ m_aStates.top().setDestination(Destination::TOCENTRY);
+ break;
+ case RTFKeyword::REVTBL:
+ m_aStates.top().setDestination(Destination::REVISIONTABLE);
+ break;
+ case RTFKeyword::ANNOTATION:
+ if (!m_pSuperstream)
+ {
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ resolveSubstream(m_nGroupStartPos - 1, NS_ooxml::LN_annotation);
+ }
+ else
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
+ aAttributes.set(Id(1), new RTFValue(NS_ooxml::LN_annotation));
+ aAttributes.set(Id(2), new RTFValue(OUString()));
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
+ }
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ else
+ {
+ // If there is an author set, emit it now.
+ if (!m_aAuthor.isEmpty() || !m_aAuthorInitials.isEmpty())
+ {
+ RTFSprms aAttributes;
+ if (!m_aAuthor.isEmpty())
+ {
+ auto pValue = new RTFValue(m_aAuthor);
+ aAttributes.set(NS_ooxml::LN_CT_TrackChange_author, pValue);
+ }
+ if (!m_aAuthorInitials.isEmpty())
+ {
+ auto pValue = new RTFValue(m_aAuthorInitials);
+ aAttributes.set(NS_ooxml::LN_CT_Comment_initials, pValue);
+ }
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes));
+ Mapper().props(pProperties);
+ }
+ }
+ break;
+ case RTFKeyword::SHPTXT:
+ case RTFKeyword::DPTXBXTEXT:
+ {
+ bool bPictureFrame = false;
+ for (const auto& rProperty : m_aStates.top().getShape().getProperties())
+ {
+ if (rProperty.first == "shapeType"
+ && rProperty.second
+ == std::u16string_view(
+ OUString::number(ESCHER_ShpInst_PictureFrame)))
+ {
+ bPictureFrame = true;
+ break;
+ }
+ }
+ if (bPictureFrame)
+ // Skip text on picture frames.
+ m_aStates.top().setDestination(Destination::SKIP);
+ else
+ {
+ m_aStates.top().setDestination(Destination::SHAPETEXT);
+ checkFirstRun();
+ dispatchFlag(RTFKeyword::PARD);
+ m_bNeedPap = true;
+ if (nKeyword == RTFKeyword::SHPTXT)
+ {
+ if (!m_aStates.top().getCurrentBuffer())
+ m_pSdrImport->resolve(m_aStates.top().getShape(), false,
+ RTFSdrImport::SHAPE);
+ else
+ {
+ auto pValue = new RTFValue(m_aStates.top().getShape());
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_STARTSHAPE, pValue, nullptr));
+ }
+ }
+ }
+ }
+ break;
+ case RTFKeyword::FORMFIELD:
+ if (m_aStates.top().getDestination() == Destination::FIELDINSTRUCTION)
+ m_aStates.top().setDestination(Destination::FORMFIELD);
+ break;
+ case RTFKeyword::FFNAME:
+ m_aStates.top().setDestination(Destination::FORMFIELDNAME);
+ break;
+ case RTFKeyword::FFL:
+ m_aStates.top().setDestination(Destination::FORMFIELDLIST);
+ break;
+ case RTFKeyword::DATAFIELD:
+ m_aStates.top().setDestination(Destination::DATAFIELD);
+ break;
+ case RTFKeyword::INFO:
+ m_aStates.top().setDestination(Destination::INFO);
+ break;
+ case RTFKeyword::CREATIM:
+ m_aStates.top().setDestination(Destination::CREATIONTIME);
+ break;
+ case RTFKeyword::REVTIM:
+ m_aStates.top().setDestination(Destination::REVISIONTIME);
+ break;
+ case RTFKeyword::PRINTIM:
+ m_aStates.top().setDestination(Destination::PRINTTIME);
+ break;
+ case RTFKeyword::AUTHOR:
+ m_aStates.top().setDestination(Destination::AUTHOR);
+ break;
+ case RTFKeyword::KEYWORDS:
+ m_aStates.top().setDestination(Destination::KEYWORDS);
+ break;
+ case RTFKeyword::OPERATOR:
+ m_aStates.top().setDestination(Destination::OPERATOR);
+ break;
+ case RTFKeyword::COMPANY:
+ m_aStates.top().setDestination(Destination::COMPANY);
+ break;
+ case RTFKeyword::COMMENT:
+ m_aStates.top().setDestination(Destination::COMMENT);
+ break;
+ case RTFKeyword::OBJECT:
+ {
+ // beginning of an OLE Object
+ m_aStates.top().setDestination(Destination::OBJECT);
+
+ // check if the object is in a special container (e.g. a table)
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ // the object is in a table or another container.
+ // Don't try to treat it as an OLE object (fdo#53594).
+ // Use the \result (RTFKeyword::RESULT) element of the object instead,
+ // the result element contain picture representing the OLE Object.
+ m_bObject = true;
+ }
+ }
+ break;
+ case RTFKeyword::OBJDATA:
+ // check if the object is in a special container (e.g. a table)
+ if (m_aStates.top().getCurrentBuffer())
+ {
+ // the object is in a table or another container.
+ // Use the \result (RTFKeyword::RESULT) element of the object instead,
+ // of the \objdata.
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ else
+ {
+ m_aStates.top().setDestination(Destination::OBJDATA);
+ }
+ break;
+ case RTFKeyword::OBJCLASS:
+ m_aStates.top().setDestination(Destination::OBJCLASS);
+ break;
+ case RTFKeyword::RESULT:
+ m_aStates.top().setDestination(Destination::RESULT);
+ break;
+ case RTFKeyword::ATNDATE:
+ m_aStates.top().setDestination(Destination::ANNOTATIONDATE);
+ break;
+ case RTFKeyword::ATNAUTHOR:
+ m_aStates.top().setDestination(Destination::ANNOTATIONAUTHOR);
+ break;
+ case RTFKeyword::ATNREF:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCE);
+ break;
+ case RTFKeyword::FALT:
+ m_aStates.top().setDestination(Destination::FALT);
+ break;
+ case RTFKeyword::FLYMAINCNT:
+ m_aStates.top().setDestination(Destination::FLYMAINCONTENT);
+ break;
+ case RTFKeyword::LISTTEXT:
+ // Should be ignored by any reader that understands Word 97 through Word 2007 numbering.
+ case RTFKeyword::NONESTTABLES:
+ // This destination should be ignored by readers that support nested tables.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::DO:
+ m_aStates.top().setDestination(Destination::DRAWINGOBJECT);
+ break;
+ case RTFKeyword::PN:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING);
+ break;
+ case RTFKeyword::PNTEXT:
+ // This destination should be ignored by readers that support paragraph numbering.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::PNTXTA:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTAFTER);
+ break;
+ case RTFKeyword::PNTXTB:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTBEFORE);
+ break;
+ case RTFKeyword::TITLE:
+ m_aStates.top().setDestination(Destination::TITLE);
+ break;
+ case RTFKeyword::SUBJECT:
+ m_aStates.top().setDestination(Destination::SUBJECT);
+ break;
+ case RTFKeyword::DOCCOMM:
+ m_aStates.top().setDestination(Destination::DOCCOMM);
+ break;
+ case RTFKeyword::ATRFSTART:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCESTART);
+ break;
+ case RTFKeyword::ATRFEND:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCEEND);
+ break;
+ case RTFKeyword::ATNID:
+ m_aStates.top().setDestination(Destination::ATNID);
+ break;
+ case RTFKeyword::MMATH:
+ case RTFKeyword::MOMATHPARA:
+ // Nothing to do here (just enter the destination) till RTFKeyword::MMATHPR is implemented.
+ break;
+ case RTFKeyword::MR:
+ m_aStates.top().setDestination(Destination::MR);
+ break;
+ case RTFKeyword::MCHR:
+ m_aStates.top().setDestination(Destination::MCHR);
+ break;
+ case RTFKeyword::MPOS:
+ m_aStates.top().setDestination(Destination::MPOS);
+ break;
+ case RTFKeyword::MVERTJC:
+ m_aStates.top().setDestination(Destination::MVERTJC);
+ break;
+ case RTFKeyword::MSTRIKEH:
+ m_aStates.top().setDestination(Destination::MSTRIKEH);
+ break;
+ case RTFKeyword::MDEGHIDE:
+ m_aStates.top().setDestination(Destination::MDEGHIDE);
+ break;
+ case RTFKeyword::MTYPE:
+ m_aStates.top().setDestination(Destination::MTYPE);
+ break;
+ case RTFKeyword::MGROW:
+ m_aStates.top().setDestination(Destination::MGROW);
+ break;
+ case RTFKeyword::MHIDETOP:
+ case RTFKeyword::MHIDEBOT:
+ case RTFKeyword::MHIDELEFT:
+ case RTFKeyword::MHIDERIGHT:
+ // SmOoxmlImport::handleBorderBox will ignore these anyway, so silently ignore for now.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::MSUBHIDE:
+ m_aStates.top().setDestination(Destination::MSUBHIDE);
+ break;
+ case RTFKeyword::MSUPHIDE:
+ m_aStates.top().setDestination(Destination::MSUPHIDE);
+ break;
+ case RTFKeyword::MBEGCHR:
+ m_aStates.top().setDestination(Destination::MBEGCHR);
+ break;
+ case RTFKeyword::MSEPCHR:
+ m_aStates.top().setDestination(Destination::MSEPCHR);
+ break;
+ case RTFKeyword::MENDCHR:
+ m_aStates.top().setDestination(Destination::MENDCHR);
+ break;
+ case RTFKeyword::UPR:
+ m_aStates.top().setDestination(Destination::UPR);
+ break;
+ case RTFKeyword::UD:
+ // Anything inside \ud is just normal Unicode content.
+ m_aStates.top().setDestination(Destination::NORMAL);
+ break;
+ case RTFKeyword::BACKGROUND:
+ m_aStates.top().setDestination(Destination::BACKGROUND);
+ m_aStates.top().setInBackground(true);
+ break;
+ case RTFKeyword::SHPGRP:
+ {
+ RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
+ if (!aLookahead.hasTable())
+ {
+ uno::Reference<drawing::XShapes> xGroupShape(
+ m_xModelFactory->createInstance("com.sun.star.drawing.GroupShape"),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc,
+ uno::UNO_QUERY);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShape> xShape(xGroupShape, uno::UNO_QUERY);
+ // set default VertOrient before inserting
+ uno::Reference<beans::XPropertySet>(xShape, uno::UNO_QUERY_THROW)
+ ->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::NONE));
+ xDrawSupplier->getDrawPage()->add(xShape);
+ }
+ m_pSdrImport->pushParent(xGroupShape);
+ m_aStates.top().setCreatedShapeGroup(true);
+ }
+ m_aStates.top().setDestination(Destination::SHAPEGROUP);
+ m_aStates.top().setInShapeGroup(true);
+ }
+ break;
+ case RTFKeyword::FTNSEP:
+ m_aStates.top().setDestination(Destination::FOOTNOTESEPARATOR);
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_FtnEdn_type,
+ new RTFValue(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator));
+ break;
+ case RTFKeyword::USERPROPS:
+ // Container of all user-defined properties.
+ m_aStates.top().setDestination(Destination::USERPROPS);
+ if (m_xDocumentProperties.is())
+ // Create a custom document properties to be able to process them later all at once.
+ m_xDocumentProperties = document::DocumentProperties::create(m_xContext);
+ break;
+ case RTFKeyword::PROPNAME:
+ m_aStates.top().setDestination(Destination::PROPNAME);
+ break;
+ case RTFKeyword::STATICVAL:
+ m_aStates.top().setDestination(Destination::STATICVAL);
+ break;
+ case RTFKeyword::GENERATOR:
+ m_aStates.top().setDestination(Destination::GENERATOR);
+ break;
+ default:
+ {
+ // Check if it's a math token.
+ RTFMathSymbol aSymbol(nKeyword);
+ if (RTFTokenizer::lookupMathKeyword(aSymbol))
+ {
+ m_aMathBuffer.appendOpeningTag(aSymbol.GetToken());
+ m_aStates.top().setDestination(aSymbol.GetDestination());
+ return RTFError::OK;
+ }
+
+ SAL_INFO("writerfilter",
+ "TODO handle destination '" << keywordToString(nKeyword) << "'");
+ // Make sure we skip destinations (even without \*) till we don't handle them
+ m_aStates.top().setDestination(Destination::SKIP);
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+
+ // new destination => use new destination text
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+
+ return RTFError::OK;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchflag.cxx b/writerfilter/source/rtftok/rtfdispatchflag.cxx
new file mode 100644
index 000000000..0ef4f2172
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchflag.cxx
@@ -0,0 +1,1258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <filter/msfilter/escherex.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+#include "rtfsdrimport.hxx"
+#include "rtfskipdestination.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nParam = -1;
+ int nSprm = -1;
+
+ // Underline flags.
+ switch (nKeyword)
+ {
+ case RTFKeyword::ULD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotted;
+ break;
+ case RTFKeyword::ULW:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_words;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue = new RTFValue(nSprm);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Indentation
+ switch (nKeyword)
+ {
+ case RTFKeyword::QC:
+ nParam = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case RTFKeyword::QJ:
+ nParam = NS_ooxml::LN_Value_ST_Jc_both;
+ break;
+ case RTFKeyword::QL:
+ nParam = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case RTFKeyword::QR:
+ nParam = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ case RTFKeyword::QD:
+ nParam = NS_ooxml::LN_Value_ST_Jc_distribute;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_jc, pValue);
+ m_bNeedPap = true;
+ return RTFError::OK;
+ }
+
+ // Font Alignment
+ switch (nKeyword)
+ {
+ case RTFKeyword::FAFIXED:
+ case RTFKeyword::FAAUTO:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_auto;
+ break;
+ case RTFKeyword::FAHANG:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_top;
+ break;
+ case RTFKeyword::FACENTER:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_center;
+ break;
+ case RTFKeyword::FAROMAN:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_baseline;
+ break;
+ case RTFKeyword::FAVAR:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_bottom;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_textAlignment, pValue);
+ return RTFError::OK;
+ }
+
+ // Tab kind.
+ switch (nKeyword)
+ {
+ case RTFKeyword::TQR:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_right;
+ break;
+ case RTFKeyword::TQC:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_center;
+ break;
+ case RTFKeyword::TQDEC:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_decimal;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Tab lead.
+ switch (nKeyword)
+ {
+ case RTFKeyword::TLDOT:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_dot;
+ break;
+ case RTFKeyword::TLMDOT:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_middleDot;
+ break;
+ case RTFKeyword::TLHYPH:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_hyphen;
+ break;
+ case RTFKeyword::TLUL:
+ case RTFKeyword::TLTH:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_underscore;
+ break;
+ case RTFKeyword::TLEQ:
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_leader, pValue);
+ return RTFError::OK;
+ }
+
+ // Border types
+ {
+ switch (nKeyword)
+ {
+ // brdrhair and brdrs are the same, brdrw will make a difference
+ // map to values in ooxml/model.xml resource ST_Border
+ case RTFKeyword::BRDRHAIR:
+ case RTFKeyword::BRDRS:
+ nParam = NS_ooxml::LN_Value_ST_Border_single;
+ break;
+ case RTFKeyword::BRDRDOT:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotted;
+ break;
+ case RTFKeyword::BRDRDASH:
+ nParam = NS_ooxml::LN_Value_ST_Border_dashed;
+ break;
+ case RTFKeyword::BRDRDB:
+ nParam = NS_ooxml::LN_Value_ST_Border_double;
+ break;
+ case RTFKeyword::BRDRTNTHSG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickSmallGap;
+ break;
+ case RTFKeyword::BRDRTNTHMG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickMediumGap;
+ break;
+ case RTFKeyword::BRDRTNTHLG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickLargeGap;
+ break;
+ case RTFKeyword::BRDRTHTNSG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinSmallGap;
+ break;
+ case RTFKeyword::BRDRTHTNMG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinMediumGap;
+ break;
+ case RTFKeyword::BRDRTHTNLG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinLargeGap;
+ break;
+ case RTFKeyword::BRDREMBOSS:
+ nParam = NS_ooxml::LN_Value_ST_Border_threeDEmboss;
+ break;
+ case RTFKeyword::BRDRENGRAVE:
+ nParam = NS_ooxml::LN_Value_ST_Border_threeDEngrave;
+ break;
+ case RTFKeyword::BRDROUTSET:
+ nParam = NS_ooxml::LN_Value_ST_Border_outset;
+ break;
+ case RTFKeyword::BRDRINSET:
+ nParam = NS_ooxml::LN_Value_ST_Border_inset;
+ break;
+ case RTFKeyword::BRDRDASHSM:
+ nParam = NS_ooxml::LN_Value_ST_Border_dashSmallGap;
+ break;
+ case RTFKeyword::BRDRDASHD:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotDash;
+ break;
+ case RTFKeyword::BRDRDASHDD:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotDotDash;
+ break;
+ case RTFKeyword::BRDRNONE:
+ nParam = NS_ooxml::LN_Value_ST_Border_none;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_val, pValue);
+ return RTFError::OK;
+ }
+ }
+
+ // Section breaks
+ switch (nKeyword)
+ {
+ case RTFKeyword::SBKNONE:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_continuous;
+ break;
+ case RTFKeyword::SBKCOL:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_nextColumn;
+ break;
+ case RTFKeyword::SBKPAGE:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ break;
+ case RTFKeyword::SBKEVEN:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_evenPage;
+ break;
+ case RTFKeyword::SBKODD:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_oddPage;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid)
+ {
+ m_nResetBreakOnSectBreak = nKeyword;
+ }
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pValue);
+ return RTFError::OK;
+ }
+
+ // Footnote numbering
+ switch (nKeyword)
+ {
+ case RTFKeyword::FTNNAR:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal;
+ break;
+ case RTFKeyword::FTNNALC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter;
+ break;
+ case RTFKeyword::FTNNAUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter;
+ break;
+ case RTFKeyword::FTNNRLC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman;
+ break;
+ case RTFKeyword::FTNNRUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman;
+ break;
+ case RTFKeyword::FTNNCHI:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pInner = new RTFValue(nParam);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumFmt_val, pInner);
+ auto pOuter = new RTFValue(aAttributes);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr, NS_ooxml::LN_CT_FtnProps_numFmt,
+ pOuter);
+ return RTFError::OK;
+ }
+
+ // Footnote restart type
+ switch (nKeyword)
+ {
+ case RTFKeyword::FTNRSTPG:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachPage;
+ break;
+ case RTFKeyword::FTNRESTART:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachSect;
+ break;
+ case RTFKeyword::FTNRSTCONT:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_continuous;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue);
+ return RTFError::OK;
+ }
+
+ // Endnote numbering
+ switch (nKeyword)
+ {
+ case RTFKeyword::AFTNNAR:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal;
+ break;
+ case RTFKeyword::AFTNNALC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter;
+ break;
+ case RTFKeyword::AFTNNAUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter;
+ break;
+ case RTFKeyword::AFTNNRLC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman;
+ break;
+ case RTFKeyword::AFTNNRUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman;
+ break;
+ case RTFKeyword::AFTNNCHI:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pInner = new RTFValue(nParam);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumFmt_val, pInner);
+ auto pOuter = new RTFValue(aAttributes);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(), NS_ooxml::LN_EG_SectPrContents_endnotePr,
+ NS_ooxml::LN_CT_EdnProps_numFmt, pOuter);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRQL:
+ nParam = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case RTFKeyword::TRQC:
+ nParam = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case RTFKeyword::TRQR:
+ nParam = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TrPrBase_jc, pValue);
+ return RTFError::OK;
+ }
+
+ // Cell Text Flow
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLTXLRTB:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTb;
+ break;
+ case RTFKeyword::CLTXTBRL:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRl;
+ break;
+ case RTFKeyword::CLTXBTLR:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_btLr;
+ break;
+ case RTFKeyword::CLTXLRTBV:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTbV;
+ break;
+ case RTFKeyword::CLTXTBRLV:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRlV;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_textDirection, pValue);
+ }
+
+ // Trivial paragraph flags
+ switch (nKeyword)
+ {
+ case RTFKeyword::KEEP:
+ if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
+ nParam = NS_ooxml::LN_CT_PPrBase_keepLines;
+ break;
+ case RTFKeyword::KEEPN:
+ nParam = NS_ooxml::LN_CT_PPrBase_keepNext;
+ break;
+ case RTFKeyword::INTBL:
+ {
+ m_aStates.top().setCurrentBuffer(&m_aTableBufferStack.back());
+ nParam = NS_ooxml::LN_inTbl;
+ }
+ break;
+ case RTFKeyword::PAGEBB:
+ nParam = NS_ooxml::LN_CT_PPrBase_pageBreakBefore;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getParagraphSprms().set(nParam, pValue);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::FNIL:
+ case RTFKeyword::FROMAN:
+ case RTFKeyword::FSWISS:
+ case RTFKeyword::FMODERN:
+ case RTFKeyword::FSCRIPT:
+ case RTFKeyword::FDECOR:
+ case RTFKeyword::FTECH:
+ case RTFKeyword::FBIDI:
+ // TODO ooxml:CT_Font_family seems to be ignored by the domain mapper
+ break;
+ case RTFKeyword::ANSI:
+ m_aStates.top().setCurrentEncoding(RTL_TEXTENCODING_MS_1252);
+ break;
+ case RTFKeyword::MAC:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_APPLE_ROMAN);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PC:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_437);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PCA:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_850);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PLAIN:
+ {
+ m_aStates.top().getCharacterSprms() = getDefaultState().getCharacterSprms();
+ m_aStates.top().setCurrentEncoding(getEncoding(getFontIndex(m_nDefaultFontIndex)));
+ m_aStates.top().getCharacterAttributes() = getDefaultState().getCharacterAttributes();
+ m_aStates.top().setCurrentCharacterStyleIndex(-1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ }
+ break;
+ case RTFKeyword::PARD:
+ {
+ if (m_bHadPicture)
+ dispatchSymbol(RTFKeyword::PAR);
+ // \pard is allowed between \cell and \row, but in that case it should not reset the fact that we're inside a table.
+ // It should not reset the paragraph style, either, so remember the old paragraph style.
+ RTFValue::Pointer_t pOldStyle
+ = m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pStyle);
+ m_aStates.top().getParagraphSprms() = m_aDefaultState.getParagraphSprms();
+ m_aStates.top().getParagraphAttributes() = m_aDefaultState.getParagraphAttributes();
+
+ if (m_nTopLevelCells == 0 && m_nNestedCells == 0)
+ {
+ // Reset that we're in a table.
+ m_aStates.top().setCurrentBuffer(nullptr);
+ }
+ else
+ {
+ // We are still in a table.
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_inTbl, new RTFValue(1));
+ if (m_bAfterCellBeforeRow && pOldStyle)
+ // And we still have the same paragraph style.
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ pOldStyle);
+ // Ideally getDefaultSPRM() would take care of this, but it would not when we're buffering.
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_tabs,
+ new RTFValue());
+ }
+ resetFrame();
+
+ // Reset currently selected paragraph style as well, unless we are in the special "after \cell, before \row" state.
+ // By default the style with index 0 is applied.
+ if (!m_bAfterCellBeforeRow)
+ {
+ OUString const aName = getStyleName(0);
+ // But only in case it's not a character style.
+ if (!aName.isEmpty()
+ && getStyleType(0) != NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ new RTFValue(aName));
+ }
+ m_aStates.top().setCurrentStyleIndex(0);
+ }
+ // Need to send paragraph properties again, if there will be any.
+ m_bNeedPap = true;
+ break;
+ }
+ case RTFKeyword::SECTD:
+ {
+ m_aStates.top().getSectionSprms() = m_aDefaultState.getSectionSprms();
+ m_aStates.top().getSectionAttributes() = m_aDefaultState.getSectionAttributes();
+ }
+ break;
+ case RTFKeyword::TROWD:
+ {
+ // Back these up, in case later we still need this info.
+ backupTableRowProperties();
+ resetTableRowProperties();
+ // In case the table definition is in the middle of the row
+ // (invalid), make sure table definition is emitted.
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::WIDCTLPAR:
+ case RTFKeyword::NOWIDCTLPAR:
+ {
+ auto pValue = new RTFValue(int(nKeyword == RTFKeyword::WIDCTLPAR));
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_widowControl, pValue);
+ }
+ break;
+ case RTFKeyword::BOX:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(aAttributes);
+ for (int i = 0; i < 4; i++)
+ m_aStates.top().getParagraphSprms().set(getParagraphBorder(i), pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PARAGRAPH_BOX);
+ }
+ break;
+ case RTFKeyword::LTRSECT:
+ case RTFKeyword::RTLSECT:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LTRSECT ? 0 : 1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection,
+ pValue);
+ }
+ break;
+ case RTFKeyword::LTRPAR:
+ case RTFKeyword::RTLPAR:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LTRPAR ? 0 : 1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_bidi, pValue);
+ }
+ break;
+ case RTFKeyword::LTRROW:
+ case RTFKeyword::RTLROW:
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getTableRowSprms().set(
+ NS_ooxml::LN_CT_TblPrBase_bidiVisual,
+ new RTFValue(int(nKeyword == RTFKeyword::RTLROW)));
+ break;
+ case RTFKeyword::LTRCH:
+ // dmapper does not support this.
+ if (m_aStates.top().getRunType() == RTFParserState::RunType::RTLCH_LTRCH_1)
+ m_aStates.top().setRunType(RTFParserState::RunType::RTLCH_LTRCH_2);
+ else
+ m_aStates.top().setRunType(RTFParserState::RunType::LTRCH_RTLCH_1);
+ break;
+ case RTFKeyword::RTLCH:
+ if (m_aStates.top().getRunType() == RTFParserState::RunType::LTRCH_RTLCH_1)
+ m_aStates.top().setRunType(RTFParserState::RunType::LTRCH_RTLCH_2);
+ else
+ m_aStates.top().setRunType(RTFParserState::RunType::RTLCH_LTRCH_1);
+
+ if (m_aDefaultState.getCurrentEncoding() == RTL_TEXTENCODING_MS_1255)
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::ULNONE:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Underline_none);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ }
+ break;
+ case RTFKeyword::NONSHPPICT:
+ case RTFKeyword::MMATHPICT: // Picture group used by readers not understanding \moMath group
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::CLBRDRT:
+ case RTFKeyword::CLBRDRL:
+ case RTFKeyword::CLBRDRB:
+ case RTFKeyword::CLBRDRR:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLBRDRT:
+ nSprm = NS_ooxml::LN_CT_TcBorders_top;
+ break;
+ case RTFKeyword::CLBRDRL:
+ nSprm = NS_ooxml::LN_CT_TcBorders_left;
+ break;
+ case RTFKeyword::CLBRDRB:
+ nSprm = NS_ooxml::LN_CT_TcBorders_bottom;
+ break;
+ case RTFKeyword::CLBRDRR:
+ nSprm = NS_ooxml::LN_CT_TcBorders_right;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcBorders,
+ nSprm, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::CELL);
+ }
+ break;
+ case RTFKeyword::PGBRDRT:
+ case RTFKeyword::PGBRDRL:
+ case RTFKeyword::PGBRDRB:
+ case RTFKeyword::PGBRDRR:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::PGBRDRT:
+ nSprm = NS_ooxml::LN_CT_PageBorders_top;
+ break;
+ case RTFKeyword::PGBRDRL:
+ nSprm = NS_ooxml::LN_CT_PageBorders_left;
+ break;
+ case RTFKeyword::PGBRDRB:
+ nSprm = NS_ooxml::LN_CT_PageBorders_bottom;
+ break;
+ case RTFKeyword::PGBRDRR:
+ nSprm = NS_ooxml::LN_CT_PageBorders_right;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders, nSprm, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PAGE);
+ }
+ break;
+ case RTFKeyword::BRDRT:
+ case RTFKeyword::BRDRL:
+ case RTFKeyword::BRDRB:
+ case RTFKeyword::BRDRR:
+ case RTFKeyword::BRDRBTW:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::BRDRT:
+ nSprm = getParagraphBorder(0);
+ break;
+ case RTFKeyword::BRDRL:
+ nSprm = getParagraphBorder(1);
+ break;
+ case RTFKeyword::BRDRB:
+ nSprm = getParagraphBorder(2);
+ break;
+ case RTFKeyword::BRDRR:
+ nSprm = getParagraphBorder(3);
+ break;
+ case RTFKeyword::BRDRBTW:
+ nSprm = getParagraphBorder(4);
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nSprm,
+ pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PARAGRAPH);
+ }
+ break;
+ case RTFKeyword::CHBRDR:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(aAttributes);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_bdr, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::CHARACTER);
+ }
+ break;
+ case RTFKeyword::CLMGF:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_restart);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLMRG:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_continue);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVMGF:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_restart);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVMRG:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_continue);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVERTALT:
+ case RTFKeyword::CLVERTALC:
+ case RTFKeyword::CLVERTALB:
+ {
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLVERTALT:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_top;
+ break;
+ case RTFKeyword::CLVERTALC:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_center;
+ break;
+ case RTFKeyword::CLVERTALB:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_bottom;
+ break;
+ default:
+ break;
+ }
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vAlign, pValue);
+ }
+ break;
+ case RTFKeyword::TRKEEP:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TrPrBase_cantSplit, pValue);
+ }
+ break;
+ case RTFKeyword::SECTUNLOCKED:
+ {
+ auto pValue = new RTFValue(0);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_formProt, pValue);
+ }
+ break;
+ case RTFKeyword::PGNBIDIA:
+ case RTFKeyword::PGNBIDIB:
+ // These should be mapped to NS_ooxml::LN_EG_SectPrContents_pgNumType, but dmapper has no API for that at the moment.
+ break;
+ case RTFKeyword::LOCH:
+ m_aStates.top().setRunType(RTFParserState::RunType::LOCH);
+ break;
+ case RTFKeyword::HICH:
+ m_aStates.top().setRunType(RTFParserState::RunType::HICH);
+ break;
+ case RTFKeyword::DBCH:
+ m_aStates.top().setRunType(RTFParserState::RunType::DBCH);
+ break;
+ case RTFKeyword::TITLEPG:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_titlePg, pValue);
+ }
+ break;
+ case RTFKeyword::SUPER:
+ {
+ // Make sure character properties are not lost if the document
+ // starts with a footnote.
+ if (!isStyleSheetImport())
+ {
+ checkFirstRun();
+ checkNeedPap();
+ }
+
+ if (!m_aStates.top().getCurrentBuffer())
+ m_aStates.top().setCurrentBuffer(&m_aSuperBuffer);
+
+ auto pValue = new RTFValue("superscript");
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue);
+ }
+ break;
+ case RTFKeyword::SUB:
+ {
+ auto pValue = new RTFValue("subscript");
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue);
+ }
+ break;
+ case RTFKeyword::NOSUPERSUB:
+ {
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ {
+ replayBuffer(m_aSuperBuffer, nullptr, nullptr);
+ m_aStates.top().setCurrentBuffer(nullptr);
+ }
+ m_aStates.top().getCharacterSprms().erase(NS_ooxml::LN_EG_RPrBase_vertAlign);
+ }
+ break;
+ case RTFKeyword::LINEPPAGE:
+ case RTFKeyword::LINECONT:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LINEPPAGE
+ ? NS_ooxml::LN_Value_ST_LineNumberRestart_newPage
+ : NS_ooxml::LN_Value_ST_LineNumberRestart_continuous);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_restart, pValue);
+ }
+ break;
+ case RTFKeyword::AENDDOC:
+ // Noop, this is the default in Writer.
+ case RTFKeyword::AENDNOTES:
+ // Noop
+ case RTFKeyword::AFTNRSTCONT:
+ // Noop, this is the default in Writer.
+ case RTFKeyword::AFTNRESTART:
+ // Noop
+ case RTFKeyword::FTNBJ:
+ // Noop, this is the default in Writer.
+ break;
+ case RTFKeyword::ENDDOC:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_RestartNumber_eachSect);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue);
+ }
+ break;
+ case RTFKeyword::NOLINE:
+ eraseNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_distance);
+ break;
+ case RTFKeyword::FORMSHADE:
+ // Noop, this is the default in Writer.
+ break;
+ case RTFKeyword::PNGBLIP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::PNG;
+ break;
+ case RTFKeyword::JPEGBLIP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::JPEG;
+ break;
+ case RTFKeyword::POSYT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_top);
+ break;
+ case RTFKeyword::POSYB:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_bottom);
+ break;
+ case RTFKeyword::POSYC:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_center);
+ break;
+ case RTFKeyword::POSYIN:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_inside);
+ break;
+ case RTFKeyword::POSYOUT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_outside);
+ break;
+ case RTFKeyword::POSYIL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_inline);
+ break;
+
+ case RTFKeyword::PHMRG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_margin);
+ break;
+ case RTFKeyword::PVMRG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_margin);
+ break;
+ case RTFKeyword::PHPG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_page);
+ break;
+ case RTFKeyword::PVPG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_page);
+ break;
+ case RTFKeyword::PHCOL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_text);
+ break;
+ case RTFKeyword::PVPARA:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_text);
+ break;
+
+ case RTFKeyword::POSXC:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_center);
+ break;
+ case RTFKeyword::POSXI:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_inside);
+ break;
+ case RTFKeyword::POSXO:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_outside);
+ break;
+ case RTFKeyword::POSXL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_left);
+ break;
+ case RTFKeyword::POSXR:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_right);
+ break;
+
+ case RTFKeyword::DPLINE:
+ case RTFKeyword::DPRECT:
+ case RTFKeyword::DPELLIPSE:
+ case RTFKeyword::DPTXBX:
+ case RTFKeyword::DPPOLYLINE:
+ case RTFKeyword::DPPOLYGON:
+ {
+ sal_Int32 nType = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::DPLINE:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.LineShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPPOLYLINE:
+ {
+ // The reason this is not a simple CustomShape is that in the old syntax we have no ViewBox info.
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.PolyLineShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPPOLYGON:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.PolyPolygonShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPRECT:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.RectangleShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPELLIPSE:
+ nType = ESCHER_ShpInst_Ellipse;
+ break;
+ case RTFKeyword::DPTXBX:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.text.TextFrame"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ std::vector<beans::PropertyValue> aDefaults
+ = RTFSdrImport::getTextFrameDefaults(false);
+ for (const auto& rDefault : aDefaults)
+ {
+ if (!findPropertyName(
+ m_aStates.top().getDrawingObject().getPendingProperties(),
+ rDefault.Name))
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(
+ rDefault);
+ }
+ checkFirstRun();
+ Mapper().startShape(m_aStates.top().getDrawingObject().getShape());
+ m_aStates.top().getDrawingObject().setHadShapeText(true);
+ }
+ break;
+ default:
+ break;
+ }
+ if (nType)
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.CustomShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ }
+ uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPropertySet(
+ m_aStates.top().getDrawingObject().getShape(), uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setPropertySet(xPropertySet);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
+ if (xShapes.is() && nKeyword != RTFKeyword::DPTXBX)
+ {
+ // set default VertOrient before inserting
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ "VertOrient", uno::Any(text::VertOrientation::NONE));
+ xShapes->add(m_aStates.top().getDrawingObject().getShape());
+ }
+ }
+ if (nType)
+ {
+ uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(
+ m_aStates.top().getDrawingObject().getShape(), uno::UNO_QUERY);
+ xDefaulter->createCustomShapeDefaults(OUString::number(nType));
+ }
+ std::vector<beans::PropertyValue>& rPendingProperties
+ = m_aStates.top().getDrawingObject().getPendingProperties();
+ for (const auto& rPendingProperty : rPendingProperties)
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ rPendingProperty.Name, rPendingProperty.Value);
+ m_pSdrImport->resolveDhgt(m_aStates.top().getDrawingObject().getPropertySet(),
+ m_aStates.top().getDrawingObject().getDhgt(),
+ /*bOldStyle=*/true);
+ }
+ break;
+ case RTFKeyword::DOBXMARGIN:
+ case RTFKeyword::DOBYMARGIN:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name
+ = (nKeyword == RTFKeyword::DOBXMARGIN ? std::u16string_view(u"HoriOrientRelation")
+ : std::u16string_view(u"VertOrientRelation"));
+ aPropertyValue.Value <<= text::RelOrientation::PAGE_PRINT_AREA;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::DOBXPAGE:
+ case RTFKeyword::DOBYPAGE:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name
+ = (nKeyword == RTFKeyword::DOBXPAGE ? std::u16string_view(u"HoriOrientRelation")
+ : std::u16string_view(u"VertOrientRelation"));
+ aPropertyValue.Value <<= text::RelOrientation::PAGE_FRAME;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::DOBYPARA:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name = "VertOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::CONTEXTUALSPACE:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_contextualSpacing,
+ pValue);
+ }
+ break;
+ case RTFKeyword::LINKSTYLES:
+ {
+ auto pValue = new RTFValue(1);
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_linkStyles, pValue);
+ }
+ break;
+ case RTFKeyword::PNLVLBODY:
+ {
+ auto pValue = new RTFValue(2);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid, pValue);
+ }
+ break;
+ case RTFKeyword::PNDEC:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_decimal);
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val, pValue);
+ }
+ break;
+ case RTFKeyword::PNLVLBLT:
+ {
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid,
+ new RTFValue(1));
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_bullet));
+ }
+ break;
+ case RTFKeyword::LANDSCAPE:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_PageOrientation_landscape);
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient,
+ pValue);
+ [[fallthrough]]; // set the default + current value
+ }
+ case RTFKeyword::LNDSCPSXN:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_PageOrientation_landscape);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient,
+ pValue);
+ }
+ break;
+ case RTFKeyword::SHPBXPAGE:
+ m_aStates.top().getShape().setHoriOrientRelation(text::RelOrientation::PAGE_FRAME);
+ m_aStates.top().getShape().setHoriOrientRelationToken(
+ NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_page);
+ break;
+ case RTFKeyword::SHPBYPAGE:
+ m_aStates.top().getShape().setVertOrientRelation(text::RelOrientation::PAGE_FRAME);
+ m_aStates.top().getShape().setVertOrientRelationToken(
+ NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page);
+ break;
+ case RTFKeyword::DPLINEHOLLOW:
+ m_aStates.top().getDrawingObject().setFLine(0);
+ break;
+ case RTFKeyword::DPROUNDR:
+ if (m_aStates.top().getDrawingObject().getPropertySet().is())
+ // Seems this old syntax has no way to specify a custom radius, and this is the default
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ "CornerRadius", uno::Any(sal_Int32(83)));
+ break;
+ case RTFKeyword::NOWRAP:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_notBeside);
+ break;
+ case RTFKeyword::MNOR:
+ m_bMathNor = true;
+ break;
+ case RTFKeyword::REVISIONS:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_trackRevisions, new RTFValue(1));
+ break;
+ case RTFKeyword::BRDRSH:
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_shadow, new RTFValue(1));
+ break;
+ case RTFKeyword::NOCOLBAL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_noColumnBalance, new RTFValue(1));
+ break;
+ case RTFKeyword::MARGMIRROR:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_mirrorMargins, new RTFValue(1));
+ break;
+ case RTFKeyword::SAUTOUPD:
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_autoRedefine,
+ new RTFValue(1));
+ break;
+ case RTFKeyword::WIDOWCTRL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_widowControl, new RTFValue(1));
+ break;
+ case RTFKeyword::LINEBETCOL:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_sep,
+ new RTFValue(1));
+ break;
+ case RTFKeyword::PGNRESTART:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_start, new RTFValue(1));
+ break;
+ case RTFKeyword::PGNUCLTR:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_upperLetter);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNLCLTR:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNUCRM:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_upperRoman);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNLCRM:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNDEC:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_decimal);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::HTMAUTSP:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_doNotUseHTMLParagraphAutoSpacing,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::DNTBLNSBDB:
+ // tdf#128428 switch off longer space sequence
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::GUTTERPRL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_gutterAtTop, new RTFValue(1));
+ break;
+ case RTFKeyword::RTLGUTTER:
+ {
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_rtlGutter,
+ new RTFValue(1));
+ }
+ break;
+ case RTFKeyword::FLDLOCK:
+ {
+ if (m_aStates.top().getDestination() == Destination::FIELD)
+ m_aStates.top().setFieldLocked(true);
+ }
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter", "TODO handle flag '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchsymbol.cxx b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx
new file mode 100644
index 000000000..3f9ed20bf
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx
@@ -0,0 +1,442 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <svl/lngmisc.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ if (nKeyword != RTFKeyword::HEXCHAR)
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ else
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
+ RTFSkipDestination aSkip(*this);
+
+ if (RTFKeyword::LINE == nKeyword)
+ {
+ // very special handling since text() will eat lone '\n'
+ singleChar('\n', /*bRunProps=*/true);
+ return RTFError::OK;
+ }
+ // Trivial symbols
+ sal_uInt8 cCh = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::TAB:
+ cCh = '\t';
+ break;
+ case RTFKeyword::BACKSLASH:
+ cCh = '\\';
+ break;
+ case RTFKeyword::LBRACE:
+ cCh = '{';
+ break;
+ case RTFKeyword::RBRACE:
+ cCh = '}';
+ break;
+ case RTFKeyword::EMDASH:
+ cCh = 151;
+ break;
+ case RTFKeyword::ENDASH:
+ cCh = 150;
+ break;
+ case RTFKeyword::BULLET:
+ cCh = 149;
+ break;
+ case RTFKeyword::LQUOTE:
+ cCh = 145;
+ break;
+ case RTFKeyword::RQUOTE:
+ cCh = 146;
+ break;
+ case RTFKeyword::LDBLQUOTE:
+ cCh = 147;
+ break;
+ case RTFKeyword::RDBLQUOTE:
+ cCh = 148;
+ break;
+ default:
+ break;
+ }
+ if (cCh > 0)
+ {
+ OUString aStr(OStringToOUString(OStringChar(char(cCh)), RTL_TEXTENCODING_MS_1252));
+ text(aStr);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::IGNORE:
+ {
+ m_bSkipUnknown = true;
+ aSkip.setReset(false);
+ return RTFError::OK;
+ }
+ break;
+ case RTFKeyword::PAR:
+ {
+ if (m_aStates.top().getDestination() == Destination::FOOTNOTESEPARATOR)
+ break; // just ignore it - only thing we read in here is CHFTNSEP
+ checkFirstRun();
+ bool bNeedPap = m_bNeedPap;
+ checkNeedPap();
+ if (bNeedPap)
+ runProps();
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ parBreak();
+ // Not in table? Reset max width.
+ if (m_nCellxMax)
+ {
+ // Was in table, but not anymore -> tblEnd.
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblEnd, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+ m_nCellxMax = 0;
+ }
+ else if (m_aStates.top().getDestination() != Destination::SHAPETEXT)
+ {
+ RTFValue::Pointer_t pValue;
+ m_aStates.top().getCurrentBuffer()->push_back(Buf_t(BUFFER_PAR, pValue, nullptr));
+ }
+ // but don't emit properties yet, since they may change till the first text token arrives
+ m_bNeedPap = true;
+ if (!m_aStates.top().getFrame().inFrame())
+ m_bNeedPar = false;
+ m_bNeedFinalPar = false;
+ }
+ break;
+ case RTFKeyword::SECT:
+ {
+ if (m_bNeedCr)
+ dispatchSymbol(RTFKeyword::PAR);
+
+ m_bHadSect = true;
+ if (m_bIgnoreNextContSectBreak)
+ m_bIgnoreNextContSectBreak = false;
+ else
+ {
+ sectBreak();
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid)
+ {
+ // this should run on _second_ \sect after \page
+ dispatchSymbol(m_nResetBreakOnSectBreak); // lazy reset
+ m_nResetBreakOnSectBreak = RTFKeyword::invalid;
+ m_bNeedSect = false; // dispatchSymbol set it
+ }
+ }
+ }
+ break;
+ case RTFKeyword::NOBREAK:
+ {
+ OUString aStr(SVT_HARD_SPACE);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::NOBRKHYPH:
+ {
+ OUString aStr(SVT_HARD_HYPHEN);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::OPTHYPH:
+ {
+ OUString aStr(SVT_SOFT_HYPHEN);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::HEXCHAR:
+ m_aStates.top().setInternalState(RTFInternalState::HEX);
+ break;
+ case RTFKeyword::CELL:
+ case RTFKeyword::NESTCELL:
+ {
+ if (nKeyword == RTFKeyword::CELL)
+ m_bAfterCellBeforeRow = true;
+
+ checkFirstRun();
+ if (m_bNeedPap)
+ {
+ // There were no runs in the cell, so we need to send paragraph and character properties here.
+ auto pPValue = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ bufferProperties(m_aTableBufferStack.back(), pPValue, nullptr);
+ auto pCValue = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+ bufferProperties(m_aTableBufferStack.back(), pCValue, nullptr);
+ }
+
+ RTFValue::Pointer_t pValue;
+ m_aTableBufferStack.back().emplace_back(Buf_t(BUFFER_CELLEND, pValue, nullptr));
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::NESTROW:
+ {
+ tools::SvRef<TableRowBuffer> const pBuffer(
+ new TableRowBuffer(m_aTableBufferStack.back(), m_aNestedTableCellsSprms,
+ m_aNestedTableCellsAttributes, m_nNestedCells));
+ prepareProperties(m_aStates.top(), pBuffer->GetParaProperties(),
+ pBuffer->GetFrameProperties(), pBuffer->GetRowProperties(),
+ m_nNestedCells, m_nNestedCurrentCellX - m_nNestedTRLeft);
+
+ if (m_aTableBufferStack.size() == 1 || !m_aStates.top().getCurrentBuffer())
+ {
+ throw io::WrongFormatException("mismatch between \\itap and number of \\nestrow",
+ nullptr);
+ }
+ assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back());
+ // note: there may be several states pointing to table buffer!
+ for (std::size_t i = 0; i < m_aStates.size(); ++i)
+ {
+ if (m_aStates[i].getCurrentBuffer() == &m_aTableBufferStack.back())
+ {
+ m_aStates[i].setCurrentBuffer(
+ &m_aTableBufferStack[m_aTableBufferStack.size() - 2]);
+ }
+ }
+ m_aTableBufferStack.pop_back();
+ m_aTableBufferStack.back().emplace_back(
+ Buf_t(BUFFER_NESTROW, RTFValue::Pointer_t(), pBuffer));
+
+ m_aNestedTableCellsSprms.clear();
+ m_aNestedTableCellsAttributes.clear();
+ m_nNestedCells = 0;
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::ROW:
+ {
+ m_bAfterCellBeforeRow = false;
+ if (m_aStates.top().getTableRowWidthAfter() > 0)
+ {
+ // Add fake cellx / cell, RTF equivalent of
+ // OOXMLFastContextHandlerTextTableRow::handleGridAfter().
+ auto pXValue = new RTFValue(m_aStates.top().getTableRowWidthAfter());
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ dispatchSymbol(RTFKeyword::CELL);
+
+ // Adjust total width, which is done in the \cellx handler for normal cells.
+ m_nTopLevelCurrentCellX += m_aStates.top().getTableRowWidthAfter();
+
+ m_aStates.top().setTableRowWidthAfter(0);
+ }
+
+ bool bRestored = false;
+ // Ending a row, but no cells defined?
+ // See if there was an invalid table row reset, so we can restore cell infos to help invalid documents.
+ if (!m_nTopLevelCurrentCellX && m_nBackupTopLevelCurrentCellX)
+ {
+ restoreTableRowProperties();
+ bRestored = true;
+ }
+
+ // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): resize the last cell
+ const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames.
+ if ((m_nCellxMax - m_nTopLevelCurrentCellX) >= MINLAY)
+ {
+ auto pXValueLast = m_aStates.top().getTableRowSprms().find(
+ NS_ooxml::LN_CT_TblGridBase_gridCol, false);
+ const int nXValueLast = pXValueLast ? pXValueLast->getInt() : 0;
+ auto pXValue = new RTFValue(nXValueLast + m_nCellxMax - m_nTopLevelCurrentCellX);
+ m_aStates.top().getTableRowSprms().eraseLast(NS_ooxml::LN_CT_TblGridBase_gridCol);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ m_nTopLevelCurrentCellX = m_nCellxMax;
+ }
+
+ if (m_nTopLevelCells)
+ {
+ // Make a backup before we start popping elements
+ m_aTableInheritingCellsSprms = m_aTopLevelTableCellsSprms;
+ m_aTableInheritingCellsAttributes = m_aTopLevelTableCellsAttributes;
+ m_nInheritingCells = m_nTopLevelCells;
+ }
+ else
+ {
+ // No table definition? Then inherit from the previous row
+ m_aTopLevelTableCellsSprms = m_aTableInheritingCellsSprms;
+ m_aTopLevelTableCellsAttributes = m_aTableInheritingCellsAttributes;
+ m_nTopLevelCells = m_nInheritingCells;
+ }
+
+ while (m_aTableBufferStack.size() > 1)
+ {
+ SAL_WARN("writerfilter.rtf", "dropping extra table buffer");
+ // note: there may be several states pointing to table buffer!
+ for (std::size_t i = 0; i < m_aStates.size(); ++i)
+ {
+ if (m_aStates[i].getCurrentBuffer() == &m_aTableBufferStack.back())
+ {
+ m_aStates[i].setCurrentBuffer(&m_aTableBufferStack.front());
+ }
+ }
+ m_aTableBufferStack.pop_back();
+ }
+
+ replayRowBuffer(m_aTableBufferStack.back(), m_aTopLevelTableCellsSprms,
+ m_aTopLevelTableCellsAttributes, m_nTopLevelCells);
+
+ // The scope of the table cell defaults is one row.
+ m_aDefaultState.getTableCellSprms().clear();
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+
+ writerfilter::Reference<Properties>::Pointer_t paraProperties;
+ writerfilter::Reference<Properties>::Pointer_t frameProperties;
+ writerfilter::Reference<Properties>::Pointer_t rowProperties;
+ prepareProperties(m_aStates.top(), paraProperties, frameProperties, rowProperties,
+ m_nTopLevelCells, m_nTopLevelCurrentCellX - m_nTopLevelTRLeft);
+ sendProperties(paraProperties, frameProperties, rowProperties);
+
+ m_bNeedPap = true;
+ m_bNeedFinalPar = true;
+ m_aTableBufferStack.back().clear();
+ m_nTopLevelCells = 0;
+
+ if (bRestored)
+ // We restored cell definitions, clear these now.
+ // This is necessary, as later cell definitions want to overwrite the restored ones.
+ resetTableRowProperties();
+ }
+ break;
+ case RTFKeyword::COLUMN:
+ {
+ bool bColumns = false; // If we have multiple columns
+ RTFValue::Pointer_t pCols
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_cols);
+ if (pCols)
+ {
+ RTFValue::Pointer_t pNum = pCols->getAttributes().find(NS_ooxml::LN_CT_Columns_num);
+ if (pNum && pNum->getInt() > 1)
+ bColumns = true;
+ }
+ checkFirstRun();
+ if (bColumns)
+ {
+ sal_uInt8 const sBreak[] = { 0xe };
+ Mapper().startCharacterGroup();
+ Mapper().text(sBreak, 1);
+ Mapper().endCharacterGroup();
+ }
+ else
+ dispatchSymbol(RTFKeyword::PAGE);
+ }
+ break;
+ case RTFKeyword::CHFTN:
+ {
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ // Stop buffering, there will be no custom mark for this footnote or endnote.
+ m_aStates.top().setCurrentBuffer(nullptr);
+ break;
+ }
+ case RTFKeyword::PAGE:
+ {
+ // Ignore page breaks inside tables.
+ if (m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back())
+ break;
+
+ // If we're inside a continuous section, we should send a section break, not a page one.
+ RTFValue::Pointer_t pBreak
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ // Unless we're on a title page.
+ RTFValue::Pointer_t pTitlePg
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_titlePg);
+ if (((pBreak
+ && pBreak->getInt()
+ == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous))
+ || m_nResetBreakOnSectBreak == RTFKeyword::SBKNONE)
+ && !(pTitlePg && pTitlePg->getInt()))
+ {
+ if (m_bWasInFrame)
+ {
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bWasInFrame = false;
+ }
+ sectBreak();
+ // note: this will not affect the following section break
+ // but the one just pushed
+ dispatchFlag(RTFKeyword::SBKPAGE);
+ if (m_bNeedPar)
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bIgnoreNextContSectBreak = true;
+ // arrange to clean up the synthetic RTFKeyword::SBKPAGE
+ m_nResetBreakOnSectBreak = RTFKeyword::SBKNONE;
+ }
+ else
+ {
+ bool bFirstRun = m_bFirstRun;
+ checkFirstRun();
+ checkNeedPap();
+ sal_uInt8 const sBreak[] = { 0xc };
+ Mapper().text(sBreak, 1);
+ if (bFirstRun || m_bNeedCr)
+ {
+ // If we don't have content in the document yet (so the break-before can't move
+ // to a second layout page) or we already have characters sent (so the paragraph
+ // properties are already finalized), then continue inserting a fake paragraph.
+ if (!m_bNeedPap)
+ {
+ parBreak();
+ m_bNeedPap = true;
+ }
+ }
+ m_bNeedCr = true;
+ }
+ }
+ break;
+ case RTFKeyword::CHPGN:
+ {
+ OUString aStr("PAGE");
+ singleChar(cFieldStart);
+ text(aStr);
+ singleChar(cFieldSep, true);
+ singleChar(cFieldEnd);
+ }
+ break;
+ case RTFKeyword::CHFTNSEP:
+ {
+ static const sal_Unicode uFtnEdnSep = 0x3;
+ Mapper().utext(reinterpret_cast<const sal_uInt8*>(&uFtnEdnSep), 1);
+ }
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter.rtf",
+ "TODO handle symbol '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchvalue.cxx b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
new file mode 100644
index 000000000..2bea9dc9e
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
@@ -0,0 +1,1832 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <comphelper/sequence.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+#include <rtl/tencinfo.h>
+#include <tools/UnitConversion.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include "rtfcharsets.hxx"
+#include "rtffly.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+
+#include <unotools/defaultencoding.hxx>
+#include <unotools/wincodepage.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter
+{
+static int getNumberFormat(int nParam)
+{
+ static const int aMap[]
+ = { NS_ooxml::LN_Value_ST_NumberFormat_decimal,
+ NS_ooxml::LN_Value_ST_NumberFormat_upperRoman,
+ NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman,
+ NS_ooxml::LN_Value_ST_NumberFormat_upperLetter,
+ NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter,
+ NS_ooxml::LN_Value_ST_NumberFormat_ordinal,
+ NS_ooxml::LN_Value_ST_NumberFormat_cardinalText,
+ NS_ooxml::LN_Value_ST_NumberFormat_ordinalText,
+ NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
+ NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_aiueo,
+ NS_ooxml::LN_Value_ST_NumberFormat_iroha,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2,
+ NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalZero,
+ NS_ooxml::LN_Value_ST_NumberFormat_bullet,
+ NS_ooxml::LN_Value_ST_NumberFormat_ganada,
+ NS_ooxml::LN_Value_ST_NumberFormat_chosung,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimal,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2,
+ NS_ooxml::LN_Value_ST_NumberFormat_hebrew1,
+ NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha,
+ NS_ooxml::LN_Value_ST_NumberFormat_hebrew2,
+ NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad };
+ const int nLen = SAL_N_ELEMENTS(aMap);
+ int nValue = 0;
+ if (nParam >= 0 && nParam < nLen)
+ nValue = aMap[nParam];
+ else // 255 and the other cases.
+ nValue = NS_ooxml::LN_Value_ST_NumberFormat_none;
+ return nValue;
+}
+
+namespace rtftok
+{
+bool RTFDocumentImpl::dispatchTableSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+ switch (nKeyword)
+ {
+ case RTFKeyword::LEVELJC:
+ {
+ nSprm = NS_ooxml::LN_CT_Lvl_lvlJc;
+ int nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ }
+ pIntValue = new RTFValue(nValue);
+ break;
+ }
+ case RTFKeyword::LEVELSTARTAT:
+ nSprm = NS_ooxml::LN_CT_Lvl_start;
+ break;
+ case RTFKeyword::LEVELPICTURE:
+ nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId;
+ break;
+ case RTFKeyword::SBASEDON:
+ nSprm = NS_ooxml::LN_CT_Style_basedOn;
+ pIntValue = new RTFValue(getStyleName(nParam));
+ break;
+ case RTFKeyword::SNEXT:
+ nSprm = NS_ooxml::LN_CT_Style_next;
+ pIntValue = new RTFValue(getStyleName(nParam));
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pIntValue);
+ return true;
+ }
+ if (nKeyword == RTFKeyword::LEVELNFC)
+ {
+ pIntValue = new RTFValue(getNumberFormat(nParam));
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val, pIntValue);
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::FS:
+ case RTFKeyword::AFS:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_szCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_sz;
+ break;
+ }
+ break;
+ case RTFKeyword::EXPNDTW:
+ nSprm = NS_ooxml::LN_EG_RPrBase_spacing;
+ break;
+ case RTFKeyword::KERNING:
+ nSprm = NS_ooxml::LN_EG_RPrBase_kern;
+ break;
+ case RTFKeyword::CHARSCALEX:
+ nSprm = NS_ooxml::LN_EG_RPrBase_w;
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pIntValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pIntValue);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::LANG:
+ case RTFKeyword::ALANG:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_CT_Language_bidi;
+ break;
+ case RTFParserState::RunType::DBCH:
+ nSprm = NS_ooxml::LN_CT_Language_eastAsia;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ default:
+ nSprm = NS_ooxml::LN_CT_Language_val;
+ break;
+ }
+ break;
+ case RTFKeyword::LANGFE: // this one is always CJK apparently
+ nSprm = NS_ooxml::LN_CT_Language_eastAsia;
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
+ auto pValue = new RTFValue(aTag.getBcp47());
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_lang, nSprm,
+ pValue);
+ // Language is a character property, but we should store it at a paragraph level as well for fields.
+ if (nKeyword == RTFKeyword::LANG && m_bNeedPap)
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_EG_RPrBase_lang,
+ nSprm, pValue);
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::ITAP:
+ nSprm = NS_ooxml::LN_tblDepth;
+ // tdf#117268: If \itap0 is encountered inside tables (between \cellxN and \cell), then
+ // use the default value (1), as Word apparently does
+ if (nParam == 0 && (m_nTopLevelCells != 0 || m_nNestedCells != 0))
+ {
+ nParam = 1;
+ pIntValue = new RTFValue(nParam);
+ }
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ m_aStates.top().getParagraphSprms().set(nSprm, pIntValue);
+ if (nKeyword == RTFKeyword::ITAP && nParam > 0)
+ {
+ while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam))
+ {
+ m_aTableBufferStack.emplace_back();
+ }
+ // Invalid tables may omit INTBL after ITAP
+ dispatchFlag(RTFKeyword::INTBL); // sets newly pushed buffer as current
+ assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchInfoValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::YR:
+ {
+ m_aStates.top().setYear(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::MO:
+ {
+ m_aStates.top().setMonth(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::DY:
+ {
+ m_aStates.top().setDay(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::HR:
+ {
+ m_aStates.top().setHour(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::MIN:
+ {
+ m_aStates.top().setMinute(nParam);
+ nSprm = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return nSprm > 0;
+}
+
+bool RTFDocumentImpl::dispatchFrameValue(RTFKeyword nKeyword, int nParam)
+{
+ Id nId = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::ABSW:
+ nId = NS_ooxml::LN_CT_FramePr_w;
+ break;
+ case RTFKeyword::ABSH:
+ nId = NS_ooxml::LN_CT_FramePr_h;
+ break;
+ case RTFKeyword::POSX:
+ {
+ nId = NS_ooxml::LN_CT_FramePr_x;
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0);
+ }
+ break;
+ case RTFKeyword::POSY:
+ {
+ nId = NS_ooxml::LN_CT_FramePr_y;
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_bNeedPap = true;
+ // Don't try to support text frames inside tables for now.
+ if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
+ m_aStates.top().getFrame().setSprm(nId, nParam);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::CELLX:
+ {
+ int& rCurrentCellX(
+ (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ ? m_nNestedCurrentCellX
+ : m_nTopLevelCurrentCellX);
+ int nCellX = nParam - rCurrentCellX;
+ const int COL_DFLT_WIDTH
+ = 41; // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells.
+ if (!nCellX)
+ nCellX = COL_DFLT_WIDTH;
+
+ // If there is a negative left margin, then the first cellx is relative to that.
+ RTFValue::Pointer_t pTblInd
+ = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblInd);
+ if (rCurrentCellX == 0 && pTblInd)
+ {
+ RTFValue::Pointer_t pWidth
+ = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
+ if (pWidth && pWidth->getInt() < 0)
+ nCellX = -1 * (pWidth->getInt() - nParam);
+ }
+
+ rCurrentCellX = nParam;
+ auto pXValue = new RTFValue(nCellX);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ {
+ m_nNestedCells++;
+ // Push cell properties.
+ m_aNestedTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_aNestedTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
+ }
+ else
+ {
+ m_nTopLevelCells++;
+ // Push cell properties.
+ m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
+ }
+
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+ // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token
+ dispatchFlag(RTFKeyword::INTBL);
+ if (!m_nCellxMax)
+ {
+ // Wasn't in table, but now is -> tblStart.
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+ m_nCellxMax = std::max(m_nCellxMax, nParam);
+ return true;
+ }
+ break;
+ case RTFKeyword::TRRH:
+ {
+ OUString hRule("auto");
+ if (nParam < 0)
+ {
+ tools::SvRef<RTFValue> pAbsValue(new RTFValue(-nParam));
+ std::swap(pIntValue, pAbsValue);
+
+ hRule = "exact";
+ }
+ else if (nParam > 0)
+ hRule = "atLeast";
+
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_val,
+ pIntValue);
+
+ auto pHRule = new RTFValue(hRule);
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_hRule,
+ pHRule);
+ return true;
+ }
+ break;
+ case RTFKeyword::TRLEFT:
+ {
+ // the value is in twips
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd,
+ NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd,
+ NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ auto const aDestination = m_aStates.top().getDestination();
+ int& rCurrentTRLeft((Destination::NESTEDTABLEPROPERTIES == aDestination)
+ ? m_nNestedTRLeft
+ : m_nTopLevelTRLeft);
+ int& rCurrentCellX((Destination::NESTEDTABLEPROPERTIES == aDestination)
+ ? m_nNestedCurrentCellX
+ : m_nTopLevelCurrentCellX);
+ rCurrentTRLeft = rCurrentCellX = nParam;
+ return true;
+ }
+ break;
+ case RTFKeyword::CLSHDNG:
+ {
+ int nValue = -1;
+
+ if (nParam < 1)
+ nValue = NS_ooxml::LN_Value_ST_Shd_clear;
+ else if (nParam < 750)
+ // Values in between 1 and 250 visually closer to 0% shading (white)
+ // But this will mean "no shading" while cell actually have some.
+ // So lets use minimal available value.
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct5;
+ else if (nParam < 1100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct10;
+ else if (nParam < 1350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct12;
+ else if (nParam < 1750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct15;
+ else if (nParam < 2250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct20;
+ else if (nParam < 2750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct25;
+ else if (nParam < 3250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct30;
+ else if (nParam < 3600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct35;
+ else if (nParam < 3850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct37;
+ else if (nParam < 4250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct40;
+ else if (nParam < 4750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct45;
+ else if (nParam < 5250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct50;
+ else if (nParam < 5750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct55;
+ else if (nParam < 6100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct60;
+ else if (nParam < 6350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct62;
+ else if (nParam < 6750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct65;
+ else if (nParam < 7250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct70;
+ else if (nParam < 7750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct75;
+ else if (nParam < 8250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct80;
+ else if (nParam < 8600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct85;
+ else if (nParam < 8850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct87;
+ else if (nParam < 9250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct90;
+ else if (nParam < 9750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct95;
+ else
+ // Solid fill
+ nValue = NS_ooxml::LN_Value_ST_Shd_solid;
+
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
+ NS_ooxml::LN_CT_Shd_val, new RTFValue(nValue));
+ return true;
+ }
+ break;
+ case RTFKeyword::CLPADB:
+ case RTFKeyword::CLPADL:
+ case RTFKeyword::CLPADR:
+ case RTFKeyword::CLPADT:
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ // Top and left is swapped, that's what Word does.
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLPADB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::CLPADL:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ case RTFKeyword::CLPADR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::CLPADT:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ break;
+ case RTFKeyword::TRPADDFB:
+ case RTFKeyword::TRPADDFL:
+ case RTFKeyword::TRPADDFR:
+ case RTFKeyword::TRPADDFT:
+ {
+ RTFSprms aAttributes;
+ switch (nParam)
+ {
+ case 3:
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ break;
+ }
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRPADDFB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::TRPADDFL:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ case RTFKeyword::TRPADDFR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::TRPADDFT:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ default:
+ break;
+ }
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar, nSprm,
+ new RTFValue(aAttributes));
+ // tdf#74795 also set on current cell, and as default for table cells
+ // (why isn't this done by domainmapper?)
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ putNestedAttribute(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ break;
+ case RTFKeyword::TRPADDB:
+ case RTFKeyword::TRPADDL:
+ case RTFKeyword::TRPADDR:
+ case RTFKeyword::TRPADDT:
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRPADDB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::TRPADDL:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ case RTFKeyword::TRPADDR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::TRPADDT:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ nSprm, new RTFValue(aAttributes));
+ // tdf#74795 also set on current cell, and as default for table cells
+ // (why isn't this done by domainmapper?)
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ putNestedSprm(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ case RTFKeyword::TRGAPH:
+ // Half of the space between the cells of a table row: default left/right table cell margin.
+ if (nParam > 0)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, pIntValue);
+ // FIXME: this is wrong, it is half-gap, needs to be distinguished from margin! depending on TRPADDFL/TRPADDFR
+ putNestedSprm(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_left,
+ new RTFValue(aAttributes));
+ putNestedSprm(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
+ }
+ return true;
+ case RTFKeyword::TRFTSWIDTH:
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_type, pIntValue);
+ return true;
+ case RTFKeyword::TRWWIDTH:
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_w, pIntValue);
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/nKeyword != RTFKeyword::U, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+ // Trivial table sprms.
+ if (dispatchTableSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial character sprms.
+ if (dispatchCharacterSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial character attributes.
+ if (dispatchCharacterAttributeValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial paragraph sprms.
+ if (dispatchParagraphSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Info group.
+ if (dispatchInfoValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Frame size / position.
+ if (dispatchFrameValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Table-related values.
+ if (dispatchTableValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Then check for the more complex ones.
+ switch (nKeyword)
+ {
+ case RTFKeyword::F:
+ case RTFKeyword::AF:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_CT_Fonts_cs;
+ break;
+ case RTFParserState::RunType::DBCH:
+ nSprm = NS_ooxml::LN_CT_Fonts_eastAsia;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ default:
+ nSprm = NS_ooxml::LN_CT_Fonts_ascii;
+ break;
+ }
+
+ if (m_aStates.top().getDestination() == Destination::FONTTABLE
+ || m_aStates.top().getDestination() == Destination::FONTENTRY)
+ {
+ // Some text in buffer? It is font name. So previous font definition is complete
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
+ m_aFontIndexes.push_back(nParam);
+ m_nCurrentFontIndex = getFontIndex(nParam);
+ }
+ else if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ RTFSprms aFontAttributes;
+ aFontAttributes.set(nSprm, new RTFValue(m_aFontNames[getFontIndex(nParam)]));
+ RTFSprms aRunPropsSprms;
+ aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aFontAttributes));
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_rPr,
+ new RTFValue(RTFSprms(), aRunPropsSprms),
+ RTFOverwrite::NO_APPEND);
+ }
+ else
+ {
+ m_nCurrentFontIndex = getFontIndex(nParam);
+ auto pValue = new RTFValue(getFontName(m_nCurrentFontIndex));
+ putNestedAttribute(m_aStates.top().getCharacterSprms(),
+ NS_ooxml::LN_EG_RPrBase_rFonts, nSprm, pValue);
+ if (nKeyword == RTFKeyword::F)
+ m_aStates.top().setCurrentEncoding(getEncoding(m_nCurrentFontIndex));
+ }
+ break;
+ case RTFKeyword::RED:
+ m_aStates.top().getCurrentColor().SetRed(nParam);
+ break;
+ case RTFKeyword::GREEN:
+ m_aStates.top().getCurrentColor().SetGreen(nParam);
+ break;
+ case RTFKeyword::BLUE:
+ m_aStates.top().getCurrentColor().SetBlue(nParam);
+ break;
+ case RTFKeyword::FCHARSET:
+ {
+ // we always send text to the domain mapper in OUString, so no
+ // need to send encoding info
+ int i;
+ for (i = 0; i < nRTFEncodings; i++)
+ {
+ if (aRTFEncodings[i].charset == nParam)
+ break;
+ }
+ if (i == nRTFEncodings)
+ // not found
+ return RTFError::OK;
+
+ m_nCurrentEncoding
+ = aRTFEncodings[i].codepage == 0 // Default (CP_ACP)
+ ? osl_getThreadTextEncoding()
+ : rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage);
+ m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
+ }
+ break;
+ case RTFKeyword::ANSICPG:
+ case RTFKeyword::CPG:
+ {
+ rtl_TextEncoding nEncoding
+ = (nParam == 0)
+ ? utl_getWinTextEncodingFromLangStr(utl_getLocaleForGlobalDefaultEncoding())
+ : rtl_getTextEncodingFromWindowsCodePage(nParam);
+ if (nKeyword == RTFKeyword::ANSICPG)
+ m_aDefaultState.setCurrentEncoding(nEncoding);
+ else
+ m_nCurrentEncoding = nEncoding;
+ m_aStates.top().setCurrentEncoding(nEncoding);
+ }
+ break;
+ case RTFKeyword::CF:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_color,
+ new RTFValue(aAttributes));
+ }
+ break;
+ case RTFKeyword::S:
+ {
+ m_aStates.top().setCurrentStyleIndex(nParam);
+
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // paragraph style
+ }
+ else
+ {
+ OUString aName = getStyleName(nParam);
+ if (!aName.isEmpty())
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_pStyle,
+ new RTFValue(aName));
+ else
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ new RTFValue(aName));
+ }
+ }
+ }
+ break;
+ case RTFKeyword::CS:
+ m_aStates.top().setCurrentCharacterStyleIndex(nParam);
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_character);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // character style
+ }
+ else
+ {
+ OUString aName = getStyleName(nParam);
+ if (!aName.isEmpty())
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_rStyle,
+ new RTFValue(aName));
+ }
+ break;
+ case RTFKeyword::DS:
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(0); // TODO no value in enum StyleType?
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // section style
+ }
+ break;
+ case RTFKeyword::TS:
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ // FIXME the correct value would be NS_ooxml::LN_Value_ST_StyleType_table but maybe table styles mess things up in dmapper, be cautious and disable them for now
+ auto pValue = new RTFValue(0);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // table style
+ }
+ break;
+ case RTFKeyword::DEFF:
+ m_nDefaultFontIndex = nParam;
+ break;
+ case RTFKeyword::STSHFDBCH:
+ // tdf#123703 switch off longer space sequence except in the case of the fixed compatibility setting font id 31505
+ if (nParam != 31505)
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::DEFLANG:
+ case RTFKeyword::ADEFLANG:
+ {
+ LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
+ auto pValue = new RTFValue(aTag.getBcp47());
+ putNestedAttribute(m_aStates.top().getCharacterSprms(),
+ (nKeyword == RTFKeyword::DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang
+ : NS_ooxml::LN_CT_Language_bidi),
+ nSprm, pValue);
+ }
+ break;
+ case RTFKeyword::CHCBPAT:
+ {
+ auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::CLCBPAT:
+ case RTFKeyword::CLCBPATRAW:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::CBPAT:
+ if (nParam)
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::ULC:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ m_aStates.top().getCharacterSprms().set(0x6877, pValue);
+ }
+ break;
+ case RTFKeyword::HIGHLIGHT:
+ {
+ auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_highlight, pValue);
+ }
+ break;
+ case RTFKeyword::UP:
+ case RTFKeyword::DN:
+ {
+ auto pValue = new RTFValue(nParam * (nKeyword == RTFKeyword::UP ? 1 : -1));
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_position, pValue);
+ }
+ break;
+ case RTFKeyword::HORZVERT:
+ {
+ auto pValue = new RTFValue(int(true));
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_vert,
+ pValue);
+ if (nParam)
+ // rotate fits to a single line
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue);
+ }
+ break;
+ case RTFKeyword::EXPND:
+ {
+ // Convert quarter-points to twentieths of a point
+ auto pValue = new RTFValue(nParam * 5);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_spacing, pValue);
+ }
+ break;
+ case RTFKeyword::TWOINONE:
+ {
+ auto pValue = new RTFValue(int(true));
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_combine,
+ pValue);
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_none;
+ break;
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_round;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_square;
+ break;
+ case 3:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_angle;
+ break;
+ case 4:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_curly;
+ break;
+ }
+ if (nId > 0)
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, new RTFValue(nId));
+ }
+ break;
+ case RTFKeyword::SL:
+ {
+ // This is similar to RTFKeyword::ABSH, negative value means 'exact', positive means 'at least'.
+ tools::SvRef<RTFValue> pValue(
+ new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast));
+ if (nParam < 0)
+ {
+ pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact);
+ pIntValue = new RTFValue(-nParam);
+ }
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, pValue);
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_line, pIntValue);
+ }
+ break;
+ case RTFKeyword::SLMULT:
+ if (nParam > 0)
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule,
+ pValue);
+ }
+ break;
+ case RTFKeyword::BRDRW:
+ {
+ // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0
+ if (nParam > 1)
+ nParam = nParam * 2 / 5;
+ auto pValue = new RTFValue(nParam);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_sz, pValue);
+ }
+ break;
+ case RTFKeyword::BRDRCF:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue);
+ }
+ break;
+ case RTFKeyword::BRSP:
+ {
+ // dmapper expects it in points, we have it in twip
+ auto pValue = new RTFValue(nParam / 20);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_space, pValue);
+ }
+ break;
+ case RTFKeyword::TX:
+ {
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_pos, pIntValue);
+ auto pValue = new RTFValue(m_aStates.top().getTabAttributes());
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
+ NS_ooxml::LN_CT_Tabs_tab, pValue);
+ else
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
+ NS_ooxml::LN_CT_Tabs_tab, pValue);
+ m_aStates.top().getTabAttributes().clear();
+ }
+ break;
+ case RTFKeyword::ILVL:
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_ilvl, pIntValue);
+ break;
+ case RTFKeyword::LISTTEMPLATEID:
+ // This one is not referenced anywhere, so it's pointless to store it at the moment.
+ break;
+ case RTFKeyword::LISTID:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTENTRY)
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_abstractNumId,
+ pIntValue);
+ else if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue);
+ m_aStates.top().setCurrentListIndex(nParam);
+ }
+ break;
+ case RTFKeyword::LS:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ {
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid,
+ pIntValue);
+ m_aStates.top().setCurrentListOverrideIndex(nParam);
+ }
+ else
+ {
+ // Insert at the start, so properties inherited from the list
+ // can be overridden by direct formatting. But still allow the
+ // case when old-style paragraph numbering is already
+ // tokenized.
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_numId, pIntValue, RTFOverwrite::YES_PREPEND);
+ }
+ }
+ break;
+ case RTFKeyword::UC:
+ if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16))
+ m_aStates.top().setUc(nParam);
+ break;
+ case RTFKeyword::U:
+ // sal_Unicode is unsigned 16-bit, RTF may represent that as a
+ // signed SAL_MIN_INT16..SAL_MAX_INT16 or 0..SAL_MAX_UINT16. The
+ // static_cast() will do the right thing.
+ if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_UINT16))
+ {
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
+ {
+ if (nParam != ';')
+ m_aStates.top().getLevelNumbers().push_back(sal_Int32(nParam));
+ else
+ // ';' in \u form is not considered valid.
+ m_aStates.top().setLevelNumbersValid(false);
+ }
+ else
+ m_aUnicodeBuffer.append(static_cast<sal_Unicode>(nParam));
+ m_aStates.top().getCharsToSkip() = m_aStates.top().getUc();
+ }
+ break;
+ case RTFKeyword::LEVELFOLLOW:
+ {
+ OUString sValue;
+ switch (nParam)
+ {
+ case 0:
+ sValue = "tab";
+ break;
+ case 1:
+ sValue = "space";
+ break;
+ case 2:
+ sValue = "nothing";
+ break;
+ }
+ if (!sValue.isEmpty())
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_suff, new RTFValue(sValue));
+ }
+ break;
+ case RTFKeyword::FPRQ:
+ {
+ sal_Int32 nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_default;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_fixed;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_variable;
+ break;
+ }
+ if (nValue)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Pitch_val, new RTFValue(nValue));
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Font_pitch,
+ new RTFValue(aAttributes));
+ }
+ }
+ break;
+ case RTFKeyword::LISTOVERRIDECOUNT:
+ // Ignore this for now, the exporter always emits it with a zero parameter.
+ break;
+ case RTFKeyword::PICSCALEX:
+ m_aStates.top().getPicture().nScaleX = nParam;
+ break;
+ case RTFKeyword::PICSCALEY:
+ m_aStates.top().getPicture().nScaleY = nParam;
+ break;
+ case RTFKeyword::PICW:
+ m_aStates.top().getPicture().nWidth = nParam;
+ break;
+ case RTFKeyword::PICH:
+ m_aStates.top().getPicture().nHeight = nParam;
+ break;
+ case RTFKeyword::PICWGOAL:
+ m_aStates.top().getPicture().nGoalWidth = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICHGOAL:
+ m_aStates.top().getPicture().nGoalHeight = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPL:
+ m_aStates.top().getPicture().nCropL = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPR:
+ m_aStates.top().getPicture().nCropR = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPT:
+ m_aStates.top().getPicture().nCropT = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPB:
+ m_aStates.top().getPicture().nCropB = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::SHPWRK:
+ {
+ int nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right;
+ break;
+ case 3:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest;
+ break;
+ default:
+ break;
+ }
+ auto pValue = new RTFValue(nValue);
+ RTFValue::Pointer_t pTight
+ = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_WrapType_wrapTight);
+ if (pTight)
+ pTight->getAttributes().set(NS_ooxml::LN_CT_WrapTight_wrapText, pValue);
+ else
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_WrapSquare_wrapText,
+ pValue);
+ }
+ break;
+ case RTFKeyword::SHPWR:
+ {
+ switch (nParam)
+ {
+ case 1:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_NONE);
+ break;
+ case 2:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
+ break;
+ case 3:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapNone,
+ new RTFValue());
+ break;
+ case 4:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapTight,
+ new RTFValue());
+ break;
+ case 5:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
+ break;
+ }
+ }
+ break;
+ case RTFKeyword::COLS:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num,
+ pIntValue);
+ break;
+ case RTFKeyword::COLSX:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space,
+ pIntValue);
+ break;
+ case RTFKeyword::COLNO:
+ putNestedSprm(m_aStates.top().getSectionSprms(), NS_ooxml::LN_EG_SectPrContents_cols,
+ NS_ooxml::LN_CT_Columns_col, pIntValue);
+ break;
+ case RTFKeyword::COLW:
+ case RTFKeyword::COLSR:
+ {
+ RTFSprms& rAttributes = getLastAttributes(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols);
+ rAttributes.set((nKeyword == RTFKeyword::COLW ? NS_ooxml::LN_CT_Column_w
+ : NS_ooxml::LN_CT_Column_space),
+ pIntValue);
+ }
+ break;
+ case RTFKeyword::PAPERH:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::PGHSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
+ pIntValue);
+ break;
+ case RTFKeyword::PAPERW:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::PGWSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGL:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGLSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGR:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGRSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGT:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGTSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGB:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGBSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
+ pIntValue);
+ break;
+ case RTFKeyword::HEADERY:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header,
+ pIntValue);
+ break;
+ case RTFKeyword::FOOTERY:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer,
+ pIntValue);
+ break;
+ case RTFKeyword::GUTTER:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_gutter,
+ pIntValue);
+ break;
+ case RTFKeyword::DEFTAB:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue);
+ break;
+ case RTFKeyword::LINEMOD:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_countBy, pIntValue);
+ break;
+ case RTFKeyword::LINEX:
+ if (nParam)
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_distance, pIntValue);
+ break;
+ case RTFKeyword::LINESTARTS:
+ {
+ // OOXML <w:lnNumType w:start="..."/> is 0-based, RTF is 1-based.
+ auto pStart = tools::make_ref<RTFValue>(nParam - 1);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_start, pStart);
+ }
+ break;
+ case RTFKeyword::REVAUTH:
+ case RTFKeyword::REVAUTHDEL:
+ {
+ auto pValue = new RTFValue(m_aAuthors[nParam]);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_CT_TrackChange_author, pValue);
+ }
+ break;
+ case RTFKeyword::REVDTTM:
+ case RTFKeyword::REVDTTMDEL:
+ {
+ OUString aStr(
+ OStringToOUString(DTTM22OString(nParam), m_aStates.top().getCurrentEncoding()));
+ auto pValue = new RTFValue(aStr);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_CT_TrackChange_date, pValue);
+ }
+ break;
+ case RTFKeyword::SHPLEFT:
+ m_aStates.top().getShape().setLeft(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPTOP:
+ m_aStates.top().getShape().setTop(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPRIGHT:
+ m_aStates.top().getShape().setRight(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPBOTTOM:
+ m_aStates.top().getShape().setBottom(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPZ:
+ m_aStates.top().getShape().setZ(nParam);
+ break;
+ case RTFKeyword::FFTYPE:
+ switch (nParam)
+ {
+ case 0:
+ m_nFormFieldType = RTFFormFieldType::TEXT;
+ break;
+ case 1:
+ m_nFormFieldType = RTFFormFieldType::CHECKBOX;
+ break;
+ case 2:
+ m_nFormFieldType = RTFFormFieldType::LIST;
+ break;
+ default:
+ m_nFormFieldType = RTFFormFieldType::NONE;
+ break;
+ }
+ break;
+ case RTFKeyword::FFDEFRES:
+ if (m_nFormFieldType == RTFFormFieldType::CHECKBOX)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_default, pIntValue);
+ else if (m_nFormFieldType == RTFFormFieldType::LIST)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_default, pIntValue);
+ break;
+ case RTFKeyword::FFRES:
+ // 25 means undefined, see [MS-DOC] 2.9.79, FFDataBits.
+ if (m_nFormFieldType == RTFFormFieldType::CHECKBOX && nParam != 25)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_checked, pIntValue);
+ else if (m_nFormFieldType == RTFFormFieldType::LIST)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_result, pIntValue);
+ break;
+ case RTFKeyword::EDMINS:
+ if (m_xDocumentProperties.is())
+ {
+ // tdf#116851 some RTF may be malformed
+ if (nParam < 0)
+ nParam = -nParam;
+ m_xDocumentProperties->setEditingDuration(nParam);
+ }
+ break;
+ case RTFKeyword::NOFPAGES:
+ case RTFKeyword::NOFWORDS:
+ case RTFKeyword::NOFCHARS:
+ case RTFKeyword::NOFCHARSWS:
+ if (m_xDocumentProperties.is())
+ {
+ comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics();
+ OUString aName;
+ switch (nKeyword)
+ {
+ case RTFKeyword::NOFPAGES:
+ aName = "PageCount";
+ nParam = 99;
+ break;
+ case RTFKeyword::NOFWORDS:
+ aName = "WordCount";
+ break;
+ case RTFKeyword::NOFCHARS:
+ aName = "CharacterCount";
+ break;
+ case RTFKeyword::NOFCHARSWS:
+ aName = "NonWhitespaceCharacterCount";
+ break;
+ default:
+ break;
+ }
+ if (!aName.isEmpty())
+ {
+ aSeq[aName] <<= sal_Int32(nParam);
+ m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList());
+ }
+ }
+ break;
+ case RTFKeyword::VERSION:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setEditingCycles(nParam);
+ break;
+ case RTFKeyword::VERN:
+ // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers.
+ break;
+ case RTFKeyword::FTNSTART:
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
+ break;
+ case RTFKeyword::AFTNSTART:
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_endnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
+ break;
+ case RTFKeyword::DFRMTXTX:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
+ break;
+ case RTFKeyword::DFRMTXTY:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
+ break;
+ case RTFKeyword::DXFRTEXT:
+ {
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
+ }
+ break;
+ case RTFKeyword::FLYVERT:
+ {
+ RTFVertOrient aVertOrient(nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ aVertOrient.GetAlign());
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ aVertOrient.GetAnchor());
+ }
+ break;
+ case RTFKeyword::FLYHORZ:
+ {
+ RTFHoriOrient aHoriOrient(nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ aHoriOrient.GetAlign());
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ aHoriOrient.GetAnchor());
+ }
+ break;
+ case RTFKeyword::FLYANCHOR:
+ break;
+ case RTFKeyword::WMETAFILE:
+ m_aStates.top().getPicture().eWMetafile = nParam;
+ break;
+ case RTFKeyword::SB:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_before, pIntValue);
+ break;
+ case RTFKeyword::SA:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_after, pIntValue);
+ break;
+ case RTFKeyword::DPX:
+ m_aStates.top().getDrawingObject().setLeft(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPY:
+ m_aStates.top().getDrawingObject().setTop(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPXSIZE:
+ m_aStates.top().getDrawingObject().setRight(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPYSIZE:
+ m_aStates.top().getDrawingObject().setBottom(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::PNSTART:
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_start, pIntValue);
+ break;
+ case RTFKeyword::PNF:
+ {
+ auto pValue = new RTFValue(m_aFontNames[getFontIndex(nParam)]);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Fonts_ascii, pValue);
+ putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_rPr,
+ NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aAttributes));
+ }
+ break;
+ case RTFKeyword::VIEWSCALE:
+ m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue);
+ break;
+ case RTFKeyword::BIN:
+ {
+ m_aStates.top().setInternalState(RTFInternalState::BIN);
+ m_aStates.top().setBinaryToRead(nParam);
+ }
+ break;
+ case RTFKeyword::DPLINECOR:
+ m_aStates.top().getDrawingObject().setLineColorR(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPLINECOG:
+ m_aStates.top().getDrawingObject().setLineColorG(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPLINECOB:
+ m_aStates.top().getDrawingObject().setLineColorB(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCR:
+ m_aStates.top().getDrawingObject().setFillColorR(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCG:
+ m_aStates.top().getDrawingObject().setFillColorG(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCB:
+ m_aStates.top().getDrawingObject().setFillColorB(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DODHGT:
+ m_aStates.top().getDrawingObject().setDhgt(nParam);
+ break;
+ case RTFKeyword::DPPOLYCOUNT:
+ if (nParam >= 0)
+ {
+ m_aStates.top().getDrawingObject().setPolyLineCount(nParam);
+ }
+ break;
+ case RTFKeyword::DPPTX:
+ {
+ RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
+
+ if (rDrawingObject.getPolyLinePoints().empty())
+ dispatchValue(RTFKeyword::DPPOLYCOUNT, 2);
+
+ rDrawingObject.getPolyLinePoints().emplace_back(convertTwipToMm100(nParam), 0);
+ }
+ break;
+ case RTFKeyword::DPPTY:
+ {
+ RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
+ if (!rDrawingObject.getPolyLinePoints().empty())
+ {
+ rDrawingObject.getPolyLinePoints().back().Y = convertTwipToMm100(nParam);
+ rDrawingObject.setPolyLineCount(rDrawingObject.getPolyLineCount() - 1);
+ if (rDrawingObject.getPolyLineCount() == 0 && rDrawingObject.getPropertySet().is())
+ {
+ uno::Sequence<uno::Sequence<awt::Point>> aPointSequenceSequence
+ = { comphelper::containerToSequence(rDrawingObject.getPolyLinePoints()) };
+ rDrawingObject.getPropertySet()->setPropertyValue(
+ "PolyPolygon", uno::Any(aPointSequenceSequence));
+ }
+ }
+ }
+ break;
+ case RTFKeyword::SHPFBLWTXT:
+ // Shape is below text -> send it to the background.
+ m_aStates.top().getShape().setInBackground(nParam != 0);
+ break;
+ case RTFKeyword::FI:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ if (m_aStates.top().getLevelNumbersValid())
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
+ else
+ m_aInvalidListLevelFirstIndents[m_nListLevel] = nParam;
+ }
+ else
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
+ break;
+ }
+ case RTFKeyword::LI:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ if (m_aStates.top().getLevelNumbersValid())
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_left, pIntValue);
+ }
+ else
+ {
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_left, pIntValue);
+ }
+ // It turns out \li should reset the \fi inherited from the stylesheet.
+ // So set the direct formatting to zero, if we don't have such direct formatting yet.
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, new RTFValue(0),
+ RTFOverwrite::NO_IGNORE);
+ }
+ break;
+ case RTFKeyword::RI:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_right, pIntValue);
+ break;
+ case RTFKeyword::LIN:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_start, pIntValue);
+ break;
+ case RTFKeyword::RIN:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_end, pIntValue);
+ break;
+ case RTFKeyword::OUTLINELEVEL:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue);
+ break;
+ case RTFKeyword::PROPTYPE:
+ {
+ switch (nParam)
+ {
+ case 3:
+ m_aStates.top().setPropType(cppu::UnoType<sal_Int32>::get());
+ break;
+ case 5:
+ m_aStates.top().setPropType(cppu::UnoType<double>::get());
+ break;
+ case 11:
+ m_aStates.top().setPropType(cppu::UnoType<bool>::get());
+ break;
+ case 30:
+ m_aStates.top().setPropType(cppu::UnoType<OUString>::get());
+ break;
+ case 64:
+ m_aStates.top().setPropType(cppu::UnoType<util::DateTime>::get());
+ break;
+ }
+ }
+ break;
+ case RTFKeyword::DIBITMAP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::DIBITMAP;
+ break;
+ case RTFKeyword::TRWWIDTHA:
+ m_aStates.top().setTableRowWidthAfter(nParam);
+ break;
+ case RTFKeyword::ANIMTEXT:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_TextEffect_none;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_TextEffect_blinkBackground;
+ break;
+ }
+
+ if (nId > 0)
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_effect,
+ new RTFValue(nId));
+ break;
+ }
+ case RTFKeyword::VIEWBKSP:
+ {
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_displayBackgroundShape, pIntValue);
+ // Send this token immediately, if it only appears before the first
+ // run, it will be too late, we ignored the background shape already by then.
+ outputSettingsTable();
+ break;
+ }
+ case RTFKeyword::STEXTFLOW:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_TextDirection_lrTb;
+ break;
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_TextDirection_tbRl;
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection,
+ new RTFValue(nId));
+ }
+ }
+ break;
+ case RTFKeyword::LBR:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_BrClear_left;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_BrClear_right;
+ break;
+ case 3:
+ nId = NS_ooxml::LN_Value_ST_BrClear_all;
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Br_clear,
+ new RTFValue(nId));
+ }
+ }
+ break;
+ case RTFKeyword::PGBRDROPT:
+ {
+ sal_Int16 nOffsetFrom = (nParam & 0xe0) >> 5;
+ bool bFromEdge = nOffsetFrom == 1;
+ if (bFromEdge)
+ {
+ Id nId = NS_ooxml::LN_Value_doc_ST_PageBorderOffset_page;
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders,
+ NS_ooxml::LN_CT_PageBorders_offsetFrom, new RTFValue(nId));
+ }
+ }
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter", "TODO handle value '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+} // namespace rtftok
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdocumentfactory.cxx b/writerfilter/source/rtftok/rtfdocumentfactory.cxx
new file mode 100644
index 000000000..75b109b68
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdocumentfactory.cxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfdocumentimpl.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFDocument::Pointer_t RTFDocumentFactory::createDocument(
+ css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor)
+{
+ return new RTFDocumentImpl(xContext, xInputStream, xDstDoc, xFrame, xStatusIndicator,
+ rMediaDescriptor);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
new file mode 100644
index 000000000..4011a17d5
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -0,0 +1,3992 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfdocumentimpl.hxx"
+#include <algorithm>
+#include <memory>
+#include <string_view>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XDependentTextField.hpp>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <filter/msfilter/util.hxx>
+#include <filter/msfilter/rtfutil.hxx>
+#include <comphelper/string.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/globname.hxx>
+#include <tools/datetimeutils.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <svl/lngmisc.hxx>
+#include <sfx2/sfxbasemodel.hxx>
+#include <sfx2/classificationhelper.hxx>
+#include <oox/mathml/import.hxx>
+#include <ooxml/resourceids.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <rtl/uri.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <oox/helper/graphichelper.hxx>
+#include <vcl/wmfexternal.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include "rtfsdrimport.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+#include "rtftokenizer.hxx"
+#include "rtflookahead.hxx"
+#include "rtfcharsets.hxx"
+
+using namespace com::sun::star;
+
+namespace
+{
+/// Returns an util::DateTime from a 'YYYY. MM. DD.' string.
+util::DateTime getDateTimeFromUserProp(const OUString& rString)
+{
+ util::DateTime aRet;
+ sal_Int32 nLen = rString.getLength();
+ if (nLen >= 4)
+ {
+ aRet.Year = o3tl::toInt32(rString.subView(0, 4));
+
+ if (nLen >= 8 && rString.match(". ", 4))
+ {
+ aRet.Month = o3tl::toInt32(rString.subView(6, 2));
+
+ if (nLen >= 12 && rString.match(". ", 8))
+ aRet.Day = o3tl::toInt32(rString.subView(10, 2));
+ }
+ }
+ return aRet;
+}
+} // anonymous namespace
+
+namespace writerfilter::rtftok
+{
+Id getParagraphBorder(sal_uInt32 nIndex)
+{
+ static const Id aBorderIds[]
+ = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left, NS_ooxml::LN_CT_PBdr_bottom,
+ NS_ooxml::LN_CT_PBdr_right, NS_ooxml::LN_CT_PBdr_between };
+
+ return aBorderIds[nIndex];
+}
+
+void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite, bool bAttribute)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent, /*bFirst=*/true, /*bForWrite=*/true);
+ if (!pParent)
+ {
+ RTFSprms aAttributes;
+ if (nParent == NS_ooxml::LN_CT_TcPrBase_shd)
+ {
+ // RTF default is 'auto', see writerfilter::dmapper::CellColorHandler
+ aAttributes.set(NS_ooxml::LN_CT_Shd_color, new RTFValue(sal_uInt32(COL_AUTO)));
+ aAttributes.set(NS_ooxml::LN_CT_Shd_fill, new RTFValue(sal_uInt32(COL_AUTO)));
+ }
+ auto pParentValue = new RTFValue(aAttributes);
+ rSprms.set(nParent, pParentValue, eOverwrite);
+ pParent = pParentValue;
+ }
+ RTFSprms& rAttributes = (bAttribute ? pParent->getAttributes() : pParent->getSprms());
+ rAttributes.set(nId, pValue, eOverwrite);
+}
+
+void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite)
+{
+ putNestedAttribute(rSprms, nParent, nId, pValue, eOverwrite, false);
+}
+
+RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ return RTFValue::Pointer_t();
+ RTFSprms& rAttributes = pParent->getAttributes();
+ return rAttributes.find(nId);
+}
+
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ return RTFValue::Pointer_t();
+ RTFSprms& rInner = pParent->getSprms();
+ return rInner.find(nId);
+}
+
+bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ // It doesn't even have a parent, we're done.
+ return false;
+ RTFSprms& rAttributes = pParent->getAttributes();
+ return rAttributes.erase(nId);
+}
+
+RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId)
+{
+ RTFValue::Pointer_t p = rSprms.find(nId);
+ if (p && !p->getSprms().empty())
+ return p->getSprms().back().second->getAttributes();
+
+ SAL_WARN("writerfilter.rtf", "trying to set property when no type is defined");
+ return rSprms;
+}
+
+void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue)
+{
+ RTFSprms* pAttributes = nullptr;
+ if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH_BOX)
+ for (int i = 0; i < 4; i++)
+ {
+ RTFValue::Pointer_t p = aStates.top().getParagraphSprms().find(getParagraphBorder(i));
+ if (p)
+ {
+ RTFSprms& rAttributes = p->getAttributes();
+ rAttributes.set(nId, pValue);
+ }
+ }
+ else if (aStates.top().getBorderState() == RTFBorderState::CHARACTER)
+ {
+ RTFValue::Pointer_t pPointer
+ = aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_RPrBase_bdr);
+ if (pPointer)
+ {
+ RTFSprms& rAttributes = pPointer->getAttributes();
+ rAttributes.set(nId, pValue);
+ }
+ }
+ // Attributes of the last border type
+ else if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH)
+ pAttributes
+ = &getLastAttributes(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr);
+ else if (aStates.top().getBorderState() == RTFBorderState::CELL)
+ pAttributes = &getLastAttributes(aStates.top().getTableCellSprms(),
+ NS_ooxml::LN_CT_TcPrBase_tcBorders);
+ else if (aStates.top().getBorderState() == RTFBorderState::PAGE)
+ pAttributes = &getLastAttributes(aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders);
+ else if (aStates.top().getBorderState() == RTFBorderState::NONE)
+ {
+ // this is invalid, but Word apparently clears or overrides all paragraph borders now
+ for (int i = 0; i < 4; ++i)
+ {
+ auto const nBorder = getParagraphBorder(i);
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aAttributes.set(NS_ooxml::LN_CT_Border_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
+ putNestedSprm(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nBorder,
+ new RTFValue(aAttributes, aSprms), RTFOverwrite::YES);
+ }
+ }
+
+ if (pAttributes)
+ pAttributes->set(nId, pValue);
+}
+
+OString DTTM22OString(tools::Long nDTTM)
+{
+ return DateTimeToOString(msfilter::util::DTTM2DateTime(nDTTM));
+}
+
+static RTFSprms lcl_getBookmarkProperties(int nPos, const OUString& rString)
+{
+ RTFSprms aAttributes;
+ auto pPos = new RTFValue(nPos);
+ if (!rString.isEmpty())
+ {
+ // If present, this should be sent first.
+ auto pString = new RTFValue(rString);
+ aAttributes.set(NS_ooxml::LN_CT_Bookmark_name, pString);
+ }
+ aAttributes.set(NS_ooxml::LN_CT_MarkupRangeBookmark_id, pPos);
+ return aAttributes;
+}
+
+const char* keywordToString(RTFKeyword nKeyword)
+{
+ for (int i = 0; i < nRTFControlWords; i++)
+ {
+ if (nKeyword == aRTFControlWords[i].GetIndex())
+ return aRTFControlWords[i].GetKeyword();
+ }
+ return nullptr;
+}
+
+static util::DateTime lcl_getDateTime(RTFParserState const& aState)
+{
+ return { 0 /*100sec*/,
+ 0 /*sec*/,
+ aState.getMinute(),
+ aState.getHour(),
+ aState.getDay(),
+ aState.getMonth(),
+ static_cast<sal_Int16>(aState.getYear()),
+ false };
+}
+
+static void lcl_DestinationToMath(OUStringBuffer* pDestinationText,
+ oox::formulaimport::XmlStreamBuilder& rMathBuffer, bool& rMathNor)
+{
+ if (!pDestinationText)
+ return;
+ OUString aStr = pDestinationText->makeStringAndClear();
+ if (aStr.isEmpty())
+ return;
+ rMathBuffer.appendOpeningTag(M_TOKEN(r));
+ if (rMathNor)
+ {
+ rMathBuffer.appendOpeningTag(M_TOKEN(rPr));
+ // Same as M_TOKEN(lit)
+ rMathBuffer.appendOpeningTag(M_TOKEN(nor));
+ rMathBuffer.appendClosingTag(M_TOKEN(nor));
+ rMathBuffer.appendClosingTag(M_TOKEN(rPr));
+ rMathNor = false;
+ }
+ rMathBuffer.appendOpeningTag(M_TOKEN(t));
+ rMathBuffer.appendCharacters(aStr);
+ rMathBuffer.appendClosingTag(M_TOKEN(t));
+ rMathBuffer.appendClosingTag(M_TOKEN(r));
+}
+
+RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& xContext,
+ uno::Reference<io::XInputStream> const& xInputStream,
+ uno::Reference<lang::XComponent> const& xDstDoc,
+ uno::Reference<frame::XFrame> const& xFrame,
+ uno::Reference<task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor)
+ : m_xContext(xContext)
+ , m_xInputStream(xInputStream)
+ , m_xDstDoc(xDstDoc)
+ , m_xFrame(xFrame)
+ , m_xStatusIndicator(xStatusIndicator)
+ , m_pMapperStream(nullptr)
+ , m_aDefaultState(this)
+ , m_bSkipUnknown(false)
+ , m_bFirstRun(true)
+ , m_bFirstRunException(false)
+ , m_bNeedPap(true)
+ , m_bNeedCr(false)
+ , m_bNeedCrOrig(false)
+ , m_bNeedPar(true)
+ , m_bNeedFinalPar(false)
+ , m_nNestedCells(0)
+ , m_nTopLevelCells(0)
+ , m_nInheritingCells(0)
+ , m_nNestedTRLeft(0)
+ , m_nTopLevelTRLeft(0)
+ , m_nNestedCurrentCellX(0)
+ , m_nTopLevelCurrentCellX(0)
+ , m_nBackupTopLevelCurrentCellX(0)
+ , m_aTableBufferStack(1) // create top-level buffer already
+ , m_pSuperstream(nullptr)
+ , m_nStreamType(0)
+ , m_nGroupStartPos(0)
+ , m_nFormFieldType(RTFFormFieldType::NONE)
+ , m_bObject(false)
+ , m_nCurrentFontIndex(0)
+ , m_nCurrentEncoding(-1)
+ , m_nDefaultFontIndex(-1)
+ , m_pStyleTableEntries(new RTFReferenceTable::Entries_t)
+ , m_nCurrentStyleIndex(0)
+ , m_bFormField(false)
+ , m_bMathNor(false)
+ , m_bIgnoreNextContSectBreak(false)
+ , m_nResetBreakOnSectBreak(RTFKeyword::invalid)
+ , m_bNeedSect(false) // done by checkFirstRun
+ , m_bWasInFrame(false)
+ , m_bHadPicture(false)
+ , m_bHadSect(false)
+ , m_nCellxMax(0)
+ , m_nListPictureId(0)
+ , m_bIsNewDoc(!rMediaDescriptor.getUnpackedValueOrDefault("InsertMode", false))
+ , m_rMediaDescriptor(rMediaDescriptor)
+ , m_hasRHeader(false)
+ , m_hasFHeader(false)
+ , m_hasRFooter(false)
+ , m_hasFFooter(false)
+ , m_bAfterCellBeforeRow(false)
+{
+ OSL_ASSERT(xInputStream.is());
+ m_pInStream = utl::UcbStreamHelper::CreateStream(xInputStream, true);
+
+ m_xModelFactory.set(m_xDstDoc, uno::UNO_QUERY);
+
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
+ m_xDstDoc, uno::UNO_QUERY);
+ if (xDocumentPropertiesSupplier.is())
+ m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+
+ m_pGraphicHelper = std::make_shared<oox::GraphicHelper>(m_xContext, xFrame, oox::StorageRef());
+
+ m_pTokenizer = new RTFTokenizer(*this, m_pInStream.get(), m_xStatusIndicator);
+ m_pSdrImport = new RTFSdrImport(*this, m_xDstDoc);
+}
+
+RTFDocumentImpl::~RTFDocumentImpl() = default;
+
+SvStream& RTFDocumentImpl::Strm() { return *m_pInStream; }
+
+void RTFDocumentImpl::setSuperstream(RTFDocumentImpl* pSuperstream)
+{
+ m_pSuperstream = pSuperstream;
+}
+
+bool RTFDocumentImpl::isSubstream() const { return m_pSuperstream != nullptr; }
+
+void RTFDocumentImpl::finishSubstream() { checkUnicode(/*bUnicode =*/true, /*bHex =*/true); }
+
+void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId)
+{
+ resolveSubstream(nPos, nId, OUString());
+}
+void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst)
+{
+ sal_uInt64 const nCurrent = Strm().Tell();
+ // Seek to header position, parse, then seek back.
+ auto pImpl = new RTFDocumentImpl(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame,
+ m_xStatusIndicator, m_rMediaDescriptor);
+ pImpl->setSuperstream(this);
+ pImpl->m_nStreamType = nId;
+ pImpl->m_aIgnoreFirst = rIgnoreFirst;
+ if (!m_aAuthor.isEmpty())
+ {
+ pImpl->m_aAuthor = m_aAuthor;
+ m_aAuthor.clear();
+ }
+ if (!m_aAuthorInitials.isEmpty())
+ {
+ pImpl->m_aAuthorInitials = m_aAuthorInitials;
+ m_aAuthorInitials.clear();
+ }
+ pImpl->m_nDefaultFontIndex = m_nDefaultFontIndex;
+ pImpl->m_pStyleTableEntries = m_pStyleTableEntries;
+ pImpl->Strm().Seek(nPos);
+ SAL_INFO("writerfilter.rtf", "substream start");
+ Mapper().substream(nId, pImpl);
+ SAL_INFO("writerfilter.rtf", "substream end");
+ Strm().Seek(nCurrent);
+}
+
+void RTFDocumentImpl::outputSettingsTable()
+{
+ // tdf#136740: do not change target document settings when pasting
+ if (!m_bIsNewDoc)
+ return;
+ writerfilter::Reference<Properties>::Pointer_t pProp
+ = new RTFReferenceProperties(m_aSettingsTableAttributes, m_aSettingsTableSprms);
+ RTFReferenceTable::Entries_t aSettingsTableEntries;
+ aSettingsTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t pTable
+ = new RTFReferenceTable(std::move(aSettingsTableEntries));
+ Mapper().table(NS_ooxml::LN_settings_settings, pTable);
+}
+
+void RTFDocumentImpl::checkFirstRun()
+{
+ if (!m_bFirstRun)
+ return;
+
+ outputSettingsTable();
+ // start initial paragraph
+ m_bFirstRun = false;
+ assert(!m_bNeedSect || m_bFirstRunException);
+ setNeedSect(true); // first call that succeeds
+
+ // set the requested default font, if there are none for each state in stack
+ RTFValue::Pointer_t pFont
+ = getNestedAttribute(m_aDefaultState.getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii);
+ if (!pFont)
+ return;
+
+ for (size_t i = 0; i < m_aStates.size(); i++)
+ {
+ RTFValue::Pointer_t pCurrentFont
+ = getNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii);
+ if (!pCurrentFont)
+ putNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii, pFont);
+ }
+}
+
+void RTFDocumentImpl::setNeedPar(bool bNeedPar) { m_bNeedPar = bNeedPar; }
+
+void RTFDocumentImpl::setNeedSect(bool bNeedSect)
+{
+ if (!m_bNeedSect && bNeedSect && m_bFirstRun)
+ {
+ RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
+ if (aLookahead.hasTable() && aLookahead.hasColumns())
+ {
+ m_bFirstRunException = true;
+ }
+ }
+
+ // ignore setting before checkFirstRun - every keyword calls setNeedSect!
+ // except the case of a table in a multicolumn section
+ if (!m_bNeedSect && bNeedSect && (!m_bFirstRun || m_bFirstRunException))
+ {
+ if (!m_pSuperstream) // no sections in header/footer!
+ {
+ Mapper().startSectionGroup();
+ }
+ // set flag in substream too - otherwise multiple startParagraphGroup
+ m_bNeedSect = bNeedSect;
+ Mapper().startParagraphGroup();
+ setNeedPar(true);
+ }
+ else if (m_bNeedSect && !bNeedSect)
+ {
+ m_bNeedSect = bNeedSect;
+ }
+}
+
+/// Copy rProps to rStyleAttributes and rStyleSprms, but in case of nested sprms, copy their children as toplevel sprms/attributes.
+static void lcl_copyFlatten(RTFReferenceProperties& rProps, RTFSprms& rStyleAttributes,
+ RTFSprms& rStyleSprms)
+{
+ for (auto& rSprm : rProps.getSprms())
+ {
+ // createStyleProperties() puts properties to rPr, but here we need a flat list.
+ if (rSprm.first == NS_ooxml::LN_CT_Style_rPr)
+ {
+ // rPr can have both attributes and SPRMs, copy over both types.
+ RTFSprms& rRPrSprms = rSprm.second->getSprms();
+ for (const auto& rRPrSprm : rRPrSprms)
+ rStyleSprms.set(rRPrSprm.first, rRPrSprm.second);
+
+ RTFSprms& rRPrAttributes = rSprm.second->getAttributes();
+ for (const auto& rRPrAttribute : rRPrAttributes)
+ rStyleAttributes.set(rRPrAttribute.first, rRPrAttribute.second);
+ }
+ else
+ rStyleSprms.set(rSprm.first, rSprm.second);
+ }
+
+ RTFSprms& rAttributes = rProps.getAttributes();
+ for (const auto& rAttribute : rAttributes)
+ rStyleAttributes.set(rAttribute.first, rAttribute.second);
+}
+
+writerfilter::Reference<Properties>::Pointer_t
+RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType)
+{
+ RTFSprms aSprms(rSprms);
+ RTFValue::Pointer_t pAbstractList;
+ int nAbstractListId = -1;
+ RTFValue::Pointer_t pNumId
+ = getNestedSprm(aSprms, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_numId);
+ if (pNumId)
+ {
+ // We have a numbering, look up the abstract list for property
+ // deduplication and duplication.
+ auto itNumId = m_aListOverrideTable.find(pNumId->getInt());
+ if (itNumId != m_aListOverrideTable.end())
+ {
+ nAbstractListId = itNumId->second;
+ auto itAbstract = m_aListTable.find(nAbstractListId);
+ if (itAbstract != m_aListTable.end())
+ pAbstractList = itAbstract->second;
+ }
+ }
+
+ if (pAbstractList)
+ {
+ auto it = m_aInvalidListTableFirstIndents.find(nAbstractListId);
+ if (it != m_aInvalidListTableFirstIndents.end())
+ aSprms.deduplicateList(it->second);
+ }
+
+ int nStyle = 0;
+ if (!m_aStates.empty())
+ nStyle = m_aStates.top().getCurrentStyleIndex();
+ auto it = m_pStyleTableEntries->find(nStyle);
+ if (it != m_pStyleTableEntries->end())
+ {
+ // cloneAndDeduplicate() wants to know about only a single "style", so
+ // let's merge paragraph and character style properties here.
+ auto itChar = m_pStyleTableEntries->end();
+ if (!m_aStates.empty())
+ {
+ int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex();
+ itChar = m_pStyleTableEntries->find(nCharStyle);
+ }
+
+ RTFSprms aStyleSprms;
+ RTFSprms aStyleAttributes;
+ // Ensure the paragraph style is a flat list.
+ // Take paragraph style into account for character properties as well,
+ // as paragraph style may contain character properties.
+ RTFReferenceProperties& rProps = *static_cast<RTFReferenceProperties*>(it->second.get());
+ lcl_copyFlatten(rProps, aStyleAttributes, aStyleSprms);
+
+ if (itChar != m_pStyleTableEntries->end())
+ {
+ // Found active character style, then update aStyleSprms/Attributes.
+ if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ RTFReferenceProperties& rCharProps
+ = *static_cast<RTFReferenceProperties*>(itChar->second.get());
+ lcl_copyFlatten(rCharProps, aStyleAttributes, aStyleSprms);
+ }
+ }
+
+ // Get rid of direct formatting what is already in the style.
+ RTFSprms sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true, &aSprms));
+ RTFSprms attributes(rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true));
+ return new RTFReferenceProperties(std::move(attributes), std::move(sprms));
+ }
+
+ if (pAbstractList)
+ aSprms.duplicateList(pAbstractList);
+ writerfilter::Reference<Properties>::Pointer_t pRet
+ = new RTFReferenceProperties(rAttributes, std::move(aSprms));
+ return pRet;
+}
+
+void RTFDocumentImpl::checkNeedPap()
+{
+ if (!m_bNeedPap)
+ return;
+
+ m_bNeedPap = false; // reset early, so we can avoid recursion when calling ourselves
+
+ if (m_aStates.empty())
+ return;
+
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties(getProperties(
+ m_aStates.top().getParagraphAttributes(), m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_Value_ST_StyleType_paragraph));
+
+ // Writer will ignore a page break before a text frame, so guard it with empty paragraphs
+ bool hasBreakBeforeFrame
+ = m_aStates.top().getFrame().hasProperties()
+ && m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pageBreakBefore);
+ if (hasBreakBeforeFrame)
+ {
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bNeedPap = false;
+ }
+ Mapper().props(pParagraphProperties);
+ if (hasBreakBeforeFrame)
+ dispatchSymbol(RTFKeyword::PAR);
+
+ if (m_aStates.top().getFrame().hasProperties())
+ {
+ writerfilter::Reference<Properties>::Pointer_t const pFrameProperties(
+ new RTFReferenceProperties(RTFSprms(), m_aStates.top().getFrame().getSprms()));
+ Mapper().props(pFrameProperties);
+ }
+ }
+ else
+ {
+ auto pValue = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
+ }
+}
+
+void RTFDocumentImpl::runProps()
+{
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ Reference<Properties>::Pointer_t const pProperties = getProperties(
+ m_aStates.top().getCharacterAttributes(), m_aStates.top().getCharacterSprms(),
+ NS_ooxml::LN_Value_ST_StyleType_character);
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto pValue = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
+ }
+
+ // Delete the sprm, so the trackchange range will be started only once.
+ // OTOH set a boolean flag, so we'll know we need to end the range later.
+ RTFValue::Pointer_t pTrackchange
+ = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_trackchange);
+ if (pTrackchange)
+ {
+ m_aStates.top().setStartedTrackchange(true);
+ m_aStates.top().getCharacterSprms().erase(NS_ooxml::LN_trackchange);
+ }
+}
+
+void RTFDocumentImpl::runBreak()
+{
+ sal_uInt8 const sBreak[] = { 0xd };
+ Mapper().text(sBreak, 1);
+ m_bNeedCr = false;
+}
+
+void RTFDocumentImpl::tableBreak()
+{
+ runBreak();
+ Mapper().endParagraphGroup();
+ Mapper().startParagraphGroup();
+}
+
+void RTFDocumentImpl::parBreak()
+{
+ checkFirstRun();
+ checkNeedPap();
+ // end previous paragraph
+ Mapper().startCharacterGroup();
+ runBreak();
+ Mapper().endCharacterGroup();
+ Mapper().endParagraphGroup();
+
+ m_bHadPicture = false;
+
+ // start new one
+ Mapper().startParagraphGroup();
+}
+
+void RTFDocumentImpl::sectBreak(bool bFinal)
+{
+ SAL_INFO("writerfilter.rtf", __func__ << ": final? " << bFinal << ", needed? " << m_bNeedSect);
+ bool bNeedSect = m_bNeedSect;
+ RTFValue::Pointer_t pBreak
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ bool bContinuous = pBreak && pBreak->getInt() == NS_ooxml::LN_Value_ST_SectionMark_continuous;
+ // If there is no paragraph in this section, then insert a dummy one, as required by Writer,
+ // unless this is the end of the doc, we had nothing since the last section break and this is not a continuous one.
+ // Also, when pasting, it's fine to not have any paragraph inside the document at all.
+ if (m_bNeedPar && (!bFinal || m_bNeedSect || bContinuous) && !isSubstream() && m_bIsNewDoc)
+ dispatchSymbol(RTFKeyword::PAR);
+ // It's allowed to not have a non-table paragraph at the end of an RTF doc, add it now if required.
+ if (m_bNeedFinalPar && bFinal)
+ {
+ dispatchFlag(RTFKeyword::PARD);
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bNeedSect = bNeedSect;
+ }
+ while (!m_nHeaderFooterPositions.empty())
+ {
+ std::pair<Id, std::size_t> aPair = m_nHeaderFooterPositions.front();
+ m_nHeaderFooterPositions.pop();
+ resolveSubstream(aPair.second, aPair.first);
+ }
+
+ // Normally a section break at the end of the doc is necessary. Unless the
+ // last control word in the document is a section break itself.
+ if (!bNeedSect || !m_bHadSect)
+ {
+ // In case the last section is a continuous one, we don't need to output a section break.
+ if (bFinal && bContinuous)
+ m_aStates.top().getSectionSprms().erase(NS_ooxml::LN_EG_SectPrContents_type);
+ }
+
+ // Section properties are a paragraph sprm.
+ auto pValue
+ = new RTFValue(m_aStates.top().getSectionAttributes(), m_aStates.top().getSectionSprms());
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_CT_PPr_sectPr, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+
+ if (bFinal && !m_pSuperstream)
+ // This is the end of the document, not just the end of e.g. a header.
+ // This makes sure that dmapper can set DontBalanceTextColumns=true for this section if necessary.
+ Mapper().markLastSectionGroup();
+
+ // The trick is that we send properties of the previous section right now, which will be exactly what dmapper expects.
+ Mapper().props(pProperties);
+ Mapper().endParagraphGroup();
+
+ // End Section
+ if (!m_pSuperstream)
+ {
+ m_hasFHeader = false;
+ m_hasRHeader = false;
+ m_hasRFooter = false;
+ m_hasFFooter = false;
+ Mapper().endSectionGroup();
+ }
+ m_bNeedPar = false;
+ m_bNeedSect = false;
+}
+
+Color RTFDocumentImpl::getColorTable(sal_uInt32 nIndex)
+{
+ if (!m_pSuperstream)
+ {
+ if (nIndex < m_aColorTable.size())
+ return m_aColorTable[nIndex];
+ return 0;
+ }
+
+ return m_pSuperstream->getColorTable(nIndex);
+}
+
+rtl_TextEncoding RTFDocumentImpl::getEncoding(int nFontIndex)
+{
+ if (!m_pSuperstream)
+ {
+ auto it = m_aFontEncodings.find(nFontIndex);
+ if (it != m_aFontEncodings.end())
+ // We have a font encoding associated to this font.
+ return it->second;
+ if (m_aDefaultState.getCurrentEncoding() != rtl_getTextEncodingFromWindowsCharset(0))
+ // We have a default encoding.
+ return m_aDefaultState.getCurrentEncoding();
+ // Guess based on locale.
+ return msfilter::util::getBestTextEncodingFromLocale(
+ Application::GetSettings().GetLanguageTag().getLocale());
+ }
+
+ return m_pSuperstream->getEncoding(nFontIndex);
+}
+
+OUString RTFDocumentImpl::getFontName(int nIndex)
+{
+ if (!m_pSuperstream)
+ return m_aFontNames[nIndex];
+
+ return m_pSuperstream->getFontName(nIndex);
+}
+
+int RTFDocumentImpl::getFontIndex(int nIndex)
+{
+ if (!m_pSuperstream)
+ return std::find(m_aFontIndexes.begin(), m_aFontIndexes.end(), nIndex)
+ - m_aFontIndexes.begin();
+
+ return m_pSuperstream->getFontIndex(nIndex);
+}
+
+OUString RTFDocumentImpl::getStyleName(int nIndex)
+{
+ if (!m_pSuperstream)
+ {
+ OUString aRet;
+ if (m_aStyleNames.find(nIndex) != m_aStyleNames.end())
+ aRet = m_aStyleNames[nIndex];
+ return aRet;
+ }
+
+ return m_pSuperstream->getStyleName(nIndex);
+}
+
+Id RTFDocumentImpl::getStyleType(int nIndex)
+{
+ if (!m_pSuperstream)
+ {
+ Id nRet = 0;
+ if (m_aStyleTypes.find(nIndex) != m_aStyleTypes.end())
+ nRet = m_aStyleTypes[nIndex];
+ return nRet;
+ }
+
+ return m_pSuperstream->getStyleType(nIndex);
+}
+
+RTFParserState& RTFDocumentImpl::getDefaultState()
+{
+ if (!m_pSuperstream)
+ return m_aDefaultState;
+
+ return m_pSuperstream->getDefaultState();
+}
+
+oox::GraphicHelper& RTFDocumentImpl::getGraphicHelper() { return *m_pGraphicHelper; }
+
+bool RTFDocumentImpl::isStyleSheetImport()
+{
+ if (m_aStates.empty())
+ return false;
+ Destination eDestination = m_aStates.top().getDestination();
+ return eDestination == Destination::STYLESHEET || eDestination == Destination::STYLEENTRY;
+}
+
+void RTFDocumentImpl::resolve(Stream& rMapper)
+{
+ m_pMapperStream = &rMapper;
+ switch (m_pTokenizer->resolveParse())
+ {
+ case RTFError::OK:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: finished without errors");
+ break;
+ case RTFError::GROUP_UNDER:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '}'");
+ break;
+ case RTFError::GROUP_OVER:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '{'");
+ throw io::WrongFormatException(m_pTokenizer->getPosition());
+ break;
+ case RTFError::UNEXPECTED_EOF:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unexpected end of file");
+ throw io::WrongFormatException(m_pTokenizer->getPosition());
+ break;
+ case RTFError::HEX_INVALID:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: invalid hex char");
+ throw io::WrongFormatException(m_pTokenizer->getPosition());
+ break;
+ case RTFError::CHAR_OVER:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: characters after last '}'");
+ break;
+ case RTFError::CLASSIFICATION:
+ SAL_INFO("writerfilter.rtf",
+ "RTFDocumentImpl::resolve: classification prevented paste");
+ break;
+ }
+}
+
+void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XShape> const& rShape)
+{
+ SvMemoryStream aStream;
+ SvStream* pStream = nullptr;
+ if (!m_pBinaryData)
+ {
+ pStream = &aStream;
+ int b = 0;
+ int count = 2;
+
+ // Feed the destination text to a stream.
+ OString aStr = OUStringToOString(m_aStates.top().getDestinationText().makeStringAndClear(),
+ RTL_TEXTENCODING_ASCII_US);
+ for (int i = 0; i < aStr.getLength(); ++i)
+ {
+ char ch = aStr[i];
+ if (ch != 0x0d && ch != 0x0a && ch != 0x20)
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return;
+ b += parsed;
+ count--;
+ if (!count)
+ {
+ aStream.WriteChar(static_cast<char>(b));
+ count = 2;
+ b = 0;
+ }
+ }
+ }
+ }
+ else
+ pStream = m_pBinaryData.get();
+
+ if (!pStream->Tell())
+ // No destination text? Then we'll get it later.
+ return;
+
+ SvMemoryStream aDIBStream;
+ if (m_aStates.top().getPicture().eStyle == RTFBmpStyle::DIBITMAP)
+ {
+ // Construct a BITMAPFILEHEADER structure before the real data.
+ SvStream& rBodyStream = *pStream;
+ aDIBStream.WriteChar('B');
+ aDIBStream.WriteChar('M');
+ // The size of the real data.
+ aDIBStream.WriteUInt32(rBodyStream.Tell());
+ // Reserved.
+ aDIBStream.WriteUInt32(0);
+ // The offset of the real data, i.e. the size of the header, including this number.
+ aDIBStream.WriteUInt32(14);
+ rBodyStream.Seek(0);
+ aDIBStream.WriteStream(rBodyStream);
+ pStream = &aDIBStream;
+ }
+
+ // Store, and get its URL.
+ pStream->Seek(0);
+ uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(pStream));
+ WmfExternal aExtHeader;
+ aExtHeader.mapMode = m_aStates.top().getPicture().eWMetafile;
+ if (m_aStates.top().getPicture().nGoalWidth == 0
+ || m_aStates.top().getPicture().nGoalHeight == 0)
+ {
+ // Don't use the values provided by picw and pich if the desired size is provided.
+
+ aExtHeader.xExt = sal_uInt16(std::clamp<sal_Int32>(
+ m_aStates.top().getPicture().nWidth, 0,
+ SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
+ aExtHeader.yExt = sal_uInt16(std::clamp<sal_Int32>(
+ m_aStates.top().getPicture().nHeight, 0,
+ SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
+ }
+ WmfExternal* pExtHeader = &aExtHeader;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_aStates.top().getDrawingObject().getShape(),
+ uno::UNO_QUERY);
+ if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ pExtHeader = nullptr;
+
+ uno::Reference<graphic::XGraphic> xGraphic
+ = m_pGraphicHelper->importGraphic(xInputStream, pExtHeader);
+
+ if (m_aStates.top().getPicture().eStyle != RTFBmpStyle::NONE)
+ {
+ // In case of PNG/JPEG, the real size is known, don't use the values
+ // provided by picw and pich.
+
+ Graphic aGraphic(xGraphic);
+ Size aSize(aGraphic.GetPrefSize());
+ MapMode aMap(MapUnit::Map100thMM);
+ if (aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMap);
+ else
+ aSize = OutputDevice::LogicToLogic(aSize, aGraphic.GetPrefMapMode(), aMap);
+ m_aStates.top().getPicture().nWidth = aSize.Width();
+ m_aStates.top().getPicture().nHeight = aSize.Height();
+ }
+
+ uno::Reference<drawing::XShape> xShape(rShape);
+ if (m_aStates.top().getInShape() && xShape.is())
+ {
+ awt::Size aSize = xShape->getSize();
+ if (aSize.Width || aSize.Height)
+ {
+ // resolvePict() is processing pib structure inside shape
+ // So if shape has dimensions we should use them instead of
+ // \picwN, \pichN, \picscalexN, \picscaleyN given with picture
+ m_aStates.top().getPicture().nGoalWidth = aSize.Width;
+ m_aStates.top().getPicture().nGoalHeight = aSize.Height;
+ m_aStates.top().getPicture().nScaleX = 100;
+ m_aStates.top().getPicture().nScaleY = 100;
+ }
+ }
+
+ // Wrap it in an XShape.
+ if (xShape.is())
+ {
+ uno::Reference<lang::XServiceInfo> xSI(xShape, uno::UNO_QUERY_THROW);
+ if (!xSI->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ // it's sometimes an error to get here - but it's possible to have
+ // a \pict inside the \shptxt of a \shp of shapeType 202 "TextBox"
+ // and in that case xShape is the text frame; we actually need a
+ // new GraphicObject then (example: fdo37691-1.rtf)
+ SAL_INFO("writerfilter.rtf",
+ "cannot set graphic on existing shape, creating a new GraphicObjectShape");
+ xShape.clear();
+ }
+ }
+ if (!xShape.is())
+ {
+ if (m_xModelFactory.is())
+ xShape.set(m_xModelFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPageSupplier> const xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
+ if (xShapes.is())
+ xShapes->add(xShape);
+ }
+ }
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("Graphic", uno::Any(xGraphic));
+
+ // check if the picture is in an OLE object and if the \objdata element is used
+ // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
+ if (m_bObject)
+ {
+ // Set the object size
+ awt::Size aSize;
+ aSize.Width
+ = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
+ : m_aStates.top().getPicture().nWidth);
+ aSize.Height
+ = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
+ : m_aStates.top().getPicture().nHeight);
+ xShape->setSize(aSize);
+
+ // Replacement graphic is inline by default, see oox::vml::SimpleShape::implConvertAndInsert().
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+
+ auto pShapeValue = new RTFValue(xShape);
+ m_aObjectAttributes.set(NS_ooxml::LN_shape, pShapeValue);
+ return;
+ }
+
+ if (m_aStates.top().getInListpicture())
+ {
+ // Send the shape directly, no section is started, to additional properties will be ignored anyway.
+ Mapper().startShape(xShape);
+ Mapper().endShape();
+ return;
+ }
+
+ // Send it to the dmapper.
+ RTFSprms aSprms;
+ RTFSprms aAttributes;
+ // shape attribute
+ RTFSprms aPicAttributes;
+ auto pShapeValue = new RTFValue(xShape);
+ aPicAttributes.set(NS_ooxml::LN_shape, pShapeValue);
+ // pic sprm
+ RTFSprms aGraphicDataAttributes;
+ RTFSprms aGraphicDataSprms;
+ auto pPicValue = new RTFValue(aPicAttributes);
+ aGraphicDataSprms.set(NS_ooxml::LN_pic_pic, pPicValue);
+ // graphicData sprm
+ RTFSprms aGraphicAttributes;
+ RTFSprms aGraphicSprms;
+ auto pGraphicDataValue = new RTFValue(aGraphicDataAttributes, aGraphicDataSprms);
+ aGraphicSprms.set(NS_ooxml::LN_CT_GraphicalObject_graphicData, pGraphicDataValue);
+ // graphic sprm
+ auto pGraphicValue = new RTFValue(aGraphicAttributes, aGraphicSprms);
+ // extent sprm
+ RTFSprms aExtentAttributes;
+ int nXExt = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
+ : m_aStates.top().getPicture().nWidth);
+ int nYExt = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
+ : m_aStates.top().getPicture().nHeight);
+ if (m_aStates.top().getPicture().nScaleX != 100)
+ nXExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleX)
+ * (nXExt
+ - (m_aStates.top().getPicture().nCropL + m_aStates.top().getPicture().nCropR)))
+ / 100L;
+ if (m_aStates.top().getPicture().nScaleY != 100)
+ nYExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleY)
+ * (nYExt
+ - (m_aStates.top().getPicture().nCropT + m_aStates.top().getPicture().nCropB)))
+ / 100L;
+ auto pXExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nXExt));
+ auto pYExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nYExt));
+ aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cx, pXExtValue);
+ aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cy, pYExtValue);
+ auto pExtentValue = new RTFValue(aExtentAttributes);
+ // docpr sprm
+ RTFSprms aDocprAttributes;
+ for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
+ if (rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_name
+ || rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_descr)
+ aDocprAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
+ auto pDocprValue = new RTFValue(aDocprAttributes);
+ if (bInline)
+ {
+ RTFSprms aInlineAttributes;
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distT, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distB, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distL, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distR, new RTFValue(0));
+ RTFSprms aInlineSprms;
+ aInlineSprms.set(NS_ooxml::LN_CT_Inline_extent, pExtentValue);
+ aInlineSprms.set(NS_ooxml::LN_CT_Inline_docPr, pDocprValue);
+ aInlineSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
+ // inline sprm
+ auto pValue = new RTFValue(aInlineAttributes, aInlineSprms);
+ aSprms.set(NS_ooxml::LN_inline_inline, pValue);
+ }
+ else // anchored
+ {
+ // wrap sprm
+ RTFSprms aAnchorWrapAttributes;
+ m_aStates.top().getShape().getAnchorAttributes().set(
+ NS_ooxml::LN_CT_Anchor_behindDoc,
+ new RTFValue((m_aStates.top().getShape().getInBackground()) ? 1 : 0));
+ RTFSprms aAnchorSprms;
+ for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
+ {
+ if (rCharacterAttribute.first == NS_ooxml::LN_CT_WrapSquare_wrapText)
+ aAnchorWrapAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
+ }
+ sal_Int32 nWrap = -1;
+ for (auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
+ {
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
+ || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
+ {
+ nWrap = rCharacterSprm.first;
+
+ // If there is a wrap polygon prepared by RTFSdrImport, pick it up here.
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight
+ && !m_aStates.top().getShape().getWrapPolygonSprms().empty())
+ rCharacterSprm.second->getSprms().set(
+ NS_ooxml::LN_CT_WrapTight_wrapPolygon,
+ new RTFValue(RTFSprms(), m_aStates.top().getShape().getWrapPolygonSprms()));
+
+ aAnchorSprms.set(rCharacterSprm.first, rCharacterSprm.second);
+ }
+ }
+
+ if (m_aStates.top().getShape().getWrapSprm().first != 0)
+ // Replay of a buffered shape, wrap sprm there has priority over
+ // character sprms of the current state.
+ aAnchorSprms.set(m_aStates.top().getShape().getWrapSprm().first,
+ m_aStates.top().getShape().getWrapSprm().second);
+
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_extent, pExtentValue);
+ if (!aAnchorWrapAttributes.empty() && nWrap == -1)
+ aAnchorSprms.set(NS_ooxml::LN_EG_WrapType_wrapSquare,
+ new RTFValue(aAnchorWrapAttributes));
+
+ // See OOXMLFastContextHandler::positionOffset(), we can't just put offset values in an RTFValue.
+ RTFSprms aPoshAttributes;
+ RTFSprms aPoshSprms;
+ if (m_aStates.top().getShape().getHoriOrientRelationToken() > 0)
+ aPoshAttributes.set(
+ NS_ooxml::LN_CT_PosH_relativeFrom,
+ new RTFValue(m_aStates.top().getShape().getHoriOrientRelationToken()));
+ if (m_aStates.top().getShape().getLeft() != 0)
+ {
+ Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
+ m_aStates.top().getShape().getLeft())),
+ /*bVertical=*/false);
+ aPoshSprms.set(NS_ooxml::LN_CT_PosH_posOffset, new RTFValue());
+ }
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionH,
+ new RTFValue(aPoshAttributes, aPoshSprms));
+
+ RTFSprms aPosvAttributes;
+ RTFSprms aPosvSprms;
+ if (m_aStates.top().getShape().getVertOrientRelationToken() > 0)
+ aPosvAttributes.set(
+ NS_ooxml::LN_CT_PosV_relativeFrom,
+ new RTFValue(m_aStates.top().getShape().getVertOrientRelationToken()));
+ if (m_aStates.top().getShape().getTop() != 0)
+ {
+ Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
+ m_aStates.top().getShape().getTop())),
+ /*bVertical=*/true);
+ aPosvSprms.set(NS_ooxml::LN_CT_PosV_posOffset, new RTFValue());
+ }
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionV,
+ new RTFValue(aPosvAttributes, aPosvSprms));
+
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_docPr, pDocprValue);
+ aAnchorSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
+ // anchor sprm
+ auto pValue = new RTFValue(m_aStates.top().getShape().getAnchorAttributes(), aAnchorSprms);
+ aSprms.set(NS_ooxml::LN_anchor_anchor, pValue);
+ }
+ checkFirstRun();
+
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ // Make sure we don't lose these properties with a too early reset.
+ m_bHadPicture = true;
+ }
+ else
+ {
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
+ }
+}
+
+RTFError RTFDocumentImpl::resolveChars(char ch)
+{
+ if (m_aStates.top().getInternalState() == RTFInternalState::BIN)
+ {
+ m_pBinaryData = std::make_shared<SvMemoryStream>();
+ m_pBinaryData->WriteChar(ch);
+ for (int i = 0; i < m_aStates.top().getBinaryToRead() - 1; ++i)
+ {
+ Strm().ReadChar(ch);
+ m_pBinaryData->WriteChar(ch);
+ }
+ m_aStates.top().setInternalState(RTFInternalState::NORMAL);
+ return RTFError::OK;
+ }
+
+ OStringBuffer aBuf(512);
+
+ bool bUnicodeChecked = false;
+ bool bSkipped = false;
+
+ while (!Strm().eof()
+ && (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ || (ch != '{' && ch != '}' && ch != '\\')))
+ {
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ || (ch != 0x0d && ch != 0x0a))
+ {
+ if (m_aStates.top().getCharsToSkip() == 0)
+ {
+ if (!bUnicodeChecked)
+ {
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
+ bUnicodeChecked = true;
+ }
+ aBuf.append(ch);
+ }
+ else
+ {
+ bSkipped = true;
+ m_aStates.top().getCharsToSkip()--;
+ }
+ }
+
+ // read a single char if we're in hex mode
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX)
+ break;
+
+ if (RTL_TEXTENCODING_MS_932 == m_aStates.top().getCurrentEncoding())
+ {
+ unsigned char uch = ch;
+ if ((uch >= 0x80 && uch <= 0x9F) || uch >= 0xE0)
+ {
+ // read second byte of 2-byte Shift-JIS - may be \ { }
+ Strm().ReadChar(ch);
+ if (m_aStates.top().getCharsToSkip() == 0)
+ {
+ // fdo#79384: Word will reject Shift-JIS following \loch
+ // but apparently OOo could read and (worse) write such documents
+ SAL_INFO_IF(m_aStates.top().getRunType() != RTFParserState::RunType::DBCH,
+ "writerfilter.rtf", "invalid Shift-JIS without DBCH");
+ assert(bUnicodeChecked);
+ aBuf.append(ch);
+ }
+ else
+ {
+ assert(bSkipped);
+ // anybody who uses \ucN with Shift-JIS is insane
+ m_aStates.top().getCharsToSkip()--;
+ }
+ }
+ }
+
+ Strm().ReadChar(ch);
+ }
+ if (m_aStates.top().getInternalState() != RTFInternalState::HEX && !Strm().eof())
+ Strm().SeekRel(-1);
+
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ && m_aStates.top().getDestination() != Destination::LEVELNUMBERS)
+ {
+ if (!bSkipped)
+ {
+ // note: apparently \'0d\'0a is interpreted as 2 breaks, not 1
+ if ((ch == '\r' || ch == '\n')
+ && m_aStates.top().getDestination() != Destination::DOCCOMM
+ && m_aStates.top().getDestination() != Destination::LEVELNUMBERS
+ && m_aStates.top().getDestination() != Destination::LEVELTEXT)
+ {
+ checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
+ dispatchSymbol(RTFKeyword::PAR);
+ }
+ else
+ {
+ m_aHexBuffer.append(ch);
+ }
+ }
+ return RTFError::OK;
+ }
+
+ if (m_aStates.top().getDestination() == Destination::SKIP)
+ return RTFError::OK;
+ OString aStr = aBuf.makeStringAndClear();
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
+ {
+ if (aStr.toChar() != ';')
+ m_aStates.top().getLevelNumbers().push_back(sal_Int32(ch));
+ return RTFError::OK;
+ }
+
+ SAL_INFO("writerfilter.rtf",
+ "RTFDocumentImpl::resolveChars: collected '"
+ << OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()) << "'");
+
+ if (m_aStates.top().getDestination() == Destination::COLORTABLE)
+ {
+ // we hit a ';' at the end of each color entry
+ m_aColorTable.push_back(m_aStates.top().getCurrentColor().GetColor());
+ // set components back to zero
+ m_aStates.top().getCurrentColor() = RTFColorTableEntry();
+ }
+ else if (!aStr.isEmpty())
+ m_aHexBuffer.append(aStr);
+
+ checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
+ return RTFError::OK;
+}
+
+bool RTFFrame::inFrame() const { return m_nW > 0 || m_nH > 0 || m_nX > 0 || m_nY > 0; }
+
+void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps)
+{
+ sal_uInt8 sValue[] = { nValue };
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+
+ if (!pCurrentBuffer)
+ {
+ Mapper().startCharacterGroup();
+ }
+ else
+ {
+ pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, nullptr, nullptr));
+ }
+
+ // Should we send run properties?
+ if (bRunProps)
+ runProps();
+
+ if (!pCurrentBuffer)
+ {
+ Mapper().text(sValue, 1);
+ Mapper().endCharacterGroup();
+ }
+ else
+ {
+ auto pValue = new RTFValue(*sValue);
+ pCurrentBuffer->push_back(Buf_t(BUFFER_TEXT, pValue, nullptr));
+ pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, nullptr, nullptr));
+ }
+}
+
+void RTFDocumentImpl::handleFontTableEntry()
+{
+ OUString aName = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+
+ if (aName.isEmpty())
+ return;
+
+ if (aName.endsWith(";"))
+ {
+ aName = aName.copy(0, aName.getLength() - 1);
+ }
+
+ // Old documents can contain no encoding information in fontinfo,
+ // but there can be font name suffixes: Arial CE is not a special
+ // font, it is ordinal Arial, but with used cp 1250 encoding.
+ // Moreover these suffixes have priority over \cpgN and \fcharsetN
+ // in MS Word.
+ OUString aFontSuffix;
+ OUString aNameNoSuffix(aName);
+ sal_Int32 nLastSpace = aName.lastIndexOf(' ');
+ if (nLastSpace >= 0)
+ {
+ aFontSuffix = aName.copy(nLastSpace + 1);
+ aNameNoSuffix = aName.copy(0, nLastSpace);
+ sal_Int32 nEncoding = RTL_TEXTENCODING_DONTKNOW;
+ for (int i = 0; aRTFFontNameSuffixes[i].codepage != RTL_TEXTENCODING_DONTKNOW; i++)
+ {
+ if (aFontSuffix.equalsAscii(aRTFFontNameSuffixes[i].suffix))
+ {
+ nEncoding = aRTFFontNameSuffixes[i].codepage;
+ break;
+ }
+ }
+ if (nEncoding > RTL_TEXTENCODING_DONTKNOW)
+ {
+ m_nCurrentEncoding = nEncoding;
+ m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
+ }
+ else
+ {
+ // Unknown suffix: looks like it is just a part of font name, restore it
+ aNameNoSuffix = aName;
+ }
+ }
+
+ m_aFontNames[m_nCurrentFontIndex] = aNameNoSuffix;
+ if (m_nCurrentEncoding >= 0)
+ {
+ m_aFontEncodings[m_nCurrentFontIndex] = m_nCurrentEncoding;
+ m_nCurrentEncoding = -1;
+ }
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name,
+ new RTFValue(aNameNoSuffix));
+
+ writerfilter::Reference<Properties>::Pointer_t const pProp(new RTFReferenceProperties(
+ m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
+
+ //See fdo#47347 initial invalid font entry properties are inserted first,
+ //so when we attempt to insert the correct ones, there's already an
+ //entry in the map for them, so the new ones aren't inserted.
+ auto lb = m_aFontTableEntries.lower_bound(m_nCurrentFontIndex);
+ if (lb != m_aFontTableEntries.end()
+ && !(m_aFontTableEntries.key_comp()(m_nCurrentFontIndex, lb->first)))
+ lb->second = pProp;
+ else
+ m_aFontTableEntries.insert(lb, std::make_pair(m_nCurrentFontIndex, pProp));
+}
+
+void RTFDocumentImpl::text(OUString& rString)
+{
+ if (rString.getLength() == 1 && m_aStates.top().getDestination() != Destination::DOCCOMM)
+ {
+ // No cheating! Tokenizer ignores bare \r and \n, their hex \'0d / \'0a form doesn't count, either.
+ sal_Unicode ch = rString[0];
+ if (ch == 0x0d || ch == 0x0a)
+ return;
+ }
+
+ bool bRet = true;
+ switch (m_aStates.top().getDestination())
+ {
+ // Note: in stylesheet and revtbl groups are mandatory
+ case Destination::STYLEENTRY:
+ case Destination::LISTNAME:
+ case Destination::REVISIONENTRY:
+ {
+ // ; is the end of the entry
+ bool bEnd = false;
+ if (rString.endsWith(";"))
+ {
+ rString = rString.copy(0, rString.getLength() - 1);
+ bEnd = true;
+ }
+ m_aStates.top().appendDestinationText(rString);
+ if (bEnd)
+ {
+ // always clear, necessary in case of group-less fonttable
+ OUString const aName
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ switch (m_aStates.top().getDestination())
+ {
+ case Destination::STYLEENTRY:
+ {
+ RTFValue::Pointer_t pType
+ = m_aStates.top().getTableAttributes().find(NS_ooxml::LN_CT_Style_type);
+ if (pType)
+ {
+ // Word strips whitespace around style names.
+ m_aStyleNames[m_nCurrentStyleIndex] = aName.trim();
+ m_aStyleTypes[m_nCurrentStyleIndex] = pType->getInt();
+ auto pValue = new RTFValue(aName.trim());
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_styleId,
+ pValue);
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_name, pValue);
+
+ writerfilter::Reference<Properties>::Pointer_t const pProp(
+ createStyleProperties());
+ m_pStyleTableEntries->insert(
+ std::make_pair(m_nCurrentStyleIndex, pProp));
+ }
+ else
+ SAL_INFO("writerfilter.rtf", "no RTF style type defined, ignoring");
+ break;
+ }
+ case Destination::LISTNAME:
+ // TODO: what can be done with a list name?
+ break;
+ case Destination::REVISIONENTRY:
+ m_aAuthors[m_aAuthors.size()] = aName;
+ break;
+ default:
+ break;
+ }
+ resetAttributes();
+ resetSprms();
+ }
+ }
+ break;
+ case Destination::DOCVAR:
+ {
+ m_aStates.top().appendDocVar(rString);
+ }
+ break;
+ case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
+ case Destination::LEVELTEXT:
+ case Destination::SHAPEPROPERTYNAME:
+ case Destination::SHAPEPROPERTYVALUE:
+ case Destination::BOOKMARKEND:
+ case Destination::PICT:
+ case Destination::SHAPEPROPERTYVALUEPICT:
+ case Destination::FORMFIELDNAME:
+ case Destination::FORMFIELDLIST:
+ case Destination::DATAFIELD:
+ case Destination::AUTHOR:
+ case Destination::KEYWORDS:
+ case Destination::OPERATOR:
+ case Destination::COMPANY:
+ case Destination::COMMENT:
+ case Destination::OBJDATA:
+ case Destination::OBJCLASS:
+ case Destination::ANNOTATIONDATE:
+ case Destination::ANNOTATIONAUTHOR:
+ case Destination::ANNOTATIONREFERENCE:
+ case Destination::FALT:
+ case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
+ case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
+ case Destination::TITLE:
+ case Destination::SUBJECT:
+ case Destination::DOCCOMM:
+ case Destination::ATNID:
+ case Destination::ANNOTATIONREFERENCESTART:
+ case Destination::ANNOTATIONREFERENCEEND:
+ case Destination::MR:
+ case Destination::MCHR:
+ case Destination::MPOS:
+ case Destination::MVERTJC:
+ case Destination::MSTRIKEH:
+ case Destination::MDEGHIDE:
+ case Destination::MBEGCHR:
+ case Destination::MSEPCHR:
+ case Destination::MENDCHR:
+ case Destination::MSUBHIDE:
+ case Destination::MSUPHIDE:
+ case Destination::MTYPE:
+ case Destination::MGROW:
+ case Destination::INDEXENTRY:
+ case Destination::TOCENTRY:
+ case Destination::PROPNAME:
+ case Destination::STATICVAL:
+ m_aStates.top().appendDestinationText(rString);
+ break;
+ case Destination::GENERATOR:
+ // don't enlarge space sequences, eg. it was saved in LibreOffice
+ if (!rString.startsWithIgnoreAsciiCase("Microsoft"))
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ default:
+ bRet = false;
+ break;
+ }
+ if (bRet)
+ return;
+
+ if (!m_aIgnoreFirst.isEmpty() && m_aIgnoreFirst == rString)
+ {
+ m_aIgnoreFirst.clear();
+ return;
+ }
+
+ // Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
+ if (m_aStates.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign)
+ && m_nTopLevelCells == 0)
+ {
+ m_aTableBufferStack.back().emplace_back(BUFFER_UTEXT, new RTFValue(rString), nullptr);
+ return;
+ }
+
+ checkFirstRun();
+ checkNeedPap();
+
+ // Don't return earlier, a bookmark start has to be in a paragraph group.
+ if (m_aStates.top().getDestination() == Destination::BOOKMARKSTART)
+ {
+ m_aStates.top().appendDestinationText(rString);
+ return;
+ }
+
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+
+ if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
+ Mapper().startCharacterGroup();
+ else if (pCurrentBuffer)
+ {
+ RTFValue::Pointer_t pValue;
+ pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, pValue, nullptr));
+ }
+
+ if (m_aStates.top().getDestination() == Destination::NORMAL
+ || m_aStates.top().getDestination() == Destination::FIELDRESULT
+ || m_aStates.top().getDestination() == Destination::SHAPETEXT)
+ runProps();
+
+ if (!pCurrentBuffer)
+ Mapper().utext(reinterpret_cast<sal_uInt8 const*>(rString.getStr()), rString.getLength());
+ else
+ {
+ auto pValue = new RTFValue(rString);
+ pCurrentBuffer->push_back(Buf_t(BUFFER_UTEXT, pValue, nullptr));
+ }
+
+ m_bNeedCr = true;
+
+ if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
+ Mapper().endCharacterGroup();
+ else if (pCurrentBuffer)
+ {
+ RTFValue::Pointer_t pValue;
+ pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, pValue, nullptr));
+ }
+}
+
+void RTFDocumentImpl::prepareProperties(
+ RTFParserState& rState, writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpTableRowProperties, int const nCells,
+ int const nCurrentCellX)
+{
+ o_rpParagraphProperties
+ = getProperties(rState.getParagraphAttributes(), rState.getParagraphSprms(),
+ NS_ooxml::LN_Value_ST_StyleType_paragraph);
+
+ if (rState.getFrame().hasProperties())
+ {
+ o_rpFrameProperties = new RTFReferenceProperties(RTFSprms(), rState.getFrame().getSprms());
+ }
+
+ // Table width.
+ RTFValue::Pointer_t const pTableWidthProps
+ = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblW);
+ if (!pTableWidthProps)
+ {
+ auto pUnitValue = new RTFValue(3);
+ putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_type, pUnitValue);
+ auto pWValue = new RTFValue(nCurrentCellX);
+ putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_w, pWValue);
+ }
+
+ if (nCells > 0)
+ rState.getTableRowSprms().set(NS_ooxml::LN_tblRow, new RTFValue(1));
+
+ RTFValue::Pointer_t const pCellMar
+ = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblCellMar);
+ if (!pCellMar)
+ {
+ // If no cell margins are defined, the default left/right margin is 0 in Word, but not in Writer.
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(0));
+ putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ NS_ooxml::LN_CT_TblCellMar_left, new RTFValue(aAttributes));
+ putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
+ }
+
+ o_rpTableRowProperties
+ = new RTFReferenceProperties(rState.getTableRowAttributes(), rState.getTableRowSprms());
+}
+
+void RTFDocumentImpl::sendProperties(
+ writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties)
+{
+ Mapper().props(pParagraphProperties);
+
+ if (pFrameProperties)
+ {
+ Mapper().props(pFrameProperties);
+ }
+
+ Mapper().props(pTableRowProperties);
+
+ tableBreak();
+}
+
+void RTFDocumentImpl::replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSrpms,
+ ::std::deque<RTFSprms>& rCellsAttributes, int const nCells)
+{
+ for (int i = 0; i < nCells; ++i)
+ {
+ replayBuffer(rBuffer, &rCellsSrpms.front(), &rCellsAttributes.front());
+ rCellsSrpms.pop_front();
+ rCellsAttributes.pop_front();
+ }
+ for (Buf_t& i : rBuffer)
+ {
+ SAL_WARN_IF(BUFFER_CELLEND == std::get<0>(i), "writerfilter.rtf", "dropping table cell!");
+ }
+ assert(rCellsSrpms.empty());
+ assert(rCellsAttributes.empty());
+}
+
+void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms,
+ RTFSprms const* const pAttributes)
+{
+ while (!rBuffer.empty())
+ {
+ Buf_t aTuple(rBuffer.front());
+ rBuffer.pop_front();
+ if (std::get<0>(aTuple) == BUFFER_PROPS)
+ {
+ // Construct properties via getProperties() and not directly, to take care of deduplication.
+ writerfilter::Reference<Properties>::Pointer_t const pProp(getProperties(
+ std::get<1>(aTuple)->getAttributes(), std::get<1>(aTuple)->getSprms(), 0));
+ Mapper().props(pProp);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_NESTROW)
+ {
+ TableRowBuffer& rRowBuffer(*std::get<2>(aTuple));
+
+ replayRowBuffer(rRowBuffer.GetBuffer(), rRowBuffer.GetCellsSprms(),
+ rRowBuffer.GetCellsAttributes(), rRowBuffer.GetCells());
+
+ sendProperties(rRowBuffer.GetParaProperties(), rRowBuffer.GetFrameProperties(),
+ rRowBuffer.GetRowProperties());
+ }
+ else if (std::get<0>(aTuple) == BUFFER_CELLEND)
+ {
+ assert(pSprms && pAttributes);
+ auto pValue = new RTFValue(1);
+ pSprms->set(NS_ooxml::LN_tblCell, pValue);
+ writerfilter::Reference<Properties>::Pointer_t const pTableCellProperties(
+ new RTFReferenceProperties(*pAttributes, *pSprms));
+ Mapper().props(pTableCellProperties);
+ tableBreak();
+ break;
+ }
+ else if (std::get<0>(aTuple) == BUFFER_STARTRUN)
+ Mapper().startCharacterGroup();
+ else if (std::get<0>(aTuple) == BUFFER_TEXT)
+ {
+ sal_uInt8 const nValue = std::get<1>(aTuple)->getInt();
+ Mapper().text(&nValue, 1);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_UTEXT)
+ {
+ OUString const aString(std::get<1>(aTuple)->getString());
+ Mapper().utext(reinterpret_cast<sal_uInt8 const*>(aString.getStr()),
+ aString.getLength());
+ }
+ else if (std::get<0>(aTuple) == BUFFER_ENDRUN)
+ Mapper().endCharacterGroup();
+ else if (std::get<0>(aTuple) == BUFFER_PAR)
+ parBreak();
+ else if (std::get<0>(aTuple) == BUFFER_STARTSHAPE)
+ m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), false, RTFSdrImport::SHAPE);
+ else if (std::get<0>(aTuple) == BUFFER_RESOLVESHAPE)
+ {
+ // Make sure there is no current buffer while replaying the shape,
+ // otherwise it gets re-buffered.
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+ m_aStates.top().setCurrentBuffer(nullptr);
+
+ // Set current shape during replay, needed by e.g. wrap in
+ // background.
+ RTFShape aShape = m_aStates.top().getShape();
+ m_aStates.top().getShape() = std::get<1>(aTuple)->getShape();
+
+ m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), true, RTFSdrImport::SHAPE);
+ m_aStates.top().getShape() = aShape;
+ m_aStates.top().setCurrentBuffer(pCurrentBuffer);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_ENDSHAPE)
+ m_pSdrImport->close();
+ else if (std::get<0>(aTuple) == BUFFER_RESOLVESUBSTREAM)
+ {
+ RTFSprms& rAttributes = std::get<1>(aTuple)->getAttributes();
+ std::size_t nPos = rAttributes.find(0)->getInt();
+ Id nId = rAttributes.find(1)->getInt();
+ OUString aCustomMark = rAttributes.find(2)->getString();
+ resolveSubstream(nPos, nId, aCustomMark);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_PICTURE)
+ m_aStates.top().getPicture() = std::get<1>(aTuple)->getPicture();
+ else if (std::get<0>(aTuple) == BUFFER_SETSTYLE)
+ {
+ if (!m_aStates.empty())
+ m_aStates.top().setCurrentStyleIndex(std::get<1>(aTuple)->getInt());
+ }
+ else
+ assert(false);
+ }
+}
+
+bool findPropertyName(const std::vector<beans::PropertyValue>& rProperties, const OUString& rName)
+{
+ return std::any_of(
+ rProperties.begin(), rProperties.end(),
+ [&rName](const beans::PropertyValue& rProperty) { return rProperty.Name == rName; });
+}
+
+void RTFDocumentImpl::backupTableRowProperties()
+{
+ if (m_nTopLevelCurrentCellX)
+ {
+ m_aBackupTableRowSprms = m_aStates.top().getTableRowSprms();
+ m_aBackupTableRowAttributes = m_aStates.top().getTableRowAttributes();
+ m_nBackupTopLevelCurrentCellX = m_nTopLevelCurrentCellX;
+ }
+}
+
+void RTFDocumentImpl::restoreTableRowProperties()
+{
+ m_aStates.top().getTableRowSprms() = m_aBackupTableRowSprms;
+ m_aStates.top().getTableRowAttributes() = m_aBackupTableRowAttributes;
+ m_nTopLevelCurrentCellX = m_nBackupTopLevelCurrentCellX;
+}
+
+void RTFDocumentImpl::resetTableRowProperties()
+{
+ m_aStates.top().getTableRowSprms() = m_aDefaultState.getTableRowSprms();
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, new RTFValue(-1),
+ RTFOverwrite::NO_APPEND);
+ m_aStates.top().getTableRowAttributes() = m_aDefaultState.getTableRowAttributes();
+ if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ {
+ m_nNestedTRLeft = 0;
+ m_nNestedCurrentCellX = 0;
+ }
+ else
+ {
+ m_nTopLevelTRLeft = 0;
+ m_nTopLevelCurrentCellX = 0;
+ }
+}
+
+RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nSprm = -1;
+ tools::SvRef<RTFValue> pBoolValue(new RTFValue(int(!bParam || nParam != 0)));
+
+ // Underline toggles.
+ switch (nKeyword)
+ {
+ case RTFKeyword::UL:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_single;
+ break;
+ case RTFKeyword::ULDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dash;
+ break;
+ case RTFKeyword::ULDASHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotDash;
+ break;
+ case RTFKeyword::ULDASHDD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotDotDash;
+ break;
+ case RTFKeyword::ULDB:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_double;
+ break;
+ case RTFKeyword::ULHWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wavyHeavy;
+ break;
+ case RTFKeyword::ULLDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashLong;
+ break;
+ case RTFKeyword::ULTH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_thick;
+ break;
+ case RTFKeyword::ULTHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dottedHeavy;
+ break;
+ case RTFKeyword::ULTHDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashedHeavy;
+ break;
+ case RTFKeyword::ULTHDASHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotHeavy;
+ break;
+ case RTFKeyword::ULTHDASHDD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy;
+ break;
+ case RTFKeyword::ULTHLDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashLongHeavy;
+ break;
+ case RTFKeyword::ULULDBWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wavyDouble;
+ break;
+ case RTFKeyword::ULWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wave;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue
+ = new RTFValue((!bParam || nParam != 0) ? nSprm : NS_ooxml::LN_Value_ST_Underline_none);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Accent characters (over dot / over comma).
+ switch (nKeyword)
+ {
+ case RTFKeyword::ACCNONE:
+ nSprm = NS_ooxml::LN_Value_ST_Em_none;
+ break;
+ case RTFKeyword::ACCDOT:
+ nSprm = NS_ooxml::LN_Value_ST_Em_dot;
+ break;
+ case RTFKeyword::ACCCOMMA:
+ nSprm = NS_ooxml::LN_Value_ST_Em_comma;
+ break;
+ case RTFKeyword::ACCCIRCLE:
+ nSprm = NS_ooxml::LN_Value_ST_Em_circle;
+ break;
+ case RTFKeyword::ACCUNDERDOT:
+ nSprm = NS_ooxml::LN_Value_ST_Em_underDot;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue = new RTFValue((!bParam || nParam != 0) ? nSprm : 0);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_em, pValue);
+ return RTFError::OK;
+ }
+
+ // Trivial character sprms.
+ switch (nKeyword)
+ {
+ case RTFKeyword::B:
+ case RTFKeyword::AB:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_bCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_b;
+ break;
+ }
+ break;
+ case RTFKeyword::I:
+ case RTFKeyword::AI:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_iCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_i;
+ break;
+ }
+ break;
+ case RTFKeyword::OUTL:
+ nSprm = NS_ooxml::LN_EG_RPrBase_outline;
+ break;
+ case RTFKeyword::SHAD:
+ nSprm = NS_ooxml::LN_EG_RPrBase_shadow;
+ break;
+ case RTFKeyword::V:
+ nSprm = NS_ooxml::LN_EG_RPrBase_vanish;
+ break;
+ case RTFKeyword::STRIKE:
+ nSprm = NS_ooxml::LN_EG_RPrBase_strike;
+ break;
+ case RTFKeyword::STRIKED:
+ nSprm = NS_ooxml::LN_EG_RPrBase_dstrike;
+ break;
+ case RTFKeyword::SCAPS:
+ nSprm = NS_ooxml::LN_EG_RPrBase_smallCaps;
+ break;
+ case RTFKeyword::IMPR:
+ nSprm = NS_ooxml::LN_EG_RPrBase_imprint;
+ break;
+ case RTFKeyword::CAPS:
+ nSprm = NS_ooxml::LN_EG_RPrBase_caps;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pBoolValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue);
+ }
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::ASPALPHA:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE,
+ pBoolValue);
+ break;
+ case RTFKeyword::DELETED:
+ case RTFKeyword::REVISED:
+ {
+ auto pValue
+ = new RTFValue(nKeyword == RTFKeyword::DELETED ? oox::XML_del : oox::XML_ins);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_token, pValue);
+ }
+ break;
+ case RTFKeyword::SBAUTO:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_beforeAutospacing, pBoolValue);
+ break;
+ case RTFKeyword::SAAUTO:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_afterAutospacing, pBoolValue);
+ break;
+ case RTFKeyword::FACINGP:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders, pBoolValue);
+ break;
+ case RTFKeyword::HYPHAUTO:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_autoHyphenation, pBoolValue);
+ break;
+ case RTFKeyword::HYPHPAR:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens,
+ new RTFValue(int(bParam && nParam == 0)));
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter.rtf",
+ "TODO handle toggle '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+RTFError RTFDocumentImpl::pushState()
+{
+ //SAL_INFO("writerfilter.rtf", __func__ << " before push: " << m_pTokenizer->getGroup());
+
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ m_nGroupStartPos = Strm().Tell();
+
+ if (m_aStates.empty())
+ m_aStates.push(m_aDefaultState);
+ else
+ {
+ // fdo#85812 group resets run type of _current_ and new state (but not RTL)
+ if (m_aStates.top().getRunType() != RTFParserState::RunType::LTRCH_RTLCH_2
+ && m_aStates.top().getRunType() != RTFParserState::RunType::RTLCH_LTRCH_2)
+ {
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ }
+
+ if (m_aStates.top().getDestination() == Destination::MR)
+ lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
+ m_bMathNor);
+ m_aStates.push(m_aStates.top());
+ }
+ m_aStates.top().getDestinationText().setLength(0); // was copied: always reset!
+
+ m_pTokenizer->pushGroup();
+
+ switch (m_aStates.top().getDestination())
+ {
+ case Destination::FONTTABLE:
+ // this is a "faked" destination for the font entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::FONTENTRY);
+ break;
+ case Destination::STYLESHEET:
+ // this is a "faked" destination for the style sheet entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::STYLEENTRY);
+ {
+ // the *default* is \s0 i.e. paragraph style default
+ // this will be overwritten by \sN \csN \dsN \tsN
+ m_nCurrentStyleIndex = 0;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, pValue);
+ }
+ break;
+ case Destination::FIELDRESULT:
+ case Destination::SHAPETEXT:
+ case Destination::FORMFIELD:
+ case Destination::FIELDINSTRUCTION:
+ case Destination::PICT:
+ m_aStates.top().setDestination(Destination::NORMAL);
+ break;
+ case Destination::MNUM:
+ case Destination::MDEN:
+ case Destination::ME:
+ case Destination::MFNAME:
+ case Destination::MLIM:
+ case Destination::MSUB:
+ case Destination::MSUP:
+ case Destination::MDEG:
+ case Destination::MOMATH:
+ m_aStates.top().setDestination(Destination::MR);
+ break;
+ case Destination::REVISIONTABLE:
+ // this is a "faked" destination for the revision table entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::REVISIONENTRY);
+ break;
+ default:
+ break;
+ }
+
+ // If this is true, then ooxml:endtrackchange will be generated. Make sure
+ // we don't generate more ooxml:endtrackchange than ooxml:trackchange: new
+ // state does not inherit this flag.
+ m_aStates.top().setStartedTrackchange(false);
+
+ return RTFError::OK;
+}
+
+writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStyleProperties()
+{
+ int nBasedOn = 0;
+ RTFValue::Pointer_t pBasedOn
+ = m_aStates.top().getTableSprms().find(NS_ooxml::LN_CT_Style_basedOn);
+ if (pBasedOn)
+ nBasedOn = pBasedOn->getInt();
+ if (nBasedOn == 0)
+ {
+ // No parent style, then mimic what Word does: ignore attributes which
+ // would set a margin as formatting, but with a default value.
+ for (const auto& nId :
+ { NS_ooxml::LN_CT_Ind_firstLine, NS_ooxml::LN_CT_Ind_left, NS_ooxml::LN_CT_Ind_right,
+ NS_ooxml::LN_CT_Ind_start, NS_ooxml::LN_CT_Ind_end })
+ {
+ RTFValue::Pointer_t pValue = getNestedAttribute(m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_CT_PPrBase_ind, nId);
+ if (pValue && pValue->getInt() == 0)
+ eraseNestedAttribute(m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_CT_PPrBase_ind, nId);
+ }
+ }
+
+ RTFValue::Pointer_t pParaProps = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ RTFValue::Pointer_t pCharProps = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+
+ // resetSprms will clean up this modification
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_pPr, pParaProps);
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_rPr, pCharProps);
+
+ writerfilter::Reference<Properties>::Pointer_t pProps(new RTFReferenceProperties(
+ m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
+ return pProps;
+}
+
+/** 2 different representations of the styles are needed:
+
+ 1) flat content, as read from the input file:
+ stored in m_pStyleTableEntries, used as reference input for
+ deduplication both here and for hard formatting in getProperties()
+
+ 2) real content, with proper override of sprms/attributes where it differs
+ from parent style; this is produced here and sent to domain mapper
+ */
+RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
+{
+ RTFReferenceTable::Entries_t ret;
+ for (auto const& it : *m_pStyleTableEntries)
+ {
+ auto pStyle = it.second;
+ ret[it.first] = pStyle;
+ // ugly downcasts here, but can't easily replace the members with
+ // RTFReferenceProperties because dmapper wants SvRef<Properties> anyway
+ RTFValue::Pointer_t const pBasedOn(
+ static_cast<RTFReferenceProperties&>(*pStyle).getSprms().find(
+ NS_ooxml::LN_CT_Style_basedOn));
+ if (pBasedOn)
+ {
+ int const nBasedOn(pBasedOn->getInt());
+ // don't deduplicate yourself - especially a potential problem for the default style.
+ if (it.first == nBasedOn)
+ continue;
+
+ auto const itParent(m_pStyleTableEntries->find(nBasedOn)); // definition as read!
+ if (itParent != m_pStyleTableEntries->end())
+ {
+ auto const pStyleType(
+ static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find(
+ NS_ooxml::LN_CT_Style_type));
+ assert(pStyleType);
+ int const nStyleType(pStyleType->getInt());
+ RTFSprms sprms(
+ static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate(
+ static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(),
+ nStyleType));
+ RTFSprms attributes(
+ static_cast<RTFReferenceProperties&>(*pStyle)
+ .getAttributes()
+ .cloneAndDeduplicate(
+ static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(),
+ nStyleType));
+
+ ret[it.first] = new RTFReferenceProperties(std::move(attributes), std::move(sprms));
+ }
+ else
+ {
+ SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn);
+ }
+ }
+ }
+ assert(ret.size() == m_pStyleTableEntries->size());
+ return ret;
+}
+
+void RTFDocumentImpl::resetSprms()
+{
+ m_aStates.top().getTableSprms().clear();
+ m_aStates.top().getCharacterSprms().clear();
+ m_aStates.top().getParagraphSprms().clear();
+}
+
+void RTFDocumentImpl::resetAttributes()
+{
+ m_aStates.top().getTableAttributes().clear();
+ m_aStates.top().getCharacterAttributes().clear();
+ m_aStates.top().getParagraphAttributes().clear();
+}
+
+static bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties,
+ std::u16string_view rName)
+{
+ return std::any_of(rProperties.begin(), rProperties.end(),
+ [&](const beans::Property& rProperty) { return rProperty.Name == rName; });
+}
+
+RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState)
+{
+ switch (rState.getDestination())
+ {
+ //Note: in fonttbl there may or may not be groups, so process it as no groups
+ case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
+ {
+ // Some text unhandled? Seems it is last font name
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
+ if (rState.getDestination() == Destination::FONTTABLE)
+ {
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(m_aFontTableEntries));
+ Mapper().table(NS_ooxml::LN_FONTTABLE, pTable);
+ if (m_nDefaultFontIndex >= 0)
+ {
+ auto pValue = new RTFValue(m_aFontNames[getFontIndex(m_nDefaultFontIndex)]);
+ putNestedAttribute(m_aDefaultState.getCharacterSprms(),
+ NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii,
+ pValue);
+ }
+ }
+ }
+ break;
+ case Destination::STYLESHEET:
+ {
+ RTFReferenceTable::Entries_t pStyleTableDeduplicated(deduplicateStyleTable());
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(pStyleTableDeduplicated)));
+ Mapper().table(NS_ooxml::LN_STYLESHEET, pTable);
+ }
+ break;
+ case Destination::LISTOVERRIDETABLE:
+ {
+ RTFSprms aListTableAttributes;
+ writerfilter::Reference<Properties>::Pointer_t pProp
+ = new RTFReferenceProperties(std::move(aListTableAttributes), m_aListTableSprms);
+ RTFReferenceTable::Entries_t aListTableEntries;
+ aListTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(aListTableEntries)));
+ Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
+ }
+ break;
+ case Destination::LISTENTRY:
+ for (const auto& rListLevelEntry : rState.getListLevelEntries())
+ rState.getTableSprms().set(rListLevelEntry.first, rListLevelEntry.second,
+ RTFOverwrite::NO_APPEND);
+ break;
+ case Destination::FIELDINSTRUCTION:
+ {
+ auto pValue = new RTFValue(m_aFormfieldAttributes, m_aFormfieldSprms);
+ RTFSprms aFFAttributes;
+ RTFSprms aFFSprms;
+ aFFSprms.set(NS_ooxml::LN_ffdata, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aFFAttributes), std::move(aFFSprms));
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto pFFValue = new RTFValue(aFFAttributes, aFFSprms);
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pFFValue, nullptr);
+ }
+ m_aFormfieldAttributes.clear();
+ m_aFormfieldSprms.clear();
+
+ if (m_aStates.top().isFieldLocked())
+ singleChar(cFieldLock);
+ singleChar(cFieldSep);
+ }
+ break;
+ case Destination::FIELDRESULT:
+ singleChar(cFieldEnd);
+
+ if (!m_aPicturePath.isEmpty())
+ {
+ // Read the picture into m_aStates.top().aDestinationText.
+ pushState();
+ dispatchDestination(RTFKeyword::PICT);
+ if (m_aPicturePath.endsWith(".png"))
+ dispatchFlag(RTFKeyword::PNGBLIP);
+ OUString aFileURL = m_rMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_URL, OUString());
+ OUString aPictureURL;
+ try
+ {
+ aPictureURL = rtl::Uri::convertRelToAbs(aFileURL, m_aPicturePath);
+ }
+ catch (const rtl::MalformedUriException& rException)
+ {
+ SAL_WARN("writerfilter.rtf",
+ "rtl::Uri::convertRelToAbs() failed: " << rException.getMessage());
+ }
+
+ if (!aPictureURL.isEmpty())
+ {
+ SvFileStream aStream(aPictureURL, StreamMode::READ);
+ if (aStream.IsOpen())
+ {
+ OUStringBuffer aBuf;
+ while (aStream.good())
+ {
+ unsigned char ch = 0;
+ aStream.ReadUChar(ch);
+ if (ch < 16)
+ aBuf.append("0");
+ aBuf.append(static_cast<sal_Int32>(ch), 16);
+ }
+ m_aStates.top().getDestinationText() = aBuf;
+ }
+ }
+ popState();
+ m_aPicturePath.clear();
+ }
+
+ break;
+ case Destination::LEVELTEXT:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+
+ // The first character is the length of the string (the rest should be ignored).
+ sal_Int32 nLength(aStr.toChar());
+ OUString aValue;
+ if (nLength < aStr.getLength())
+ aValue = aStr.copy(1, nLength);
+ else
+ aValue = aStr;
+ auto pValue = new RTFValue(aValue, true);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
+ }
+ break;
+ case Destination::LEVELNUMBERS:
+ {
+ bool bNestedLevelNumbers = false;
+ if (m_aStates.size() > 1)
+ // Current destination is levelnumbers and parent destination is levelnumbers as well.
+ bNestedLevelNumbers
+ = m_aStates[m_aStates.size() - 2].getDestination() == Destination::LEVELNUMBERS;
+ if (!bNestedLevelNumbers && rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText))
+ {
+ RTFSprms& rAttributes
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText)->getAttributes();
+ RTFValue::Pointer_t pValue = rAttributes.find(NS_ooxml::LN_CT_LevelText_val);
+ if (pValue && rState.getLevelNumbersValid())
+ {
+ OUString aOrig = pValue->getString();
+
+ OUStringBuffer aBuf(aOrig.getLength() * 2);
+ sal_Int32 nReplaces = 1;
+ for (int i = 0; i < aOrig.getLength(); i++)
+ {
+ if (std::find(rState.getLevelNumbers().begin(),
+ rState.getLevelNumbers().end(), i + 1)
+ != rState.getLevelNumbers().end())
+ {
+ aBuf.append('%');
+ // '1.1.1' -> '%1.%2.%3', but '1.' (with '2.' prefix omitted) is %2.
+ aBuf.append(sal_Int32(nReplaces++ + rState.getListLevelNum() + 1
+ - rState.getLevelNumbers().size()));
+ }
+ else
+ aBuf.append(aOrig[i]);
+ }
+
+ pValue->setString(aBuf.makeStringAndClear());
+ }
+ else if (pValue)
+ // Have a value, but levelnumbers is not valid -> ignore it.
+ pValue->setString(OUString());
+ }
+ break;
+ }
+ case Destination::SHAPEPROPERTYNAME:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ rState.getShape().getProperties().emplace_back(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear(), OUString());
+ break;
+ case Destination::SHAPEPROPERTYVALUE:
+ if (!rState.getShape().getProperties().empty())
+ {
+ rState.getShape().getProperties().back().second
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ if (m_aStates.top().getHadShapeText())
+ m_pSdrImport->append(rState.getShape().getProperties().back().first,
+ rState.getShape().getProperties().back().second);
+ else if (rState.getInShapeGroup() && !rState.getInShape()
+ && rState.getShape().getProperties().back().first == "rotation")
+ {
+ // Rotation should be applied on the groupshape itself, not on each shape.
+ rState.getShape().getGroupProperties().push_back(
+ rState.getShape().getProperties().back());
+ rState.getShape().getProperties().pop_back();
+ }
+ }
+ break;
+ case Destination::PICPROP:
+ case Destination::SHAPEINSTRUCTION:
+ if (m_aStates.size() > 1
+ && m_aStates[m_aStates.size() - 2].getDestination()
+ == Destination::SHAPEINSTRUCTION)
+ {
+ // Do not resolve shape if shape instruction destination is inside other shape instruction
+ }
+ else if (!m_bObject && !rState.getInListpicture() && !rState.getHadShapeText()
+ && (!rState.getInShapeGroup() || rState.getInShape()))
+ {
+ // Don't trigger a shape import in case we're only leaving the \shpinst of the groupshape itself.
+ RTFSdrImport::ShapeOrPict eType
+ = (rState.getDestination() == Destination::SHAPEINSTRUCTION)
+ ? RTFSdrImport::SHAPE
+ : RTFSdrImport::PICT;
+ if (!m_aStates.top().getCurrentBuffer() || eType != RTFSdrImport::SHAPE)
+ m_pSdrImport->resolve(m_aStates.top().getShape(), true, eType);
+ else
+ {
+ // Shape inside table: buffer the import to have correct anchor position.
+ // Also buffer the RTFPicture of the state stack as it contains
+ // the shape size.
+ auto pPictureValue = new RTFValue(m_aStates.top().getPicture());
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_PICTURE, pPictureValue, nullptr));
+ auto pValue = new RTFValue(m_aStates.top().getShape());
+
+ // Buffer wrap type.
+ for (const auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
+ {
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
+ || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
+ {
+ m_aStates.top().getShape().getWrapSprm() = rCharacterSprm;
+ break;
+ }
+ }
+
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESHAPE, pValue, nullptr));
+ }
+ }
+ else if (rState.getInShapeGroup() && !rState.getInShape())
+ {
+ // End of a groupshape, as we're in shapegroup, but not in a real shape.
+ for (const auto& rGroupProperty : rState.getShape().getGroupProperties())
+ m_pSdrImport->appendGroupProperty(rGroupProperty.first, rGroupProperty.second);
+ rState.getShape().getGroupProperties().clear();
+ }
+ break;
+ case Destination::BOOKMARKSTART:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ int nPos = m_aBookmarks.size();
+ m_aBookmarks[aStr] = nPos;
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(lcl_getBookmarkProperties(nPos, aStr)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(lcl_getBookmarkProperties(nPos, aStr)), nullptr);
+ }
+ break;
+ case Destination::BOOKMARKEND:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(
+ lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)),
+ nullptr);
+ }
+ break;
+ case Destination::INDEXENTRY:
+ case Destination::TOCENTRY:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString str(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ // dmapper expects this as a field, so let's fake something...
+ auto const field((Destination::INDEXENTRY == rState.getDestination())
+ ? std::u16string_view(u"XE")
+ : std::u16string_view(u"TC"));
+ str = OUString::Concat(field) + " \"" + str.replaceAll("\"", "\\\"") + "\"";
+ singleChar(cFieldStart);
+ Mapper().utext(reinterpret_cast<sal_uInt8 const*>(str.getStr()), str.getLength());
+ singleChar(cFieldSep);
+ // no result
+ singleChar(cFieldEnd);
+ }
+ break;
+ case Destination::FORMFIELDNAME:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pValue);
+ }
+ break;
+ case Destination::FORMFIELDLIST:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ // OOXML puts these into a LN_CT_FFData_ddList but FFDataHandler should handle this too
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_listEntry, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ break;
+ case Destination::DATAFIELD:
+ {
+ if (m_bFormField)
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OString aStr = OUStringToOString(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear(),
+ rState.getCurrentEncoding());
+ // decode hex dump
+ OStringBuffer aBuf;
+ int b = 0;
+ int count = 2;
+ for (int i = 0; i < aStr.getLength(); ++i)
+ {
+ char ch = aStr[i];
+ if (ch != 0x0d && ch != 0x0a)
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return RTFError::HEX_INVALID;
+ b += parsed;
+ count--;
+ if (!count)
+ {
+ aBuf.append(static_cast<char>(b));
+ count = 2;
+ b = 0;
+ }
+ }
+ }
+ aStr = aBuf.makeStringAndClear();
+
+ // ignore the first bytes
+ if (aStr.getLength() > 8)
+ aStr = aStr.copy(8);
+ // extract name
+ sal_Int32 nLength = aStr.toChar();
+ if (!aStr.isEmpty())
+ aStr = aStr.copy(1);
+ nLength = std::min(nLength, aStr.getLength());
+ OString aName = aStr.copy(0, nLength);
+ if (aStr.getLength() > nLength)
+ aStr = aStr.copy(nLength + 1); // zero-terminated string
+ else
+ aStr.clear();
+ // extract default text
+ nLength = aStr.toChar();
+ if (!aStr.isEmpty())
+ aStr = aStr.copy(1);
+ auto pNValue = new RTFValue(OStringToOUString(aName, rState.getCurrentEncoding()));
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pNValue);
+ if (nLength > 0)
+ {
+ OString aDefaultText = aStr.copy(0, std::min(nLength, aStr.getLength()));
+ auto pDValue = new RTFValue(
+ OStringToOUString(aDefaultText, rState.getCurrentEncoding()));
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFTextInput_default, pDValue);
+ }
+
+ m_bFormField = false;
+ }
+ }
+ break;
+ case Destination::CREATIONTIME:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setCreationDate(lcl_getDateTime(rState));
+ break;
+ case Destination::REVISIONTIME:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setModificationDate(lcl_getDateTime(rState));
+ break;
+ case Destination::PRINTTIME:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setPrintDate(lcl_getDateTime(rState));
+ break;
+ case Destination::AUTHOR:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setAuthor(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::KEYWORDS:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setKeywords(comphelper::string::convertCommaSeparated(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear()));
+ break;
+ case Destination::COMMENT:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setGenerator(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::SUBJECT:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setSubject(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::TITLE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setTitle(
+ rState.getCurrentDestinationText()->makeStringAndClear());
+ }
+ break;
+
+ case Destination::DOCCOMM:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setDescription(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::OPERATOR:
+ case Destination::COMPANY:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aName = rState.getDestination() == Destination::OPERATOR ? OUString("Operator")
+ : OUString("Company");
+ uno::Any aValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ if (m_xDocumentProperties.is())
+ {
+ uno::Reference<beans::XPropertyContainer> xUserDefinedProperties
+ = m_xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties,
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo
+ = xPropertySet->getPropertySetInfo();
+ if (xPropertySetInfo->hasPropertyByName(aName))
+ xPropertySet->setPropertyValue(aName, aValue);
+ else
+ xUserDefinedProperties->addProperty(aName, beans::PropertyAttribute::REMOVABLE,
+ aValue);
+ }
+ }
+ break;
+ case Destination::OBJDATA:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+
+ RTFError eError = handleEmbeddedObject();
+ if (eError != RTFError::OK)
+ return eError;
+ }
+ break;
+ case Destination::OBJCLASS:
+ {
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ m_aOLEAttributes.set(NS_ooxml::LN_CT_OLEObject_ProgID, pValue);
+ break;
+ }
+ case Destination::OBJECT:
+ {
+ if (!m_bObject)
+ {
+ // if the object is in a special container we will use the \result
+ // element instead of the \objdata
+ // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
+ break;
+ }
+
+ RTFSprms aObjectSprms;
+ auto pOLEValue = new RTFValue(m_aOLEAttributes);
+ aObjectSprms.set(NS_ooxml::LN_OLEObject_OLEObject, pOLEValue);
+
+ RTFSprms aObjAttributes;
+ RTFSprms aObjSprms;
+ auto pValue = new RTFValue(m_aObjectAttributes, aObjectSprms);
+ aObjSprms.set(NS_ooxml::LN_object, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aObjAttributes), std::move(aObjSprms));
+ uno::Reference<drawing::XShape> xShape;
+ RTFValue::Pointer_t pShape = m_aObjectAttributes.find(NS_ooxml::LN_shape);
+ OSL_ASSERT(pShape);
+ if (pShape)
+ pShape->getAny() >>= xShape;
+ if (xShape.is())
+ {
+ Mapper().startShape(xShape);
+ Mapper().props(pProperties);
+ Mapper().endShape();
+ }
+ m_aObjectAttributes.clear();
+ m_aOLEAttributes.clear();
+ m_bObject = false;
+ }
+ break;
+ case Destination::ANNOTATIONDATE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr(OStringToOUString(
+ DTTM22OString(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear().toInt32()),
+ rState.getCurrentEncoding()));
+ auto pValue = new RTFValue(aStr);
+ RTFSprms aAnnAttributes;
+ aAnnAttributes.set(NS_ooxml::LN_CT_TrackChange_date, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAnnAttributes));
+ Mapper().props(pProperties);
+ }
+ break;
+ case Destination::ANNOTATIONAUTHOR:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ m_aAuthor = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ break;
+ case Destination::ATNID:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ m_aAuthorInitials = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ break;
+ case Destination::ANNOTATIONREFERENCESTART:
+ case Destination::ANNOTATIONREFERENCEEND:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ auto pValue = new RTFValue(aStr.toInt32());
+ RTFSprms aAttributes;
+ if (rState.getDestination() == Destination::ANNOTATIONREFERENCESTART)
+ aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart, pValue);
+ else
+ aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes));
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto const pValue2 = new RTFValue(aAttributes, RTFSprms());
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue2, nullptr);
+ }
+ }
+ break;
+ case Destination::ANNOTATIONREFERENCE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ RTFSprms aAnnAttributes;
+ aAnnAttributes.set(NS_ooxml::LN_CT_Markup_id, new RTFValue(aStr.toInt32()));
+ Mapper().props(new RTFReferenceProperties(std::move(aAnnAttributes)));
+ }
+ break;
+ case Destination::FALT:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ auto pValue = new RTFValue(aStr);
+ rState.getTableSprms().set(NS_ooxml::LN_CT_Font_altName, pValue);
+ }
+ break;
+ case Destination::DRAWINGOBJECT:
+ if (m_aStates.top().getDrawingObject().getShape().is())
+ {
+ RTFDrawingObject& rDrawing = m_aStates.top().getDrawingObject();
+ const uno::Reference<drawing::XShape>& xShape(rDrawing.getShape());
+ const uno::Reference<beans::XPropertySet>& xPropertySet(rDrawing.getPropertySet());
+
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
+ bool bTextFrame = xServiceInfo->supportsService("com.sun.star.text.TextFrame");
+
+ // The default is certainly not inline, but then what Word supports is just at-character.
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+
+ if (bTextFrame)
+ {
+ xPropertySet->setPropertyValue("HoriOrientPosition",
+ uno::Any(rDrawing.getLeft()));
+ xPropertySet->setPropertyValue("VertOrientPosition",
+ uno::Any(rDrawing.getTop()));
+ }
+ else
+ {
+ xShape->setPosition(awt::Point(rDrawing.getLeft(), rDrawing.getTop()));
+ }
+ xShape->setSize(awt::Size(rDrawing.getRight(), rDrawing.getBottom()));
+
+ if (rDrawing.getHasLineColor())
+ {
+ uno::Any aLineColor(sal_uInt32((rDrawing.getLineColorR() << 16)
+ + (rDrawing.getLineColorG() << 8)
+ + rDrawing.getLineColorB()));
+ uno::Any aLineWidth;
+ RTFSdrImport::resolveLineColorAndWidth(bTextFrame, xPropertySet, aLineColor,
+ aLineWidth);
+ }
+ if (rDrawing.getHasFillColor())
+ xPropertySet->setPropertyValue(
+ "FillColor", uno::Any(sal_uInt32((rDrawing.getFillColorR() << 16)
+ + (rDrawing.getFillColorG() << 8)
+ + rDrawing.getFillColorB())));
+ else if (!bTextFrame)
+ // If there is no fill, the Word default is 100% transparency.
+ xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_Int32(100)));
+
+ RTFSdrImport::resolveFLine(xPropertySet, rDrawing.getFLine());
+
+ if (!m_aStates.top().getDrawingObject().getHadShapeText())
+ {
+ Mapper().startShape(xShape);
+ }
+ Mapper().endShape();
+ }
+ break;
+ case Destination::PICT:
+ // fdo#79319 ignore picture data if it's really a shape
+ if (!m_pSdrImport->isFakePict())
+ {
+ resolvePict(true, m_pSdrImport->getCurrentShape());
+ }
+ m_bNeedFinalPar = true;
+ break;
+ case Destination::SHAPE:
+ m_bNeedFinalPar = true;
+ m_bNeedCr = m_bNeedCrOrig;
+ if (rState.getFrame().inFrame())
+ {
+ // parBreak() modifies m_aStates.top() so we can't apply resetFrame() directly on aState
+ resetFrame();
+ parBreak();
+ // Save this state for later use, so we only reset frame status only for the first shape inside a frame.
+ rState = m_aStates.top();
+ m_bNeedPap = true;
+ }
+ break;
+ case Destination::MOMATH:
+ {
+ m_aMathBuffer.appendClosingTag(M_TOKEN(oMath));
+
+ SvGlobalName aGlobalName(SO3_SM_CLASSID);
+ comphelper::EmbeddedObjectContainer aContainer;
+ OUString aName;
+ uno::Reference<embed::XEmbeddedObject> xObject
+ = aContainer.CreateEmbeddedObject(aGlobalName.GetByteSequence(), aName);
+ if (xObject) // rhbz#1766990 starmath might not be available
+ {
+ uno::Reference<util::XCloseable> xComponent(xObject->getComponent(),
+ uno::UNO_SET_THROW);
+ // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
+ // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
+ // to RTLD_GLOBAL, so most probably a gcc bug.
+ auto& rImport = dynamic_cast<oox::FormulaImportBase&>(
+ dynamic_cast<SfxBaseModel&>(*xComponent));
+ rImport.readFormulaOoxml(m_aMathBuffer);
+
+ auto pValue = new RTFValue(xObject);
+ RTFSprms aMathAttributes;
+ aMathAttributes.set(NS_ooxml::LN_starmath, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aMathAttributes));
+ Mapper().props(pProperties);
+ }
+
+ m_aMathBuffer = oox::formulaimport::XmlStreamBuilder();
+ }
+ break;
+ case Destination::MR:
+ lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
+ m_bMathNor);
+ break;
+ case Destination::MF:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(f));
+ break;
+ case Destination::MFPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(fPr));
+ break;
+ case Destination::MCTRLPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(ctrlPr));
+ break;
+ case Destination::MNUM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(num));
+ break;
+ case Destination::MDEN:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(den));
+ break;
+ case Destination::MACC:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(acc));
+ break;
+ case Destination::MACCPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(accPr));
+ break;
+ case Destination::MCHR:
+ case Destination::MPOS:
+ case Destination::MVERTJC:
+ case Destination::MSTRIKEH:
+ case Destination::MDEGHIDE:
+ case Destination::MBEGCHR:
+ case Destination::MSEPCHR:
+ case Destination::MENDCHR:
+ case Destination::MSUBHIDE:
+ case Destination::MSUPHIDE:
+ case Destination::MTYPE:
+ case Destination::MGROW:
+ {
+ sal_Int32 nMathToken = 0;
+ switch (rState.getDestination())
+ {
+ case Destination::MCHR:
+ nMathToken = M_TOKEN(chr);
+ break;
+ case Destination::MPOS:
+ nMathToken = M_TOKEN(pos);
+ break;
+ case Destination::MVERTJC:
+ nMathToken = M_TOKEN(vertJc);
+ break;
+ case Destination::MSTRIKEH:
+ nMathToken = M_TOKEN(strikeH);
+ break;
+ case Destination::MDEGHIDE:
+ nMathToken = M_TOKEN(degHide);
+ break;
+ case Destination::MBEGCHR:
+ nMathToken = M_TOKEN(begChr);
+ break;
+ case Destination::MSEPCHR:
+ nMathToken = M_TOKEN(sepChr);
+ break;
+ case Destination::MENDCHR:
+ nMathToken = M_TOKEN(endChr);
+ break;
+ case Destination::MSUBHIDE:
+ nMathToken = M_TOKEN(subHide);
+ break;
+ case Destination::MSUPHIDE:
+ nMathToken = M_TOKEN(supHide);
+ break;
+ case Destination::MTYPE:
+ nMathToken = M_TOKEN(type);
+ break;
+ case Destination::MGROW:
+ nMathToken = M_TOKEN(grow);
+ break;
+ default:
+ break;
+ }
+
+ oox::formulaimport::XmlStream::AttributeList aAttribs;
+ aAttribs[M_TOKEN(val)]
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ m_aMathBuffer.appendOpeningTag(nMathToken, aAttribs);
+ m_aMathBuffer.appendClosingTag(nMathToken);
+ }
+ break;
+ case Destination::ME:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(e));
+ break;
+ case Destination::MBAR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(bar));
+ break;
+ case Destination::MBARPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(barPr));
+ break;
+ case Destination::MD:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(d));
+ break;
+ case Destination::MDPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(dPr));
+ break;
+ case Destination::MFUNC:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(func));
+ break;
+ case Destination::MFUNCPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(funcPr));
+ break;
+ case Destination::MFNAME:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(fName));
+ break;
+ case Destination::MLIMLOW:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limLow));
+ break;
+ case Destination::MLIMLOWPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limLowPr));
+ break;
+ case Destination::MLIM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(lim));
+ break;
+ case Destination::MM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(m));
+ break;
+ case Destination::MMPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(mPr));
+ break;
+ case Destination::MMR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(mr));
+ break;
+ case Destination::MNARY:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(nary));
+ break;
+ case Destination::MNARYPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(naryPr));
+ break;
+ case Destination::MSUB:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sub));
+ break;
+ case Destination::MSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sup));
+ break;
+ case Destination::MLIMUPP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limUpp));
+ break;
+ case Destination::MLIMUPPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limUppPr));
+ break;
+ case Destination::MGROUPCHR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(groupChr));
+ break;
+ case Destination::MGROUPCHRPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(groupChrPr));
+ break;
+ case Destination::MBORDERBOX:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(borderBox));
+ break;
+ case Destination::MBORDERBOXPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(borderBoxPr));
+ break;
+ case Destination::MRAD:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(rad));
+ break;
+ case Destination::MRADPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(radPr));
+ break;
+ case Destination::MDEG:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(deg));
+ break;
+ case Destination::MSSUB:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSub));
+ break;
+ case Destination::MSSUBPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubPr));
+ break;
+ case Destination::MSSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSup));
+ break;
+ case Destination::MSSUPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSupPr));
+ break;
+ case Destination::MSSUBSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSup));
+ break;
+ case Destination::MSSUBSUPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSupPr));
+ break;
+ case Destination::MSPRE:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sPre));
+ break;
+ case Destination::MSPREPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sPrePr));
+ break;
+ case Destination::MBOX:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(box));
+ break;
+ case Destination::MEQARR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(eqArr));
+ break;
+ case Destination::SHAPEGROUP:
+ if (rState.getCreatedShapeGroup())
+ m_pSdrImport->popParent();
+ break;
+ case Destination::PROPNAME:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ rState.setPropName(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::STATICVAL:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ {
+ // Find out what is the key, value type and value we want to set.
+ uno::Reference<beans::XPropertyContainer> xPropertyContainer
+ = m_xDocumentProperties->getUserDefinedProperties();
+ const OUString& rKey = m_aStates.top().getPropName();
+ OUString aStaticVal
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ uno::Any aAny;
+ if (m_aStates.top().getPropType() == cppu::UnoType<OUString>::get())
+ aAny <<= aStaticVal;
+ else if (m_aStates.top().getPropType() == cppu::UnoType<sal_Int32>::get())
+ aAny <<= aStaticVal.toInt32();
+ else if (m_aStates.top().getPropType() == cppu::UnoType<bool>::get())
+ aAny <<= aStaticVal.toBoolean();
+ else if (m_aStates.top().getPropType() == cppu::UnoType<util::DateTime>::get())
+ aAny <<= getDateTimeFromUserProp(aStaticVal);
+ else if (m_aStates.top().getPropType() == cppu::UnoType<double>::get())
+ aAny <<= aStaticVal.toDouble();
+
+ xPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aAny);
+ }
+ break;
+ case Destination::USERPROPS:
+ {
+ // These are the imported properties.
+ uno::Reference<document::XDocumentProperties> xDocumentProperties
+ = m_xDocumentProperties;
+
+ // These are the real document properties.
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
+ m_xDstDoc, uno::UNO_QUERY);
+ if (xDocumentPropertiesSupplier.is())
+ m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+
+ if (m_xDocumentProperties.is())
+ {
+ if (!m_bIsNewDoc)
+ {
+ // Check classification.
+ if (!SfxClassificationHelper::ShowPasteInfo(SfxClassificationHelper::CheckPaste(
+ xDocumentProperties, m_xDocumentProperties)))
+ return RTFError::CLASSIFICATION;
+ }
+
+ uno::Reference<beans::XPropertyContainer> xClipboardPropertyContainer
+ = xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertyContainer> xDocumentPropertyContainer
+ = m_xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xClipboardPropertySet(
+ xClipboardPropertyContainer, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xDocumentPropertySet(xDocumentPropertyContainer,
+ uno::UNO_QUERY);
+ const uno::Sequence<beans::Property> aClipboardProperties
+ = xClipboardPropertySet->getPropertySetInfo()->getProperties();
+ uno::Sequence<beans::Property> aDocumentProperties
+ = xDocumentPropertySet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aClipboardProperties)
+ {
+ const OUString& rKey = rProperty.Name;
+ uno::Any aValue = xClipboardPropertySet->getPropertyValue(rKey);
+
+ try
+ {
+ if (lcl_containsProperty(aDocumentProperties, rKey))
+ {
+ // When pasting, don't update existing properties.
+ if (!m_bIsNewDoc)
+ xDocumentPropertySet->setPropertyValue(rKey, aValue);
+ }
+ else
+ xDocumentPropertyContainer->addProperty(
+ rKey, beans::PropertyAttribute::REMOVABLE, aValue);
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.rtf", "failed to set property " << rKey);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return RTFError::OK;
+}
+
+void RTFDocumentImpl::afterPopState(RTFParserState& rState)
+{
+ // list table
+ switch (rState.getDestination())
+ {
+ case Destination::LISTENTRY:
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pValue,
+ RTFOverwrite::NO_APPEND);
+ m_aListTable[rState.getCurrentListIndex()] = pValue;
+ m_nListLevel = -1;
+ m_aInvalidListTableFirstIndents[rState.getCurrentListIndex()]
+ = m_aInvalidListLevelFirstIndents;
+ m_aInvalidListLevelFirstIndents.clear();
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING:
+ {
+ RTFValue::Pointer_t pIdValue
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_AbstractNum_nsid);
+ if (pIdValue && !m_aStates.empty())
+ {
+ // Abstract numbering
+ RTFSprms aLeveltextAttributes;
+ OUString aTextValue;
+ RTFValue::Pointer_t pTextBefore
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelText_val);
+ if (pTextBefore)
+ aTextValue += pTextBefore->getString();
+ aTextValue += "%1";
+ RTFValue::Pointer_t pTextAfter
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelSuffix_val);
+ if (pTextAfter)
+ aTextValue += pTextAfter->getString();
+ auto pTextValue = new RTFValue(aTextValue);
+ aLeveltextAttributes.set(NS_ooxml::LN_CT_LevelText_val, pTextValue);
+
+ RTFSprms aLevelAttributes;
+ RTFSprms aLevelSprms;
+ auto pIlvlValue = new RTFValue(0);
+ aLevelAttributes.set(NS_ooxml::LN_CT_Lvl_ilvl, pIlvlValue);
+
+ RTFValue::Pointer_t pFmtValue
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_numFmt);
+ if (pFmtValue)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_numFmt, pFmtValue);
+
+ RTFValue::Pointer_t pStartatValue
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_start);
+ if (pStartatValue)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_start, pStartatValue);
+
+ auto pLeveltextValue = new RTFValue(aLeveltextAttributes);
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_lvlText, pLeveltextValue);
+ RTFValue::Pointer_t pRunProps
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_rPr);
+ if (pRunProps)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_rPr, pRunProps);
+
+ RTFSprms aAbstractAttributes;
+ RTFSprms aAbstractSprms;
+ aAbstractAttributes.set(NS_ooxml::LN_CT_AbstractNum_abstractNumId, pIdValue);
+ auto pLevelValue = new RTFValue(aLevelAttributes, aLevelSprms);
+ aAbstractSprms.set(NS_ooxml::LN_CT_AbstractNum_lvl, pLevelValue,
+ RTFOverwrite::NO_APPEND);
+
+ RTFSprms aListTableSprms;
+ auto pAbstractValue = new RTFValue(aAbstractAttributes, aAbstractSprms);
+ // It's important that Numbering_abstractNum and Numbering_num never overwrites previous values.
+ aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pAbstractValue,
+ RTFOverwrite::NO_APPEND);
+
+ // Numbering
+ RTFSprms aNumberingAttributes;
+ RTFSprms aNumberingSprms;
+ aNumberingAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, pIdValue);
+ aNumberingSprms.set(NS_ooxml::LN_CT_Num_abstractNumId, pIdValue);
+ auto pNumberingValue = new RTFValue(aNumberingAttributes, aNumberingSprms);
+ aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pNumberingValue,
+ RTFOverwrite::NO_APPEND);
+
+ // Table
+ RTFSprms aListTableAttributes;
+ writerfilter::Reference<Properties>::Pointer_t pProp = new RTFReferenceProperties(
+ std::move(aListTableAttributes), std::move(aListTableSprms));
+
+ RTFReferenceTable::Entries_t aListTableEntries;
+ aListTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(aListTableEntries)));
+ Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
+
+ // Use it
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_ilvl, pIlvlValue, RTFOverwrite::YES_PREPEND);
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_numId, pIdValue, RTFOverwrite::YES_PREPEND);
+ }
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
+ if (!m_aStates.empty())
+ {
+ // FIXME: don't use pDestinationText, points to popped state
+ auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelSuffix_val, pValue);
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
+ if (!m_aStates.empty())
+ {
+ // FIXME: don't use pDestinationText, points to popped state
+ auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
+ }
+ break;
+ case Destination::LISTNAME:
+ break;
+ case Destination::LISTLEVEL:
+ if (!m_aStates.empty())
+ {
+ auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_Lvl_ilvl, pInnerValue);
+
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ if (m_aStates.top().getDestination() != Destination::LFOLEVEL)
+ m_aStates.top().getListLevelEntries().set(NS_ooxml::LN_CT_AbstractNum_lvl,
+ pValue, RTFOverwrite::NO_APPEND);
+ else
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_NumLvl_lvl, pValue);
+ }
+ break;
+ case Destination::LFOLEVEL:
+ if (!m_aStates.empty())
+ {
+ auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_NumLvl_ilvl, pInnerValue);
+
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_lvlOverride, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ break;
+ // list override table
+ case Destination::LISTOVERRIDEENTRY:
+ if (!m_aStates.empty())
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ {
+ // copy properties upwards so upper popState() inserts it
+ m_aStates.top().getTableAttributes() = rState.getTableAttributes();
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ }
+ else
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pValue,
+ RTFOverwrite::NO_APPEND);
+ m_aListOverrideTable[rState.getCurrentListOverrideIndex()]
+ = rState.getCurrentListIndex();
+ }
+ }
+ break;
+ case Destination::LEVELTEXT:
+ if (!m_aStates.empty())
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes());
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_lvlText, pValue);
+ }
+ break;
+ case Destination::LEVELNUMBERS:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS
+ || m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ // Parent state is level number or list level, current state is
+ // level numbers: mark parent as invalid as well if necessary.
+ m_aStates.top().setLevelNumbersValid(rState.getLevelNumbersValid());
+ }
+ break;
+ case Destination::FIELDINSTRUCTION:
+ if (!m_aStates.empty())
+ m_aStates.top().setFieldStatus(RTFFieldStatus::INSTRUCTION);
+ break;
+ case Destination::FIELDRESULT:
+ if (!m_aStates.empty())
+ m_aStates.top().setFieldStatus(RTFFieldStatus::RESULT);
+ break;
+ case Destination::FIELD:
+ if (rState.getFieldStatus() == RTFFieldStatus::INSTRUCTION)
+ singleChar(cFieldEnd);
+ break;
+ case Destination::DOCVAR:
+ if (!m_aStates.empty())
+ {
+ OUString docvar(rState.getDocVar());
+ if (m_aStates.top().getDocVarName().isEmpty())
+ {
+ m_aStates.top().setDocVarName(docvar);
+ }
+ else
+ {
+ uno::Reference<beans::XPropertySet> xMaster(
+ m_xModelFactory->createInstance("com.sun.star.text.FieldMaster.User"),
+ uno::UNO_QUERY_THROW);
+ xMaster->setPropertyValue("Name", uno::Any(m_aStates.top().getDocVarName()));
+ uno::Reference<text::XDependentTextField> xField(
+ m_xModelFactory->createInstance("com.sun.star.text.TextField.User"),
+ uno::UNO_QUERY);
+ xField->attachTextFieldMaster(xMaster);
+ xField->getTextFieldMaster()->setPropertyValue("Content", uno::Any(docvar));
+
+ m_aStates.top().clearDocVarName();
+ }
+ }
+ break;
+ case Destination::SHAPEPROPERTYVALUEPICT:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getPicture() = rState.getPicture();
+ // both \sp and \sv are destinations, copy the text up-ward for later
+ m_aStates.top().getDestinationText() = rState.getDestinationText();
+ }
+ break;
+ case Destination::FALT:
+ if (!m_aStates.empty())
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ break;
+ case Destination::SHAPEPROPERTYNAME:
+ case Destination::SHAPEPROPERTYVALUE:
+ case Destination::SHAPEPROPERTY:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getShape() = rState.getShape();
+ m_aStates.top().getPicture() = rState.getPicture();
+ m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
+ }
+ break;
+ case Destination::SHAPEINSTRUCTION:
+ if (!m_aStates.empty()
+ && m_aStates.top().getDestination() == Destination::SHAPEINSTRUCTION)
+ {
+ // Shape instruction inside other shape instruction: just copy new shape settings:
+ // it will be resolved on end of topmost shape instruction destination
+ m_aStates.top().getShape() = rState.getShape();
+ m_aStates.top().getPicture() = rState.getPicture();
+ m_aStates.top().getCharacterSprms() = rState.getCharacterSprms();
+ m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
+ }
+ break;
+ case Destination::FLYMAINCONTENT:
+ case Destination::SHPPICT:
+ case Destination::SHAPE:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getFrame() = rState.getFrame();
+ if (rState.getDestination() == Destination::SHPPICT
+ && m_aStates.top().getDestination() == Destination::LISTPICTURE)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumPicBullet_numPicBulletId,
+ new RTFValue(m_nListPictureId++));
+ RTFSprms aSprms;
+ // Dummy value, real picture is already sent to dmapper.
+ aSprms.set(NS_ooxml::LN_CT_NumPicBullet_pict, new RTFValue(0));
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_numPicBullet, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ }
+ break;
+ case Destination::SHAPETEXT:
+ if (!m_aStates.empty())
+ {
+ // If we're leaving the shapetext group (it may have nested ones) and this is a shape, not an old drawingobject.
+ if (m_aStates.top().getDestination() != Destination::SHAPETEXT
+ && !m_aStates.top().getDrawingObject().getHadShapeText())
+ {
+ m_aStates.top().setHadShapeText(true);
+ if (!m_aStates.top().getCurrentBuffer())
+ m_pSdrImport->close();
+ else
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_ENDSHAPE, nullptr, nullptr));
+ }
+
+ // It's allowed to declare these inside the shape text, and they
+ // are expected to have an effect for the whole shape.
+ if (rState.getDrawingObject().getLeft())
+ m_aStates.top().getDrawingObject().setLeft(rState.getDrawingObject().getLeft());
+ if (rState.getDrawingObject().getTop())
+ m_aStates.top().getDrawingObject().setTop(rState.getDrawingObject().getTop());
+ if (rState.getDrawingObject().getRight())
+ m_aStates.top().getDrawingObject().setRight(
+ rState.getDrawingObject().getRight());
+ if (rState.getDrawingObject().getBottom())
+ m_aStates.top().getDrawingObject().setBottom(
+ rState.getDrawingObject().getBottom());
+ }
+ break;
+ case Destination::PROPNAME:
+ if (m_aStates.top().getDestination() == Destination::USERPROPS)
+ m_aStates.top().setPropName(rState.getPropName());
+ break;
+ default:
+ {
+ if (!m_aStates.empty() && m_aStates.top().getDestination() == Destination::PICT)
+ m_aStates.top().getPicture() = rState.getPicture();
+ }
+ break;
+ }
+}
+
+RTFError RTFDocumentImpl::popState()
+{
+ //SAL_INFO("writerfilter", __func__ << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
+ // ", dest state: " << m_aStates.top().eDestination);
+
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFParserState aState(m_aStates.top());
+ m_bWasInFrame = aState.getFrame().inFrame();
+
+ // dmapper expects some content in header/footer, so if there would be nothing, add an empty paragraph.
+ if (m_pTokenizer->getGroup() == 1 && m_bFirstRun)
+ {
+ switch (m_nStreamType)
+ {
+ case NS_ooxml::LN_headerl:
+ case NS_ooxml::LN_headerr:
+ case NS_ooxml::LN_headerf:
+ case NS_ooxml::LN_footerl:
+ case NS_ooxml::LN_footerr:
+ case NS_ooxml::LN_footerf:
+ dispatchSymbol(RTFKeyword::PAR);
+ break;
+ }
+ }
+
+ RTFError eError = beforePopState(aState);
+ if (eError != RTFError::OK)
+ return eError;
+
+ // See if we need to end a track change
+ if (aState.getStartedTrackchange())
+ {
+ RTFSprms aTCSprms;
+ auto pValue = new RTFValue(0);
+ aTCSprms.set(NS_ooxml::LN_endtrackchange, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(RTFSprms(), std::move(aTCSprms)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(RTFSprms(), aTCSprms), nullptr);
+ }
+
+ // This is the end of the doc, see if we need to close the last section.
+ if (m_pTokenizer->getGroup() == 1 && !m_bFirstRun)
+ {
+ // \par means an empty paragraph at the end of footnotes/endnotes, but
+ // not in case of other substreams, like headers.
+ if (m_bNeedCr && m_nStreamType != NS_ooxml::LN_footnote
+ && m_nStreamType != NS_ooxml::LN_endnote && m_bIsNewDoc)
+ dispatchSymbol(RTFKeyword::PAR);
+ if (m_bNeedSect) // may be set by dispatchSymbol above!
+ sectBreak(true);
+ }
+
+ m_aStates.pop();
+
+ m_pTokenizer->popGroup();
+
+ afterPopState(aState);
+
+ if (aState.getCurrentBuffer() == &m_aSuperBuffer)
+ {
+ OSL_ASSERT(!m_aStates.empty() && m_aStates.top().getCurrentBuffer() == nullptr);
+
+ if (!m_aSuperBuffer.empty())
+ replayBuffer(m_aSuperBuffer, nullptr, nullptr);
+ }
+
+ if (!m_aStates.empty() && m_aStates.top().getTableRowWidthAfter() > 0
+ && aState.getTableRowWidthAfter() == 0)
+ // An RTFKeyword::ROW in the inner group already parsed nTableRowWidthAfter,
+ // don't do it again in the outer state later.
+ m_aStates.top().setTableRowWidthAfter(0);
+
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid && !m_aStates.empty())
+ {
+ // Section break type created for \page still has an effect in the
+ // outer state as well.
+ RTFValue::Pointer_t pType
+ = aState.getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ if (pType)
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pType);
+ }
+
+ return RTFError::OK;
+}
+
+RTFError RTFDocumentImpl::handleEmbeddedObject()
+{
+ OString aStr
+ = OUStringToOString(m_aStates.top().getCurrentDestinationText()->makeStringAndClear(),
+ RTL_TEXTENCODING_ASCII_US);
+ std::unique_ptr<SvStream> pStream(new SvMemoryStream());
+ if (!msfilter::rtfutil::ExtractOLE2FromObjdata(aStr, *pStream))
+ return RTFError::HEX_INVALID;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(pStream.release(), /*_bOwner=*/true));
+ auto pStreamValue = new RTFValue(xInputStream);
+ m_aOLEAttributes.set(NS_ooxml::LN_inputstream, pStreamValue);
+
+ return RTFError::OK;
+}
+
+bool RTFDocumentImpl::isInBackground() { return m_aStates.top().getInBackground(); }
+
+RTFInternalState RTFDocumentImpl::getInternalState() { return m_aStates.top().getInternalState(); }
+
+void RTFDocumentImpl::setInternalState(RTFInternalState nInternalState)
+{
+ m_aStates.top().setInternalState(nInternalState);
+}
+
+Destination RTFDocumentImpl::getDestination() { return m_aStates.top().getDestination(); }
+
+void RTFDocumentImpl::setDestination(Destination eDestination)
+{
+ m_aStates.top().setDestination(eDestination);
+}
+
+// this is a questionably named method that is used only in a very special
+// situation where it looks like the "current" buffer is needed?
+void RTFDocumentImpl::setDestinationText(std::u16string_view rString)
+{
+ m_aStates.top().getDestinationText().setLength(0);
+ m_aStates.top().getDestinationText().append(rString);
+}
+
+bool RTFDocumentImpl::getSkipUnknown() { return m_bSkipUnknown; }
+
+void RTFDocumentImpl::setSkipUnknown(bool bSkipUnknown) { m_bSkipUnknown = bSkipUnknown; }
+
+static auto FilterControlChars(Destination const destination, OUString const& rString) -> OUString
+{
+ if (destination == Destination::LEVELNUMBERS || destination == Destination::LEVELTEXT)
+ { // control characters are magic here!
+ return rString;
+ }
+ OUStringBuffer buf(rString.getLength());
+ for (sal_Int32 i = 0; i < rString.getLength(); ++i)
+ {
+ sal_Unicode const ch(rString[i]);
+ if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
+ {
+ buf.append(ch);
+ }
+ else
+ {
+ SAL_INFO("writerfilter.rtf", "filtering control character");
+ }
+ }
+ return buf.makeStringAndClear();
+}
+
+void RTFDocumentImpl::checkUnicode(bool bUnicode, bool bHex)
+{
+ if (bUnicode && !m_aUnicodeBuffer.isEmpty())
+ {
+ OUString aString = m_aUnicodeBuffer.toString();
+ m_aUnicodeBuffer.setLength(0);
+ aString = FilterControlChars(m_aStates.top().getDestination(), aString);
+ text(aString);
+ }
+ if (bHex && !m_aHexBuffer.isEmpty())
+ {
+ rtl_TextEncoding nEncoding = m_aStates.top().getCurrentEncoding();
+ if (m_aStates.top().getDestination() == Destination::FONTENTRY
+ && m_aStates.top().getCurrentEncoding() == RTL_TEXTENCODING_SYMBOL)
+ nEncoding = RTL_TEXTENCODING_MS_1252;
+ OUString aString = OStringToOUString(m_aHexBuffer, nEncoding);
+ m_aHexBuffer.setLength(0);
+ aString = FilterControlChars(m_aStates.top().getDestination(), aString);
+ text(aString);
+ }
+}
+
+RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl)
+ : m_pDocumentImpl(pDocumentImpl)
+ , m_nInternalState(RTFInternalState::NORMAL)
+ , m_eDestination(Destination::NORMAL)
+ , m_eFieldStatus(RTFFieldStatus::NONE)
+ , m_bFieldLocked(false)
+ , m_nBorderState(RTFBorderState::NONE)
+ , m_nCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(0))
+ , m_nUc(1)
+ , m_nCharsToSkip(0)
+ , m_nBinaryToRead(0)
+ , m_nListLevelNum(0)
+ , m_bLevelNumbersValid(true)
+ , m_aFrame(this)
+ , m_eRunType(RunType::NONE)
+ , m_nYear(0)
+ , m_nMonth(0)
+ , m_nDay(0)
+ , m_nHour(0)
+ , m_nMinute(0)
+ , m_pCurrentDestinationText(nullptr)
+ , m_nCurrentStyleIndex(0)
+ , m_nCurrentCharacterStyleIndex(-1)
+ , m_pCurrentBuffer(nullptr)
+ , m_bInListpicture(false)
+ , m_bInBackground(false)
+ , m_bHadShapeText(false)
+ , m_bInShapeGroup(false)
+ , m_bInShape(false)
+ , m_bCreatedShapeGroup(false)
+ , m_bStartedTrackchange(false)
+ , m_nTableRowWidthAfter(0)
+{
+}
+
+void RTFDocumentImpl::resetFrame() { m_aStates.top().getFrame() = RTFFrame(&m_aStates.top()); }
+
+void RTFDocumentImpl::bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
+ const tools::SvRef<TableRowBuffer>& pTableProperties)
+{
+ rBuffer.emplace_back(BUFFER_SETSTYLE, new RTFValue(m_aStates.top().getCurrentStyleIndex()),
+ nullptr);
+ rBuffer.emplace_back(BUFFER_PROPS, pValue, pTableProperties);
+}
+
+RTFShape::RTFShape() = default;
+
+RTFDrawingObject::RTFDrawingObject() = default;
+
+RTFFrame::RTFFrame(RTFParserState* pParserState)
+ : m_pDocumentImpl(pParserState->getDocumentImpl())
+ , m_nX(0)
+ , m_nY(0)
+ , m_nW(0)
+ , m_nH(0)
+ , m_nHoriPadding(0)
+ , m_nVertPadding(0)
+ , m_nHoriAlign(0)
+ , m_nHoriAnchor(0)
+ , m_nVertAlign(0)
+ , m_nVertAnchor(0)
+ , m_nHRule(NS_ooxml::LN_Value_doc_ST_HeightRule_auto)
+{
+}
+
+void RTFFrame::setSprm(Id nId, Id nValue)
+{
+ if (m_pDocumentImpl->getFirstRun() && !m_pDocumentImpl->isStyleSheetImport())
+ {
+ m_pDocumentImpl->checkFirstRun();
+ m_pDocumentImpl->setNeedPar(false);
+ }
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_FramePr_w:
+ m_nW = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ m_nH = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_x:
+ m_nX = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_y:
+ m_nY = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ m_nHoriPadding = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ m_nVertPadding = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_xAlign:
+ m_nHoriAlign = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_hAnchor:
+ m_nHoriAnchor = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_yAlign:
+ m_nVertAlign = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_vAnchor:
+ m_nVertAnchor = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ m_oWrap = nValue;
+ break;
+ default:
+ break;
+ }
+}
+
+RTFSprms RTFFrame::getSprms()
+{
+ RTFSprms sprms;
+
+ static const Id pNames[]
+ = { NS_ooxml::LN_CT_FramePr_x, NS_ooxml::LN_CT_FramePr_y,
+ NS_ooxml::LN_CT_FramePr_hRule, // Make sure nHRule is processed before nH
+ NS_ooxml::LN_CT_FramePr_h, NS_ooxml::LN_CT_FramePr_w,
+ NS_ooxml::LN_CT_FramePr_hSpace, NS_ooxml::LN_CT_FramePr_vSpace,
+ NS_ooxml::LN_CT_FramePr_hAnchor, NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_CT_FramePr_wrap, NS_ooxml::LN_CT_FramePr_dropCap,
+ NS_ooxml::LN_CT_FramePr_lines };
+
+ for (Id nId : pNames)
+ {
+ RTFValue::Pointer_t pValue;
+
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_FramePr_x:
+ if (m_nX != 0)
+ pValue = new RTFValue(m_nX);
+ break;
+ case NS_ooxml::LN_CT_FramePr_y:
+ if (m_nY != 0)
+ pValue = new RTFValue(m_nY);
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ if (m_nH != 0)
+ {
+ if (m_nHRule == NS_ooxml::LN_Value_doc_ST_HeightRule_exact)
+ pValue = new RTFValue(-m_nH); // The negative value just sets nHRule
+ else
+ pValue = new RTFValue(m_nH);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_w:
+ if (m_nW != 0)
+ pValue = new RTFValue(m_nW);
+ break;
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ if (m_nHoriPadding != 0)
+ pValue = new RTFValue(m_nHoriPadding);
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ if (m_nVertPadding != 0)
+ pValue = new RTFValue(m_nVertPadding);
+ break;
+ case NS_ooxml::LN_CT_FramePr_hAnchor:
+ {
+ if (m_nHoriAnchor == 0)
+ m_nHoriAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_margin;
+ pValue = new RTFValue(m_nHoriAnchor);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_vAnchor:
+ {
+ if (m_nVertAnchor == 0)
+ m_nVertAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_margin;
+ pValue = new RTFValue(m_nVertAnchor);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_xAlign:
+ pValue = new RTFValue(m_nHoriAlign);
+ break;
+ case NS_ooxml::LN_CT_FramePr_yAlign:
+ pValue = new RTFValue(m_nVertAlign);
+ break;
+ case NS_ooxml::LN_CT_FramePr_hRule:
+ {
+ if (m_nH < 0)
+ m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_exact;
+ else if (m_nH > 0)
+ m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_atLeast;
+ pValue = new RTFValue(m_nHRule);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ if (m_oWrap)
+ pValue = new RTFValue(*m_oWrap);
+ break;
+ default:
+ break;
+ }
+
+ if (pValue)
+ sprms.set(nId, pValue);
+ }
+
+ RTFSprms frameprSprms;
+ frameprSprms.set(NS_ooxml::LN_CT_PPrBase_framePr, new RTFValue(sprms));
+ return frameprSprms;
+}
+
+bool RTFFrame::hasProperties() const
+{
+ return m_nX != 0 || m_nY != 0 || m_nW != 0 || m_nH != 0 || m_nHoriPadding != 0
+ || m_nVertPadding != 0 || m_nHoriAlign != 0 || m_nHoriAnchor != 0 || m_nVertAlign != 0
+ || m_nVertAnchor != 0;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
new file mode 100644
index 000000000..e859c01c9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -0,0 +1,994 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <queue>
+#include <tuple>
+#include <vector>
+#include <optional>
+
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <oox/mathml/importutils.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/color.hxx>
+#include <tools/long.hxx>
+
+#include <rtftok/RTFDocument.hxx>
+#include "rtfreferencetable.hxx"
+#include "rtfsprm.hxx"
+#include "rtflistener.hxx"
+
+class SvStream;
+namespace oox
+{
+class GraphicHelper;
+}
+namespace com::sun::star
+{
+namespace beans
+{
+class XPropertySet;
+}
+namespace document
+{
+class XDocumentProperties;
+}
+namespace lang
+{
+class XMultiServiceFactory;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFParserState;
+class RTFDocumentImpl;
+class RTFTokenizer;
+class RTFSdrImport;
+class TableRowBuffer;
+
+enum class RTFBorderState
+{
+ NONE,
+ PARAGRAPH,
+ PARAGRAPH_BOX,
+ CELL,
+ PAGE,
+ CHARACTER
+};
+
+/// Different kind of buffers for table cell contents.
+enum RTFBufferTypes
+{
+ BUFFER_SETSTYLE,
+ /// Stores properties, should be created only in bufferProperties().
+ BUFFER_PROPS,
+ BUFFER_NESTROW,
+ BUFFER_CELLEND,
+ BUFFER_STARTRUN,
+ BUFFER_TEXT,
+ BUFFER_UTEXT,
+ BUFFER_ENDRUN,
+ BUFFER_PAR,
+ BUFFER_STARTSHAPE,
+ /// Imports a shape.
+ BUFFER_RESOLVESHAPE,
+ BUFFER_ENDSHAPE,
+ BUFFER_RESOLVESUBSTREAM,
+ /// Restores RTFParserState::aPicture.
+ BUFFER_PICTURE
+};
+
+/// Form field types
+enum class RTFFormFieldType
+{
+ NONE,
+ TEXT,
+ CHECKBOX,
+ LIST
+};
+
+enum class RTFBmpStyle
+{
+ NONE,
+ PNG,
+ JPEG,
+ DIBITMAP
+};
+
+enum class RTFFieldStatus
+{
+ NONE,
+ INSTRUCTION,
+ RESULT
+};
+
+/// A buffer storing dmapper calls.
+using Buf_t = std::tuple<RTFBufferTypes, RTFValue::Pointer_t, tools::SvRef<TableRowBuffer>>;
+using RTFBuffer_t = std::deque<Buf_t>;
+
+/// holds one nested table row
+class TableRowBuffer : public virtual SvRefBase
+{
+ RTFBuffer_t m_aBuffer;
+ ::std::deque<RTFSprms> m_aCellsSprms;
+ ::std::deque<RTFSprms> m_aCellsAttributes;
+ int m_nCells;
+ writerfilter::Reference<Properties>::Pointer_t m_pParaProperties;
+ writerfilter::Reference<Properties>::Pointer_t m_pFrameProperties;
+ writerfilter::Reference<Properties>::Pointer_t m_pRowProperties;
+
+public:
+ TableRowBuffer(RTFBuffer_t aBuffer, std::deque<RTFSprms> aSprms,
+ std::deque<RTFSprms> aAttributes, int const nCells)
+ : m_aBuffer(std::move(aBuffer))
+ , m_aCellsSprms(std::move(aSprms))
+ , m_aCellsAttributes(std::move(aAttributes))
+ , m_nCells(nCells)
+ {
+ }
+
+ RTFBuffer_t& GetBuffer() { return m_aBuffer; }
+ std::deque<RTFSprms>& GetCellsSprms() { return m_aCellsSprms; }
+ std::deque<RTFSprms>& GetCellsAttributes() { return m_aCellsAttributes; }
+ int GetCells() const { return m_nCells; }
+ writerfilter::Reference<Properties>::Pointer_t& GetParaProperties()
+ {
+ return m_pParaProperties;
+ }
+ writerfilter::Reference<Properties>::Pointer_t& GetFrameProperties()
+ {
+ return m_pFrameProperties;
+ }
+ writerfilter::Reference<Properties>::Pointer_t& GetRowProperties() { return m_pRowProperties; }
+};
+
+/// An entry in the color table.
+class RTFColorTableEntry
+{
+public:
+ void SetRed(sal_uInt8 nRed)
+ {
+ m_bAuto = false;
+ m_nR = nRed;
+ }
+ void SetGreen(sal_uInt8 nGreen)
+ {
+ m_bAuto = false;
+ m_nG = nGreen;
+ }
+ void SetBlue(sal_uInt8 nBlue)
+ {
+ m_bAuto = false;
+ m_nB = nBlue;
+ }
+ Color GetColor() const { return m_bAuto ? COL_AUTO : Color(m_nR, m_nG, m_nB); }
+
+private:
+ bool m_bAuto = true;
+ sal_uInt8 m_nR = 0;
+ sal_uInt8 m_nG = 0;
+ sal_uInt8 m_nB = 0;
+};
+
+/// Stores the properties of a shape.
+class RTFShape : public virtual SvRefBase
+{
+public:
+ RTFShape();
+
+ std::vector<std::pair<OUString, OUString>>& getProperties() { return m_aProperties; }
+
+ const std::vector<std::pair<OUString, OUString>>& getProperties() const
+ {
+ return m_aProperties;
+ }
+
+ std::vector<std::pair<OUString, OUString>>& getGroupProperties() { return m_aGroupProperties; }
+
+ void setLeft(sal_Int32 nLeft) { m_nLeft = nLeft; }
+
+ sal_Int32 getLeft() const { return m_nLeft; }
+
+ void setTop(sal_Int32 nTop) { m_nTop = nTop; }
+
+ sal_Int32 getTop() const { return m_nTop; }
+
+ void setRight(sal_Int32 nRight) { m_nRight = nRight; }
+
+ sal_Int32 getRight() const { return m_nRight; }
+
+ void setBottom(sal_Int32 nBottom) { m_nBottom = nBottom; }
+
+ sal_Int32 getBottom() const { return m_nBottom; }
+
+ void setZ(sal_Int32 nZ) { m_oZ = nZ; }
+
+ bool hasZ() const { return bool(m_oZ); }
+
+ sal_Int32 getZ() const { return *m_oZ; }
+
+ void setHoriOrientRelation(sal_Int16 nHoriOrientRelation)
+ {
+ m_nHoriOrientRelation = nHoriOrientRelation;
+ }
+
+ sal_Int16 getHoriOrientRelation() const { return m_nHoriOrientRelation; }
+
+ void setVertOrientRelation(sal_Int16 nVertOrientRelation)
+ {
+ m_nVertOrientRelation = nVertOrientRelation;
+ }
+
+ sal_Int16 getVertOrientRelation() const { return m_nVertOrientRelation; }
+
+ void setHoriOrientRelationToken(sal_uInt32 nHoriOrientRelationToken)
+ {
+ m_nHoriOrientRelationToken = nHoriOrientRelationToken;
+ }
+
+ sal_uInt32 getHoriOrientRelationToken() const { return m_nHoriOrientRelationToken; }
+
+ void setVertOrientRelationToken(sal_uInt32 nVertOrientRelationToken)
+ {
+ m_nVertOrientRelationToken = nVertOrientRelationToken;
+ }
+
+ sal_uInt32 getVertOrientRelationToken() const { return m_nVertOrientRelationToken; }
+
+ void setWrap(css::text::WrapTextMode nWrap) { m_nWrap = nWrap; }
+
+ css::text::WrapTextMode getWrap() const { return m_nWrap; }
+
+ void setInBackground(bool bInBackground) { m_bInBackground = bInBackground; }
+
+ bool getInBackground() const { return m_bInBackground; }
+
+ RTFSprms& getWrapPolygonSprms() { return m_aWrapPolygonSprms; }
+
+ RTFSprms& getAnchorAttributes() { return m_aAnchorAttributes; }
+
+ std::pair<Id, RTFValue::Pointer_t>& getWrapSprm() { return m_aWrapSprm; }
+
+private:
+ std::vector<std::pair<OUString, OUString>> m_aProperties; ///< Properties of a single shape.
+ std::vector<std::pair<OUString, OUString>>
+ m_aGroupProperties; ///< Properties applied on the groupshape.
+ sal_Int32 m_nLeft = 0;
+ sal_Int32 m_nTop = 0;
+ sal_Int32 m_nRight = 0;
+ sal_Int32 m_nBottom = 0;
+ std::optional<sal_Int32> m_oZ; ///< Z-Order of the shape.
+ sal_Int16 m_nHoriOrientRelation
+ = 0; ///< Horizontal text::RelOrientation for drawinglayer shapes.
+ sal_Int16 m_nVertOrientRelation = 0; ///< Vertical text::RelOrientation for drawinglayer shapes.
+ sal_uInt32 m_nHoriOrientRelationToken = 0; ///< Horizontal dmapper token for Writer pictures.
+ sal_uInt32 m_nVertOrientRelationToken = 0; ///< Vertical dmapper token for Writer pictures.
+ css::text::WrapTextMode m_nWrap = css::text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE;
+ /// If shape is below text (true) or text is below shape (false).
+ bool m_bInBackground = false;
+ /// Wrap polygon, written by RTFSdrImport::resolve(), read by RTFDocumentImpl::resolvePict().
+ RTFSprms m_aWrapPolygonSprms;
+ /// Anchor attributes like wrap distance, written by RTFSdrImport::resolve(), read by RTFDocumentImpl::resolvePict().
+ RTFSprms m_aAnchorAttributes;
+ /// Wrap type, written by RTFDocumentImpl::popState(), read by RTFDocumentImpl::resolvePict().
+ std::pair<Id, RTFValue::Pointer_t> m_aWrapSprm{ 0, nullptr };
+};
+
+/// Stores the properties of a drawing object.
+class RTFDrawingObject : public RTFShape
+{
+public:
+ RTFDrawingObject();
+
+ void setShape(const css::uno::Reference<css::drawing::XShape>& xShape) { m_xShape = xShape; }
+ const css::uno::Reference<css::drawing::XShape>& getShape() const { return m_xShape; }
+ void setPropertySet(const css::uno::Reference<css::beans::XPropertySet>& xPropertySet)
+ {
+ m_xPropertySet = xPropertySet;
+ }
+ const css::uno::Reference<css::beans::XPropertySet>& getPropertySet() const
+ {
+ return m_xPropertySet;
+ }
+ std::vector<css::beans::PropertyValue>& getPendingProperties() { return m_aPendingProperties; }
+ void setLineColorR(sal_uInt8 nLineColorR) { m_nLineColorR = nLineColorR; }
+ sal_uInt8 getLineColorR() const { return m_nLineColorR; }
+ void setLineColorG(sal_uInt8 nLineColorG) { m_nLineColorG = nLineColorG; }
+ sal_uInt8 getLineColorG() const { return m_nLineColorG; }
+ void setLineColorB(sal_uInt8 nLineColorB) { m_nLineColorB = nLineColorB; }
+ sal_uInt8 getLineColorB() const { return m_nLineColorB; }
+ void setHasLineColor(bool bHasLineColor) { m_bHasLineColor = bHasLineColor; }
+ bool getHasLineColor() const { return m_bHasLineColor; }
+ void setFillColorR(sal_uInt8 nFillColorR) { m_nFillColorR = nFillColorR; }
+ sal_uInt8 getFillColorR() const { return m_nFillColorR; }
+ void setFillColorG(sal_uInt8 nFillColorG) { m_nFillColorG = nFillColorG; }
+ sal_uInt8 getFillColorG() const { return m_nFillColorG; }
+ void setFillColorB(sal_uInt8 nFillColorB) { m_nFillColorB = nFillColorB; }
+ sal_uInt8 getFillColorB() const { return m_nFillColorB; }
+ void setHasFillColor(bool bHasFillColor) { m_bHasFillColor = bHasFillColor; }
+ bool getHasFillColor() const { return m_bHasFillColor; }
+ void setDhgt(sal_Int32 nDhgt) { m_nDhgt = nDhgt; }
+ sal_Int32 getDhgt() const { return m_nDhgt; }
+ void setFLine(sal_Int32 nFLine) { m_nFLine = nFLine; }
+ sal_Int32 getFLine() const { return m_nFLine; }
+ void setPolyLineCount(sal_Int32 nPolyLineCount) { m_nPolyLineCount = nPolyLineCount; }
+ sal_Int32 getPolyLineCount() const { return m_nPolyLineCount; }
+ std::vector<css::awt::Point>& getPolyLinePoints() { return m_aPolyLinePoints; }
+ void setHadShapeText(bool bHadShapeText) { m_bHadShapeText = bHadShapeText; }
+ bool getHadShapeText() const { return m_bHadShapeText; }
+
+private:
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ css::uno::Reference<css::beans::XPropertySet> m_xPropertySet;
+ std::vector<css::beans::PropertyValue> m_aPendingProperties;
+ sal_uInt8 m_nLineColorR = 0;
+ sal_uInt8 m_nLineColorG = 0;
+ sal_uInt8 m_nLineColorB = 0;
+ bool m_bHasLineColor = false;
+ sal_uInt8 m_nFillColorR = 0;
+ sal_uInt8 m_nFillColorG = 0;
+ sal_uInt8 m_nFillColorB = 0;
+ bool m_bHasFillColor = false;
+ sal_Int32 m_nDhgt = 0;
+ sal_Int32 m_nFLine = -1;
+ sal_Int32 m_nPolyLineCount = 0;
+ std::vector<css::awt::Point> m_aPolyLinePoints;
+ bool m_bHadShapeText = false;
+};
+
+/// Stores the properties of a picture.
+class RTFPicture : public virtual SvRefBase
+{
+public:
+ sal_Int32 nWidth = 0;
+ sal_Int32 nHeight = 0;
+ sal_Int32 nGoalWidth = 0;
+ sal_Int32 nGoalHeight = 0;
+ sal_uInt16 nScaleX = 100;
+ sal_uInt16 nScaleY = 100;
+ short nCropT = 0;
+ short nCropB = 0;
+ short nCropL = 0;
+ short nCropR = 0;
+ sal_uInt16 eWMetafile = 0;
+ RTFBmpStyle eStyle = RTFBmpStyle::NONE;
+};
+
+/// Stores the properties of a frame
+class RTFFrame
+{
+private:
+ RTFDocumentImpl* m_pDocumentImpl;
+ sal_Int32 m_nX, m_nY, m_nW, m_nH;
+ sal_Int32 m_nHoriPadding, m_nVertPadding;
+ sal_Int32 m_nHoriAlign, m_nHoriAnchor, m_nVertAlign, m_nVertAnchor;
+ Id m_nHRule;
+ std::optional<Id> m_oWrap;
+
+public:
+ explicit RTFFrame(RTFParserState* pParserState);
+
+ /// Convert the stored properties to Sprms
+ RTFSprms getSprms();
+ /// Store a property
+ void setSprm(Id nId, Id nValue);
+ bool hasProperties() const;
+ /// If we got tokens indicating we're in a frame.
+ bool inFrame() const;
+};
+
+/// State of the parser, which gets saved / restored when changing groups.
+class RTFParserState
+{
+public:
+ /// Maps to OOXML's ascii, cs or eastAsia.
+ enum class RunType
+ {
+ NONE,
+ LOCH,
+ HICH,
+ DBCH,
+ LTRCH_RTLCH_1,
+ LTRCH_RTLCH_2,
+ RTLCH_LTRCH_1,
+ RTLCH_LTRCH_2
+ };
+
+ explicit RTFParserState(RTFDocumentImpl* pDocumentImpl);
+
+ void appendDestinationText(std::u16string_view rString)
+ {
+ if (m_pCurrentDestinationText)
+ m_pCurrentDestinationText->append(rString);
+ }
+
+ void setPropName(const OUString& rPropName) { m_aPropName = rPropName; }
+ OUString const& getPropName() const { return m_aPropName; }
+ void setPropType(const css::uno::Type& rPropType) { m_aPropType = rPropType; }
+ css::uno::Type const& getPropType() const { return m_aPropType; }
+ void setTableRowWidthAfter(int nTableRowWidthAfter)
+ {
+ m_nTableRowWidthAfter = nTableRowWidthAfter;
+ }
+ int getTableRowWidthAfter() const { return m_nTableRowWidthAfter; }
+ void setStartedTrackchange(bool bStartedTrackchange)
+ {
+ m_bStartedTrackchange = bStartedTrackchange;
+ }
+ bool getStartedTrackchange() const { return m_bStartedTrackchange; }
+ void setCreatedShapeGroup(bool bCreatedShapeGroup)
+ {
+ m_bCreatedShapeGroup = bCreatedShapeGroup;
+ }
+ bool getCreatedShapeGroup() const { return m_bCreatedShapeGroup; }
+ void setInShape(bool bInShape) { m_bInShape = bInShape; }
+ bool getInShape() const { return m_bInShape; }
+ void setInShapeGroup(bool bInShapeGroup) { m_bInShapeGroup = bInShapeGroup; }
+ bool getInShapeGroup() const { return m_bInShapeGroup; }
+ void setHadShapeText(bool bHadShapeText) { m_bHadShapeText = bHadShapeText; }
+ bool getHadShapeText() const { return m_bHadShapeText; }
+ void setInBackground(bool bInBackground) { m_bInBackground = bInBackground; }
+ bool getInBackground() const { return m_bInBackground; }
+ void setInListpicture(bool bInListpicture) { m_bInListpicture = bInListpicture; }
+ bool getInListpicture() const { return m_bInListpicture; }
+ void setCurrentBuffer(RTFBuffer_t* pCurrentBuffer) { m_pCurrentBuffer = pCurrentBuffer; }
+ RTFBuffer_t* getCurrentBuffer() const { return m_pCurrentBuffer; }
+ void setCurrentListOverrideIndex(int nCurrentListOverrideIndex)
+ {
+ m_nCurrentListOverrideIndex = nCurrentListOverrideIndex;
+ }
+ int getCurrentListOverrideIndex() const { return m_nCurrentListOverrideIndex; }
+ void setCurrentListIndex(int nCurrentListIndex) { m_nCurrentListIndex = nCurrentListIndex; }
+ int getCurrentListIndex() const { return m_nCurrentListIndex; }
+ void setCurrentCharacterStyleIndex(int nCurrentCharacterStyleIndex)
+ {
+ m_nCurrentCharacterStyleIndex = nCurrentCharacterStyleIndex;
+ }
+ int getCurrentCharacterStyleIndex() const { return m_nCurrentCharacterStyleIndex; }
+ void setCurrentStyleIndex(int nCurrentStyleIndex) { m_nCurrentStyleIndex = nCurrentStyleIndex; }
+ int getCurrentStyleIndex() const { return m_nCurrentStyleIndex; }
+ void setCurrentDestinationText(OUStringBuffer* pDestinationText)
+ {
+ m_pCurrentDestinationText = pDestinationText;
+ }
+ OUStringBuffer* getCurrentDestinationText() const { return m_pCurrentDestinationText; }
+ OUStringBuffer& getDestinationText() { return m_aDestinationText; }
+ void setMinute(sal_uInt16 nMinute) { m_nMinute = nMinute; }
+ sal_uInt16 getMinute() const { return m_nMinute; }
+ void setHour(sal_uInt16 nHour) { m_nHour = nHour; }
+ sal_uInt16 getHour() const { return m_nHour; }
+ void setDay(sal_uInt16 nDay) { m_nDay = nDay; }
+ sal_uInt16 getDay() const { return m_nDay; }
+ void setMonth(sal_uInt16 nMonth) { m_nMonth = nMonth; }
+ sal_uInt16 getMonth() const { return m_nMonth; }
+ void setYear(sal_uInt16 nYear) { m_nYear = nYear; }
+ sal_uInt16 getYear() const { return m_nYear; }
+ void setRunType(RunType eRunType) { m_eRunType = eRunType; }
+ RunType getRunType() const { return m_eRunType; }
+ RTFFrame& getFrame() { return m_aFrame; }
+ RTFDrawingObject& getDrawingObject() { return m_aDrawingObject; }
+ RTFShape& getShape() { return m_aShape; }
+ RTFPicture& getPicture() { return m_aPicture; }
+ void setLevelNumbersValid(bool bLevelNumbersValid)
+ {
+ m_bLevelNumbersValid = bLevelNumbersValid;
+ }
+ bool getLevelNumbersValid() const { return m_bLevelNumbersValid; }
+ std::vector<sal_Int32>& getLevelNumbers() { return m_aLevelNumbers; }
+ RTFSprms& getListLevelEntries() { return m_aListLevelEntries; }
+ int& getListLevelNum() { return m_nListLevelNum; }
+ void setBinaryToRead(int nBinaryToRead) { m_nBinaryToRead = nBinaryToRead; }
+ int getBinaryToRead() const { return m_nBinaryToRead; }
+ int& getCharsToSkip() { return m_nCharsToSkip; }
+ void setUc(int nUc) { m_nUc = nUc; }
+ int getUc() const { return m_nUc; }
+ void setCurrentEncoding(rtl_TextEncoding nCurrentEncoding)
+ {
+ m_nCurrentEncoding = nCurrentEncoding;
+ }
+ rtl_TextEncoding getCurrentEncoding() const { return m_nCurrentEncoding; }
+ RTFColorTableEntry& getCurrentColor() { return m_aCurrentColor; }
+ RTFSprms& getTabAttributes() { return m_aTabAttributes; }
+ RTFSprms& getTableCellAttributes() { return m_aTableCellAttributes; }
+ RTFSprms& getTableCellSprms() { return m_aTableCellSprms; }
+ RTFSprms& getTableRowAttributes() { return m_aTableRowAttributes; }
+ RTFSprms& getTableRowSprms() { return m_aTableRowSprms; }
+ RTFSprms& getSectionAttributes() { return m_aSectionAttributes; }
+ RTFSprms& getSectionSprms() { return m_aSectionSprms; }
+ RTFSprms& getParagraphAttributes() { return m_aParagraphAttributes; }
+ RTFSprms& getParagraphSprms() { return m_aParagraphSprms; }
+ RTFSprms& getCharacterAttributes() { return m_aCharacterAttributes; }
+ RTFSprms& getCharacterSprms() { return m_aCharacterSprms; }
+ RTFSprms& getTableAttributes() { return m_aTableAttributes; }
+ RTFSprms& getTableSprms() { return m_aTableSprms; }
+ void setBorderState(RTFBorderState nBorderState) { m_nBorderState = nBorderState; }
+ RTFBorderState getBorderState() const { return m_nBorderState; }
+ void setFieldStatus(RTFFieldStatus eFieldStatus) { m_eFieldStatus = eFieldStatus; }
+ RTFFieldStatus getFieldStatus() const { return m_eFieldStatus; }
+ void setFieldLocked(bool bSet) { m_bFieldLocked = bSet; }
+ bool isFieldLocked() const { return m_bFieldLocked; }
+ void setDestination(Destination eDestination) { m_eDestination = eDestination; }
+ Destination getDestination() const { return m_eDestination; }
+ void setInternalState(RTFInternalState nInternalState) { m_nInternalState = nInternalState; }
+ RTFInternalState getInternalState() const { return m_nInternalState; }
+ RTFDocumentImpl* getDocumentImpl() { return m_pDocumentImpl; }
+ OUString getDocVar() { return m_aDocVar; }
+ void appendDocVar(OUString& aDocVar) { m_aDocVar += aDocVar; };
+ OUString getDocVarName() { return m_aDocVarName; }
+ void setDocVarName(OUString& aDocVarName) { m_aDocVarName = aDocVarName; }
+ void clearDocVarName() { m_aDocVarName = ""; }
+
+private:
+ RTFDocumentImpl* m_pDocumentImpl;
+ RTFInternalState m_nInternalState;
+ Destination m_eDestination;
+ RTFFieldStatus m_eFieldStatus;
+ bool m_bFieldLocked;
+ RTFBorderState m_nBorderState;
+ // font table, stylesheet table
+ RTFSprms m_aTableSprms;
+ RTFSprms m_aTableAttributes;
+ // reset by plain
+ RTFSprms m_aCharacterSprms;
+ RTFSprms m_aCharacterAttributes;
+ // reset by pard
+ RTFSprms m_aParagraphSprms;
+ RTFSprms m_aParagraphAttributes;
+ // reset by sectd
+ RTFSprms m_aSectionSprms;
+ RTFSprms m_aSectionAttributes;
+ // reset by trowd
+ RTFSprms m_aTableRowSprms;
+ RTFSprms m_aTableRowAttributes;
+ // reset by cellx
+ RTFSprms m_aTableCellSprms;
+ RTFSprms m_aTableCellAttributes;
+ // reset by tx
+ RTFSprms m_aTabAttributes;
+
+ RTFColorTableEntry m_aCurrentColor;
+
+ rtl_TextEncoding m_nCurrentEncoding;
+
+ /// Current \uc value.
+ int m_nUc;
+ /// Characters to skip, set to nUc by \u.
+ int m_nCharsToSkip;
+ /// Characters to read, once in binary mode.
+ int m_nBinaryToRead;
+
+ /// Next list level index to use when parsing list table.
+ int m_nListLevelNum;
+ /// List level entries, which will form a list entry later.
+ RTFSprms m_aListLevelEntries;
+ /// List of character positions in leveltext to replace.
+ std::vector<sal_Int32> m_aLevelNumbers;
+ /// If aLevelNumbers should be read at all.
+ bool m_bLevelNumbersValid;
+
+ RTFPicture m_aPicture;
+ RTFShape m_aShape;
+ RTFDrawingObject m_aDrawingObject;
+ RTFFrame m_aFrame;
+
+ RunType m_eRunType;
+
+ // Info group.
+ sal_Int16 m_nYear;
+ sal_uInt16 m_nMonth;
+ sal_uInt16 m_nDay;
+ sal_uInt16 m_nHour;
+ sal_uInt16 m_nMinute;
+
+ /// Text from special destinations.
+ OUStringBuffer m_aDestinationText{ 512 };
+ /// point to the buffer of the current destination
+ OUStringBuffer* m_pCurrentDestinationText;
+
+ /// Index of the current style.
+ int m_nCurrentStyleIndex;
+ /// Index of the current character style.
+ int m_nCurrentCharacterStyleIndex;
+ /// Current listid, points to a listtable entry.
+ int m_nCurrentListIndex = -1;
+ /// Current ls, points to a listoverridetable entry.
+ int m_nCurrentListOverrideIndex = -1;
+
+ /// Points to the active buffer, if there is one.
+ RTFBuffer_t* m_pCurrentBuffer;
+
+ /// If we're inside a \listpicture group.
+ bool m_bInListpicture;
+
+ /// If we're inside a \background group.
+ bool m_bInBackground;
+
+ bool m_bHadShapeText;
+ bool m_bInShapeGroup; ///< If we're inside a \shpgrp group.
+ bool m_bInShape; ///< If we're inside a \shp group.
+ bool m_bCreatedShapeGroup; ///< A GroupShape was created and pushed to the parent stack.
+ bool m_bStartedTrackchange; ///< Track change is started, need to end it before popping.
+
+ /// User-defined property: key name.
+ OUString m_aPropName;
+ /// User-defined property: value type.
+ css::uno::Type m_aPropType;
+
+ /// Width of invisible cell at the end of the row.
+ int m_nTableRowWidthAfter;
+
+ /// For importing document variables which are not referenced in the document
+ OUString m_aDocVar;
+ OUString m_aDocVarName;
+};
+
+/// An RTF stack is similar to std::stack, except that it has an operator[].
+struct RTFStack
+{
+private:
+ std::deque<RTFParserState> m_Impl;
+
+public:
+ RTFParserState& top()
+ {
+ if (m_Impl.empty())
+ throw css::io::WrongFormatException(
+ "Parser state is empty! Invalid usage of destination braces in RTF?", nullptr);
+ return m_Impl.back();
+ }
+ void pop()
+ {
+ if (m_Impl.empty())
+ throw css::io::WrongFormatException(
+ "Parser state is empty! Invalid usage of destination braces in RTF?", nullptr);
+ return m_Impl.pop_back();
+ }
+ void push(RTFParserState const& rState) { return m_Impl.push_back(rState); }
+ bool empty() const { return m_Impl.empty(); }
+ size_t size() const { return m_Impl.size(); }
+ const RTFParserState& operator[](size_t nIndex) const { return m_Impl[nIndex]; }
+ RTFParserState& operator[](size_t nIndex) { return m_Impl[nIndex]; }
+};
+
+void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue);
+void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::NO_APPEND);
+Id getParagraphBorder(sal_uInt32 nIndex);
+void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::YES, bool bAttribute = true);
+bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Looks up the nParent then the nested nId attribute in rSprms.
+RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Looks up the nParent then the nested nId sprm in rSprms.
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Checks if rName is contained at least once in rProperties as a key.
+bool findPropertyName(const std::vector<css::beans::PropertyValue>& rProperties,
+ const OUString& rName);
+RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId);
+OString DTTM22OString(tools::Long nDTTM);
+
+/// Implementation of the RTFDocument interface.
+class RTFDocumentImpl : public RTFDocument, public RTFListener
+{
+public:
+ using Pointer_t = tools::SvRef<RTFDocumentImpl>;
+ RTFDocumentImpl(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor);
+ ~RTFDocumentImpl() override;
+
+ // RTFDocument
+ void resolve(Stream& rMapper) override;
+
+ // RTFListener
+ RTFError dispatchDestination(RTFKeyword nKeyword) override;
+ RTFError dispatchFlag(RTFKeyword nKeyword) override;
+ RTFError dispatchSymbol(RTFKeyword nKeyword) override;
+ RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) override;
+ RTFError dispatchValue(RTFKeyword nKeyword, int nParam) override;
+ bool dispatchTableSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchInfoValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchFrameValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchTableValue(RTFKeyword nKeyword, int nParam);
+ RTFError resolveChars(char ch) override;
+ RTFError pushState() override;
+ RTFError beforePopState(RTFParserState& rState);
+ RTFError popState() override;
+ void afterPopState(RTFParserState& rState);
+ Destination getDestination() override;
+ void setDestination(Destination eDestination) override;
+ RTFInternalState getInternalState() override;
+ void setInternalState(RTFInternalState nInternalState) override;
+ bool getSkipUnknown() override;
+ void setSkipUnknown(bool bSkipUnknown) override;
+ void finishSubstream() override;
+ bool isSubstream() const override;
+
+ Stream& Mapper() { return *m_pMapperStream; }
+ void setSuperstream(RTFDocumentImpl* pSuperstream);
+ const css::uno::Reference<css::lang::XMultiServiceFactory>& getModelFactory() const
+ {
+ return m_xModelFactory;
+ }
+ bool isInBackground();
+ void setDestinationText(std::u16string_view rString);
+ /// Resolve a picture: If not inline, then anchored.
+ void resolvePict(bool bInline, css::uno::Reference<css::drawing::XShape> const& rShape);
+
+ /// If this is the first run of the document, starts the initial paragraph.
+ void checkFirstRun();
+ /// Send NS_ooxml::LN_settings_settings to dmapper.
+ void outputSettingsTable();
+ /// If the initial paragraph is started.
+ bool getFirstRun() const { return m_bFirstRun; }
+ /// If we need to add a dummy paragraph before a section break.
+ void setNeedPar(bool bNeedPar);
+ /// Return the dmapper index of an RTF index for fonts.
+ int getFontIndex(int nIndex);
+ /// Return the name of the font, based on a dmapper index.
+ OUString getFontName(int nIndex);
+ /// Return the style name of an RTF style index.
+ OUString getStyleName(int nIndex);
+ /// Return the style type of an RTF style index.
+ Id getStyleType(int nIndex);
+ /// Return the encoding associated with a font index.
+ rtl_TextEncoding getEncoding(int nFontIndex);
+ /// Get the default parser state.
+ RTFParserState& getDefaultState();
+ oox::GraphicHelper& getGraphicHelper();
+ /// Are we inside the stylesheet table?
+ bool isStyleSheetImport();
+ /// Resets m_aStates.top().aFrame.
+ void resetFrame();
+ /// Buffers properties to be sent later.
+ void bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
+ const tools::SvRef<TableRowBuffer>& pTableProperties);
+ /// implement non-obvious RTF specific style inheritance
+ RTFReferenceTable::Entries_t deduplicateStyleTable();
+
+private:
+ SvStream& Strm();
+ Color getColorTable(sal_uInt32 nIndex);
+ writerfilter::Reference<Properties>::Pointer_t createStyleProperties();
+ void resetSprms();
+ void resetAttributes();
+ void resolveSubstream(std::size_t nPos, Id nId);
+ void resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst);
+
+ void text(OUString& rString);
+ // Sends a single character to dmapper, taking care of buffering.
+ void singleChar(sal_uInt8 nValue, bool bRunProps = false);
+ // Sends run properties to dmapper, taking care of buffering.
+ void runProps();
+ void runBreak();
+ void parBreak();
+ void tableBreak();
+ writerfilter::Reference<Properties>::Pointer_t
+ getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType);
+ void checkNeedPap();
+ void handleFontTableEntry();
+ void sectBreak(bool bFinal = false);
+ void prepareProperties(RTFParserState& rState,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpTableRowProperties,
+ int nCells, int nCurrentCellX);
+ /// Send the passed properties to dmapper.
+ void sendProperties(writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties);
+ void replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSrpms,
+ ::std::deque<RTFSprms>& rCellsAttributes, int nCells);
+ void replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* pSprms, RTFSprms const* pAttributes);
+ /// If we have some unicode or hex characters to send.
+ void checkUnicode(bool bUnicode, bool bHex);
+ /// If we need a final section break at the end of the document.
+ void setNeedSect(bool bNeedSect);
+ void resetTableRowProperties();
+ void backupTableRowProperties();
+ void restoreTableRowProperties();
+ /// Turns the destination text into an input stream of the current OLE attributes.
+ RTFError handleEmbeddedObject();
+
+ css::uno::Reference<css::uno::XComponentContext> const& m_xContext;
+ css::uno::Reference<css::io::XInputStream> const& m_xInputStream;
+ css::uno::Reference<css::lang::XComponent> const& m_xDstDoc;
+ css::uno::Reference<css::frame::XFrame> const& m_xFrame;
+ css::uno::Reference<css::task::XStatusIndicator> const& m_xStatusIndicator;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xModelFactory;
+ css::uno::Reference<css::document::XDocumentProperties> m_xDocumentProperties;
+ std::unique_ptr<SvStream> m_pInStream;
+ Stream* m_pMapperStream;
+ tools::SvRef<RTFSdrImport> m_pSdrImport;
+ tools::SvRef<RTFTokenizer> m_pTokenizer;
+ RTFStack m_aStates;
+ /// Read by RTF_PARD.
+ RTFParserState m_aDefaultState;
+ bool m_bSkipUnknown;
+ /// Font index <-> encoding map, *not* part of the parser state
+ std::map<int, rtl_TextEncoding> m_aFontEncodings;
+ /// Font index <-> name map.
+ std::map<int, OUString> m_aFontNames;
+ /// Maps the non-continuous font indexes to the continuous dmapper indexes.
+ std::vector<int> m_aFontIndexes;
+ /// Maps style indexes to style names.
+ std::map<int, OUString> m_aStyleNames;
+ /// Maps style indexes to style types.
+ std::map<int, Id> m_aStyleTypes;
+ /// Color index <-> RGB color value map
+ std::vector<Color> m_aColorTable;
+ /// to start initial paragraph / section after font/style tables
+ bool m_bFirstRun;
+ /// except in the case of tables in initial multicolumn section (global for assertion)
+ bool m_bFirstRunException;
+ /// If paragraph properties should be emitted on next run.
+ bool m_bNeedPap;
+ /// If we need to emit a CR at the end of substream.
+ bool m_bNeedCr;
+ /// Original value of m_bNeedCr -- saved/restored before/after textframes.
+ bool m_bNeedCrOrig;
+ bool m_bNeedPar;
+ /// If set, an empty paragraph will be added at the end of the document.
+ bool m_bNeedFinalPar;
+ /// The list table and list override table combined.
+ RTFSprms m_aListTableSprms;
+ /// Maps between listoverridetable and listtable indexes.
+ std::map<int, int> m_aListOverrideTable;
+ /// Maps listtable indexes to listtable entries.
+ std::map<int, RTFValue::Pointer_t> m_aListTable;
+ /// Index of the current list level in a list table entry.
+ int m_nListLevel = -1;
+ /// Maps List level indexes to removed values in the current list entry.
+ std::map<int, int> m_aInvalidListLevelFirstIndents;
+ /// Maps list table indexes to levels (and their removed values).
+ std::map<int, std::map<int, int>> m_aInvalidListTableFirstIndents;
+ /// The settings table attributes.
+ RTFSprms m_aSettingsTableAttributes;
+ /// The settings table sprms.
+ RTFSprms m_aSettingsTableSprms;
+
+ std::shared_ptr<oox::GraphicHelper> m_pGraphicHelper;
+
+ /// cell props buffer for nested tables, reset by \nestrow
+ /// the \nesttableprops is a destination and must follow the
+ /// nested cells, so it should be sufficient to store the
+ /// currently active one, no need for a stack of them
+ int m_nNestedCells;
+ std::deque<RTFSprms> m_aNestedTableCellsSprms;
+ std::deque<RTFSprms> m_aNestedTableCellsAttributes;
+ /// cell props buffer for top-level table, reset by \row
+ int m_nTopLevelCells;
+ std::deque<RTFSprms> m_aTopLevelTableCellsSprms;
+ std::deque<RTFSprms> m_aTopLevelTableCellsAttributes;
+ /// backup of top-level props, to support inheriting cell props
+ int m_nInheritingCells;
+ std::deque<RTFSprms> m_aTableInheritingCellsSprms;
+ std::deque<RTFSprms> m_aTableInheritingCellsAttributes;
+
+ // Left row margin (for nested and top-level rows)
+ int m_nNestedTRLeft;
+ int m_nTopLevelTRLeft;
+
+ /// Current cellx value (nested table)
+ int m_nNestedCurrentCellX;
+ /// Current cellx value (top-level table)
+ int m_nTopLevelCurrentCellX;
+
+ // Backup of what \trowd clears, to work around invalid input.
+ RTFSprms m_aBackupTableRowSprms;
+ RTFSprms m_aBackupTableRowAttributes;
+ int m_nBackupTopLevelCurrentCellX;
+
+ /// Buffered table cells, till cell definitions are not reached.
+ /// for nested table, one buffer per table level
+ std::deque<RTFBuffer_t> m_aTableBufferStack;
+ /// Buffered superscript, till footnote is reached (or not).
+ RTFBuffer_t m_aSuperBuffer;
+
+ /// Superstream of this substream.
+ RTFDocumentImpl* m_pSuperstream;
+ /// Type of the stream: header, footer, footnote, etc.
+ Id m_nStreamType;
+ std::queue<std::pair<Id, std::size_t>> m_nHeaderFooterPositions;
+ std::size_t m_nGroupStartPos;
+ /// Ignore the first occurrence of this text.
+ OUString m_aIgnoreFirst;
+ /// Bookmark name <-> index map.
+ std::map<OUString, int> m_aBookmarks;
+ /// Revision index <-> author map.
+ std::map<int, OUString> m_aAuthors;
+ /// Annotation author of the next annotation.
+ OUString m_aAuthor;
+ /// Initials of author of the next annotation.
+ OUString m_aAuthorInitials;
+
+ RTFSprms m_aFormfieldSprms;
+ RTFSprms m_aFormfieldAttributes;
+ RTFFormFieldType m_nFormFieldType;
+
+ /// OLE attributes are attributes of the ooxml:OLEObject_OLEObject sprm.
+ RTFSprms m_aOLEAttributes;
+ RTFSprms m_aObjectAttributes;
+ /** If we are in an object group and if the we use its
+ * \objdata element.
+ * (if we don't use the \objdata we use the \result element)*/
+ bool m_bObject;
+ /// If the data for a picture is a binary one, it's stored here.
+ std::shared_ptr<SvStream> m_pBinaryData;
+
+ RTFReferenceTable::Entries_t m_aFontTableEntries;
+ int m_nCurrentFontIndex;
+ /// Used only during font table parsing till we don't know the font name.
+ int m_nCurrentEncoding;
+ /// Raw default font index, use getFont() on it to get a real one.
+ int m_nDefaultFontIndex;
+
+ /// To avoid copying entries between DomainMapper instances it is stored as pointer
+ std::shared_ptr<RTFReferenceTable::Entries_t> m_pStyleTableEntries;
+ int m_nCurrentStyleIndex;
+ bool m_bFormField;
+ /// For the INCLUDEPICTURE field's argument.
+ OUString m_aPicturePath;
+ // Unicode characters are collected here so we don't have to send them one by one.
+ OUStringBuffer m_aUnicodeBuffer{ 512 };
+ /// Same for hex characters.
+ OStringBuffer m_aHexBuffer{ 512 };
+ /// Formula import.
+ oox::formulaimport::XmlStreamBuilder m_aMathBuffer;
+ /// Normal text property, that is math italic and math spacing are not applied to the current run.
+ bool m_bMathNor;
+ /// If the next continuous section break should be ignored.
+ bool m_bIgnoreNextContSectBreak;
+ /// clean up a synthetic page break, see RTF_PAGE
+ /// if inactive value is -1, otherwise the RTF_SKB* to restore
+ RTFKeyword m_nResetBreakOnSectBreak;
+ /// If a section break is needed before the end of the doc (false right after a section break).
+ bool m_bNeedSect;
+ /// If aFrame.inFrame() was true in the previous state.
+ bool m_bWasInFrame;
+ /// A picture was seen in the current paragraph.
+ bool m_bHadPicture;
+ /// The document has multiple sections.
+ bool m_bHadSect;
+ /// Max width of the rows in the current table.
+ int m_nCellxMax;
+ /// ID of the next \listlevel picture.
+ int m_nListPictureId;
+
+ /// New document means not pasting into an existing one.
+ bool m_bIsNewDoc;
+ /// The media descriptor contains e.g. the base URL of the document.
+ const utl::MediaDescriptor& m_rMediaDescriptor;
+
+ /// Flags for ensuring that only one header and footer is added per section
+ bool m_hasRHeader;
+ bool m_hasFHeader;
+ bool m_hasRFooter;
+ bool m_hasFFooter;
+
+ /// Are we after a \cell, but before a \row?
+ bool m_bAfterCellBeforeRow;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtffly.hxx b/writerfilter/source/rtftok/rtffly.hxx
new file mode 100644
index 000000000..b1dec0c77
--- /dev/null
+++ b/writerfilter/source/rtftok/rtffly.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+
+#include <ooxml/resourceids.hxx>
+#include <osl/endian.h>
+
+namespace writerfilter::rtftok
+{
+/// Stores the vertical orientation properties of an RTF fly frame.
+class RTFVertOrient
+{
+public:
+ explicit RTFVertOrient(sal_uInt16 nValue)
+ : m_nVal(nValue)
+ {
+ }
+
+ sal_uInt16 GetOrient() const { return OSL_LONIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_uInt16 GetRelation() const { return OSL_HINIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_Int32 GetAlign() const
+ {
+ sal_Int32 nAlign = 0;
+ switch (GetOrient())
+ {
+ case css::text::VertOrientation::CENTER:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_center;
+ break;
+ case css::text::VertOrientation::TOP:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_top;
+ break;
+ case css::text::VertOrientation::BOTTOM:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_bottom;
+ break;
+ }
+
+ return nAlign;
+ }
+
+ sal_Int32 GetAnchor() const
+ {
+ sal_Int32 nAnchor = 0;
+ switch (GetRelation())
+ {
+ case css::text::RelOrientation::FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_text;
+ break;
+ case css::text::RelOrientation::PAGE_FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_page;
+ break;
+ case css::text::RelOrientation::PAGE_PRINT_AREA:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_margin;
+ break;
+ }
+
+ return nAnchor;
+ }
+
+private:
+ sal_uInt16 m_nVal;
+};
+
+/// Stores the horizontal orientation properties of an RTF fly frame.
+class RTFHoriOrient
+{
+public:
+ explicit RTFHoriOrient(sal_uInt16 nValue)
+ : m_nVal(nValue)
+ {
+ }
+
+ sal_uInt16 GetOrient() const { return OSL_LONIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_uInt16 GetRelation() const { return OSL_LONIBBLE(OSL_HIBYTE(m_nVal)); }
+
+ sal_Int32 GetAlign() const
+ {
+ sal_Int32 nAlign = 0;
+ switch (GetOrient())
+ {
+ case css::text::HoriOrientation::CENTER:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_center;
+ break;
+ case css::text::HoriOrientation::RIGHT:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_right;
+ break;
+ case css::text::HoriOrientation::LEFT:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_left;
+ break;
+ case css::text::HoriOrientation::INSIDE:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_inside;
+ break;
+ case css::text::HoriOrientation::OUTSIDE:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_outside;
+ break;
+ }
+
+ return nAlign;
+ }
+
+ sal_Int32 GetAnchor() const
+ {
+ sal_Int32 nAnchor = 0;
+ switch (GetRelation())
+ {
+ case css::text::RelOrientation::FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_text;
+ break;
+ case css::text::RelOrientation::PAGE_FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_page;
+ break;
+ case css::text::RelOrientation::PAGE_PRINT_AREA:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_margin;
+ break;
+ }
+
+ return nAnchor;
+ }
+
+private:
+ sal_uInt16 m_nVal;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtflistener.hxx b/writerfilter/source/rtftok/rtflistener.hxx
new file mode 100644
index 000000000..150440afb
--- /dev/null
+++ b/writerfilter/source/rtftok/rtflistener.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "rtfcontrolwords.hxx"
+
+namespace writerfilter::rtftok
+{
+enum class RTFInternalState
+{
+ NORMAL,
+ BIN,
+ HEX
+};
+
+enum class RTFError
+{
+ OK,
+ GROUP_UNDER,
+ GROUP_OVER,
+ UNEXPECTED_EOF,
+ HEX_INVALID,
+ CHAR_OVER,
+ CLASSIFICATION
+};
+
+/**
+ * RTFTokenizer needs a class implementing this interface. While
+ * RTFTokenizer separates control words (and their arguments) from
+ * text, the class implementing this interface is expected to map the
+ * raw RTF tokens to dmapper tokens.
+ */
+class RTFListener
+{
+public:
+ virtual ~RTFListener() = default;
+ // Dispatching of control words and characters.
+ virtual RTFError dispatchDestination(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchFlag(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchSymbol(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) = 0;
+ virtual RTFError dispatchValue(RTFKeyword nKeyword, int nParam) = 0;
+ virtual RTFError resolveChars(char ch) = 0;
+
+ // State handling.
+ virtual RTFError pushState() = 0;
+ virtual RTFError popState() = 0;
+
+ virtual Destination getDestination() = 0;
+ virtual void setDestination(Destination eDestination) = 0;
+ virtual RTFInternalState getInternalState() = 0;
+ virtual void setInternalState(RTFInternalState nInternalState) = 0;
+ virtual bool getSkipUnknown() = 0;
+ virtual void setSkipUnknown(bool bSkipUnknown) = 0;
+
+ // Substream handling.
+ virtual void finishSubstream() = 0;
+ virtual bool isSubstream() const = 0;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtflookahead.cxx b/writerfilter/source/rtftok/rtflookahead.cxx
new file mode 100644
index 000000000..033feacce
--- /dev/null
+++ b/writerfilter/source/rtftok/rtflookahead.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtflookahead.hxx"
+#include <com/sun/star/uno/Reference.hxx>
+#include <tools/stream.hxx>
+#include "rtftokenizer.hxx"
+
+namespace com::sun::star::task
+{
+class XStatusIndicator;
+}
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFLookahead::RTFLookahead(SvStream& rStream, sal_uInt64 nGroupStart)
+ : m_rStream(rStream)
+ , m_bHasTable(false)
+ , m_bHasColumns(false)
+{
+ sal_uInt64 const nPos = m_rStream.Tell();
+ m_rStream.Seek(nGroupStart);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+ m_pTokenizer = new RTFTokenizer(*this, &m_rStream, xStatusIndicator);
+ m_pTokenizer->resolveParse();
+ m_rStream.Seek(nPos);
+}
+
+RTFLookahead::~RTFLookahead() = default;
+
+RTFError RTFLookahead::dispatchDestination(RTFKeyword /*nKeyword*/) { return RTFError::OK; }
+
+RTFError RTFLookahead::dispatchFlag(RTFKeyword nKeyword)
+{
+ if (nKeyword == RTFKeyword::INTBL)
+ m_bHasTable = true;
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::dispatchSymbol(RTFKeyword /*nKeyword*/) { return RTFError::OK; }
+
+RTFError RTFLookahead::dispatchToggle(RTFKeyword /*nKeyword*/, bool /*bParam*/, int /*nParam*/)
+{
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::dispatchValue(RTFKeyword nKeyword, int nParam)
+{
+ if (nKeyword == RTFKeyword::COLS && nParam >= 2)
+ m_bHasColumns = true;
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::resolveChars(char ch)
+{
+ while (!m_rStream.eof() && (ch != '{' && ch != '}' && ch != '\\'))
+ m_rStream.ReadChar(ch);
+ if (!m_rStream.eof())
+ m_rStream.SeekRel(-1);
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::pushState()
+{
+ m_pTokenizer->pushGroup();
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::popState()
+{
+ m_pTokenizer->popGroup();
+ return RTFError::OK;
+}
+
+Destination RTFLookahead::getDestination() { return Destination::NORMAL; }
+
+void RTFLookahead::setDestination(Destination /*eDestination*/) {}
+
+RTFInternalState RTFLookahead::getInternalState() { return RTFInternalState::NORMAL; }
+
+void RTFLookahead::setInternalState(RTFInternalState /*nInternalState*/) {}
+
+bool RTFLookahead::getSkipUnknown() { return false; }
+
+void RTFLookahead::setSkipUnknown(bool /*bSkipUnknown*/) {}
+
+void RTFLookahead::finishSubstream() {}
+
+bool RTFLookahead::isSubstream() const { return false; }
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtflookahead.hxx b/writerfilter/source/rtftok/rtflookahead.hxx
new file mode 100644
index 000000000..9ec213f62
--- /dev/null
+++ b/writerfilter/source/rtftok/rtflookahead.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <tools/ref.hxx>
+#include "rtflistener.hxx"
+
+class SvStream;
+
+namespace writerfilter::rtftok
+{
+class RTFTokenizer;
+/**
+ * This acts like an importer, but used for looking ahead, e.g. to
+ * determine if the current group contains a table, etc.
+ */
+class RTFLookahead : public RTFListener
+{
+public:
+ RTFLookahead(SvStream& rStream, sal_uInt64 nGroupStart);
+ ~RTFLookahead() override;
+ RTFError dispatchDestination(RTFKeyword nKeyword) override;
+ RTFError dispatchFlag(RTFKeyword nKeyword) override;
+ RTFError dispatchSymbol(RTFKeyword nKeyword) override;
+ RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) override;
+ RTFError dispatchValue(RTFKeyword nKeyword, int nParam) override;
+ RTFError resolveChars(char ch) override;
+ RTFError pushState() override;
+ RTFError popState() override;
+ Destination getDestination() override;
+ void setDestination(Destination eDestination) override;
+ RTFInternalState getInternalState() override;
+ void setInternalState(RTFInternalState nInternalState) override;
+ bool getSkipUnknown() override;
+ void setSkipUnknown(bool bSkipUnknown) override;
+ void finishSubstream() override;
+ bool isSubstream() const override;
+ bool hasTable() const { return m_bHasTable; }
+ bool hasColumns() const { return m_bHasColumns; }
+
+private:
+ tools::SvRef<RTFTokenizer> m_pTokenizer;
+ SvStream& m_rStream;
+ bool m_bHasTable;
+ bool m_bHasColumns;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferenceproperties.cxx b/writerfilter/source/rtftok/rtfreferenceproperties.cxx
new file mode 100644
index 000000000..d32557bc7
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferenceproperties.cxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfreferenceproperties.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFReferenceProperties::RTFReferenceProperties(RTFSprms aAttributes, RTFSprms aSprms)
+ : m_aAttributes(std::move(aAttributes))
+ , m_aSprms(std::move(aSprms))
+{
+}
+
+RTFReferenceProperties::RTFReferenceProperties(RTFSprms aAttributes)
+ : m_aAttributes(std::move(aAttributes))
+{
+}
+
+RTFReferenceProperties::~RTFReferenceProperties() = default;
+
+void RTFReferenceProperties::resolve(Properties& rHandler)
+{
+ for (auto& rAttribute : m_aAttributes)
+ rHandler.attribute(rAttribute.first, *rAttribute.second);
+ for (auto& rSprm : m_aSprms)
+ {
+ RTFSprm aSprm(rSprm.first, rSprm.second);
+ rHandler.sprm(aSprm);
+ }
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferenceproperties.hxx b/writerfilter/source/rtftok/rtfreferenceproperties.hxx
new file mode 100644
index 000000000..6a5e5618b
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferenceproperties.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "rtfsprm.hxx"
+
+namespace writerfilter::rtftok
+{
+/// Sends RTFSprm instances to DomainMapper.
+class RTFReferenceProperties : public writerfilter::Reference<Properties>
+{
+public:
+ RTFReferenceProperties(RTFSprms aAttributes, RTFSprms aSprms);
+ explicit RTFReferenceProperties(RTFSprms aAttributes);
+ ~RTFReferenceProperties() override;
+ void resolve(Properties& rHandler) override;
+ RTFSprms& getAttributes() { return m_aAttributes; }
+ RTFSprms& getSprms() { return m_aSprms; }
+
+private:
+ RTFSprms m_aAttributes;
+ RTFSprms m_aSprms;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferencetable.cxx b/writerfilter/source/rtftok/rtfreferencetable.cxx
new file mode 100644
index 000000000..1a70a93d9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferencetable.cxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfreferencetable.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFReferenceTable::RTFReferenceTable(Entries_t aEntries)
+ : m_aEntries(std::move(aEntries))
+{
+}
+
+RTFReferenceTable::~RTFReferenceTable() = default;
+
+void RTFReferenceTable::resolve(Table& rHandler)
+{
+ for (const auto& rEntry : m_aEntries)
+ rHandler.entry(rEntry.first, rEntry.second);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferencetable.hxx b/writerfilter/source/rtftok/rtfreferencetable.hxx
new file mode 100644
index 000000000..76cbaacf2
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferencetable.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <map>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::rtftok
+{
+/// Sends tables (e.g. font table) to the domain mapper.
+class RTFReferenceTable : public writerfilter::Reference<Table>
+{
+public:
+ using Entries_t = std::map<int, writerfilter::Reference<Properties>::Pointer_t>;
+ using Entry_t = std::pair<int, writerfilter::Reference<Properties>::Pointer_t>;
+ explicit RTFReferenceTable(Entries_t aEntries);
+ ~RTFReferenceTable() override;
+ void resolve(Table& rHandler) override;
+
+private:
+ Entries_t m_aEntries;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsdrimport.cxx b/writerfilter/source/rtftok/rtfsdrimport.cxx
new file mode 100644
index 000000000..e928377f9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsdrimport.cxx
@@ -0,0 +1,1182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfsdrimport.hxx"
+#include <cmath>
+#include <optional>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <ooxml/resourceids.hxx>
+#include <filter/msfilter/escherex.hxx>
+#include <filter/msfilter/util.hxx>
+#include <filter/msfilter/rtfutil.hxx>
+#include <sal/log.hxx>
+#include <svx/svdtrans.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertysequence.hxx>
+#include "rtfreferenceproperties.hxx"
+#include <oox/vml/vmlformatting.hxx>
+#include <oox/helper/modelobjecthelper.hxx>
+#include <oox/drawingml/shapepropertymap.hxx>
+#include <oox/helper/propertyset.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/UnitConversion.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include "rtfdocumentimpl.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFSdrImport::RTFSdrImport(RTFDocumentImpl& rDocument,
+ uno::Reference<lang::XComponent> const& xDstDoc)
+ : m_rImport(rDocument)
+ , m_bTextFrame(false)
+ , m_bTextGraphicObject(false)
+ , m_bFakePict(false)
+{
+ uno::Reference<drawing::XDrawPageSupplier> xDrawings(xDstDoc, uno::UNO_QUERY);
+ if (xDrawings.is())
+ m_aParents.push(xDrawings->getDrawPage());
+ m_aGraphicZOrderHelpers.push(writerfilter::dmapper::GraphicZOrderHelper());
+}
+
+RTFSdrImport::~RTFSdrImport()
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ m_aGraphicZOrderHelpers.pop();
+ if (!m_aParents.empty())
+ m_aParents.pop();
+}
+
+void RTFSdrImport::createShape(const OUString& rService, uno::Reference<drawing::XShape>& xShape,
+ uno::Reference<beans::XPropertySet>& xPropertySet)
+{
+ if (m_rImport.getModelFactory().is())
+ xShape.set(m_rImport.getModelFactory()->createInstance(rService), uno::UNO_QUERY);
+ xPropertySet.set(xShape, uno::UNO_QUERY);
+}
+
+std::vector<beans::PropertyValue> RTFSdrImport::getTextFrameDefaults(bool bNew)
+{
+ std::vector<beans::PropertyValue> aRet;
+ beans::PropertyValue aPropertyValue;
+
+ aPropertyValue.Name = "HoriOrient";
+ aPropertyValue.Value <<= text::HoriOrientation::NONE;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "HoriOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "VertOrient";
+ aPropertyValue.Value <<= text::VertOrientation::NONE;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "VertOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ aRet.push_back(aPropertyValue);
+ if (!bNew)
+ {
+ aPropertyValue.Name = "BackColorTransparency";
+ aPropertyValue.Value <<= sal_Int32(100);
+ aRet.push_back(aPropertyValue);
+ }
+ // See the spec, new-style frame default margins are specified in EMUs.
+ aPropertyValue.Name = "LeftBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "RightBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "TopBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "BottomBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "SizeType";
+ aPropertyValue.Value <<= text::SizeType::FIX;
+ aRet.push_back(aPropertyValue);
+ return aRet;
+}
+
+void RTFSdrImport::pushParent(uno::Reference<drawing::XShapes> const& xParent)
+{
+ m_aParents.push(xParent);
+ m_aGraphicZOrderHelpers.push(writerfilter::dmapper::GraphicZOrderHelper());
+}
+
+void RTFSdrImport::popParent()
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ m_aGraphicZOrderHelpers.pop();
+ if (!m_aParents.empty())
+ m_aParents.pop();
+}
+
+void RTFSdrImport::resolveDhgt(uno::Reference<beans::XPropertySet> const& xPropertySet,
+ sal_Int32 const nZOrder, bool const bOldStyle)
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ {
+ writerfilter::dmapper::GraphicZOrderHelper& rHelper = m_aGraphicZOrderHelpers.top();
+ xPropertySet->setPropertyValue("ZOrder", uno::Any(rHelper.findZOrder(nZOrder, bOldStyle)));
+ rHelper.addItem(xPropertySet, nZOrder);
+ }
+}
+
+void RTFSdrImport::resolveLineColorAndWidth(bool bTextFrame,
+ const uno::Reference<beans::XPropertySet>& xPropertySet,
+ uno::Any const& rLineColor, uno::Any const& rLineWidth)
+{
+ if (!bTextFrame)
+ {
+ xPropertySet->setPropertyValue("LineColor", rLineColor);
+ xPropertySet->setPropertyValue("LineWidth", rLineWidth);
+ }
+ else
+ {
+ static const char* aBorders[]
+ = { "TopBorder", "LeftBorder", "BottomBorder", "RightBorder" };
+ for (const char* pBorder : aBorders)
+ {
+ auto aBorderLine = xPropertySet->getPropertyValue(OUString::createFromAscii(pBorder))
+ .get<table::BorderLine2>();
+ if (rLineColor.hasValue())
+ aBorderLine.Color = rLineColor.get<sal_Int32>();
+ if (rLineWidth.hasValue())
+ aBorderLine.LineWidth = rLineWidth.get<sal_Int32>();
+ xPropertySet->setPropertyValue(OUString::createFromAscii(pBorder),
+ uno::Any(aBorderLine));
+ }
+ }
+}
+
+void RTFSdrImport::resolveFLine(uno::Reference<beans::XPropertySet> const& xPropertySet,
+ sal_Int32 const nFLine)
+{
+ if (nFLine == 0)
+ xPropertySet->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE));
+ else
+ xPropertySet->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_SOLID));
+}
+
+void RTFSdrImport::applyProperty(uno::Reference<drawing::XShape> const& xShape,
+ std::u16string_view aKey, std::u16string_view aValue) const
+{
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ sal_Int16 nHoriOrient = 0;
+ sal_Int16 nVertOrient = 0;
+ std::optional<bool> obFitShapeToText;
+ bool bFilled = true;
+
+ if (aKey == u"posh")
+ {
+ switch (o3tl::toInt32(aValue))
+ {
+ case 1:
+ nHoriOrient = text::HoriOrientation::LEFT;
+ break;
+ case 2:
+ nHoriOrient = text::HoriOrientation::CENTER;
+ break;
+ case 3:
+ nHoriOrient = text::HoriOrientation::RIGHT;
+ break;
+ case 4:
+ nHoriOrient = text::HoriOrientation::INSIDE;
+ break;
+ case 5:
+ nHoriOrient = text::HoriOrientation::OUTSIDE;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (aKey == u"posv")
+ {
+ switch (o3tl::toInt32(aValue))
+ {
+ case 1:
+ nVertOrient = text::VertOrientation::TOP;
+ break;
+ case 2:
+ nVertOrient = text::VertOrientation::CENTER;
+ break;
+ case 3:
+ nVertOrient = text::VertOrientation::BOTTOM;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (aKey == u"fFitShapeToText")
+ obFitShapeToText = o3tl::toInt32(aValue) == 1;
+ else if (aKey == u"fFilled")
+ bFilled = o3tl::toInt32(aValue) == 1;
+ else if (aKey == u"rotation")
+ {
+ // See DffPropertyReader::Fix16ToAngle(): in RTF, positive rotation angles are clockwise, we have them as counter-clockwise.
+ // Additionally, RTF type is 0..360*2^16, our is 0..360*100.
+ sal_Int32 nRotation = o3tl::toInt32(aValue) * 100 / RTF_MULTIPLIER;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
+ if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ xPropertySet->setPropertyValue(
+ "RotateAngle", uno::Any(NormAngle36000(Degree100(nRotation * -1)).get()));
+ }
+
+ if (nHoriOrient != 0 && xPropertySet.is())
+ xPropertySet->setPropertyValue("HoriOrient", uno::Any(nHoriOrient));
+ if (nVertOrient != 0 && xPropertySet.is())
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(nVertOrient));
+ if (obFitShapeToText.has_value() && xPropertySet.is())
+ {
+ xPropertySet->setPropertyValue(
+ "SizeType", uno::Any(*obFitShapeToText ? text::SizeType::MIN : text::SizeType::FIX));
+ xPropertySet->setPropertyValue("FrameIsAutomaticHeight", uno::Any(*obFitShapeToText));
+ }
+ if (!bFilled && xPropertySet.is())
+ {
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("BackColorTransparency", uno::Any(sal_Int32(100)));
+ else
+ xPropertySet->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE));
+ }
+}
+
+int RTFSdrImport::initShape(uno::Reference<drawing::XShape>& o_xShape,
+ uno::Reference<beans::XPropertySet>& o_xPropSet, bool& o_rIsCustomShape,
+ RTFShape const& rShape, bool const bClose,
+ ShapeOrPict const shapeOrPict)
+{
+ assert(!o_xShape.is());
+ assert(!o_xPropSet.is());
+ o_rIsCustomShape = false;
+ m_bFakePict = false;
+
+ // first, find the shape type
+ int nType = -1;
+ auto iter = std::find_if(rShape.getProperties().begin(), rShape.getProperties().end(),
+ [](const std::pair<OUString, OUString>& rProperty) {
+ return rProperty.first == "shapeType";
+ });
+
+ if (iter == rShape.getProperties().end())
+ {
+ if (SHAPE == shapeOrPict)
+ {
+ // The spec doesn't state what is the default for shapeType,
+ // Word seems to implement it as a rectangle.
+ nType = ESCHER_ShpInst_Rectangle;
+ }
+ else
+ {
+ // pict is picture by default but can be a rectangle too fdo#79319
+ nType = ESCHER_ShpInst_PictureFrame;
+ }
+ }
+ else
+ {
+ nType = iter->second.toInt32();
+ if (PICT == shapeOrPict && ESCHER_ShpInst_PictureFrame != nType)
+ {
+ m_bFakePict = true;
+ }
+ }
+
+ switch (nType)
+ {
+ case ESCHER_ShpInst_PictureFrame:
+ createShape("com.sun.star.drawing.GraphicObjectShape", o_xShape, o_xPropSet);
+ m_bTextGraphicObject = true;
+ break;
+ case ESCHER_ShpInst_Line:
+ createShape("com.sun.star.drawing.LineShape", o_xShape, o_xPropSet);
+ break;
+ case ESCHER_ShpInst_Rectangle:
+ case ESCHER_ShpInst_TextBox:
+ // If we're inside a groupshape, can't use text frames.
+ if (!bClose && m_aParents.size() == 1)
+ {
+ createShape("com.sun.star.text.TextFrame", o_xShape, o_xPropSet);
+ m_bTextFrame = true;
+ std::vector<beans::PropertyValue> aDefaults = getTextFrameDefaults(true);
+ for (const beans::PropertyValue& i : aDefaults)
+ o_xPropSet->setPropertyValue(i.Name, i.Value);
+ break;
+ }
+ [[fallthrough]];
+ default:
+ createShape("com.sun.star.drawing.CustomShape", o_xShape, o_xPropSet);
+ o_rIsCustomShape = true;
+ break;
+ }
+
+ // Defaults
+ if (o_xPropSet.is() && !m_bTextFrame)
+ {
+ o_xPropSet->setPropertyValue(
+ "FillColor",
+ uno::Any(sal_uInt32(0xffffff))); // White in Word, kind of blue in Writer.
+ o_xPropSet->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::NONE));
+ }
+
+ return nType;
+}
+
+void RTFSdrImport::resolve(RTFShape& rShape, bool bClose, ShapeOrPict const shapeOrPict)
+{
+ bool bPib = false;
+ m_bTextFrame = false;
+ m_bTextGraphicObject = false;
+
+ uno::Reference<drawing::XShape> xShape;
+ uno::Reference<beans::XPropertySet> xPropertySet;
+ uno::Any aAny;
+ beans::PropertyValue aPropertyValue;
+ awt::Rectangle aViewBox;
+ std::vector<beans::PropertyValue> aPath;
+ // Default line color is black in Word, blue in Writer.
+ uno::Any aLineColor(COL_BLACK);
+ // Default line width is 0.75 pt (26 mm100) in Word, 0 in Writer.
+ uno::Any aLineWidth(sal_Int32(26));
+ sal_Int16 eWritingMode = text::WritingMode2::LR_TB;
+ // Groupshape support
+ std::optional<sal_Int32> oGroupLeft;
+ std::optional<sal_Int32> oGroupTop;
+ std::optional<sal_Int32> oGroupRight;
+ std::optional<sal_Int32> oGroupBottom;
+ std::optional<sal_Int32> oRelLeft;
+ std::optional<sal_Int32> oRelTop;
+ std::optional<sal_Int32> oRelRight;
+ std::optional<sal_Int32> oRelBottom;
+
+ // Importing these are not trivial, let the VML import do the hard work.
+ oox::vml::FillModel aFillModel; // Gradient.
+ oox::vml::ShadowModel aShadowModel; // Shadow.
+
+ bool bOpaque = true;
+
+ std::optional<sal_Int16> oRelativeWidth;
+ std::optional<sal_Int16> oRelativeHeight;
+ sal_Int16 nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
+ sal_Int16 nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
+ std::optional<bool> obRelFlipV;
+ bool obFlipH(false);
+ bool obFlipV(false);
+
+ OUString aShapeText = "";
+ OUString aFontFamily = "";
+ float nFontSize = 1.0;
+
+ sal_Int32 nContrast = 0x10000;
+ sal_Int16 nBrightness = 0;
+
+ bool bCustom(false);
+ int const nType = initShape(xShape, xPropertySet, bCustom, rShape, bClose, shapeOrPict);
+
+ for (auto& rProperty : rShape.getProperties())
+ {
+ if (rProperty.first == "shapeType")
+ {
+ continue; // ignore: already handled by initShape
+ }
+ if (rProperty.first == "wzName")
+ {
+ if (m_bTextFrame)
+ {
+ uno::Reference<container::XNamed> xNamed(xShape, uno::UNO_QUERY);
+ xNamed->setName(rProperty.second);
+ }
+ else
+ xPropertySet->setPropertyValue("Name", uno::Any(rProperty.second));
+ }
+ else if (rProperty.first == "wzDescription")
+ xPropertySet->setPropertyValue("Description", uno::Any(rProperty.second));
+ else if (rProperty.first == "gtextUNICODE")
+ aShapeText = rProperty.second;
+ else if (rProperty.first == "gtextFont")
+ aFontFamily = rProperty.second;
+ else if (rProperty.first == "gtextSize")
+ {
+ // RTF size is multiplied by 2^16
+ nFontSize = static_cast<float>(rProperty.second.toUInt32()) / RTF_MULTIPLIER;
+ }
+ else if (rProperty.first == "pib")
+ {
+ m_rImport.setDestinationText(rProperty.second);
+ bPib = true;
+ }
+ else if (rProperty.first == "fillColor" && xPropertySet.is())
+ {
+ aAny <<= msfilter::util::BGRToRGB(rProperty.second.toUInt32());
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("BackColor", aAny);
+ else
+ xPropertySet->setPropertyValue("FillColor", aAny);
+
+ // fillType will decide, possible it'll be the start color of a gradient.
+ aFillModel.moColor.set(
+ "#"
+ + msfilter::util::ConvertColorOU(Color(ColorTransparency, aAny.get<sal_Int32>())));
+ }
+ else if (rProperty.first == "fillBackColor")
+ // fillType will decide, possible it'll be the end color of a gradient.
+ aFillModel.moColor2.set("#"
+ + msfilter::util::ConvertColorOU(
+ msfilter::util::BGRToRGB(rProperty.second.toInt32())));
+ else if (rProperty.first == "lineColor")
+ aLineColor <<= msfilter::util::BGRToRGB(rProperty.second.toInt32());
+ else if (rProperty.first == "lineBackColor")
+ ; // Ignore: complementer of lineColor
+ else if (rProperty.first == "txflTextFlow" && xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1: // Top to bottom ASCII font
+ case 3: // Top to bottom non-ASCII font
+ eWritingMode = text::WritingMode2::TB_RL;
+ break;
+ case 2: // Bottom to top non-ASCII font
+ eWritingMode = text::WritingMode2::BT_LR;
+ break;
+ }
+ }
+ else if (rProperty.first == "fLine" && xPropertySet.is())
+ resolveFLine(xPropertySet, rProperty.second.toInt32());
+ else if (rProperty.first == "fillOpacity" && xPropertySet.is())
+ {
+ int opacity = 100 - (rProperty.second.toInt32()) * 100 / RTF_MULTIPLIER;
+ xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_uInt32(opacity)));
+ }
+ else if (rProperty.first == "lineWidth")
+ aLineWidth <<= rProperty.second.toInt32() / 360;
+ else if (rProperty.first == "pVerticies")
+ {
+ std::vector<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
+ sal_Int32 nSize = 0; // Size of a token (its value is hardwired in the exporter)
+ sal_Int32 nCount = 0; // Number of tokens
+ sal_Int32 nCharIndex = 0; // Character index
+ do
+ {
+ std::u16string_view aToken = o3tl::getToken(rProperty.second, 0, ';', nCharIndex);
+ if (!nSize)
+ nSize = o3tl::toInt32(aToken);
+ else if (!nCount)
+ nCount = o3tl::toInt32(aToken);
+ else if (!aToken.empty())
+ {
+ // The coordinates are in an (x,y) form.
+ aToken = aToken.substr(1, aToken.size() - 2);
+ sal_Int32 nI = 0;
+ sal_Int32 nX = o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI));
+ sal_Int32 nY
+ = (nI >= 0) ? o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI)) : 0;
+ drawing::EnhancedCustomShapeParameterPair aPair;
+ aPair.First.Value <<= nX;
+ aPair.Second.Value <<= nY;
+ aCoordinates.push_back(aPair);
+ }
+ } while (nCharIndex >= 0);
+ aPropertyValue.Name = "Coordinates";
+ aPropertyValue.Value <<= comphelper::containerToSequence(aCoordinates);
+ aPath.push_back(aPropertyValue);
+ }
+ else if (rProperty.first == "pSegmentInfo")
+ {
+ std::vector<drawing::EnhancedCustomShapeSegment> aSegments;
+ sal_Int32 nSize = 0;
+ sal_Int32 nCount = 0;
+ sal_Int32 nCharIndex = 0;
+ do
+ {
+ sal_Int32 nSeg
+ = o3tl::toInt32(o3tl::getToken(rProperty.second, 0, ';', nCharIndex));
+ if (!nSize)
+ nSize = nSeg;
+ else if (!nCount)
+ nCount = nSeg;
+ else
+ {
+ sal_Int32 nPoints = 1;
+ if (nSeg >= 0x2000 && nSeg < 0x20FF)
+ {
+ nPoints = nSeg & 0x0FFF;
+ nSeg &= 0xFF00;
+ }
+
+ drawing::EnhancedCustomShapeSegment aSegment;
+ switch (nSeg)
+ {
+ case 0x0001: // lineto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
+ aSegment.Count = sal_Int32(1);
+ aSegments.push_back(aSegment);
+ break;
+ case 0x4000: // moveto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
+ aSegment.Count = sal_Int32(1);
+ aSegments.push_back(aSegment);
+ break;
+ case 0x2000: // curveto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::CURVETO;
+ aSegment.Count = nPoints;
+ aSegments.push_back(aSegment);
+ break;
+ case 0xb300: // arcto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::ARCTO;
+ aSegment.Count = sal_Int32(0);
+ aSegments.push_back(aSegment);
+ break;
+ case 0xac00:
+ case 0xaa00: // nofill
+ case 0xab00: // nostroke
+ case 0x6001: // close
+ break;
+ case 0x8000: // end
+ aSegment.Command
+ = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
+ aSegment.Count = sal_Int32(0);
+ aSegments.push_back(aSegment);
+ break;
+ default: // given number of lineto elements
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
+ aSegment.Count = nSeg;
+ aSegments.push_back(aSegment);
+ break;
+ }
+ }
+ } while (nCharIndex >= 0);
+ aPropertyValue.Name = "Segments";
+ aPropertyValue.Value <<= comphelper::containerToSequence(aSegments);
+ aPath.push_back(aPropertyValue);
+ }
+ else if (rProperty.first == "geoLeft")
+ aViewBox.X = rProperty.second.toInt32();
+ else if (rProperty.first == "geoTop")
+ aViewBox.Y = rProperty.second.toInt32();
+ else if (rProperty.first == "geoRight")
+ aViewBox.Width = rProperty.second.toInt32();
+ else if (rProperty.first == "geoBottom")
+ aViewBox.Height = rProperty.second.toInt32();
+ else if (rProperty.first == "dhgt")
+ {
+ // dhgt is Word 2007, \shpz is Word 97-2003, the later has priority.
+ if (!rShape.hasZ())
+ resolveDhgt(xPropertySet, rProperty.second.toInt32(), /*bOldStyle=*/false);
+ }
+ // These are in EMU, convert to mm100.
+ else if (rProperty.first == "dxTextLeft")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("LeftBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyTextTop")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("TopBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxTextRight")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("RightBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyTextBottom")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("BottomBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxWrapDistLeft")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distL,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("LeftMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyWrapDistTop")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distT,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("TopMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxWrapDistRight")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distR,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("RightMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyWrapDistBottom")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distB,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("BottomMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "fillType")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 7: // Shade using the fillAngle
+ aFillModel.moType.set(oox::XML_gradient);
+ break;
+ default:
+ SAL_INFO("writerfilter",
+ "TODO handle fillType value '" << rProperty.second << "'");
+ break;
+ }
+ }
+ else if (rProperty.first == "fillFocus")
+ aFillModel.moFocus.set(rProperty.second.toDouble() / 100); // percent
+ else if (rProperty.first == "fShadow" && xPropertySet.is())
+ {
+ if (rProperty.second.toInt32() == 1)
+ aShadowModel.mbHasShadow = true;
+ }
+ else if (rProperty.first == "shadowColor")
+ aShadowModel.moColor.set("#"
+ + msfilter::util::ConvertColorOU(
+ msfilter::util::BGRToRGB(rProperty.second.toInt32())));
+ else if (rProperty.first == "shadowOffsetX")
+ // EMUs to points
+ aShadowModel.moOffset.set(OUString::number(rProperty.second.toDouble() / 12700) + "pt");
+ else if (rProperty.first == "posh" || rProperty.first == "posv"
+ || rProperty.first == "fFitShapeToText" || rProperty.first == "fFilled"
+ || rProperty.first == "rotation")
+ applyProperty(xShape, rProperty.first, rProperty.second);
+ else if (rProperty.first == "posrelh")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1:
+ rShape.setHoriOrientRelation(text::RelOrientation::PAGE_FRAME);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (rProperty.first == "posrelv")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1:
+ rShape.setVertOrientRelation(text::RelOrientation::PAGE_FRAME);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (rProperty.first == "groupLeft")
+ oGroupLeft = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupTop")
+ oGroupTop = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupRight")
+ oGroupRight = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupBottom")
+ oGroupBottom = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relLeft")
+ oRelLeft = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relTop")
+ oRelTop = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relRight")
+ oRelRight = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relBottom")
+ oRelBottom = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "fBehindDocument")
+ bOpaque = !rProperty.second.toInt32();
+ else if (rProperty.first == "pctHoriz" || rProperty.first == "pctVert")
+ {
+ sal_Int16 nPercentage = rtl::math::round(rProperty.second.toDouble() / 10);
+ if (nPercentage)
+ {
+ std::optional<sal_Int16>& rPercentage
+ = rProperty.first == "pctHoriz" ? oRelativeWidth : oRelativeHeight;
+ rPercentage = nPercentage;
+ }
+ }
+ else if (rProperty.first == "sizerelh")
+ {
+ if (xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 0: // margin
+ nRelativeWidthRelation = text::RelOrientation::FRAME;
+ break;
+ case 1: // page
+ nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+ default:
+ SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelh value: "
+ << rProperty.second);
+ break;
+ }
+ }
+ }
+ else if (rProperty.first == "sizerelv")
+ {
+ if (xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 0: // margin
+ nRelativeHeightRelation = text::RelOrientation::FRAME;
+ break;
+ case 1: // page
+ nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+ default:
+ SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelv value: "
+ << rProperty.second);
+ break;
+ }
+ }
+ }
+ else if (rProperty.first == "fHorizRule") // TODO: what does "fStandardHR" do?
+ {
+ // horizontal rule: relative width defaults to 100% of paragraph
+ // TODO: does it have a default height?
+ if (!oRelativeWidth)
+ {
+ oRelativeWidth = 100;
+ }
+ nRelativeWidthRelation = text::RelOrientation::FRAME;
+ if (xPropertySet.is())
+ {
+ sal_Int16 const nVertOrient = text::VertOrientation::CENTER;
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(nVertOrient));
+ }
+ }
+ else if (rProperty.first == "pctHR")
+ {
+ // horizontal rule relative width in permille
+ oRelativeWidth = rProperty.second.toInt32() / 10;
+ }
+ else if (rProperty.first == "dxHeightHR")
+ {
+ // horizontal rule height
+ sal_uInt32 const nHeight(convertTwipToMm100(rProperty.second.toInt32()));
+ rShape.setBottom(rShape.getTop() + nHeight);
+ }
+ else if (rProperty.first == "dxWidthHR")
+ {
+ // horizontal rule width
+ sal_uInt32 const nWidth(convertTwipToMm100(rProperty.second.toInt32()));
+ rShape.setRight(rShape.getLeft() + nWidth);
+ }
+ else if (rProperty.first == "alignHR")
+ {
+ // horizontal orientation *for horizontal rule*
+ sal_Int16 nHoriOrient = text::HoriOrientation::NONE;
+ switch (rProperty.second.toInt32())
+ {
+ case 0:
+ nHoriOrient = text::HoriOrientation::LEFT;
+ break;
+ case 1:
+ nHoriOrient = text::HoriOrientation::CENTER;
+ break;
+ case 2:
+ nHoriOrient = text::HoriOrientation::RIGHT;
+ break;
+ }
+ if (xPropertySet.is() && text::HoriOrientation::NONE != nHoriOrient)
+ {
+ xPropertySet->setPropertyValue("HoriOrient", uno::Any(nHoriOrient));
+ }
+ }
+ else if (rProperty.first == "pWrapPolygonVertices")
+ {
+ RTFSprms aPolygonSprms;
+ sal_Int32 nSize = 0; // Size of a token
+ sal_Int32 nCount = 0; // Number of tokens
+ sal_Int32 nCharIndex = 0; // Character index
+ do
+ {
+ std::u16string_view aToken = o3tl::getToken(rProperty.second, 0, ';', nCharIndex);
+ if (!nSize)
+ nSize = o3tl::toInt32(aToken);
+ else if (!nCount)
+ nCount = o3tl::toInt32(aToken);
+ else if (!aToken.empty())
+ {
+ // The coordinates are in an (x,y) form.
+ aToken = aToken.substr(1, aToken.size() - 2);
+ sal_Int32 nI = 0;
+ sal_Int32 nX = o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI));
+ sal_Int32 nY
+ = (nI >= 0) ? o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI)) : 0;
+ RTFSprms aPathAttributes;
+ aPathAttributes.set(NS_ooxml::LN_CT_Point2D_x, new RTFValue(nX));
+ aPathAttributes.set(NS_ooxml::LN_CT_Point2D_y, new RTFValue(nY));
+ aPolygonSprms.set(NS_ooxml::LN_CT_WrapPath_lineTo,
+ new RTFValue(aPathAttributes), RTFOverwrite::NO_APPEND);
+ }
+ } while (nCharIndex >= 0);
+ rShape.getWrapPolygonSprms() = aPolygonSprms;
+ }
+ else if (rProperty.first == "fRelFlipV")
+ obRelFlipV = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "fFlipH")
+ obFlipH = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "fFlipV")
+ obFlipV = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "pictureContrast")
+ {
+ // Gain / contrast.
+ nContrast = rProperty.second.toInt32();
+ if (nContrast < 0x10000)
+ {
+ nContrast *= 101; // 100 + 1 to round
+ nContrast /= 0x10000;
+ nContrast -= 100;
+ }
+ }
+ else if (rProperty.first == "pictureBrightness")
+ {
+ // Blacklevel / brightness.
+ nBrightness = rProperty.second.toInt32();
+ if (nBrightness != 0)
+ {
+ nBrightness /= 327;
+ }
+ }
+ else
+ SAL_INFO("writerfilter", "TODO handle shape property '" << rProperty.first << "':'"
+ << rProperty.second << "'");
+ }
+
+ if (xPropertySet.is())
+ {
+ resolveLineColorAndWidth(m_bTextFrame, xPropertySet, aLineColor, aLineWidth);
+ if (rShape.hasZ())
+ {
+ bool bOldStyle = m_aParents.size() > 1;
+ resolveDhgt(xPropertySet, rShape.getZ(), bOldStyle);
+ }
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("WritingMode", uno::Any(eWritingMode));
+ else
+ // Only Writer textframes implement text::WritingMode2.
+ xPropertySet->setPropertyValue("TextWritingMode",
+ uno::Any(text::WritingMode(eWritingMode)));
+ }
+
+ if (!m_aParents.empty() && m_aParents.top().is() && !m_bTextFrame)
+ m_aParents.top()->add(xShape);
+
+ if (nContrast == -70 && nBrightness == 70 && xPropertySet.is())
+ {
+ // Map MSO 'washout' to our watermark colormode.
+ xPropertySet->setPropertyValue("GraphicColorMode", uno::Any(drawing::ColorMode_WATERMARK));
+ }
+
+ if (bCustom && xShape.is() && !bPib)
+ {
+ uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
+ xDefaulter->createCustomShapeDefaults(OUString::number(nType));
+ }
+
+ // Set shape text
+ if (bCustom && !aShapeText.isEmpty())
+ {
+ uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
+ if (xTextRange.is())
+ xTextRange->setString(aShapeText);
+
+ xPropertySet->setPropertyValue("CharFontName", uno::Any(aFontFamily));
+ xPropertySet->setPropertyValue("CharHeight", uno::Any(nFontSize));
+ }
+
+ // Creating CustomShapeGeometry property
+ if (bCustom && xPropertySet.is())
+ {
+ bool bChanged = false;
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(
+ xPropertySet->getPropertyValue("CustomShapeGeometry"));
+
+ if (aViewBox.X || aViewBox.Y || aViewBox.Width || aViewBox.Height)
+ {
+ aViewBox.Width -= aViewBox.X;
+ aViewBox.Height -= aViewBox.Y;
+ aCustomShapeGeometry["ViewBox"] <<= aViewBox;
+ bChanged = true;
+ }
+
+ if (!aPath.empty())
+ {
+ aCustomShapeGeometry["Path"] <<= comphelper::containerToSequence(aPath);
+ bChanged = true;
+ }
+
+ if (!aShapeText.isEmpty())
+ {
+ uno::Sequence<beans::PropertyValue> aSequence(comphelper::InitPropertySequence({
+ { "TextPath", uno::Any(true) },
+ }));
+ aCustomShapeGeometry["TextPath"] <<= aSequence;
+ xPropertySet->setPropertyValue("TextAutoGrowHeight", uno::Any(false));
+ xPropertySet->setPropertyValue("TextAutoGrowWidth", uno::Any(false));
+ bChanged = true;
+ }
+
+ if (bChanged)
+ {
+ xPropertySet->setPropertyValue(
+ "CustomShapeGeometry",
+ uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
+ }
+ }
+
+ if (obRelFlipV.has_value() && xPropertySet.is())
+ {
+ if (nType == ESCHER_ShpInst_Line)
+ {
+ // Line shape inside group shape: get the polygon sequence and transform it.
+ uno::Sequence<uno::Sequence<awt::Point>> aPolyPolySequence;
+ if ((xPropertySet->getPropertyValue("PolyPolygon") >>= aPolyPolySequence)
+ && aPolyPolySequence.hasElements())
+ {
+ uno::Sequence<awt::Point>& rPolygon = aPolyPolySequence.getArray()[0];
+ basegfx::B2DPolygon aPoly;
+ for (const awt::Point& rPoint : std::as_const(rPolygon))
+ {
+ aPoly.append(basegfx::B2DPoint(rPoint.X, rPoint.Y));
+ }
+ basegfx::B2DHomMatrix aTransformation;
+ aTransformation.scale(1.0, *obRelFlipV ? -1.0 : 1.0);
+ aPoly.transform(aTransformation);
+ auto pPolygon = rPolygon.getArray();
+ for (sal_Int32 i = 0; i < rPolygon.getLength(); ++i)
+ {
+ basegfx::B2DPoint aPoint(aPoly.getB2DPoint(i));
+ pPolygon[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()),
+ static_cast<sal_Int32>(aPoint.getY()));
+ }
+ xPropertySet->setPropertyValue("PolyPolygon", uno::Any(aPolyPolySequence));
+ }
+ }
+ }
+
+ // Set position and size
+ if (xShape.is())
+ {
+ sal_Int32 nLeft = rShape.getLeft();
+ sal_Int32 nTop = rShape.getTop();
+
+ bool bInShapeGroup = oGroupLeft && oGroupTop && oGroupRight && oGroupBottom && oRelLeft
+ && oRelTop && oRelRight && oRelBottom;
+ awt::Size aSize;
+ if (bInShapeGroup)
+ {
+ // See lclGetAbsPoint() in the VML import: rShape is the group shape, oGroup is its coordinate system, oRel is the relative child shape.
+ sal_Int32 nShapeWidth = rShape.getRight() - rShape.getLeft();
+ sal_Int32 nShapeHeight = rShape.getBottom() - rShape.getTop();
+ sal_Int32 nCoordSysWidth = *oGroupRight - *oGroupLeft;
+ sal_Int32 nCoordSysHeight = *oGroupBottom - *oGroupTop;
+ double fWidthRatio = static_cast<double>(nShapeWidth) / nCoordSysWidth;
+ double fHeightRatio = static_cast<double>(nShapeHeight) / nCoordSysHeight;
+ nLeft = static_cast<sal_Int32>(rShape.getLeft()
+ + fWidthRatio * (*oRelLeft - *oGroupLeft));
+ nTop = static_cast<sal_Int32>(rShape.getTop() + fHeightRatio * (*oRelTop - *oGroupTop));
+
+ // See lclGetAbsRect() in the VML import.
+ aSize.Width = std::lround(fWidthRatio * (*oRelRight - *oRelLeft));
+ aSize.Height = std::lround(fHeightRatio * (*oRelBottom - *oRelTop));
+ }
+
+ if (m_bTextFrame)
+ {
+ xPropertySet->setPropertyValue("HoriOrientPosition", uno::Any(nLeft));
+ xPropertySet->setPropertyValue("VertOrientPosition", uno::Any(nTop));
+ }
+ else
+ xShape->setPosition(awt::Point(nLeft, nTop));
+
+ if (bInShapeGroup)
+ xShape->setSize(aSize);
+ else
+ xShape->setSize(awt::Size(rShape.getRight() - rShape.getLeft(),
+ rShape.getBottom() - rShape.getTop()));
+
+ if (obFlipH || obFlipV)
+ {
+ if (bCustom)
+ {
+ // This has to be set after position and size is set, otherwise flip will affect the position.
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(
+ xPropertySet->getPropertyValue("CustomShapeGeometry"));
+ if (obFlipH)
+ aCustomShapeGeometry["MirroredX"] <<= true;
+ if (obFlipV)
+ aCustomShapeGeometry["MirroredY"] <<= true;
+ xPropertySet->setPropertyValue(
+ "CustomShapeGeometry",
+ uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
+ }
+ else if (SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape))
+ {
+ Point aRef1 = pObject->GetSnapRect().Center();
+ Point aRef2(aRef1);
+ if (obFlipH)
+ {
+ // Horizontal mirror means a vertical reference line.
+ aRef2.AdjustY(1);
+ }
+ if (obFlipV)
+ {
+ // Vertical mirror means a horizontal reference line.
+ aRef2.AdjustX(1);
+ }
+ pObject->Mirror(aRef1, aRef2);
+ }
+ }
+
+ if (rShape.getHoriOrientRelation() != 0)
+ xPropertySet->setPropertyValue("HoriOrientRelation",
+ uno::Any(rShape.getHoriOrientRelation()));
+ if (rShape.getVertOrientRelation() != 0)
+ xPropertySet->setPropertyValue("VertOrientRelation",
+ uno::Any(rShape.getVertOrientRelation()));
+ if (rShape.getWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE)
+ xPropertySet->setPropertyValue("Surround", uno::Any(rShape.getWrap()));
+ oox::ModelObjectHelper aModelObjectHelper(m_rImport.getModelFactory());
+ if (aFillModel.moType.has())
+ {
+ oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
+ aFillModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
+ // Sets the FillStyle and FillGradient UNO properties.
+ oox::PropertySet(xShape).setProperties(aPropMap);
+ }
+
+ if (aShadowModel.mbHasShadow)
+ {
+ oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
+ aShadowModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
+ // Sets the ShadowFormat UNO property.
+ oox::PropertySet(xShape).setProperties(aPropMap);
+ }
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ xPropertySet->setPropertyValue("Opaque", uno::Any(bOpaque));
+ if (oRelativeWidth)
+ {
+ xPropertySet->setPropertyValue("RelativeWidth", uno::Any(*oRelativeWidth));
+ xPropertySet->setPropertyValue("RelativeWidthRelation",
+ uno::Any(nRelativeWidthRelation));
+ }
+ if (oRelativeHeight)
+ {
+ xPropertySet->setPropertyValue("RelativeHeight", uno::Any(*oRelativeHeight));
+ xPropertySet->setPropertyValue("RelativeHeightRelation",
+ uno::Any(nRelativeHeightRelation));
+ }
+ }
+
+ if (bPib)
+ {
+ m_rImport.resolvePict(false, xShape);
+ }
+
+ if (nType == ESCHER_ShpInst_PictureFrame) // picture frame
+ {
+ assert(!m_bTextFrame);
+ if (!bPib) // ??? not sure if the early return should be removed on else?
+ {
+ m_xShape = xShape; // store it for later resolvePict call
+ }
+
+ // Handle horizontal flip.
+ if (obFlipH && xPropertySet.is())
+ xPropertySet->setPropertyValue("IsMirrored", uno::Any(true));
+ return;
+ }
+
+ if (m_rImport.isInBackground())
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Background_color,
+ new RTFValue(xPropertySet->getPropertyValue("FillColor").get<sal_Int32>()));
+ m_rImport.Mapper().props(new RTFReferenceProperties(std::move(aAttributes)));
+
+ uno::Reference<lang::XComponent> xComponent(xShape, uno::UNO_QUERY);
+ xComponent->dispose();
+ return;
+ }
+
+ // Send it to dmapper
+ if (xShape.is())
+ {
+ m_rImport.Mapper().startShape(xShape);
+ if (bClose)
+ {
+ m_rImport.Mapper().endShape();
+ }
+ }
+
+ // If the shape has an inner shape, the inner object's properties should not be influenced by
+ // the outer one.
+ rShape.getProperties().clear();
+
+ m_xShape = xShape;
+}
+
+void RTFSdrImport::close() { m_rImport.Mapper().endShape(); }
+
+void RTFSdrImport::append(std::u16string_view aKey, std::u16string_view aValue)
+{
+ applyProperty(m_xShape, aKey, aValue);
+}
+
+void RTFSdrImport::appendGroupProperty(std::u16string_view aKey, std::u16string_view aValue)
+{
+ if (m_aParents.empty())
+ return;
+ uno::Reference<drawing::XShape> xShape(m_aParents.top(), uno::UNO_QUERY);
+ if (xShape.is())
+ applyProperty(xShape, aKey, aValue);
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsdrimport.hxx b/writerfilter/source/rtftok/rtfsdrimport.hxx
new file mode 100644
index 000000000..16f7f9c31
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsdrimport.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <stack>
+#include <vector>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star
+{
+namespace beans
+{
+class XPropertySet;
+struct PropertyValue;
+}
+namespace drawing
+{
+class XShape;
+class XShapes;
+}
+namespace lang
+{
+class XComponent;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFDocumentImpl;
+class RTFShape;
+
+/// Handles the import of drawings using RTF markup.
+class RTFSdrImport final : public virtual SvRefBase
+{
+public:
+ RTFSdrImport(RTFDocumentImpl& rDocument,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc);
+ ~RTFSdrImport() override;
+
+ enum ShapeOrPict
+ {
+ SHAPE,
+ PICT
+ };
+ void resolve(RTFShape& rShape, bool bClose, ShapeOrPict shapeOrPict);
+ void close();
+ void append(std::u16string_view aKey, std::u16string_view aValue);
+ /// Append property on the current parent.
+ void appendGroupProperty(std::u16string_view aKey, std::u16string_view aValue);
+ void resolveDhgt(css::uno::Reference<css::beans::XPropertySet> const& xPropertySet,
+ sal_Int32 nZOrder, bool bOldStyle);
+ /// Set line color and line width on the shape, using the relevant API depending on if the shape is a text frame or not.
+ static void
+ resolveLineColorAndWidth(bool bTextFrame,
+ const css::uno::Reference<css::beans::XPropertySet>& xPropertySet,
+ css::uno::Any const& rLineColor, css::uno::Any const& rLineWidth);
+ static void resolveFLine(css::uno::Reference<css::beans::XPropertySet> const& xPropertySet,
+ sal_Int32 nFLine);
+ /**
+ * These are the default in Word, but not in Writer.
+ *
+ * @param bNew if the frame is new-style or old-style.
+ */
+ static std::vector<css::beans::PropertyValue> getTextFrameDefaults(bool bNew);
+ /// Push a new group shape to the parent stack.
+ void pushParent(css::uno::Reference<css::drawing::XShapes> const& xParent);
+ /// Pop the current group shape from the parent stack.
+ void popParent();
+ css::uno::Reference<css::drawing::XShape> const& getCurrentShape() const { return m_xShape; }
+ bool isFakePict() const { return m_bFakePict; }
+
+private:
+ void createShape(const OUString& rService, css::uno::Reference<css::drawing::XShape>& xShape,
+ css::uno::Reference<css::beans::XPropertySet>& xPropertySet);
+ void applyProperty(css::uno::Reference<css::drawing::XShape> const& xShape,
+ std::u16string_view aKey, std::u16string_view aValue) const;
+ int initShape(css::uno::Reference<css::drawing::XShape>& o_xShape,
+ css::uno::Reference<css::beans::XPropertySet>& o_xPropSet, bool& o_rIsCustomShape,
+ RTFShape const& rShape, bool bClose, ShapeOrPict shapeOrPict);
+
+ RTFDocumentImpl& m_rImport;
+ std::stack<css::uno::Reference<css::drawing::XShapes>> m_aParents;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ /// If m_xShape is imported as a Writer text frame (instead of a drawinglayer rectangle).
+ bool m_bTextFrame;
+ /// If m_xShape is imported as a Writer text graphic object (instead of a drawinglayer shape).
+ bool m_bTextGraphicObject;
+ /// if inside \pict, but actually it's a shape (not a picture)
+ bool m_bFakePict;
+ std::stack<writerfilter::dmapper::GraphicZOrderHelper> m_aGraphicZOrderHelpers;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfskipdestination.cxx b/writerfilter/source/rtftok/rtfskipdestination.cxx
new file mode 100644
index 000000000..ad2122318
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfskipdestination.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfskipdestination.hxx"
+#include <sal/log.hxx>
+#include "rtflistener.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFSkipDestination::RTFSkipDestination(RTFListener& rImport)
+ : m_rImport(rImport)
+ , m_bParsed(true)
+ , m_bReset(true)
+{
+}
+
+RTFSkipDestination::~RTFSkipDestination()
+{
+ if (m_rImport.getSkipUnknown() && m_bReset)
+ {
+ if (!m_bParsed)
+ {
+ SAL_INFO("writerfilter", __func__ << ": skipping destination");
+ m_rImport.setDestination(Destination::SKIP);
+ }
+ m_rImport.setSkipUnknown(false);
+ }
+}
+
+void RTFSkipDestination::setParsed(bool bParsed) { m_bParsed = bParsed; }
+
+void RTFSkipDestination::setReset(bool bReset) { m_bReset = bReset; }
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfskipdestination.hxx b/writerfilter/source/rtftok/rtfskipdestination.hxx
new file mode 100644
index 000000000..4a894373f
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfskipdestination.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+class RTFListener;
+
+/// Skips a destination after a not parsed control word if it was prefixed with \*
+class RTFSkipDestination final
+{
+public:
+ explicit RTFSkipDestination(RTFListener& rImport);
+ ~RTFSkipDestination();
+ void setParsed(bool bParsed);
+ void setReset(bool bReset);
+
+private:
+ RTFListener& m_rImport;
+ bool m_bParsed;
+ /// If false, the destructor is a noop, required by the \* symbol itself.
+ bool m_bReset;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsprm.cxx b/writerfilter/source/rtftok/rtfsprm.cxx
new file mode 100644
index 000000000..90bc97001
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsprm.cxx
@@ -0,0 +1,476 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfsprm.hxx"
+#include <ooxml/resourceids.hxx>
+#include <ooxml/QNameToString.hxx>
+#include <rtl/strbuf.hxx>
+#include "rtfdocumentimpl.hxx"
+#include <algorithm>
+
+namespace writerfilter::rtftok
+{
+RTFSprm::RTFSprm(Id nKeyword, RTFValue::Pointer_t& pValue)
+ : m_nKeyword(nKeyword)
+ , m_pValue(pValue)
+{
+}
+
+sal_uInt32 RTFSprm::getId() const { return m_nKeyword; }
+
+Value::Pointer_t RTFSprm::getValue() { return Value::Pointer_t(m_pValue->Clone()); }
+
+writerfilter::Reference<Properties>::Pointer_t RTFSprm::getProps()
+{
+ return m_pValue->getProperties();
+}
+
+#ifdef DBG_UTIL
+std::string RTFSprm::getName() const { return "RTFSprm"; }
+#endif
+
+#ifdef DBG_UTIL
+std::string RTFSprm::toString() const
+{
+ OStringBuffer aBuf("RTFSprm");
+
+ std::string sResult = QNameToString(m_nKeyword);
+
+ aBuf.append(" ('");
+ if (sResult.length() == 0)
+ aBuf.append(sal_Int32(m_nKeyword));
+ else
+ aBuf.append(sResult.c_str());
+ aBuf.append("', '");
+ aBuf.append(m_pValue->toString().c_str());
+ aBuf.append("')");
+
+ return aBuf.makeStringAndClear().getStr();
+}
+#endif
+
+namespace
+{
+class RTFSprms_compare
+{
+ Id keyword;
+
+public:
+ RTFSprms_compare(Id kw)
+ : keyword{ kw }
+ {
+ }
+ bool operator()(const std::pair<Id, RTFValue::Pointer_t>& raPair) const
+ {
+ return raPair.first == keyword;
+ }
+};
+}
+
+RTFValue::Pointer_t RTFSprms::find(Id nKeyword, bool bFirst, bool bForWrite)
+{
+ if (bForWrite)
+ ensureCopyBeforeWrite();
+
+ RTFSprms_compare cmp{ nKeyword };
+
+ if (bFirst)
+ {
+ auto it = std::find_if(m_pSprms->begin(), m_pSprms->end(), cmp);
+ if (it != m_pSprms->end())
+ return it->second;
+ }
+ else
+ // find last
+ {
+ auto rit = std::find_if(m_pSprms->rbegin(), m_pSprms->rend(), cmp);
+ if (rit != m_pSprms->rend())
+ return rit->second;
+ }
+
+ return RTFValue::Pointer_t{};
+}
+
+void RTFSprms::set(Id nKeyword, const RTFValue::Pointer_t& pValue, RTFOverwrite eOverwrite)
+{
+ ensureCopyBeforeWrite();
+
+ switch (eOverwrite)
+ {
+ case RTFOverwrite::YES_PREPEND:
+ {
+ m_pSprms->erase(
+ std::remove_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword }),
+ m_pSprms->end());
+ m_pSprms->emplace(m_pSprms->cbegin(), nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::YES:
+ {
+ auto it
+ = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword });
+ if (it != m_pSprms->end())
+ it->second = pValue;
+ else
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::NO_IGNORE:
+ {
+ if (std::none_of(m_pSprms->cbegin(), m_pSprms->cend(), RTFSprms_compare{ nKeyword }))
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::NO_APPEND:
+ {
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ }
+}
+
+bool RTFSprms::erase(Id nKeyword)
+{
+ ensureCopyBeforeWrite();
+
+ auto i = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword });
+ if (i != m_pSprms->end())
+ {
+ m_pSprms->erase(i);
+ return true;
+ }
+ return false;
+}
+
+void RTFSprms::eraseLast(Id nKeyword)
+{
+ ensureCopyBeforeWrite();
+
+ auto i = std::find_if(m_pSprms->rbegin(), m_pSprms->rend(), RTFSprms_compare{ nKeyword });
+ if (i != m_pSprms->rend())
+ m_pSprms->erase(std::next(i).base());
+}
+
+static RTFValue::Pointer_t getDefaultSPRM(Id const id, Id nStyleType)
+{
+ if (nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ switch (id)
+ {
+ case NS_ooxml::LN_EG_RPrBase_szCs:
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ return new RTFValue(24);
+ case NS_ooxml::LN_CT_Color_val:
+ return new RTFValue(0);
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_i:
+ return new RTFValue(0);
+ case NS_ooxml::LN_CT_Underline_val:
+ return new RTFValue(NS_ooxml::LN_Value_ST_Underline_none);
+ case NS_ooxml::LN_CT_Fonts_ascii:
+ case NS_ooxml::LN_CT_Fonts_eastAsia:
+ case NS_ooxml::LN_CT_Fonts_cs:
+ return new RTFValue("Times New Roman");
+ default:
+ break;
+ }
+ }
+
+ if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_paragraph)
+ {
+ switch (id)
+ {
+ case NS_ooxml::LN_CT_Spacing_before:
+ case NS_ooxml::LN_CT_Spacing_after:
+ case NS_ooxml::LN_CT_Ind_left:
+ case NS_ooxml::LN_CT_Ind_right:
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ return new RTFValue(0);
+
+ case NS_ooxml::LN_CT_Spacing_lineRule:
+ return new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
+ case NS_ooxml::LN_CT_Spacing_line:
+ // presumably this means 100%, cf. static const int nSingleLineSpacing = 240;
+ return new RTFValue(240);
+
+ case NS_ooxml::LN_CT_PrBase_pBdr:
+ { // tdf#150382 default all paragraph borders to none
+ RTFSprms attributes;
+ RTFSprms sprms;
+ for (int i = 0; i < 4; ++i)
+ {
+ auto const nBorder = getParagraphBorder(i);
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aAttributes.set(NS_ooxml::LN_CT_Border_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
+ sprms.set(nBorder, new RTFValue(aAttributes, aSprms));
+ }
+ return new RTFValue(attributes, sprms);
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return RTFValue::Pointer_t();
+}
+
+/// Is it problematic to deduplicate this SPRM?
+static bool isSPRMDeduplicateDenylist(Id nId, RTFSprms* pDirect)
+{
+ switch (nId)
+ {
+ // See the NS_ooxml::LN_CT_PPrBase_tabs handler in DomainMapper,
+ // deduplication is explicitly not wanted for these tokens.
+ case NS_ooxml::LN_CT_TabStop_val:
+ case NS_ooxml::LN_CT_TabStop_leader:
+ case NS_ooxml::LN_CT_TabStop_pos:
+ // \htmautsp arrives after the style table, so only the non-style value is
+ // correct, keep these.
+ case NS_ooxml::LN_CT_Spacing_beforeAutospacing:
+ case NS_ooxml::LN_CT_Spacing_afterAutospacing:
+ // \chbrdr requires *all* of the border settings to be present,
+ // otherwise a default (NONE) border is created from the removed
+ // attributes which then overrides the style-defined border.
+ // See BorderHandler.cxx and NS_ooxml::LN_EG_RPrBase_bdr in DomainMapper.
+ // This also is needed for NS_ooxml::LN_CT_PBdr_top etc.
+ case NS_ooxml::LN_CT_Border_sz:
+ case NS_ooxml::LN_CT_Border_val:
+ case NS_ooxml::LN_CT_Border_color:
+ case NS_ooxml::LN_CT_Border_space:
+ case NS_ooxml::LN_CT_Border_shadow:
+ case NS_ooxml::LN_CT_Border_frame:
+ case NS_ooxml::LN_CT_Border_themeTint:
+ case NS_ooxml::LN_CT_Border_themeColor:
+ return true;
+ // Removing \fi and \li if the style has the same value would mean taking these values from
+ // \ls, while deduplication would be done to take the values from the style.
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ case NS_ooxml::LN_CT_Ind_left:
+ return pDirect && pDirect->find(NS_ooxml::LN_CT_PPrBase_numPr);
+
+ default:
+ return false;
+ }
+}
+
+/// Should this SPRM be removed if all its children are removed?
+static bool isSPRMChildrenExpected(Id nId)
+{
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_PBdr_top:
+ case NS_ooxml::LN_CT_PBdr_left:
+ case NS_ooxml::LN_CT_PBdr_bottom:
+ case NS_ooxml::LN_CT_PBdr_right:
+ // Expected children are NS_ooxml::LN_CT_Border_*.
+ case NS_ooxml::LN_CT_PrBase_shd:
+ // Expected children are NS_ooxml::LN_CT_Shd_*.
+ case NS_ooxml::LN_CT_PPrBase_ind:
+ // Expected children are NS_ooxml::LN_CT_Ind_*.
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/// Does the clone / deduplication of a single sprm.
+static void cloneAndDeduplicateSprm(std::pair<Id, RTFValue::Pointer_t> const& rSprm, RTFSprms& ret,
+ Id nStyleType, RTFSprms* pDirect = nullptr)
+{
+ RTFValue::Pointer_t const pValue(ret.find(rSprm.first));
+ if (pValue)
+ {
+ if (rSprm.second->equals(*pValue))
+ {
+ if (!isSPRMDeduplicateDenylist(rSprm.first, pDirect))
+ {
+ ret.erase(rSprm.first); // duplicate to style
+ }
+ }
+ else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty())
+ {
+ RTFSprms const sprms(pValue->getSprms().cloneAndDeduplicate(
+ rSprm.second->getSprms(), nStyleType, /*bImplicitPPr =*/false, pDirect));
+ RTFSprms const attributes(pValue->getAttributes().cloneAndDeduplicate(
+ rSprm.second->getAttributes(), nStyleType, /*bImplicitPPr =*/false, pDirect));
+ // Don't copy the sprm in case we expect it to have children but it doesn't have some.
+ if (!isSPRMChildrenExpected(rSprm.first) || !sprms.empty() || !attributes.empty())
+ ret.set(rSprm.first,
+ RTFValue::Pointer_t(pValue->CloneWithSprms(attributes, sprms)));
+ }
+ }
+ else
+ {
+ // not found - try to override style with default
+ RTFValue::Pointer_t const pDefault(getDefaultSPRM(rSprm.first, nStyleType));
+ if (pDefault)
+ {
+ ret.set(rSprm.first, pDefault);
+ }
+ else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty())
+ {
+ RTFSprms const sprms(
+ RTFSprms().cloneAndDeduplicate(rSprm.second->getSprms(), nStyleType));
+ RTFSprms const attributes(
+ RTFSprms().cloneAndDeduplicate(rSprm.second->getAttributes(), nStyleType));
+ if (!sprms.empty() || !attributes.empty())
+ {
+ ret.set(rSprm.first, new RTFValue(attributes, sprms));
+ }
+ }
+ }
+}
+
+/// Extracts the list level matching nLevel from pAbstract.
+static RTFValue::Pointer_t getListLevel(const RTFValue::Pointer_t& pAbstract, int nLevel)
+{
+ for (const auto& rPair : pAbstract->getSprms())
+ {
+ if (rPair.first != NS_ooxml::LN_CT_AbstractNum_lvl)
+ continue;
+
+ RTFValue::Pointer_t pLevel = rPair.second->getAttributes().find(NS_ooxml::LN_CT_Lvl_ilvl);
+ if (!pLevel)
+ continue;
+
+ if (pLevel->getInt() != nLevel)
+ continue;
+
+ return rPair.second;
+ }
+
+ return RTFValue::Pointer_t();
+}
+
+void RTFSprms::deduplicateList(const std::map<int, int>& rInvalidListLevelFirstIndents)
+{
+ int nLevel = 0;
+ RTFValue::Pointer_t pLevelId
+ = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl);
+ if (pLevelId)
+ nLevel = pLevelId->getInt();
+
+ auto it = rInvalidListLevelFirstIndents.find(nLevel);
+ if (it == rInvalidListLevelFirstIndents.end())
+ return;
+
+ int nListValue = it->second;
+
+ RTFValue::Pointer_t pParagraphValue
+ = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine);
+ if (!pParagraphValue)
+ return;
+
+ int nParagraphValue = pParagraphValue->getInt();
+
+ if (nParagraphValue == nListValue)
+ eraseNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine);
+}
+
+void RTFSprms::duplicateList(const RTFValue::Pointer_t& pAbstract)
+{
+ int nLevel = 0;
+ RTFValue::Pointer_t pLevelId
+ = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl);
+ if (pLevelId)
+ nLevel = pLevelId->getInt();
+
+ RTFValue::Pointer_t pLevel = getListLevel(pAbstract, nLevel);
+ if (!pLevel)
+ return;
+
+ RTFValue::Pointer_t pLevelInd = pLevel->getSprms().find(NS_ooxml::LN_CT_PPrBase_ind);
+ if (!pLevelInd)
+ return;
+
+ for (const auto& rListLevelPair : pLevelInd->getAttributes())
+ {
+ switch (rListLevelPair.first)
+ {
+ case NS_ooxml::LN_CT_Ind_left:
+ case NS_ooxml::LN_CT_Ind_right:
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ RTFValue::Pointer_t pParagraphValue
+ = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first);
+ if (!pParagraphValue)
+ putNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first,
+ getDefaultSPRM(rListLevelPair.first, 0));
+
+ break;
+ }
+ }
+}
+
+RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference, Id const nStyleType,
+ bool const bImplicitPPr, RTFSprms* pDirect) const
+{
+ RTFSprms ret(*this);
+ ret.ensureCopyBeforeWrite();
+
+ // Note: apparently some attributes are set with OVERWRITE_NO_APPEND;
+ // it is probably a bad idea to mess with those in any way here?
+ for (auto& rSprm : rReference)
+ {
+ // Paragraph formatting sprms are directly contained in case of
+ // paragraphs, but they are below NS_ooxml::LN_CT_Style_pPr in case of
+ // styles. So handle those children directly, to avoid unexpected
+ // addition of direct formatting sprms at the paragraph level.
+ if (bImplicitPPr && rSprm.first == NS_ooxml::LN_CT_Style_pPr)
+ {
+ for (const auto& i : rSprm.second->getSprms())
+ cloneAndDeduplicateSprm(i, ret, nStyleType, pDirect);
+ }
+ else
+ cloneAndDeduplicateSprm(rSprm, ret, nStyleType, pDirect);
+ }
+ return ret;
+}
+
+bool RTFSprms::equals(const RTFValue& rOther) const
+{
+ return std::all_of(m_pSprms->cbegin(), m_pSprms->cend(),
+ [&](const std::pair<Id, RTFValue::Pointer_t>& raPair) -> bool {
+ return raPair.second->equals(rOther);
+ });
+}
+
+void RTFSprms::ensureCopyBeforeWrite()
+{
+ if (m_pSprms->GetRefCount() > 1)
+ {
+ tools::SvRef<RTFSprmsImpl> pClone(new RTFSprmsImpl);
+ for (auto& rSprm : *m_pSprms)
+ pClone->push_back(
+ std::make_pair(rSprm.first, RTFValue::Pointer_t(rSprm.second->Clone())));
+ m_pSprms = pClone;
+ }
+}
+
+RTFSprms::RTFSprms()
+ : m_pSprms(new RTFSprmsImpl)
+{
+}
+
+RTFSprms::~RTFSprms() = default;
+
+void RTFSprms::clear()
+{
+ if (m_pSprms->GetRefCount() == 1)
+ return m_pSprms->clear();
+
+ m_pSprms = tools::SvRef<RTFSprmsImpl>(new RTFSprmsImpl);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsprm.hxx b/writerfilter/source/rtftok/rtfsprm.hxx
new file mode 100644
index 000000000..9f3bbd78b
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsprm.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+#include <map>
+
+#include <tools/ref.hxx>
+#include "rtfvalue.hxx"
+
+namespace writerfilter::rtftok
+{
+using RTFSprmsImplBase = std::vector<std::pair<Id, RTFValue::Pointer_t>>;
+
+/// The payload of RTFSprms which is only copied on write.
+class RTFSprmsImpl : public RTFSprmsImplBase, public virtual SvRefBase
+{
+};
+
+enum class RTFOverwrite
+{
+ YES, ///< Yes, if an existing key is found, overwrite it.
+ NO_APPEND, ///< No, always append the value to the end of the list.
+ NO_IGNORE, ///< No, if the key is already in the list, then ignore, otherwise append.
+ YES_PREPEND ///< Yes, always prepend the value to the start of the list and remove existing entries.
+};
+
+/// A list of RTFSprm with a copy constructor that performs a deep copy.
+class RTFSprms : public virtual SvRefBase
+{
+public:
+ using Pointer_t = tools::SvRef<RTFSprms>;
+ using Entry_t = std::pair<Id, RTFValue::Pointer_t>;
+ using Iterator_t = std::vector<Entry_t>::iterator;
+ using ReverseIterator_t = std::vector<Entry_t>::reverse_iterator;
+ RTFSprms();
+ ~RTFSprms() override;
+
+ RTFSprms(RTFSprms const&) = default;
+ RTFSprms(RTFSprms&&) = default;
+ RTFSprms& operator=(RTFSprms const&) = default;
+ RTFSprms& operator=(RTFSprms&&) = default;
+
+ RTFValue::Pointer_t find(Id nKeyword, bool bFirst = true, bool bForWrite = false);
+ /// Does the same as ->push_back(), except that it can overwrite or ignore existing entries.
+ void set(Id nKeyword, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::YES);
+ bool erase(Id nKeyword);
+ void eraseLast(Id nKeyword);
+ /// Removes elements which are already in the reference set.
+ /// Also insert default values to override attributes of style
+ /// (yes, really; that's what Word does).
+ /// @param bImplicitPPr implicit dereference of top-level pPr SPRM
+ /// @param pDirect pointer to the root of the direct formatting SPRM tree, if any
+ RTFSprms cloneAndDeduplicate(RTFSprms& rReference, Id nStyleType, bool bImplicitPPr = false,
+ RTFSprms* pDirect = nullptr) const;
+ /// Inserts default values to override attributes of pAbstract.
+ void duplicateList(const RTFValue::Pointer_t& pAbstract);
+ /// Removes duplicated values based on in-list properties.
+ void deduplicateList(const std::map<int, int>& rInvalidListLevelFirstIndents);
+ std::size_t size() const { return m_pSprms->size(); }
+ bool empty() const { return m_pSprms->empty(); }
+ Entry_t& back() { return m_pSprms->back(); }
+ Iterator_t begin() { return m_pSprms->begin(); }
+ Iterator_t end() { return m_pSprms->end(); }
+ void clear();
+ bool equals(const RTFValue& rOther) const;
+
+private:
+ void ensureCopyBeforeWrite();
+ tools::SvRef<RTFSprmsImpl> m_pSprms;
+};
+
+/// RTF keyword with a parameter
+class RTFSprm : public Sprm
+{
+public:
+ RTFSprm(Id nKeyword, RTFValue::Pointer_t& pValue);
+ sal_uInt32 getId() const override;
+ Value::Pointer_t getValue() override;
+ writerfilter::Reference<Properties>::Pointer_t getProps() override;
+#ifdef DBG_UTIL
+ std::string getName() const override;
+ std::string toString() const override;
+#endif
+private:
+ Id m_nKeyword;
+ RTFValue::Pointer_t& m_pValue;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtftokenizer.cxx b/writerfilter/source/rtftok/rtftokenizer.cxx
new file mode 100644
index 000000000..4dc80416c
--- /dev/null
+++ b/writerfilter/source/rtftok/rtftokenizer.cxx
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtftokenizer.hxx"
+#include <tools/stream.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <rtl/strbuf.hxx>
+#include <rtl/character.hxx>
+#include <sal/log.hxx>
+#include "rtfskipdestination.hxx"
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <filter/msfilter/rtfutil.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+std::unordered_map<OString, RTFSymbol> RTFTokenizer::s_aRTFControlWords;
+bool RTFTokenizer::s_bControlWordsInitialised;
+std::vector<RTFMathSymbol> RTFTokenizer::s_aRTFMathControlWords;
+bool RTFTokenizer::s_bMathControlWordsSorted;
+
+RTFTokenizer::RTFTokenizer(RTFListener& rImport, SvStream* pInStream,
+ uno::Reference<task::XStatusIndicator> const& xStatusIndicator)
+ : m_rImport(rImport)
+ , m_pInStream(pInStream)
+ , m_xStatusIndicator(xStatusIndicator)
+ , m_nGroup(0)
+ , m_nLineNumber(0)
+ , m_nLineStartPos(0)
+ , m_nGroupStart(0)
+{
+ if (!RTFTokenizer::s_bControlWordsInitialised)
+ {
+ RTFTokenizer::s_bControlWordsInitialised = true;
+ for (int i = 0; i < nRTFControlWords; ++i)
+ s_aRTFControlWords.emplace(OString(aRTFControlWords[i].GetKeyword()),
+ aRTFControlWords[i]);
+ }
+ if (!RTFTokenizer::s_bMathControlWordsSorted)
+ {
+ RTFTokenizer::s_bMathControlWordsSorted = true;
+ s_aRTFMathControlWords = std::vector<RTFMathSymbol>(
+ aRTFMathControlWords, aRTFMathControlWords + nRTFMathControlWords);
+ std::sort(s_aRTFMathControlWords.begin(), s_aRTFMathControlWords.end());
+ }
+}
+
+RTFTokenizer::~RTFTokenizer() = default;
+
+RTFError RTFTokenizer::resolveParse()
+{
+ SAL_INFO("writerfilter.rtf", __func__);
+ char ch;
+ RTFError ret;
+ // for hex chars
+ int b = 0;
+ int count = 2;
+ std::size_t nPercentSize = 0;
+ sal_uInt64 nLastPos = 0;
+
+ if (m_xStatusIndicator.is())
+ {
+ OUString sDocLoad(SvxResId(RID_SVXSTR_DOC_LOAD));
+
+ sal_uInt64 const nCurrentPos = Strm().Tell();
+ sal_uInt64 const nEndPos = nCurrentPos + Strm().remainingSize();
+ m_xStatusIndicator->start(sDocLoad, nEndPos);
+ nPercentSize = nEndPos / 100;
+
+ nLastPos = nCurrentPos;
+ m_xStatusIndicator->setValue(nLastPos);
+ }
+
+ while (Strm().ReadChar(ch), !Strm().eof())
+ {
+ //SAL_INFO("writerfilter", __func__ << ": parsing character '" << ch << "'");
+
+ sal_uInt64 const nCurrentPos = Strm().Tell();
+ if (m_xStatusIndicator.is() && nCurrentPos > (nLastPos + nPercentSize))
+ {
+ nLastPos = nCurrentPos;
+ m_xStatusIndicator->setValue(nLastPos);
+ }
+
+ if (m_nGroup < 0)
+ return RTFError::GROUP_UNDER;
+ if (m_nGroup > 0 && m_rImport.getInternalState() == RTFInternalState::BIN)
+ {
+ ret = m_rImport.resolveChars(ch);
+ if (ret != RTFError::OK)
+ return ret;
+ }
+ else
+ {
+ switch (ch)
+ {
+ case '{':
+ m_nGroupStart = Strm().Tell() - 1;
+ ret = m_rImport.pushState();
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case '}':
+ ret = m_rImport.popState();
+ if (ret != RTFError::OK)
+ return ret;
+ if (m_nGroup == 0)
+ {
+ if (m_rImport.isSubstream())
+ m_rImport.finishSubstream();
+ return RTFError::OK;
+ }
+ break;
+ case '\\':
+ ret = resolveKeyword();
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case 0x0d:
+ break; // ignore this
+ case 0x0a:
+ m_nLineNumber++;
+ m_nLineStartPos = nCurrentPos;
+ break;
+ default:
+ if (m_nGroup == 0)
+ return RTFError::CHAR_OVER;
+ if (m_rImport.getInternalState() == RTFInternalState::NORMAL)
+ {
+ ret = m_rImport.resolveChars(ch);
+ if (ret != RTFError::OK)
+ return ret;
+ }
+ else
+ {
+ SAL_INFO("writerfilter.rtf", __func__ << ": hex internal state");
+ // Assume that \'<number><junk> means \'0<number>.
+ if (rtl::isAsciiDigit(static_cast<unsigned char>(ch))
+ || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return RTFError::HEX_INVALID;
+ b += parsed;
+ }
+ count--;
+ if (!count)
+ {
+ ret = m_rImport.resolveChars(b);
+ if (ret != RTFError::OK)
+ return ret;
+ count = 2;
+ b = 0;
+ m_rImport.setInternalState(RTFInternalState::NORMAL);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (m_nGroup < 0)
+ return RTFError::GROUP_UNDER;
+ if (m_nGroup > 0)
+ return RTFError::GROUP_OVER;
+ return RTFError::OK;
+}
+
+void RTFTokenizer::pushGroup() { m_nGroup++; }
+
+void RTFTokenizer::popGroup() { m_nGroup--; }
+
+RTFError RTFTokenizer::resolveKeyword()
+{
+ char ch;
+
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ return RTFError::UNEXPECTED_EOF;
+
+ if (!rtl::isAsciiAlpha(static_cast<unsigned char>(ch)))
+ {
+ // control symbols aren't followed by a space, so we can return here
+ // without doing any SeekRel()
+ return dispatchKeyword(OString(ch), false, 0);
+ }
+ OStringBuffer aBuf(32);
+ while (rtl::isAsciiAlpha(static_cast<unsigned char>(ch)))
+ {
+ aBuf.append(ch);
+ if (aBuf.getLength() > 32)
+ // See RTF spec v1.9.1, page 7
+ // A control word's name cannot be longer than 32 letters.
+ throw io::BufferSizeExceededException();
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ {
+ ch = ' ';
+ break;
+ }
+ }
+
+ bool bNeg = false;
+ if (ch == '-')
+ {
+ // in case we'll have a parameter, that will be negative
+ bNeg = true;
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ return RTFError::UNEXPECTED_EOF;
+ }
+ bool bParam = false;
+ int nParam = 0;
+ if (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
+ {
+ OStringBuffer aParameter;
+
+ // we have a parameter
+ bParam = true;
+ while (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
+ {
+ aParameter.append(ch);
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ {
+ ch = ' ';
+ break;
+ }
+ }
+ nParam = aParameter.makeStringAndClear().toInt32();
+ if (bNeg)
+ nParam = -nParam;
+ }
+ if (ch != ' ')
+ Strm().SeekRel(-1);
+ OString aKeyword = aBuf.makeStringAndClear();
+ return dispatchKeyword(aKeyword, bParam, nParam);
+}
+
+bool RTFTokenizer::lookupMathKeyword(RTFMathSymbol& rSymbol)
+{
+ auto low
+ = std::lower_bound(s_aRTFMathControlWords.begin(), s_aRTFMathControlWords.end(), rSymbol);
+ if (low == s_aRTFMathControlWords.end() || rSymbol < *low)
+ return false;
+ rSymbol = *low;
+ return true;
+}
+
+RTFError RTFTokenizer::dispatchKeyword(OString const& rKeyword, bool bParam, int nParam)
+{
+ if (m_rImport.getDestination() == Destination::SKIP)
+ {
+ // skip binary data explicitly, to not trip over rtf markup
+ // control characters
+ if (rKeyword == "bin" && nParam > 0)
+ Strm().SeekRel(nParam);
+ return RTFError::OK;
+ }
+ SAL_INFO("writerfilter.rtf", __func__ << ": keyword '\\" << rKeyword << "' with param? "
+ << (bParam ? 1 : 0) << " param val: '"
+ << (bParam ? nParam : 0) << "'");
+ auto findIt = s_aRTFControlWords.find(rKeyword);
+ if (findIt == s_aRTFControlWords.end())
+ {
+ SAL_INFO("writerfilter.rtf", __func__ << ": unknown keyword '\\" << rKeyword << "'");
+ RTFSkipDestination aSkip(m_rImport);
+ aSkip.setParsed(false);
+ return RTFError::OK;
+ }
+
+ RTFError ret;
+ RTFSymbol const& rSymbol = findIt->second;
+ switch (rSymbol.GetControlType())
+ {
+ case RTFControlType::FLAG:
+ // flags ignore any parameter by definition
+ ret = m_rImport.dispatchFlag(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::DESTINATION:
+ // same for destinations
+ ret = m_rImport.dispatchDestination(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::SYMBOL:
+ // and symbols
+ ret = m_rImport.dispatchSymbol(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::TOGGLE:
+ ret = m_rImport.dispatchToggle(rSymbol.GetIndex(), bParam, nParam);
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::VALUE:
+ if (!bParam)
+ nParam = rSymbol.GetDefValue();
+ ret = m_rImport.dispatchValue(rSymbol.GetIndex(), nParam);
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ }
+
+ return RTFError::OK;
+}
+
+OUString RTFTokenizer::getPosition()
+{
+ return OUString::number(m_nLineNumber + 1) + ","
+ + OUString::number(Strm().Tell() - m_nLineStartPos + 1);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtftokenizer.hxx b/writerfilter/source/rtftok/rtftokenizer.hxx
new file mode 100644
index 000000000..feb74fc63
--- /dev/null
+++ b/writerfilter/source/rtftok/rtftokenizer.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "rtflistener.hxx"
+
+#include <vector>
+#include <unordered_map>
+
+#include <com/sun/star/uno/Reference.h>
+
+#include <rtl/ustring.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star::task
+{
+class XStatusIndicator;
+}
+class SvStream;
+
+namespace writerfilter::rtftok
+{
+/// RTF tokenizer that separates control words from text.
+class RTFTokenizer final : public virtual SvRefBase
+{
+public:
+ RTFTokenizer(RTFListener& rImport, SvStream* pInStream,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator);
+ ~RTFTokenizer() override;
+
+ RTFError resolveParse();
+ /// Number of states on the stack.
+ int getGroup() const { return m_nGroup; }
+ /// To be invoked by the pushState() callback to signal when the importer enters a group.
+ void pushGroup();
+ /// To be invoked by the popState() callback to signal when the importer leaves a group.
+ void popGroup();
+ OUString getPosition();
+ std::size_t getGroupStart() const { return m_nGroupStart; }
+ /// To look up additional properties of a math symbol.
+ static bool lookupMathKeyword(RTFMathSymbol& rSymbol);
+
+private:
+ SvStream& Strm() { return *m_pInStream; }
+ RTFError resolveKeyword();
+ RTFError dispatchKeyword(OString const& rKeyword, bool bParam, int nParam);
+
+ RTFListener& m_rImport;
+ SvStream* m_pInStream;
+ css::uno::Reference<css::task::XStatusIndicator> const& m_xStatusIndicator;
+ // This is the same as aRTFControlWords, but mapped by token name for fast lookup
+ static std::unordered_map<OString, RTFSymbol> s_aRTFControlWords;
+ static bool s_bControlWordsInitialised;
+ // This is the same as aRTFMathControlWords, but sorted
+ static std::vector<RTFMathSymbol> s_aRTFMathControlWords;
+ static bool s_bMathControlWordsSorted;
+ /// Same as the size of the importer's states, except that this can be negative for invalid input.
+ int m_nGroup;
+ sal_Int32 m_nLineNumber;
+ std::size_t m_nLineStartPos;
+ std::size_t m_nGroupStart;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfvalue.cxx b/writerfilter/source/rtftok/rtfvalue.cxx
new file mode 100644
index 000000000..42f60a1c9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfvalue.cxx
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfreferenceproperties.hxx"
+#include "rtfdocumentimpl.hxx"
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFValue::RTFValue(int nValue, OUString sValue, const RTFSprms* pAttributes, const RTFSprms* pSprms,
+ uno::Reference<drawing::XShape> xShape, uno::Reference<io::XInputStream> xStream,
+ uno::Reference<embed::XEmbeddedObject> xObject, bool bForceString,
+ const RTFShape* pShape, const RTFPicture* pPicture)
+ : m_nValue(nValue)
+ , m_sValue(std::move(sValue))
+ , m_xShape(std::move(xShape))
+ , m_xStream(std::move(xStream))
+ , m_xObject(std::move(xObject))
+ , m_bForceString(bForceString)
+{
+ if (pAttributes)
+ m_pAttributes = new RTFSprms(*pAttributes);
+ if (pSprms)
+ m_pSprms = new RTFSprms(*pSprms);
+ if (pShape)
+ m_pShape = new RTFShape(*pShape);
+ if (pPicture)
+ m_pPicture = new RTFPicture(*pPicture);
+}
+
+RTFValue::RTFValue() {}
+
+RTFValue::RTFValue(int nValue)
+ : m_nValue(nValue)
+{
+}
+
+RTFValue::RTFValue(OUString sValue, bool bForce)
+ : m_sValue(std::move(sValue))
+ , m_bForceString(bForce)
+{
+}
+
+RTFValue::RTFValue(const RTFSprms& rAttributes)
+ : m_pAttributes(new RTFSprms(rAttributes))
+{
+}
+
+RTFValue::RTFValue(const RTFSprms& rAttributes, const RTFSprms& rSprms)
+ : m_pAttributes(new RTFSprms(rAttributes))
+ , m_pSprms(new RTFSprms(rSprms))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<drawing::XShape> xShape)
+ : m_xShape(std::move(xShape))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<io::XInputStream> xStream)
+ : m_xStream(std::move(xStream))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<embed::XEmbeddedObject> xObject)
+ : m_xObject(std::move(xObject))
+{
+}
+
+RTFValue::RTFValue(const RTFShape& aShape)
+ : m_pShape(new RTFShape(aShape))
+{
+}
+
+RTFValue::RTFValue(const RTFPicture& rPicture)
+ : m_pPicture(new RTFPicture(rPicture))
+{
+}
+
+RTFValue::~RTFValue() = default;
+
+int RTFValue::getInt() const { return m_nValue; }
+
+OUString RTFValue::getString() const
+{
+ if (!m_sValue.isEmpty() || m_bForceString)
+ return m_sValue;
+
+ return OUString::number(m_nValue);
+}
+
+void RTFValue::setString(const OUString& sValue) { m_sValue = sValue; }
+
+uno::Any RTFValue::getAny() const
+{
+ uno::Any ret;
+ if (!m_sValue.isEmpty() || m_bForceString)
+ ret <<= m_sValue;
+ else if (m_xShape.is())
+ ret <<= m_xShape;
+ else if (m_xStream.is())
+ ret <<= m_xStream;
+ else if (m_xObject.is())
+ ret <<= m_xObject;
+ else
+ ret <<= static_cast<sal_Int32>(m_nValue);
+ return ret;
+}
+
+RTFShape& RTFValue::getShape() const
+{
+ if (!m_pShape)
+ m_pShape = new RTFShape();
+ return *m_pShape;
+}
+
+RTFPicture& RTFValue::getPicture() const
+{
+ if (!m_pPicture)
+ m_pPicture = new RTFPicture;
+ return *m_pPicture;
+}
+
+writerfilter::Reference<Properties>::Pointer_t RTFValue::getProperties()
+{
+ return new RTFReferenceProperties(getAttributes(), getSprms());
+}
+
+writerfilter::Reference<BinaryObj>::Pointer_t RTFValue::getBinary()
+{
+ return writerfilter::Reference<BinaryObj>::Pointer_t();
+}
+
+#ifdef DBG_UTIL
+std::string RTFValue::toString() const
+{
+ if (!m_sValue.isEmpty() || m_bForceString)
+ return OUStringToOString(m_sValue, RTL_TEXTENCODING_UTF8).getStr();
+
+ return OString::number(m_nValue).getStr();
+}
+#endif
+
+RTFValue* RTFValue::Clone() const
+{
+ return new RTFValue(m_nValue, m_sValue, m_pAttributes.get(), m_pSprms.get(), m_xShape,
+ m_xStream, m_xObject, m_bForceString, m_pShape.get(), m_pPicture.get());
+}
+
+RTFValue* RTFValue::CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms) const
+{
+ return new RTFValue(m_nValue, m_sValue, &rAttributes, &rSprms, m_xShape, m_xStream, m_xObject,
+ m_bForceString, m_pShape.get(), m_pPicture.get());
+}
+
+bool RTFValue::equals(const RTFValue& rOther) const
+{
+ if (m_nValue != rOther.m_nValue)
+ return false;
+ if (m_sValue != rOther.m_sValue)
+ return false;
+
+ if (m_pAttributes && rOther.m_pAttributes)
+ {
+ if (m_pAttributes->size() != rOther.m_pAttributes->size())
+ return false;
+ if (!m_pAttributes->equals(rOther))
+ return false;
+ }
+ else if (m_pAttributes && m_pAttributes->size())
+ {
+ return false;
+ }
+ else if (rOther.m_pAttributes && rOther.m_pAttributes->size())
+ {
+ return false;
+ }
+
+ if (m_pSprms && rOther.m_pSprms)
+ {
+ if (m_pSprms->size() != rOther.m_pSprms->size())
+ return false;
+ if (!m_pSprms->equals(rOther))
+ return false;
+ }
+ else if (m_pSprms && m_pSprms->size())
+ {
+ return false;
+ }
+ else if (rOther.m_pSprms && rOther.m_pSprms->size())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+RTFSprms& RTFValue::getAttributes() const
+{
+ if (!m_pAttributes)
+ m_pAttributes = new RTFSprms();
+ return *m_pAttributes;
+}
+
+RTFSprms& RTFValue::getSprms() const
+{
+ if (!m_pSprms)
+ m_pSprms = new RTFSprms();
+ return *m_pSprms;
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfvalue.hxx b/writerfilter/source/rtftok/rtfvalue.hxx
new file mode 100644
index 000000000..4f37a5dcb
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfvalue.hxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+
+namespace com::sun::star
+{
+namespace embed
+{
+class XEmbeddedObject;
+}
+namespace io
+{
+class XInputStream;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFSprms;
+class RTFShape;
+class RTFPicture;
+/// Value of an RTF keyword
+class RTFValue : public Value
+{
+ RTFValue(int nValue, OUString sValue, const RTFSprms* pAttributes, const RTFSprms* pSprms,
+ css::uno::Reference<css::drawing::XShape> xShape,
+ css::uno::Reference<css::io::XInputStream> xStream,
+ css::uno::Reference<css::embed::XEmbeddedObject> xObject, bool bForceString,
+ const RTFShape* pShape, const RTFPicture* pPicture);
+
+public:
+ using Pointer_t = tools::SvRef<RTFValue>;
+ RTFValue();
+ explicit RTFValue(int nValue);
+ RTFValue(OUString sValue, bool bForce = false);
+ explicit RTFValue(const RTFSprms& rAttributes);
+ RTFValue(const RTFSprms& rAttributes, const RTFSprms& rSprms);
+ explicit RTFValue(css::uno::Reference<css::drawing::XShape> xShape);
+ explicit RTFValue(css::uno::Reference<css::io::XInputStream> xStream);
+ explicit RTFValue(css::uno::Reference<css::embed::XEmbeddedObject> xObject);
+ explicit RTFValue(const RTFShape& aShape);
+ explicit RTFValue(const RTFPicture& rPicture);
+ ~RTFValue() override;
+ void setString(const OUString& sValue);
+ int getInt() const override;
+ OUString getString() const override;
+ css::uno::Any getAny() const override;
+ writerfilter::Reference<Properties>::Pointer_t getProperties() override;
+ writerfilter::Reference<BinaryObj>::Pointer_t getBinary() override;
+#ifdef DBG_UTIL
+ std::string toString() const override;
+#endif
+ RTFValue* Clone() const;
+ RTFValue* CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms) const;
+ RTFSprms& getAttributes() const;
+ RTFSprms& getSprms() const;
+ RTFShape& getShape() const;
+ RTFPicture& getPicture() const;
+ bool equals(const RTFValue& rOther) const;
+ RTFValue& operator=(RTFValue const& rOther) = delete;
+
+private:
+ int m_nValue = 0;
+ OUString m_sValue;
+ mutable tools::SvRef<RTFSprms> m_pAttributes;
+ mutable tools::SvRef<RTFSprms> m_pSprms;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ css::uno::Reference<css::io::XInputStream> m_xStream;
+ css::uno::Reference<css::embed::XEmbeddedObject> m_xObject;
+ bool m_bForceString = false;
+ mutable tools::SvRef<RTFShape> m_pShape;
+ mutable tools::SvRef<RTFPicture> m_pPicture;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */