1 /******************************************************************************
2 *
3 * Copyright (C) 1997-2021 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16 #include <string>
17 #include <fstream>
18
19 #include "rtfstyle.h"
20 #include "message.h"
21 #include "regex.h"
22
23 QCString rtf_title;
24 QCString rtf_subject;
25 QCString rtf_comments;
26 QCString rtf_company;
27 QCString rtf_logoFilename;
28 QCString rtf_author;
29 QCString rtf_manager;
30 QCString rtf_documentType;
31 QCString rtf_documentId;
32 QCString rtf_keywords;
33
34 static std::map<std::string,QCString &> g_styleMap =
35 {
36 { "Title", rtf_title },
37 { "Subject", rtf_subject },
38 { "Comments", rtf_comments },
39 { "Company", rtf_company },
40 { "LogoFilename", rtf_logoFilename },
41 { "Author", rtf_author },
42 { "Manager", rtf_manager },
43 { "DocumentType", rtf_documentType },
44 { "DocumentId", rtf_documentId },
45 { "Keywords", rtf_keywords }
46 };
47
48
49 char rtf_Style_Reset[] = "\\pard\\plain ";
50
51 #define RTF_LatexToc(lvl,nest,nxt,pos,twps) \
52 \
53 { "LatexTOC"#lvl, \
54 "\\s"#nest"\\li"#pos"\\sa"#twps"\\sb"#twps"\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ",\
55 "\\sbasedon0 \\snext"#nxt" LatexTOC "#lvl \
56 }
57
58 #define RTF_ListBullet(lvl,nest,nxt,pos,lvl2) \
59 { "ListBullet"#lvl, \
60 "\\s"#nest"\\fi-360\\li"#pos"\\widctlpar\\jclisttab\\tx"#pos"{\\*\\pn \\pnlvlbody\\ilvl0\\ls"#lvl2"\\pnrnot0\\pndec }\\ls1\\adjustright \\fs20\\cgrid ", \
61 "\\sbasedon0 \\snext"#nxt" \\sautoupd List Bullet "#lvl \
62 }
63
64 #define RTF_ListEnum(lvl,nest,nxt,pos) \
65 { "ListEnum"#lvl, \
66 "\\s"#nest"\\fi-360\\li"#pos"\\widctlpar\\fs20\\cgrid ", \
67 "\\sbasedon0 \\snext"#nxt" \\sautoupd List Enum "#lvl \
68 }
69
70 #define RTF_CodeExample(lvl,nest,nxt,pos) \
71 { "CodeExample"#lvl, \
72 "\\s"#nest"\\li"#pos"\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", \
73 "\\sbasedon0 \\snext"#nxt" Code Example "#lvl \
74 }
75
76 #define RTF_ListContinue(lvl,nest,nxt,pos) \
77 { "ListContinue"#lvl, \
78 "\\s"#nest"\\li"#pos"\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", \
79 "\\sbasedon0 \\snext"#nxt" List Continue "#lvl \
80 }
81
82 #define RTF_DescContinue(lvl,nest,nxt,pos) \
83 { "DescContinue"#lvl, \
84 "\\s"#nest"\\li"#pos"\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", \
85 "\\sbasedon0 \\snext"#nxt" DescContinue "#lvl \
86 }
87
88 Rtf_Style_Default rtf_Style_Default[] =
89 {
90 { "Heading1",
91 "\\s1\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\fs36\\kerning36\\cgrid ",
92 "\\sbasedon0 \\snext0 heading 1"
93 },
94 { "Heading2",
95 "\\s2\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\fs28\\kerning28\\cgrid ",
96 "\\sbasedon0 \\snext0 heading 2"
97 },
98 { "Heading3",
99 "\\s3\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\cgrid ",
100 "\\sbasedon0 \\snext0 heading 3"
101 },
102 { "Heading4",
103 "\\s4\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\fs20\\cgrid ",
104 "\\sbasedon0 \\snext0 heading 4;}{\\*\\cs10 \\additive Default Paragraph Font"
105 },
106 { "Heading5",
107 "\\s5\\sb90\\sa30\\keepn\\widctlpar\\adjustright \\b\\f1\\fs20\\cgrid ",
108 "\\sbasedon0 \\snext0 heading 5;}{\\*\\cs10 \\additive Default Paragraph Font"
109 },
110 { "Title",
111 "\\s15\\qc\\sb240\\sa60\\widctlpar\\outlinelevel0\\adjustright \\b\\f1\\fs32\\kerning28\\cgrid ",
112 "\\sbasedon0 \\snext15 Title"
113 },
114 { "SubTitle",
115 "\\s16\\qc\\sa60\\widctlpar\\outlinelevel1\\adjustright \\f1\\cgrid ",
116 "\\sbasedon0 \\snext16 Subtitle"
117 },
118 { "BodyText",
119 "\\s17\\sa60\\sb30\\widctlpar\\qj \\fs22\\cgrid ",
120 "\\sbasedon0 \\snext17 BodyText"
121 },
122 { "DenseText",
123 "\\s18\\widctlpar\\fs22\\cgrid ",
124 "\\sbasedon0 \\snext18 DenseText"
125 },
126 { "Header",
127 "\\s28\\widctlpar\\tqc\\tx4320\\tqr\\tx8640\\adjustright \\fs20\\cgrid ",
128 "\\sbasedon0 \\snext28 header"
129 },
130 { "Footer",
131 "\\s29\\widctlpar\\tqc\\tx4320\\tqr\\tx8640\\qr\\adjustright \\fs20\\cgrid ",
132 "\\sbasedon0 \\snext29 footer"
133 },
134 { "GroupHeader",
135 "\\s30\\li360\\sa60\\sb120\\keepn\\widctlpar\\adjustright \\b\\f1\\fs20\\cgrid ",
136 "\\sbasedon0 \\snext30 GroupHeader"
137 },
138
139 RTF_CodeExample( 0, 40, 41, 0),
140 RTF_CodeExample( 1, 41, 42, 360),
141 RTF_CodeExample( 2, 42, 43, 720),
142 RTF_CodeExample( 3, 43, 44,1080),
143 RTF_CodeExample( 4, 44, 45,1440),
144 RTF_CodeExample( 5, 45, 46,1800),
145 RTF_CodeExample( 6, 46, 47,2160),
146 RTF_CodeExample( 7, 47, 48,2520),
147 RTF_CodeExample( 8, 48, 49,2880),
148 RTF_CodeExample( 9, 49, 50,3240),
149 RTF_CodeExample(10, 50, 51,3600),
150 RTF_CodeExample(11, 51, 52,3960),
151 RTF_CodeExample(12, 52, 53,4320),
152 RTF_CodeExample(13, 53, 53,4680),
153
154 RTF_ListContinue( 0, 60, 61, 0),
155 RTF_ListContinue( 1, 61, 62, 360),
156 RTF_ListContinue( 2, 62, 63, 720),
157 RTF_ListContinue( 3, 63, 64,1080),
158 RTF_ListContinue( 4, 64, 65,1440),
159 RTF_ListContinue( 5, 65, 66,1800),
160 RTF_ListContinue( 6, 66, 67,2160),
161 RTF_ListContinue( 7, 67, 68,2520),
162 RTF_ListContinue( 8, 68, 69,2880),
163 RTF_ListContinue( 9, 69, 70,3240),
164 RTF_ListContinue(10, 70, 71,3600),
165 RTF_ListContinue(11, 71, 72,3960),
166 RTF_ListContinue(12, 72, 73,4320),
167 RTF_ListContinue(13, 73, 73,4680),
168
169 RTF_DescContinue( 0, 80, 81, 0),
170 RTF_DescContinue( 1, 81, 82, 360),
171 RTF_DescContinue( 2, 82, 83, 720),
172 RTF_DescContinue( 3, 83, 84,1080),
173 RTF_DescContinue( 4, 84, 85,1440),
174 RTF_DescContinue( 5, 85, 86,1800),
175 RTF_DescContinue( 6, 86, 87,2160),
176 RTF_DescContinue( 7, 87, 88,2520),
177 RTF_DescContinue( 8, 88, 89,2880),
178 RTF_DescContinue( 9, 89, 90,3240),
179 RTF_DescContinue(10, 90, 91,3600),
180 RTF_DescContinue(11, 91, 92,3960),
181 RTF_DescContinue(12, 92, 93,4320),
182 RTF_DescContinue(13, 93, 93,4680),
183
184 RTF_LatexToc( 0,100,101, 0,30),
185 RTF_LatexToc( 1,101,102, 360,27),
186 RTF_LatexToc( 2,102,103, 720,24),
187 RTF_LatexToc( 3,103,104,1080,21),
188 RTF_LatexToc( 4,104,105,1440,18),
189 RTF_LatexToc( 5,105,106,1800,15),
190 RTF_LatexToc( 6,106,107,2160,12),
191 RTF_LatexToc( 7,107,108,2520, 9),
192 RTF_LatexToc( 8,108,109,2880, 6),
193 RTF_LatexToc( 9,109,110,3240, 3),
194 RTF_LatexToc(10,110,111,3600, 3),
195 RTF_LatexToc(11,111,112,3960, 3),
196 RTF_LatexToc(12,112,113,4320, 3),
197 RTF_LatexToc(13,113,113,4680, 3),
198
199 RTF_ListBullet( 0,120,121, 360, 1),
200 RTF_ListBullet( 1,121,122, 720, 2),
201 RTF_ListBullet( 2,122,123,1080, 3),
202 RTF_ListBullet( 3,123,124,1440, 4),
203 RTF_ListBullet( 4,124,125,1800, 5),
204 RTF_ListBullet( 5,125,126,2160, 6),
205 RTF_ListBullet( 6,126,127,2520, 7),
206 RTF_ListBullet( 7,127,128,2880, 8),
207 RTF_ListBullet( 8,128,129,3240, 9),
208 RTF_ListBullet( 9,129,130,3600,10),
209 RTF_ListBullet(10,130,131,3960,11),
210 RTF_ListBullet(11,131,132,4320,12),
211 RTF_ListBullet(12,132,133,4680,13),
212 RTF_ListBullet(13,133,133,5040,14),
213
214 RTF_ListEnum( 0,140,141, 360),
215 RTF_ListEnum( 1,141,142, 720),
216 RTF_ListEnum( 2,142,143,1080),
217 RTF_ListEnum( 3,143,144,1440),
218 RTF_ListEnum( 4,144,145,1800),
219 RTF_ListEnum( 5,145,146,2160),
220 RTF_ListEnum( 6,146,147,2520),
221 RTF_ListEnum( 7,147,148,2880),
222 RTF_ListEnum( 8,148,149,3240),
223 RTF_ListEnum( 9,149,150,3600),
224 RTF_ListEnum(10,150,151,3960),
225 RTF_ListEnum(11,151,152,4320),
226 RTF_ListEnum(12,152,153,4680),
227 RTF_ListEnum(13,153,153,5040),
228
229 { 0,
230 0,
231 0
232 }
233 };
234
235 static const reg::Ex s_clause(R"(\\s(\d+)\s*)"); // match, e.g. '\s30' and capture '30'
236
StyleData(const std::string & reference,const std::string & definition)237 StyleData::StyleData(const std::string &reference, const std::string &definition)
238 {
239 reg::Match match;
240 if (reg::search(reference,match,s_clause))
241 {
242 m_index = static_cast<int>(std::stoul(match[1].str()));
243 }
244 else // error
245 {
246 m_index = 0;
247 }
248 m_reference = reference;
249 m_definition = definition;
250 }
251
setStyle(const std::string & command,const std::string & styleName)252 bool StyleData::setStyle(const std::string &command, const std::string &styleName)
253 {
254 reg::Match match;
255 if (!reg::search(command,match,s_clause))
256 {
257 err("Style sheet '%s' contains no '\\s' clause.\n{%s}", styleName.c_str(), command.c_str());
258 return false;
259 }
260 m_index = static_cast<int>(std::stoul(match[1].str()));
261
262 size_t index = command.find("\\sbasedon");
263 if (index!=std::string::npos)
264 {
265 m_reference = command.substr(0,index);
266 m_definition = command.substr(index);
267 }
268
269 return true;
270 }
271
272
loadStylesheet(const QCString & name,StyleDataMap & map)273 void loadStylesheet(const QCString &name, StyleDataMap& map)
274 {
275 std::ifstream file(name.str());
276 if (!file.is_open())
277 {
278 err("Can't open RTF style sheet file %s. Using defaults.",qPrint(name));
279 return;
280 }
281 msg("Loading RTF style sheet %s...\n",qPrint(name));
282
283 uint lineNr=1;
284
285 for (std::string line ; getline(file,line) ; ) // for each line
286 {
287 if (line.empty() || line[0]=='#') continue; // skip blanks & comments
288 static const reg::Ex assignment_splitter(R"(\s*=\s*)");
289 reg::Match match;
290 if (reg::search(line,match,assignment_splitter))
291 {
292 std::string key = match.prefix().str();
293 std::string value = match.suffix().str();
294 auto it = map.find(key);
295 if (it!=map.end())
296 {
297 StyleData& styleData = it->second;
298 styleData.setStyle(value,key);
299 }
300 else
301 {
302 warn(name,lineNr,"Unknown style sheet name %s ignored.",key.data());
303 }
304 }
305 else
306 {
307 warn(name,lineNr,"Assignment of style sheet name expected line='%s'!",line.c_str());
308 }
309 lineNr++;
310 }
311 }
312
313 StyleDataMap rtf_Style;
314
loadExtensions(const QCString & name)315 void loadExtensions(const QCString &name)
316 {
317 std::ifstream file(name.str());
318 if (!file.is_open())
319 {
320 err("Can't open RTF extensions file %s. Using defaults.",qPrint(name));
321 return;
322 }
323 msg("Loading RTF extensions %s...\n",qPrint(name));
324
325 uint lineNr=1;
326
327 for (std::string line ; getline(file,line) ; ) // for each line
328 {
329 if (line.empty() || line[0]=='#') continue; // skip blanks & comments
330 static const reg::Ex assignment_splitter(R"(\s*=\s*)");
331 reg::Match match;
332 if (reg::search(line,match,assignment_splitter))
333 {
334 std::string key = match.prefix().str();
335 std::string value = match.suffix().str();
336 auto it = g_styleMap.find(key);
337 if (it!=g_styleMap.end())
338 {
339 it->second = value;
340 }
341 else
342 {
343 warn(name,lineNr,"Ignoring unknown extension key '%s'...",key.c_str());
344 }
345 }
346 else
347 {
348 warn(name,lineNr,"Assignment of style sheet name expected!");
349 }
350 lineNr++;
351 }
352 }
353
354