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/.
11 #include "rtfexport.hxx"
13 #include <svtools/rtfkeywd.hxx>
14 #include <filter/msfilter/rtfutil.hxx>
16 SmRtfExport::SmRtfExport(const SmNode
* pIn
)
17 : SmWordExportBase(pIn
)
19 , m_nEncoding(RTL_TEXTENCODING_DONTKNOW
)
23 bool SmRtfExport::ConvertFromStarMath(OStringBuffer
& rBuffer
, rtl_TextEncoding nEncoding
)
28 m_nEncoding
= nEncoding
;
29 m_pBuffer
->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE LO_STRING_SVTOOLS_RTF_MOMATH
" ");
30 HandleNode(m_pTree
, 0);
31 m_pBuffer
->append("}"); // moMath
35 // NOTE: This is still work in progress and unfinished, but it already covers a good
36 // part of the rtf math stuff.
38 void SmRtfExport::HandleVerticalStack(const SmNode
* pNode
, int nLevel
)
40 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MEQARR
" ");
41 int size
= pNode
->GetNumSubNodes();
42 for (int i
= 0; i
< size
; ++i
)
44 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
45 HandleNode(pNode
->GetSubNode(i
), nLevel
+ 1);
46 m_pBuffer
->append("}"); // me
48 m_pBuffer
->append("}"); // meqArr
51 void SmRtfExport::HandleText(const SmNode
* pNode
, int /*nLevel*/)
53 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MR
" ");
55 if (pNode
->GetToken().eType
== TTEXT
) // literal text
56 m_pBuffer
->append(LO_STRING_SVTOOLS_RTF_MNOR
" ");
58 const SmTextNode
* pTemp
= static_cast<const SmTextNode
*>(pNode
);
59 SAL_INFO("starmath.rtf", "Text: " << pTemp
->GetText());
60 for (sal_Int32 i
= 0; i
< pTemp
->GetText().getLength(); i
++)
62 sal_uInt16 nChar
= pTemp
->GetText()[i
];
63 OUString
aValue(SmTextNode::ConvertSymbolToUnicode(nChar
));
64 m_pBuffer
->append(msfilter::rtfutil::OutString(aValue
, m_nEncoding
));
67 m_pBuffer
->append("}"); // mr
70 void SmRtfExport::HandleFractions(const SmNode
* pNode
, int nLevel
, const char* type
)
72 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MF
" ");
75 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MFPR
" ");
76 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MTYPE
" ");
77 m_pBuffer
->append(type
);
78 m_pBuffer
->append("}"); // mtype
79 m_pBuffer
->append("}"); // mfPr
81 OSL_ASSERT(pNode
->GetNumSubNodes() == 3);
82 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MNUM
" ");
83 HandleNode(pNode
->GetSubNode(0), nLevel
+ 1);
84 m_pBuffer
->append("}"); // mnum
85 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEN
" ");
86 HandleNode(pNode
->GetSubNode(2), nLevel
+ 1);
87 m_pBuffer
->append("}"); // mden
88 m_pBuffer
->append("}"); // mf
91 void SmRtfExport::HandleAttribute(const SmAttributNode
* pNode
, int nLevel
)
93 switch (pNode
->Attribute()->GetToken().eType
)
111 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MACC
" ");
112 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MACCPR
" ");
113 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MCHR
" ");
114 OUString
aValue(pNode
->Attribute()->GetToken().cMathChar
);
115 m_pBuffer
->append(msfilter::rtfutil::OutString(aValue
, m_nEncoding
));
116 m_pBuffer
->append("}"); // mchr
117 m_pBuffer
->append("}"); // maccPr
118 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
119 HandleNode(pNode
->Body(), nLevel
+ 1);
120 m_pBuffer
->append("}"); // me
121 m_pBuffer
->append("}"); // macc
126 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBAR
" ");
127 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBARPR
" ");
128 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MPOS
" ");
129 m_pBuffer
->append((pNode
->Attribute()->GetToken().eType
== TUNDERLINE
) ? "bot" : "top");
130 m_pBuffer
->append("}"); // mpos
131 m_pBuffer
->append("}"); // mbarPr
132 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
133 HandleNode(pNode
->Body(), nLevel
+ 1);
134 m_pBuffer
->append("}"); // me
135 m_pBuffer
->append("}"); // mbar
138 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBORDERBOX
" ");
139 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBORDERBOXPR
" ");
140 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDETOP
" 1}");
141 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDEBOT
" 1}");
142 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDELEFT
" 1}");
143 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MHIDERIGHT
" 1}");
144 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSTRIKEH
" 1}");
145 m_pBuffer
->append("}"); // mborderBoxPr
146 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
147 HandleNode(pNode
->Body(), nLevel
+ 1);
148 m_pBuffer
->append("}"); // me
149 m_pBuffer
->append("}"); // mborderBox
152 HandleAllSubNodes(pNode
, nLevel
);
157 void SmRtfExport::HandleRoot(const SmRootNode
* pNode
, int nLevel
)
159 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MRAD
" ");
160 if (const SmNode
* argument
= pNode
->Argument())
162 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEG
" ");
163 HandleNode(argument
, nLevel
+ 1);
164 m_pBuffer
->append("}"); // mdeg
168 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MRADPR
" ");
169 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEGHIDE
" 1}");
170 m_pBuffer
->append("}"); // mradPr
171 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDEG
" }"); // empty but present
173 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
174 HandleNode(pNode
->Body(), nLevel
+ 1);
175 m_pBuffer
->append("}"); // me
176 m_pBuffer
->append("}"); // mrad
181 OString
mathSymbolToString(const SmNode
* node
, rtl_TextEncoding nEncoding
)
183 assert(node
->GetType() == NMATH
|| node
->GetType() == NMATHIDENT
);
184 const SmTextNode
* txtnode
= static_cast<const SmTextNode
*>(node
);
185 if (txtnode
->GetText().isEmpty())
187 assert(txtnode
->GetText().getLength() == 1);
188 sal_Unicode chr
= SmTextNode::ConvertSymbolToUnicode(txtnode
->GetText()[0]);
189 OUString
aValue(chr
);
190 return msfilter::rtfutil::OutString(aValue
, nEncoding
);
194 void SmRtfExport::HandleOperator(const SmOperNode
* pNode
, int nLevel
)
196 SAL_INFO("starmath.rtf", "Operator: " << int(pNode
->GetToken().eType
));
197 switch (pNode
->GetToken().eType
)
210 const SmSubSupNode
* subsup
= pNode
->GetSubNode(0)->GetType() == NSUBSUP
? static_cast<const SmSubSupNode
*>(pNode
->GetSubNode(0)) : 0;
211 const SmNode
* operation
= subsup
? subsup
->GetBody() : pNode
->GetSubNode(0);
212 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MNARY
" ");
213 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MNARYPR
" ");
214 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MCHR
" ");
215 m_pBuffer
->append(mathSymbolToString(operation
, m_nEncoding
));
216 m_pBuffer
->append("}"); // mchr
217 if (!subsup
|| !subsup
->GetSubSup(CSUB
))
218 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUBHIDE
" 1}");
219 if (!subsup
|| !subsup
->GetSubSup(CSUP
))
220 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUPHIDE
" 1}");
221 m_pBuffer
->append("}"); // mnaryPr
222 if (!subsup
|| !subsup
->GetSubSup(CSUB
))
223 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" }");
226 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
227 HandleNode(subsup
->GetSubSup(CSUB
), nLevel
+ 1);
228 m_pBuffer
->append("}"); // msub
230 if (!subsup
|| !subsup
->GetSubSup(CSUP
))
231 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" }");
234 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
235 HandleNode(subsup
->GetSubSup(CSUP
), nLevel
+ 1);
236 m_pBuffer
->append("}"); // msup
238 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
239 HandleNode(pNode
->GetSubNode(1), nLevel
+ 1); // body
240 m_pBuffer
->append("}"); // me
241 m_pBuffer
->append("}"); // mnary
245 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MFUNC
" ");
246 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MFNAME
" ");
247 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMLOW
" ");
248 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
249 HandleNode(pNode
->GetSymbol(), nLevel
+ 1);
250 m_pBuffer
->append("}"); // me
251 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
252 if (const SmSubSupNode
* subsup
= pNode
->GetSubNode(0)->GetType() == NSUBSUP
? static_cast<const SmSubSupNode
*>(pNode
->GetSubNode(0)) : 0)
253 if (subsup
->GetSubSup(CSUB
))
254 HandleNode(subsup
->GetSubSup(CSUB
), nLevel
+ 1);
255 m_pBuffer
->append("}"); // mlim
256 m_pBuffer
->append("}"); // mlimLow
257 m_pBuffer
->append("}"); // mfName
258 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
259 HandleNode(pNode
->GetSubNode(1), nLevel
+ 1); // body
260 m_pBuffer
->append("}"); // me
261 m_pBuffer
->append("}"); // mfunc
264 SAL_INFO("starmath.rtf", "TODO: " << OSL_THIS_FUNC
<< " unhandled oper type");
269 void SmRtfExport::HandleSubSupScriptInternal(const SmSubSupNode
* pNode
, int nLevel
, int flags
)
271 // rtf supports only a certain combination of sub/super scripts, but LO can have any,
272 // so try to merge it using several tags if necessary
273 if (flags
== 0) // none
275 if ((flags
& (1 << RSUP
| 1 << RSUB
)) == (1 << RSUP
| 1 << RSUB
))
278 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSSUBSUP
" ");
279 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
280 flags
&= ~(1 << RSUP
| 1 << RSUB
);
282 HandleNode(pNode
->GetBody(), nLevel
+ 1);
284 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
285 m_pBuffer
->append("}"); // me
286 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
287 HandleNode(pNode
->GetSubSup(RSUB
), nLevel
+ 1);
288 m_pBuffer
->append("}"); // msub
289 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
290 HandleNode(pNode
->GetSubSup(RSUP
), nLevel
+ 1);
291 m_pBuffer
->append("}"); // msup
292 m_pBuffer
->append("}"); // msubSup
294 else if ((flags
& (1 << RSUB
)) == 1 << RSUB
)
297 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSSUB
" ");
298 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
299 flags
&= ~(1 << RSUB
);
301 HandleNode(pNode
->GetBody(), nLevel
+ 1);
303 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
304 m_pBuffer
->append("}"); // me
305 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
306 HandleNode(pNode
->GetSubSup(RSUB
), nLevel
+ 1);
307 m_pBuffer
->append("}"); // msub
308 m_pBuffer
->append("}"); // msSub
310 else if ((flags
& (1 << RSUP
)) == 1 << RSUP
)
313 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSSUP
" ");
314 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
315 flags
&= ~(1 << RSUP
);
317 HandleNode(pNode
->GetBody(), nLevel
+ 1);
319 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
320 m_pBuffer
->append("}"); // me
321 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
322 HandleNode(pNode
->GetSubSup(RSUP
), nLevel
+ 1);
323 m_pBuffer
->append("}"); // msup
324 m_pBuffer
->append("}"); // msSup
326 else if ((flags
& (1 << LSUP
| 1 << LSUB
)) == (1 << LSUP
| 1 << LSUB
))
329 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSPRE
" ");
330 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUB
" ");
331 HandleNode(pNode
->GetSubSup(LSUB
), nLevel
+ 1);
332 m_pBuffer
->append("}"); // msub
333 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSUP
" ");
334 HandleNode(pNode
->GetSubSup(LSUP
), nLevel
+ 1);
335 m_pBuffer
->append("}"); // msup
336 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
337 flags
&= ~(1 << LSUP
| 1 << LSUB
);
339 HandleNode(pNode
->GetBody(), nLevel
+ 1);
341 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
342 m_pBuffer
->append("}"); // me
343 m_pBuffer
->append("}"); // msPre
345 else if ((flags
& (1 << CSUB
)) == (1 << CSUB
))
347 // m:limLow looks like a good element for central superscript
348 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMLOW
" ");
349 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
350 flags
&= ~(1 << CSUB
);
352 HandleNode(pNode
->GetBody(), nLevel
+ 1);
354 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
355 m_pBuffer
->append("}"); // me
356 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
357 HandleNode(pNode
->GetSubSup(CSUB
), nLevel
+ 1);
358 m_pBuffer
->append("}"); // mlim
359 m_pBuffer
->append("}"); // mlimLow
361 else if ((flags
& (1 << CSUP
)) == (1 << CSUP
))
363 // m:limUpp looks like a good element for central superscript
364 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMUPP
" ");
365 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
366 flags
&= ~(1 << CSUP
);
368 HandleNode(pNode
->GetBody(), nLevel
+ 1);
370 HandleSubSupScriptInternal(pNode
, nLevel
, flags
);
371 m_pBuffer
->append("}"); // me
372 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
373 HandleNode(pNode
->GetSubSup(CSUP
), nLevel
+ 1);
374 m_pBuffer
->append("}"); // mlim
375 m_pBuffer
->append("}"); // mlimUpp
378 SAL_INFO("starmath.rtf", "TODO: " << OSL_THIS_FUNC
<< " unhandled subsup type");
381 void SmRtfExport::HandleMatrix(const SmMatrixNode
* pNode
, int nLevel
)
383 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MM
" ");
384 for (int row
= 0; row
< pNode
->GetNumRows(); ++row
)
386 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MMR
" ");
387 for (int col
= 0; col
< pNode
->GetNumCols(); ++col
)
389 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
390 if (const SmNode
* node
= pNode
->GetSubNode(row
* pNode
->GetNumCols() + col
))
391 HandleNode(node
, nLevel
+ 1);
392 m_pBuffer
->append("}"); // me
394 m_pBuffer
->append("}"); // mmr
396 m_pBuffer
->append("}"); // mm
399 void SmRtfExport::HandleBrace(const SmBraceNode
* pNode
, int nLevel
)
401 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MD
" ");
402 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MDPR
" ");
403 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MBEGCHR
" ");
404 m_pBuffer
->append(mathSymbolToString(pNode
->OpeningBrace(), m_nEncoding
));
405 m_pBuffer
->append("}"); // mbegChr
406 std::vector
< const SmNode
* > subnodes
;
407 if (pNode
->Body()->GetType() == NBRACEBODY
)
409 const SmBracebodyNode
* body
= static_cast<const SmBracebodyNode
*>(pNode
->Body());
410 bool separatorWritten
= false; // assume all separators are the same
411 for (int i
= 0; i
< body
->GetNumSubNodes(); ++i
)
413 const SmNode
* subnode
= body
->GetSubNode(i
);
414 if (subnode
->GetType() == NMATH
|| subnode
->GetType() == NMATHIDENT
)
416 // do not write, but write what separator it is
417 const SmMathSymbolNode
* math
= static_cast<const SmMathSymbolNode
*>(subnode
);
418 if (!separatorWritten
)
420 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MSEPCHR
" ");
421 m_pBuffer
->append(mathSymbolToString(math
, m_nEncoding
));
422 m_pBuffer
->append("}"); // msepChr
423 separatorWritten
= true;
427 subnodes
.push_back(subnode
);
431 subnodes
.push_back(pNode
->Body());
432 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MENDCHR
" ");
433 m_pBuffer
->append(mathSymbolToString(pNode
->ClosingBrace(), m_nEncoding
));
434 m_pBuffer
->append("}"); // mendChr
435 m_pBuffer
->append("}"); // mdPr
436 for (unsigned int i
= 0; i
< subnodes
.size(); ++i
)
438 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
439 HandleNode(subnodes
[ i
], nLevel
+ 1);
440 m_pBuffer
->append("}"); // me
442 m_pBuffer
->append("}"); // md
445 void SmRtfExport::HandleVerticalBrace(const SmVerticalBraceNode
* pNode
, int nLevel
)
447 SAL_INFO("starmath.rtf", "Vertical: " << int(pNode
->GetToken().eType
));
448 switch (pNode
->GetToken().eType
)
453 bool top
= (pNode
->GetToken().eType
== TOVERBRACE
);
455 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMUPP
" ");
457 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIMLOW
" ");
458 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
459 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MGROUPCHR
" ");
460 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MGROUPCHRPR
" ");
461 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MCHR
" ");
462 m_pBuffer
->append(mathSymbolToString(pNode
->Brace(), m_nEncoding
));
463 m_pBuffer
->append("}"); // mchr
464 // TODO not sure if pos and vertJc are correct
465 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MPOS
" ").append(top
? "top" : "bot").append("}");
466 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MVERTJC
" ").append(top
? "bot" : "top").append("}");
467 m_pBuffer
->append("}"); // mgroupChrPr
468 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_ME
" ");
469 HandleNode(pNode
->Body(), nLevel
+ 1);
470 m_pBuffer
->append("}"); // me
471 m_pBuffer
->append("}"); // mgroupChr
472 m_pBuffer
->append("}"); // me
473 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MLIM
" ");
474 HandleNode(pNode
->Script(), nLevel
+ 1);
475 m_pBuffer
->append("}"); // mlim
476 m_pBuffer
->append("}"); // mlimUpp or mlimLow
480 SAL_INFO("starmath.rtf", "TODO: " << OSL_THIS_FUNC
<< " unhandled vertical brace type");
485 void SmRtfExport::HandleBlank()
487 m_pBuffer
->append("{" LO_STRING_SVTOOLS_RTF_MR
" ");
488 m_pBuffer
->append(" ");
489 m_pBuffer
->append("}"); // mr
492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */