1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "rtfexport.hxx"
13 #include <svtools/rtfkeywd.hxx>
14 #include <filter/msfilter/rtfutil.hxx>
15 #include <sal/log.hxx>
16 #include <osl/diagnose.h>
18 SmRtfExport::SmRtfExport(const SmNode
* pIn
)
19 : SmWordExportBase(pIn
)
21 , m_nEncoding(RTL_TEXTENCODING_DONTKNOW
)
25 void SmRtfExport::ConvertFromStarMath(OStringBuffer
& rBuffer
, rtl_TextEncoding nEncoding
)
30 m_nEncoding
= nEncoding
;
31 m_pBuffer
->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE LO_STRING_SVTOOLS_RTF_MOMATH
" ");
32 HandleNode(m_pTree
, 0);
33 m_pBuffer
->append("}"); // moMath
36 // NOTE: This is still work in progress and unfinished, but it already covers a good
37 // part of the rtf math stuff.
39 void SmRtfExport::HandleVerticalStack(const SmNode
* pNode
, int nLevel
)
41 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MEQARR
" ");
42 int size
= pNode
->GetNumSubNodes();
43 for (int i
= 0; i
< size
; ++i
)
45 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
46 HandleNode(pNode
->GetSubNode(i
), nLevel
+ 1);
47 m_pBuffer
->append("}"); // me
49 m_pBuffer
->append("}"); // meqArr
52 void SmRtfExport::HandleText(const SmNode
* pNode
, int /*nLevel*/)
54 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MR
" ");
56 if (pNode
->GetToken().eType
== TTEXT
) // literal text
57 m_pBuffer
->append(LO_STRING_SVTOOLS_RTF_MNOR
" ");
59 auto pTemp
= static_cast<const SmTextNode
*>(pNode
);
60 SAL_INFO("starmath.rtf", "Text: " << pTemp
->GetText());
61 for (sal_Int32 i
= 0; i
< pTemp
->GetText().getLength(); i
++)
63 sal_uInt16 nChar
= pTemp
->GetText()[i
];
64 OUString
aValue(SmTextNode::ConvertSymbolToUnicode(nChar
));
65 m_pBuffer
->append(msfilter::rtfutil::OutString(aValue
, m_nEncoding
));
68 m_pBuffer
->append("}"); // mr
71 void SmRtfExport::HandleFractions(const SmNode
* pNode
, int nLevel
, const char* type
)
73 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MF
" ");
76 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MFPR
" ");
77 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MTYPE
" ");
78 m_pBuffer
->append(type
);
79 m_pBuffer
->append("}"); // mtype
80 m_pBuffer
->append("}"); // mfPr
82 assert(pNode
->GetNumSubNodes() == 3);
83 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MNUM
" ");
84 HandleNode(pNode
->GetSubNode(0), nLevel
+ 1);
85 m_pBuffer
->append("}"); // mnum
86 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEN
" ");
87 HandleNode(pNode
->GetSubNode(2), nLevel
+ 1);
88 m_pBuffer
->append("}"); // mden
89 m_pBuffer
->append("}"); // mf
92 void SmRtfExport::HandleAttribute(const SmAttributNode
* pNode
, int nLevel
)
94 switch (pNode
->Attribute()->GetToken().eType
)
113 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MACC
" ");
114 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MACCPR
" ");
115 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MCHR
" ");
116 OUString
aValue(pNode
->Attribute()->GetToken().cMathChar
);
117 m_pBuffer
->append(msfilter::rtfutil::OutString(aValue
, m_nEncoding
));
118 m_pBuffer
->append("}"); // mchr
119 m_pBuffer
->append("}"); // maccPr
120 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
121 HandleNode(pNode
->Body(), nLevel
+ 1);
122 m_pBuffer
->append("}"); // me
123 m_pBuffer
->append("}"); // macc
128 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBAR
" ");
129 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBARPR
" ");
130 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MPOS
" ");
131 m_pBuffer
->append((pNode
->Attribute()->GetToken().eType
== TUNDERLINE
) ? "bot" : "top");
132 m_pBuffer
->append("}"); // mpos
133 m_pBuffer
->append("}"); // mbarPr
134 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
135 HandleNode(pNode
->Body(), nLevel
+ 1);
136 m_pBuffer
->append("}"); // me
137 m_pBuffer
->append("}"); // mbar
140 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBORDERBOX
" ");
141 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBORDERBOXPR
" ");
142 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDETOP
" 1}");
143 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDEBOT
" 1}");
144 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDELEFT
" 1}");
145 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDERIGHT
" 1}");
146 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSTRIKEH
" 1}");
147 m_pBuffer
->append("}"); // mborderBoxPr
148 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
149 HandleNode(pNode
->Body(), nLevel
+ 1);
150 m_pBuffer
->append("}"); // me
151 m_pBuffer
->append("}"); // mborderBox
154 HandleAllSubNodes(pNode
, nLevel
);
159 void SmRtfExport::HandleRoot(const SmRootNode
* pNode
, int nLevel
)
161 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MRAD
" ");
162 if (const SmNode
* argument
= pNode
->Argument())
164 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEG
" ");
165 HandleNode(argument
, nLevel
+ 1);
166 m_pBuffer
->append("}"); // mdeg
170 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MRADPR
" ");
171 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEGHIDE
" 1}");
172 m_pBuffer
->append("}"); // mradPr
173 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEG
" }"); // empty but present
175 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
176 HandleNode(pNode
->Body(), nLevel
+ 1);
177 m_pBuffer
->append("}"); // me
178 m_pBuffer
->append("}"); // mrad
183 OString
mathSymbolToString(const SmNode
* node
, rtl_TextEncoding nEncoding
)
185 assert(node
->GetType() == SmNodeType::Math
|| node
->GetType() == SmNodeType::MathIdent
);
186 auto txtnode
= static_cast<const SmTextNode
*>(node
);
187 if (txtnode
->GetText().isEmpty())
189 assert(txtnode
->GetText().getLength() == 1);
190 sal_Unicode chr
= SmTextNode::ConvertSymbolToUnicode(txtnode
->GetText()[0]);
191 OUString
aValue(chr
);
192 return msfilter::rtfutil::OutString(aValue
, nEncoding
);
196 void SmRtfExport::HandleOperator(const SmOperNode
* pNode
, int nLevel
)
198 SAL_INFO("starmath.rtf", "Operator: " << int(pNode
->GetToken().eType
));
199 switch (pNode
->GetToken().eType
)
212 const SmSubSupNode
* subsup
213 = pNode
->GetSubNode(0)->GetType() == SmNodeType::SubSup
214 ? static_cast<const SmSubSupNode
*>(pNode
->GetSubNode(0))
216 const SmNode
* operation
= subsup
? subsup
->GetBody() : pNode
->GetSubNode(0);
217 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MNARY
" ");
218 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MNARYPR
" ");
219 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MCHR
" ");
220 m_pBuffer
->append(mathSymbolToString(operation
, m_nEncoding
));
221 m_pBuffer
->append("}"); // mchr
222 if (!subsup
|| !subsup
->GetSubSup(CSUB
))
223 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUBHIDE
" 1}");
224 if (!subsup
|| !subsup
->GetSubSup(CSUP
))
225 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUPHIDE
" 1}");
226 m_pBuffer
->append("}"); // mnaryPr
227 if (!subsup
|| !subsup
->GetSubSup(CSUB
))
228 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" }");
231 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
232 HandleNode(subsup
->GetSubSup(CSUB
), nLevel
+ 1);
233 m_pBuffer
->append("}"); // msub
235 if (!subsup
|| !subsup
->GetSubSup(CSUP
))
236 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" }");
239 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
240 HandleNode(subsup
->GetSubSup(CSUP
), nLevel
+ 1);
241 m_pBuffer
->append("}"); // msup
243 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
244 HandleNode(pNode
->GetSubNode(1), nLevel
+ 1); // body
245 m_pBuffer
->append("}"); // me
246 m_pBuffer
->append("}"); // mnary
250 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MFUNC
" ");
251 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MFNAME
" ");
252 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMLOW
" ");
253 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
254 HandleNode(pNode
->GetSymbol(), nLevel
+ 1);
255 m_pBuffer
->append("}"); // me
256 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
257 if (const SmSubSupNode
* subsup
258 = pNode
->GetSubNode(0)->GetType() == SmNodeType::SubSup
259 ? static_cast<const SmSubSupNode
*>(pNode
->GetSubNode(0))
261 if (subsup
->GetSubSup(CSUB
))
262 HandleNode(subsup
->GetSubSup(CSUB
), nLevel
+ 1);
263 m_pBuffer
->append("}"); // mlim
264 m_pBuffer
->append("}"); // mlimLow
265 m_pBuffer
->append("}"); // mfName
266 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
267 HandleNode(pNode
->GetSubNode(1), nLevel
+ 1); // body
268 m_pBuffer
->append("}"); // me
269 m_pBuffer
->append("}"); // mfunc
272 SAL_INFO("starmath.rtf", "TODO: " << OSL_THIS_FUNC
<< " unhandled oper type");
277 void SmRtfExport::HandleSubSupScriptInternal(const SmSubSupNode
* pNode
, int nLevel
, int flags
)
279 // rtf supports only a certain combination of sub/super scripts, but LO can have any,
280 // so try to merge it using several tags if necessary
281 if (flags
== 0) // none
283 if ((flags
& (1 << RSUP
| 1 << RSUB
)) == (1 << RSUP
| 1 << RSUB
))
286 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSSUBSUP
" ");
287 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
288 flags
&= ~(1 << RSUP
| 1 << RSUB
);
290 HandleNode(pNode
->GetBody(), nLevel
+ 1);
292 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
293 m_pBuffer
->append("}"); // me
294 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
295 HandleNode(pNode
->GetSubSup(RSUB
), nLevel
+ 1);
296 m_pBuffer
->append("}"); // msub
297 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
298 HandleNode(pNode
->GetSubSup(RSUP
), nLevel
+ 1);
299 m_pBuffer
->append("}"); // msup
300 m_pBuffer
->append("}"); // msubSup
302 else if ((flags
& (1 << RSUB
)) == 1 << RSUB
)
305 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSSUB
" ");
306 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
307 flags
&= ~(1 << RSUB
);
309 HandleNode(pNode
->GetBody(), nLevel
+ 1);
311 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
312 m_pBuffer
->append("}"); // me
313 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
314 HandleNode(pNode
->GetSubSup(RSUB
), nLevel
+ 1);
315 m_pBuffer
->append("}"); // msub
316 m_pBuffer
->append("}"); // msSub
318 else if ((flags
& (1 << RSUP
)) == 1 << RSUP
)
321 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSSUP
" ");
322 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
323 flags
&= ~(1 << RSUP
);
325 HandleNode(pNode
->GetBody(), nLevel
+ 1);
327 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
328 m_pBuffer
->append("}"); // me
329 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
330 HandleNode(pNode
->GetSubSup(RSUP
), nLevel
+ 1);
331 m_pBuffer
->append("}"); // msup
332 m_pBuffer
->append("}"); // msSup
334 else if ((flags
& (1 << LSUP
| 1 << LSUB
)) == (1 << LSUP
| 1 << LSUB
))
337 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSPRE
" ");
338 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
339 HandleNode(pNode
->GetSubSup(LSUB
), nLevel
+ 1);
340 m_pBuffer
->append("}"); // msub
341 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
342 HandleNode(pNode
->GetSubSup(LSUP
), nLevel
+ 1);
343 m_pBuffer
->append("}"); // msup
344 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
345 flags
&= ~(1 << LSUP
| 1 << LSUB
);
347 HandleNode(pNode
->GetBody(), nLevel
+ 1);
349 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
350 m_pBuffer
->append("}"); // me
351 m_pBuffer
->append("}"); // msPre
353 else if ((flags
& (1 << CSUB
)) == (1 << CSUB
))
355 // m:limLow looks like a good element for central superscript
356 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMLOW
" ");
357 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
358 flags
&= ~(1 << CSUB
);
360 HandleNode(pNode
->GetBody(), nLevel
+ 1);
362 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
363 m_pBuffer
->append("}"); // me
364 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
365 HandleNode(pNode
->GetSubSup(CSUB
), nLevel
+ 1);
366 m_pBuffer
->append("}"); // mlim
367 m_pBuffer
->append("}"); // mlimLow
369 else if ((flags
& (1 << CSUP
)) == (1 << CSUP
))
371 // m:limUpp looks like a good element for central superscript
372 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMUPP
" ");
373 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
374 flags
&= ~(1 << CSUP
);
376 HandleNode(pNode
->GetBody(), nLevel
+ 1);
378 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
379 m_pBuffer
->append("}"); // me
380 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
381 HandleNode(pNode
->GetSubSup(CSUP
), nLevel
+ 1);
382 m_pBuffer
->append("}"); // mlim
383 m_pBuffer
->append("}"); // mlimUpp
386 SAL_INFO("starmath.rtf", "TODO: " << OSL_THIS_FUNC
<< " unhandled subsup type");
389 void SmRtfExport::HandleMatrix(const SmMatrixNode
* pNode
, int nLevel
)
391 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MM
" ");
392 for (size_t row
= 0; row
< pNode
->GetNumRows(); ++row
)
394 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MMR
" ");
395 for (size_t col
= 0; col
< pNode
->GetNumCols(); ++col
)
397 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
398 if (const SmNode
* node
= pNode
->GetSubNode(row
* pNode
->GetNumCols() + col
))
399 HandleNode(node
, nLevel
+ 1);
400 m_pBuffer
->append("}"); // me
402 m_pBuffer
->append("}"); // mmr
404 m_pBuffer
->append("}"); // mm
407 void SmRtfExport::HandleBrace(const SmBraceNode
* pNode
, int nLevel
)
409 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MD
" ");
410 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDPR
" ");
411 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBEGCHR
" ");
412 m_pBuffer
->append(mathSymbolToString(pNode
->OpeningBrace(), m_nEncoding
));
413 m_pBuffer
->append("}"); // mbegChr
414 std::vector
<const SmNode
*> subnodes
;
415 if (pNode
->Body()->GetType() == SmNodeType::Bracebody
)
417 auto body
= static_cast<const SmBracebodyNode
*>(pNode
->Body());
418 bool separatorWritten
= false; // assume all separators are the same
419 for (size_t i
= 0; i
< body
->GetNumSubNodes(); ++i
)
421 const SmNode
* subnode
= body
->GetSubNode(i
);
422 if (subnode
->GetType() == SmNodeType::Math
423 || subnode
->GetType() == SmNodeType::MathIdent
)
425 // do not write, but write what separator it is
426 auto math
= static_cast<const SmMathSymbolNode
*>(subnode
);
427 if (!separatorWritten
)
429 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSEPCHR
" ");
430 m_pBuffer
->append(mathSymbolToString(math
, m_nEncoding
));
431 m_pBuffer
->append("}"); // msepChr
432 separatorWritten
= true;
436 subnodes
.push_back(subnode
);
440 subnodes
.push_back(pNode
->Body());
441 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MENDCHR
" ");
442 m_pBuffer
->append(mathSymbolToString(pNode
->ClosingBrace(), m_nEncoding
));
443 m_pBuffer
->append("}"); // mendChr
444 m_pBuffer
->append("}"); // mdPr
445 for (const SmNode
* subnode
: subnodes
)
447 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
448 HandleNode(subnode
, nLevel
+ 1);
449 m_pBuffer
->append("}"); // me
451 m_pBuffer
->append("}"); // md
454 void SmRtfExport::HandleVerticalBrace(const SmVerticalBraceNode
* pNode
, int nLevel
)
456 SAL_INFO("starmath.rtf", "Vertical: " << int(pNode
->GetToken().eType
));
457 switch (pNode
->GetToken().eType
)
462 bool top
= (pNode
->GetToken().eType
== TOVERBRACE
);
464 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMUPP
" ");
466 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMLOW
" ");
467 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
468 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MGROUPCHR
" ");
469 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MGROUPCHRPR
" ");
470 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MCHR
" ");
471 m_pBuffer
->append(mathSymbolToString(pNode
->Brace(), m_nEncoding
));
472 m_pBuffer
->append("}"); // mchr
473 // TODO not sure if pos and vertJc are correct
474 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MPOS
" ")
475 .append(top
? "top" : "bot")
477 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MVERTJC
" ")
478 .append(top
? "bot" : "top")
480 m_pBuffer
->append("}"); // mgroupChrPr
481 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
482 HandleNode(pNode
->Body(), nLevel
+ 1);
483 m_pBuffer
->append("}"); // me
484 m_pBuffer
->append("}"); // mgroupChr
485 m_pBuffer
->append("}"); // me
486 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
487 HandleNode(pNode
->Script(), nLevel
+ 1);
488 m_pBuffer
->append("}"); // mlim
489 m_pBuffer
->append("}"); // mlimUpp or mlimLow
493 SAL_INFO("starmath.rtf", "TODO: " << OSL_THIS_FUNC
<< " unhandled vertical brace type");
498 void SmRtfExport::HandleBlank()
500 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MR
" ");
501 m_pBuffer
->append(" ");
502 m_pBuffer
->append("}"); // mr
505 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */