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