Avoid potential negative array index access to cached text.
[LibreOffice.git] / writerfilter / source / rtftok / rtfdispatchdestination.cxx
blob8789c3f858a84a1d64beaf3f845ab892e66dff6d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
12 #include <string_view>
14 #include "rtfdocumentimpl.hxx"
16 #include <com/sun/star/document/DocumentProperties.hpp>
17 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
18 #include <com/sun/star/text/VertOrientation.hpp>
19 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
21 #include <filter/msfilter/escherex.hxx>
22 #include <rtl/character.hxx>
23 #include <tools/stream.hxx>
24 #include <sal/log.hxx>
26 #include <dmapper/DomainMapperFactory.hxx>
27 #include <ooxml/resourceids.hxx>
29 #include "rtflookahead.hxx"
30 #include "rtfreferenceproperties.hxx"
31 #include "rtfsdrimport.hxx"
32 #include "rtfskipdestination.hxx"
33 #include "rtftokenizer.hxx"
35 using namespace com::sun::star;
37 namespace writerfilter::rtftok
39 RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
41 setNeedSect(true);
42 checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
43 RTFSkipDestination aSkip(*this);
44 // special case \upr: ignore everything except nested \ud
45 if (Destination::UPR == m_aStates.top().getDestination() && RTFKeyword::UD != nKeyword)
47 m_aStates.top().setDestination(Destination::SKIP);
48 aSkip.setParsed(false);
50 else
51 switch (nKeyword)
53 case RTFKeyword::RTF:
54 break;
55 case RTFKeyword::FONTTBL:
56 m_aStates.top().setDestination(Destination::FONTTABLE);
57 break;
58 case RTFKeyword::COLORTBL:
59 m_aStates.top().setDestination(Destination::COLORTABLE);
60 break;
61 case RTFKeyword::STYLESHEET:
62 m_aStates.top().setDestination(Destination::STYLESHEET);
63 break;
64 case RTFKeyword::FIELD:
65 m_aStates.top().setDestination(Destination::FIELD);
66 m_aStates.top().setFieldLocked(false);
67 break;
68 case RTFKeyword::DOCVAR:
69 m_aStates.top().setDestination(Destination::DOCVAR);
70 break;
71 case RTFKeyword::FLDINST:
73 // Look for the field type
74 sal_uInt64 const nPos = Strm().Tell();
75 OStringBuffer aBuf;
76 char ch = 0;
77 bool bFoundCode = false;
78 bool bInKeyword = false;
79 while (!bFoundCode && ch != '}')
81 Strm().ReadChar(ch);
82 if ('\\' == ch)
83 bInKeyword = true;
84 if (!bInKeyword && rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
85 aBuf.append(ch);
86 else if (bInKeyword && rtl::isAsciiWhiteSpace(static_cast<unsigned char>(ch)))
87 bInKeyword = false;
88 if (!aBuf.isEmpty()
89 && !rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
90 bFoundCode = true;
93 if (std::string_view(aBuf) == "INCLUDEPICTURE")
95 // Extract the field argument of INCLUDEPICTURE: we handle that
96 // at a tokenizer level, as DOCX has no such field.
97 aBuf.append(ch);
98 while (true)
100 Strm().ReadChar(ch);
101 if (ch == '}')
102 break;
103 aBuf.append(ch);
105 OUString aFieldCommand = OStringToOUString(aBuf, RTL_TEXTENCODING_UTF8);
106 std::tuple<OUString, std::vector<OUString>, std::vector<OUString>> aResult
107 = writerfilter::dmapper::splitFieldCommand(aFieldCommand);
108 m_aPicturePath
109 = std::get<1>(aResult).empty() ? OUString() : std::get<1>(aResult).front();
112 Strm().Seek(nPos);
114 // Form data should be handled only for form fields if any
115 if (aBuf.toString().indexOf("FORM") != -1)
116 m_bFormField = true;
118 singleChar(cFieldStart);
119 m_aStates.top().setDestination(Destination::FIELDINSTRUCTION);
121 break;
122 case RTFKeyword::FLDRSLT:
123 m_aStates.top().setDestination(Destination::FIELDRESULT);
124 break;
125 case RTFKeyword::LISTTABLE:
126 m_aStates.top().setDestination(Destination::LISTTABLE);
127 break;
128 case RTFKeyword::LISTPICTURE:
129 m_aStates.top().setDestination(Destination::LISTPICTURE);
130 m_aStates.top().setInListpicture(true);
131 break;
132 case RTFKeyword::LIST:
133 m_aStates.top().setDestination(Destination::LISTENTRY);
134 break;
135 case RTFKeyword::LISTNAME:
136 m_aStates.top().setDestination(Destination::LISTNAME);
137 break;
138 case RTFKeyword::LFOLEVEL:
139 m_aStates.top().setDestination(Destination::LFOLEVEL);
140 m_aStates.top().getTableSprms().clear();
141 break;
142 case RTFKeyword::LISTOVERRIDETABLE:
143 m_aStates.top().setDestination(Destination::LISTOVERRIDETABLE);
144 break;
145 case RTFKeyword::LISTOVERRIDE:
146 m_aStates.top().setDestination(Destination::LISTOVERRIDEENTRY);
147 break;
148 case RTFKeyword::LISTLEVEL:
149 m_aStates.top().setDestination(Destination::LISTLEVEL);
150 ++m_nListLevel;
151 break;
152 case RTFKeyword::LEVELTEXT:
153 m_aStates.top().setDestination(Destination::LEVELTEXT);
154 break;
155 case RTFKeyword::LEVELNUMBERS:
156 m_aStates.top().setDestination(Destination::LEVELNUMBERS);
157 break;
158 case RTFKeyword::SHPPICT:
159 resetFrame();
160 m_aStates.top().setDestination(Destination::SHPPICT);
161 break;
162 case RTFKeyword::PICT:
163 if (m_aStates.top().getDestination() != Destination::SHAPEPROPERTYVALUE)
164 m_aStates.top().setDestination(Destination::PICT); // as character
165 else
166 m_aStates.top().setDestination(
167 Destination::SHAPEPROPERTYVALUEPICT); // anchored inside a shape
168 break;
169 case RTFKeyword::PICPROP:
170 m_aStates.top().setDestination(Destination::PICPROP);
171 break;
172 case RTFKeyword::SP:
173 m_aStates.top().setDestination(Destination::SHAPEPROPERTY);
174 break;
175 case RTFKeyword::SN:
176 m_aStates.top().setDestination(Destination::SHAPEPROPERTYNAME);
177 break;
178 case RTFKeyword::SV:
179 m_aStates.top().setDestination(Destination::SHAPEPROPERTYVALUE);
180 break;
181 case RTFKeyword::SHP:
182 m_bNeedCrOrig = m_bNeedCr;
183 m_aStates.top().setDestination(Destination::SHAPE);
184 m_aStates.top().setInShape(true);
185 break;
186 case RTFKeyword::SHPINST:
187 m_aStates.top().setDestination(Destination::SHAPEINSTRUCTION);
188 break;
189 case RTFKeyword::NESTTABLEPROPS:
190 // do not set any properties of outer table at nested table!
191 m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
192 m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
193 m_aNestedTableCellsSprms.clear();
194 m_aNestedTableCellsAttributes.clear();
195 m_nNestedCells = 0;
196 m_aStates.top().setDestination(Destination::NESTEDTABLEPROPERTIES);
197 break;
198 case RTFKeyword::HEADER:
199 case RTFKeyword::FOOTER:
200 case RTFKeyword::HEADERL:
201 case RTFKeyword::HEADERR:
202 case RTFKeyword::HEADERF:
203 case RTFKeyword::FOOTERL:
204 case RTFKeyword::FOOTERR:
205 case RTFKeyword::FOOTERF:
206 if (!m_pSuperstream)
208 Id nId = 0;
209 std::size_t nPos = m_nGroupStartPos - 1;
210 switch (nKeyword)
212 case RTFKeyword::HEADER:
213 if (!m_hasRHeader)
215 nId = NS_ooxml::LN_headerr;
216 m_hasRHeader = true;
218 break;
219 case RTFKeyword::FOOTER:
220 if (!m_hasRFooter)
222 nId = NS_ooxml::LN_footerr;
223 m_hasRFooter = true;
225 break;
226 case RTFKeyword::HEADERL:
227 nId = NS_ooxml::LN_headerl;
228 break;
229 case RTFKeyword::HEADERR:
230 nId = NS_ooxml::LN_headerr;
231 break;
232 case RTFKeyword::HEADERF:
233 if (!m_hasFHeader)
235 nId = NS_ooxml::LN_headerf;
236 m_hasFHeader = true;
238 break;
239 case RTFKeyword::FOOTERL:
240 nId = NS_ooxml::LN_footerl;
241 break;
242 case RTFKeyword::FOOTERR:
243 nId = NS_ooxml::LN_footerr;
244 break;
245 case RTFKeyword::FOOTERF:
246 if (!m_hasFFooter)
248 nId = NS_ooxml::LN_footerf;
249 m_hasFFooter = true;
251 break;
252 default:
253 break;
256 if (nId != 0)
257 m_nHeaderFooterPositions.push(std::make_pair(nId, nPos));
259 m_aStates.top().setDestination(Destination::SKIP);
261 break;
262 case RTFKeyword::FOOTNOTE:
263 checkFirstRun();
264 if (!m_pSuperstream)
266 Id nId = NS_ooxml::LN_footnote;
268 // Check if this is an endnote.
269 OStringBuffer aBuf;
270 char ch;
271 sal_uInt64 const nCurrent = Strm().Tell();
272 for (int i = 0; i < 7; ++i)
274 Strm().ReadChar(ch);
275 aBuf.append(ch);
277 Strm().Seek(nCurrent);
278 OString aKeyword = aBuf.makeStringAndClear();
279 if (aKeyword == "\\ftnalt")
280 nId = NS_ooxml::LN_endnote;
282 if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
283 m_aStates.top().setCurrentBuffer(nullptr);
284 bool bCustomMark = false;
285 OUString aCustomMark;
286 for (auto const& elem : m_aSuperBuffer)
288 if (std::get<0>(elem) == BUFFER_UTEXT)
290 aCustomMark = std::get<1>(elem)->getString();
291 bCustomMark = true;
294 m_aSuperBuffer.clear();
295 m_aStates.top().setDestination(Destination::FOOTNOTE);
296 Mapper().startCharacterGroup();
297 runProps();
298 if (!m_aStates.top().getCurrentBuffer())
299 resolveSubstream(m_nGroupStartPos - 1, nId, aCustomMark);
300 else
302 RTFSprms aAttributes;
303 aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
304 aAttributes.set(Id(1), new RTFValue(nId));
305 aAttributes.set(Id(2), new RTFValue(aCustomMark));
306 m_aStates.top().getCurrentBuffer()->push_back(
307 Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
309 if (bCustomMark)
311 m_aStates.top().getCharacterAttributes().clear();
312 m_aStates.top().getCharacterSprms().clear();
313 auto pValue = new RTFValue(1);
314 m_aStates.top().getCharacterAttributes().set(
315 NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows, pValue);
316 text(aCustomMark);
318 Mapper().endCharacterGroup();
319 m_aStates.top().setDestination(Destination::SKIP);
321 break;
322 case RTFKeyword::BKMKSTART:
323 m_aStates.top().setDestination(Destination::BOOKMARKSTART);
324 break;
325 case RTFKeyword::BKMKEND:
326 m_aStates.top().setDestination(Destination::BOOKMARKEND);
327 break;
328 case RTFKeyword::XE:
329 m_aStates.top().setDestination(Destination::INDEXENTRY);
330 break;
331 case RTFKeyword::TC:
332 case RTFKeyword::TCN:
333 m_aStates.top().setDestination(Destination::TOCENTRY);
334 break;
335 case RTFKeyword::REVTBL:
336 m_aStates.top().setDestination(Destination::REVISIONTABLE);
337 break;
338 case RTFKeyword::ANNOTATION:
339 if (!m_pSuperstream)
341 if (!m_aStates.top().getCurrentBuffer())
343 resolveSubstream(m_nGroupStartPos - 1, NS_ooxml::LN_annotation);
345 else
347 RTFSprms aAttributes;
348 aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
349 aAttributes.set(Id(1), new RTFValue(NS_ooxml::LN_annotation));
350 aAttributes.set(Id(2), new RTFValue(OUString()));
351 m_aStates.top().getCurrentBuffer()->push_back(
352 Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
354 m_aStates.top().setDestination(Destination::SKIP);
356 else
358 // If there is an author set, emit it now.
359 if (!m_aAuthor.isEmpty() || !m_aAuthorInitials.isEmpty())
361 RTFSprms aAttributes;
362 if (!m_aAuthor.isEmpty())
364 auto pValue = new RTFValue(m_aAuthor);
365 aAttributes.set(NS_ooxml::LN_CT_TrackChange_author, pValue);
367 if (!m_aAuthorInitials.isEmpty())
369 auto pValue = new RTFValue(m_aAuthorInitials);
370 aAttributes.set(NS_ooxml::LN_CT_Comment_initials, pValue);
372 writerfilter::Reference<Properties>::Pointer_t pProperties
373 = new RTFReferenceProperties(std::move(aAttributes));
374 Mapper().props(pProperties);
377 break;
378 case RTFKeyword::SHPTXT:
379 case RTFKeyword::DPTXBXTEXT:
381 bool bPictureFrame = false;
382 for (const auto& rProperty : m_aStates.top().getShape().getProperties())
384 if (rProperty.first == "shapeType"
385 && rProperty.second
386 == std::u16string_view(
387 OUString::number(ESCHER_ShpInst_PictureFrame)))
389 bPictureFrame = true;
390 break;
393 if (bPictureFrame)
394 // Skip text on picture frames.
395 m_aStates.top().setDestination(Destination::SKIP);
396 else
398 m_aStates.top().setDestination(Destination::SHAPETEXT);
399 checkFirstRun();
400 dispatchFlag(RTFKeyword::PARD);
401 m_bNeedPap = true;
402 if (nKeyword == RTFKeyword::SHPTXT)
404 if (!m_aStates.top().getCurrentBuffer())
405 m_pSdrImport->resolve(m_aStates.top().getShape(), false,
406 RTFSdrImport::SHAPE);
407 else
409 auto pValue = new RTFValue(m_aStates.top().getShape());
410 m_aStates.top().getCurrentBuffer()->push_back(
411 Buf_t(BUFFER_STARTSHAPE, pValue, nullptr));
416 break;
417 case RTFKeyword::FORMFIELD:
418 if (m_aStates.top().getDestination() == Destination::FIELDINSTRUCTION)
419 m_aStates.top().setDestination(Destination::FORMFIELD);
420 break;
421 case RTFKeyword::FFNAME:
422 m_aStates.top().setDestination(Destination::FORMFIELDNAME);
423 break;
424 case RTFKeyword::FFL:
425 m_aStates.top().setDestination(Destination::FORMFIELDLIST);
426 break;
427 case RTFKeyword::DATAFIELD:
428 m_aStates.top().setDestination(Destination::DATAFIELD);
429 break;
430 case RTFKeyword::INFO:
431 m_aStates.top().setDestination(Destination::INFO);
432 break;
433 case RTFKeyword::CREATIM:
434 m_aStates.top().setDestination(Destination::CREATIONTIME);
435 break;
436 case RTFKeyword::REVTIM:
437 m_aStates.top().setDestination(Destination::REVISIONTIME);
438 break;
439 case RTFKeyword::PRINTIM:
440 m_aStates.top().setDestination(Destination::PRINTTIME);
441 break;
442 case RTFKeyword::AUTHOR:
443 m_aStates.top().setDestination(Destination::AUTHOR);
444 break;
445 case RTFKeyword::KEYWORDS:
446 m_aStates.top().setDestination(Destination::KEYWORDS);
447 break;
448 case RTFKeyword::OPERATOR:
449 m_aStates.top().setDestination(Destination::OPERATOR);
450 break;
451 case RTFKeyword::COMPANY:
452 m_aStates.top().setDestination(Destination::COMPANY);
453 break;
454 case RTFKeyword::COMMENT:
455 m_aStates.top().setDestination(Destination::COMMENT);
456 break;
457 case RTFKeyword::OBJECT:
459 // beginning of an OLE Object
460 m_aStates.top().setDestination(Destination::OBJECT);
462 // check if the object is in a special container (e.g. a table)
463 if (!m_aStates.top().getCurrentBuffer())
465 // the object is in a table or another container.
466 // Don't try to treat it as an OLE object (fdo#53594).
467 // Use the \result (RTFKeyword::RESULT) element of the object instead,
468 // the result element contain picture representing the OLE Object.
469 m_bObject = true;
472 break;
473 case RTFKeyword::OBJDATA:
474 // check if the object is in a special container (e.g. a table)
475 if (m_aStates.top().getCurrentBuffer())
477 // the object is in a table or another container.
478 // Use the \result (RTFKeyword::RESULT) element of the object instead,
479 // of the \objdata.
480 m_aStates.top().setDestination(Destination::SKIP);
482 else
484 m_aStates.top().setDestination(Destination::OBJDATA);
486 break;
487 case RTFKeyword::OBJCLASS:
488 m_aStates.top().setDestination(Destination::OBJCLASS);
489 break;
490 case RTFKeyword::RESULT:
491 m_aStates.top().setDestination(Destination::RESULT);
492 break;
493 case RTFKeyword::ATNDATE:
494 m_aStates.top().setDestination(Destination::ANNOTATIONDATE);
495 break;
496 case RTFKeyword::ATNAUTHOR:
497 m_aStates.top().setDestination(Destination::ANNOTATIONAUTHOR);
498 break;
499 case RTFKeyword::ATNREF:
500 m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCE);
501 break;
502 case RTFKeyword::FALT:
503 m_aStates.top().setDestination(Destination::FALT);
504 break;
505 case RTFKeyword::FLYMAINCNT:
506 m_aStates.top().setDestination(Destination::FLYMAINCONTENT);
507 break;
508 case RTFKeyword::LISTTEXT:
509 // Should be ignored by any reader that understands Word 97 through Word 2007 numbering.
510 case RTFKeyword::NONESTTABLES:
511 // This destination should be ignored by readers that support nested tables.
512 m_aStates.top().setDestination(Destination::SKIP);
513 break;
514 case RTFKeyword::DO:
515 m_aStates.top().setDestination(Destination::DRAWINGOBJECT);
516 break;
517 case RTFKeyword::PN:
518 m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING);
519 break;
520 case RTFKeyword::PNTEXT:
521 // This destination should be ignored by readers that support paragraph numbering.
522 m_aStates.top().setDestination(Destination::SKIP);
523 break;
524 case RTFKeyword::PNTXTA:
525 m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTAFTER);
526 break;
527 case RTFKeyword::PNTXTB:
528 m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTBEFORE);
529 break;
530 case RTFKeyword::TITLE:
531 m_aStates.top().setDestination(Destination::TITLE);
532 break;
533 case RTFKeyword::SUBJECT:
534 m_aStates.top().setDestination(Destination::SUBJECT);
535 break;
536 case RTFKeyword::DOCCOMM:
537 m_aStates.top().setDestination(Destination::DOCCOMM);
538 break;
539 case RTFKeyword::ATRFSTART:
540 m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCESTART);
541 break;
542 case RTFKeyword::ATRFEND:
543 m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCEEND);
544 break;
545 case RTFKeyword::ATNID:
546 m_aStates.top().setDestination(Destination::ATNID);
547 break;
548 case RTFKeyword::MMATH:
549 case RTFKeyword::MOMATHPARA:
550 // Nothing to do here (just enter the destination) till RTFKeyword::MMATHPR is implemented.
551 break;
552 case RTFKeyword::MR:
553 m_aStates.top().setDestination(Destination::MR);
554 break;
555 case RTFKeyword::MCHR:
556 m_aStates.top().setDestination(Destination::MCHR);
557 break;
558 case RTFKeyword::MPOS:
559 m_aStates.top().setDestination(Destination::MPOS);
560 break;
561 case RTFKeyword::MVERTJC:
562 m_aStates.top().setDestination(Destination::MVERTJC);
563 break;
564 case RTFKeyword::MSTRIKEH:
565 m_aStates.top().setDestination(Destination::MSTRIKEH);
566 break;
567 case RTFKeyword::MDEGHIDE:
568 m_aStates.top().setDestination(Destination::MDEGHIDE);
569 break;
570 case RTFKeyword::MTYPE:
571 m_aStates.top().setDestination(Destination::MTYPE);
572 break;
573 case RTFKeyword::MGROW:
574 m_aStates.top().setDestination(Destination::MGROW);
575 break;
576 case RTFKeyword::MHIDETOP:
577 case RTFKeyword::MHIDEBOT:
578 case RTFKeyword::MHIDELEFT:
579 case RTFKeyword::MHIDERIGHT:
580 // SmOoxmlImport::handleBorderBox will ignore these anyway, so silently ignore for now.
581 m_aStates.top().setDestination(Destination::SKIP);
582 break;
583 case RTFKeyword::MSUBHIDE:
584 m_aStates.top().setDestination(Destination::MSUBHIDE);
585 break;
586 case RTFKeyword::MSUPHIDE:
587 m_aStates.top().setDestination(Destination::MSUPHIDE);
588 break;
589 case RTFKeyword::MBEGCHR:
590 m_aStates.top().setDestination(Destination::MBEGCHR);
591 break;
592 case RTFKeyword::MSEPCHR:
593 m_aStates.top().setDestination(Destination::MSEPCHR);
594 break;
595 case RTFKeyword::MENDCHR:
596 m_aStates.top().setDestination(Destination::MENDCHR);
597 break;
598 case RTFKeyword::UPR:
599 m_aStates.top().setDestination(Destination::UPR);
600 break;
601 case RTFKeyword::UD:
602 // Anything inside \ud is just normal Unicode content.
603 m_aStates.top().setDestination(Destination::NORMAL);
604 break;
605 case RTFKeyword::BACKGROUND:
606 m_aStates.top().setDestination(Destination::BACKGROUND);
607 m_aStates.top().setInBackground(true);
608 break;
609 case RTFKeyword::SHPGRP:
611 RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
612 if (!aLookahead.hasTable())
614 uno::Reference<drawing::XShapes> xGroupShape(
615 m_xModelFactory->createInstance("com.sun.star.drawing.GroupShape"),
616 uno::UNO_QUERY);
617 uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc,
618 uno::UNO_QUERY);
619 if (xDrawSupplier.is())
621 uno::Reference<drawing::XShape> xShape(xGroupShape, uno::UNO_QUERY);
622 // set default VertOrient before inserting
623 uno::Reference<beans::XPropertySet>(xShape, uno::UNO_QUERY_THROW)
624 ->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::NONE));
625 xDrawSupplier->getDrawPage()->add(xShape);
627 m_pSdrImport->pushParent(xGroupShape);
628 m_aStates.top().setCreatedShapeGroup(true);
630 m_aStates.top().setDestination(Destination::SHAPEGROUP);
631 m_aStates.top().setInShapeGroup(true);
633 break;
634 case RTFKeyword::FTNSEP:
635 m_aStates.top().setDestination(Destination::FOOTNOTESEPARATOR);
636 m_aStates.top().getCharacterAttributes().set(
637 NS_ooxml::LN_CT_FtnEdn_type,
638 new RTFValue(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator));
639 break;
640 case RTFKeyword::USERPROPS:
641 // Container of all user-defined properties.
642 m_aStates.top().setDestination(Destination::USERPROPS);
643 if (m_xDocumentProperties.is())
644 // Create a custom document properties to be able to process them later all at once.
645 m_xDocumentProperties = document::DocumentProperties::create(m_xContext);
646 break;
647 case RTFKeyword::PROPNAME:
648 m_aStates.top().setDestination(Destination::PROPNAME);
649 break;
650 case RTFKeyword::STATICVAL:
651 m_aStates.top().setDestination(Destination::STATICVAL);
652 break;
653 case RTFKeyword::GENERATOR:
654 m_aStates.top().setDestination(Destination::GENERATOR);
655 break;
656 default:
658 // Check if it's a math token.
659 RTFMathSymbol aSymbol(nKeyword);
660 if (RTFTokenizer::lookupMathKeyword(aSymbol))
662 m_aMathBuffer.appendOpeningTag(aSymbol.GetToken());
663 m_aStates.top().setDestination(aSymbol.GetDestination());
664 return RTFError::OK;
667 SAL_INFO("writerfilter",
668 "TODO handle destination '" << keywordToString(nKeyword) << "'");
669 // Make sure we skip destinations (even without \*) till we don't handle them
670 m_aStates.top().setDestination(Destination::SKIP);
671 aSkip.setParsed(false);
673 break;
676 // new destination => use new destination text
677 m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
679 return RTFError::OK;
682 } // namespace writerfilter
684 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */