/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
 
#include <sal/config.h>
 
#include <string_view>
 
#include "rtfdocumentimpl.hxx"
 
#include <com/sun/star/document/DocumentProperties.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/text/VertOrientation.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
 
#include <filter/msfilter/escherex.hxx>
#include <rtl/character.hxx>
#include <tools/stream.hxx>
#include <sal/log.hxx>
 
#include <dmapper/DomainMapperFactory.hxx>
#include <ooxml/resourceids.hxx>
 
#include "rtflookahead.hxx"
#include "rtfreferenceproperties.hxx"
#include "rtfsdrimport.hxx"
#include "rtfskipdestination.hxx"
#include "rtftokenizer.hxx"
#include <unotxdoc.hxx>
 
using namespace com::sun::star;
 
namespace writerfilter::rtftok
{
RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
{
    setNeedSect(true);
    checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
    RTFSkipDestination aSkip(*this);
    // special case \upr: ignore everything except nested \ud
    if (Destination::UPR == m_aStates.top().getDestination() && RTFKeyword::UD != nKeyword)
    {
        m_aStates.top().setDestination(Destination::SKIP);
        aSkip.setParsed(false);
    }
    else
        switch (nKeyword)
        {
            case RTFKeyword::RTF:
                break;
            case RTFKeyword::FONTTBL:
                m_aStates.top().setDestination(Destination::FONTTABLE);
                break;
            case RTFKeyword::COLORTBL:
                m_aStates.top().setDestination(Destination::COLORTABLE);
                break;
            case RTFKeyword::STYLESHEET:
                m_aStates.top().setDestination(Destination::STYLESHEET);
                break;
            case RTFKeyword::FIELD:
                m_aStates.top().setDestination(Destination::FIELD);
                m_aStates.top().setFieldLocked(false);
                break;
            case RTFKeyword::DOCVAR:
                m_aStates.top().setDestination(Destination::DOCVAR);
                break;
            case RTFKeyword::FLDINST:
            {
                // Look for the field type
                sal_uInt64 const nPos = Strm().Tell();
                OStringBuffer aBuf;
                char ch = 0;
                bool bFoundCode = false;
                bool bInKeyword = false;
                while (!bFoundCode && ch != '}')
                {
                    Strm().ReadChar(ch);
                    if ('\\' == ch)
                        bInKeyword = true;
                    if (!bInKeyword && rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
                        aBuf.append(ch);
                    else if (bInKeyword && rtl::isAsciiWhiteSpace(static_cast<unsigned char>(ch)))
                        bInKeyword = false;
                    if (!aBuf.isEmpty()
                        && !rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
                        bFoundCode = true;
                }
 
                if (std::string_view(aBuf) == "INCLUDEPICTURE")
                {
                    // Extract the field argument of INCLUDEPICTURE: we handle that
                    // at a tokenizer level, as DOCX has no such field.
                    aBuf.append(ch);
                    while (true)
                    {
                        Strm().ReadChar(ch);
                        if (ch == '}')
                            break;
                        aBuf.append(ch);
                    }
                    OUString aFieldCommand = OStringToOUString(aBuf, RTL_TEXTENCODING_UTF8);
                    std::tuple<OUString, std::vector<OUString>, std::vector<OUString>> aResult
                        = writerfilter::dmapper::splitFieldCommand(aFieldCommand);
                    m_aPicturePath
                        = std::get<1>(aResult).empty() ? OUString() : std::get<1>(aResult).front();
                }
 
                Strm().Seek(nPos);
 
                // Form data should be handled only for form fields if any
                if (aBuf.toString().indexOf("FORM") != -1)
                    m_bFormField = true;
 
                singleChar(cFieldStart);
                m_aStates.top().setDestination(Destination::FIELDINSTRUCTION);
            }
            break;
            case RTFKeyword::FLDRSLT:
                m_aStates.top().setDestination(Destination::FIELDRESULT);
                break;
            case RTFKeyword::LISTTABLE:
                m_aStates.top().setDestination(Destination::LISTTABLE);
                break;
            case RTFKeyword::LISTPICTURE:
                m_aStates.top().setDestination(Destination::LISTPICTURE);
                m_aStates.top().setInListpicture(true);
                break;
            case RTFKeyword::LIST:
                m_aStates.top().setDestination(Destination::LISTENTRY);
                break;
            case RTFKeyword::LISTNAME:
                m_aStates.top().setDestination(Destination::LISTNAME);
                break;
            case RTFKeyword::LFOLEVEL:
                m_aStates.top().setDestination(Destination::LFOLEVEL);
                m_aStates.top().getTableSprms().clear();
                break;
            case RTFKeyword::LISTOVERRIDETABLE:
                m_aStates.top().setDestination(Destination::LISTOVERRIDETABLE);
                break;
            case RTFKeyword::LISTOVERRIDE:
                m_aStates.top().setDestination(Destination::LISTOVERRIDEENTRY);
                break;
            case RTFKeyword::LISTLEVEL:
                m_aStates.top().setDestination(Destination::LISTLEVEL);
                ++m_nListLevel;
                break;
            case RTFKeyword::LEVELTEXT:
                m_aStates.top().setDestination(Destination::LEVELTEXT);
                break;
            case RTFKeyword::LEVELNUMBERS:
                m_aStates.top().setDestination(Destination::LEVELNUMBERS);
                break;
            case RTFKeyword::SHPPICT:
                resetFrame();
                m_aStates.top().setDestination(Destination::SHPPICT);
                break;
            case RTFKeyword::PICT:
                if (m_aStates.top().getDestination() != Destination::SHAPEPROPERTYVALUE)
                    m_aStates.top().setDestination(Destination::PICT); // as character
                else
                    m_aStates.top().setDestination(
                        Destination::SHAPEPROPERTYVALUEPICT); // anchored inside a shape
                break;
            case RTFKeyword::PICPROP:
                m_aStates.top().setDestination(Destination::PICPROP);
                break;
            case RTFKeyword::SP:
                m_aStates.top().setDestination(Destination::SHAPEPROPERTY);
                break;
            case RTFKeyword::SN:
                m_aStates.top().setDestination(Destination::SHAPEPROPERTYNAME);
                break;
            case RTFKeyword::SV:
                m_aStates.top().setDestination(Destination::SHAPEPROPERTYVALUE);
                break;
            case RTFKeyword::SHP:
                m_bNeedCrOrig = m_bNeedCr;
                m_aStates.top().setDestination(Destination::SHAPE);
                m_aStates.top().setInShape(true);
                break;
            case RTFKeyword::SHPINST:
                m_aStates.top().setDestination(Destination::SHAPEINSTRUCTION);
                break;
            case RTFKeyword::NESTTABLEPROPS:
                // do not set any properties of outer table at nested table!
                m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
                m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
                m_aNestedTableCellsSprms.clear();
                m_aNestedTableCellsAttributes.clear();
                m_nNestedCells = 0;
                m_aStates.top().setDestination(Destination::NESTEDTABLEPROPERTIES);
                break;
            case RTFKeyword::HEADER:
            case RTFKeyword::FOOTER:
            case RTFKeyword::HEADERL:
            case RTFKeyword::HEADERR:
            case RTFKeyword::HEADERF:
            case RTFKeyword::FOOTERL:
            case RTFKeyword::FOOTERR:
            case RTFKeyword::FOOTERF:
                if (!m_pSuperstream)
                {
                    Id nId = 0;
                    std::size_t nPos = m_nGroupStartPos - 1;
                    switch (nKeyword)
                    {
                        case RTFKeyword::HEADER:
                            if (!m_hasRHeader)
                            {
                                nId = NS_ooxml::LN_headerr;
                                m_hasRHeader = true;
                            }
                            break;
                        case RTFKeyword::FOOTER:
                            if (!m_hasRFooter)
                            {
                                nId = NS_ooxml::LN_footerr;
                                m_hasRFooter = true;
                            }
                            break;
                        case RTFKeyword::HEADERL:
                            nId = NS_ooxml::LN_headerl;
                            break;
                        case RTFKeyword::HEADERR:
                            nId = NS_ooxml::LN_headerr;
                            break;
                        case RTFKeyword::HEADERF:
                            if (!m_hasFHeader)
                            {
                                nId = NS_ooxml::LN_headerf;
                                m_hasFHeader = true;
                            }
                            break;
                        case RTFKeyword::FOOTERL:
                            nId = NS_ooxml::LN_footerl;
                            break;
                        case RTFKeyword::FOOTERR:
                            nId = NS_ooxml::LN_footerr;
                            break;
                        case RTFKeyword::FOOTERF:
                            if (!m_hasFFooter)
                            {
                                nId = NS_ooxml::LN_footerf;
                                m_hasFFooter = true;
                            }
                            break;
                        default:
                            break;
                    }
 
                    if (nId != 0)
                        m_nHeaderFooterPositions.push(std::make_pair(nId, nPos));
 
                    m_aStates.top().setDestination(Destination::SKIP);
                }
                break;
            case RTFKeyword::FOOTNOTE:
                checkFirstRun();
                if (!m_pSuperstream)
                {
                    Id nId = NS_ooxml::LN_footnote;
 
                    // Check if this is an endnote.
                    OStringBuffer aBuf;
                    char ch;
                    sal_uInt64 const nCurrent = Strm().Tell();
                    for (int i = 0; i < 7; ++i)
                    {
                        Strm().ReadChar(ch);
                        aBuf.append(ch);
                    }
                    Strm().Seek(nCurrent);
                    OString aKeyword = aBuf.makeStringAndClear();
                    if (aKeyword == "\\ftnalt")
                        nId = NS_ooxml::LN_endnote;
 
                    if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
                        m_aStates.top().setCurrentBuffer(nullptr);
                    bool bCustomMark = false;
                    OUString aCustomMark;
                    for (auto const& elem : m_aSuperBuffer)
                    {
                        if (std::get<0>(elem) == BUFFER_UTEXT)
                        {
                            aCustomMark = std::get<1>(elem)->getString();
                            bCustomMark = true;
                        }
                    }
                    m_aSuperBuffer.clear();
                    m_aStates.top().setDestination(Destination::FOOTNOTE);
                    Mapper().startCharacterGroup();
                    runProps();
                    if (!m_aStates.top().getCurrentBuffer())
                        resolveSubstream(m_nGroupStartPos - 1, nId, aCustomMark);
                    else
                    {
                        RTFSprms aAttributes;
                        aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
                        aAttributes.set(Id(1), new RTFValue(nId));
                        aAttributes.set(Id(2), new RTFValue(aCustomMark));
                        m_aStates.top().getCurrentBuffer()->push_back(
                            Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
                    }
                    if (bCustomMark)
                    {
                        m_aStates.top().getCharacterAttributes().clear();
                        m_aStates.top().getCharacterSprms().clear();
                        auto pValue = new RTFValue(1);
                        m_aStates.top().getCharacterAttributes().set(
                            NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows, pValue);
                        text(aCustomMark);
                    }
                    Mapper().endCharacterGroup();
                    m_aStates.top().setDestination(Destination::SKIP);
                }
                break;
            case RTFKeyword::BKMKSTART:
                m_aStates.top().setDestination(Destination::BOOKMARKSTART);
                break;
            case RTFKeyword::BKMKEND:
                m_aStates.top().setDestination(Destination::BOOKMARKEND);
                break;
            case RTFKeyword::XE:
                m_aStates.top().setDestination(Destination::INDEXENTRY);
                break;
            case RTFKeyword::TC:
            case RTFKeyword::TCN:
                m_aStates.top().setDestination(Destination::TOCENTRY);
                break;
            case RTFKeyword::REVTBL:
                m_aStates.top().setDestination(Destination::REVISIONTABLE);
                break;
            case RTFKeyword::ANNOTATION:
                if (!m_pSuperstream)
                {
                    if (!m_aStates.top().getCurrentBuffer())
                    {
                        resolveSubstream(m_nGroupStartPos - 1, NS_ooxml::LN_annotation);
                    }
                    else
                    {
                        RTFSprms aAttributes;
                        aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
                        aAttributes.set(Id(1), new RTFValue(NS_ooxml::LN_annotation));
                        aAttributes.set(Id(2), new RTFValue(OUString()));
                        m_aStates.top().getCurrentBuffer()->push_back(
                            Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
                    }
                    m_aStates.top().setDestination(Destination::SKIP);
                }
                else
                {
                    // If there is an author set, emit it now.
                    if (!m_aAuthor.isEmpty() || !m_aAuthorInitials.isEmpty())
                    {
                        RTFSprms aAttributes;
                        if (!m_aAuthor.isEmpty())
                        {
                            auto pValue = new RTFValue(m_aAuthor);
                            aAttributes.set(NS_ooxml::LN_CT_TrackChange_author, pValue);
                        }
                        if (!m_aAuthorInitials.isEmpty())
                        {
                            auto pValue = new RTFValue(m_aAuthorInitials);
                            aAttributes.set(NS_ooxml::LN_CT_Comment_initials, pValue);
                        }
                        writerfilter::Reference<Properties>::Pointer_t pProperties
                            = new RTFReferenceProperties(std::move(aAttributes));
                        Mapper().props(pProperties);
                    }
                }
                break;
            case RTFKeyword::SHPTXT:
            case RTFKeyword::DPTXBXTEXT:
            {
                bool bPictureFrame = false;
                for (const auto& rProperty : m_aStates.top().getShape().getProperties())
                {
                    if (rProperty.first == "shapeType"
                        && rProperty.second
                               == std::u16string_view(
                                      OUString::number(ESCHER_ShpInst_PictureFrame)))
                    {
                        bPictureFrame = true;
                        break;
                    }
                }
                if (bPictureFrame)
                    // Skip text on picture frames.
                    m_aStates.top().setDestination(Destination::SKIP);
                else
                {
                    m_aStates.top().setDestination(Destination::SHAPETEXT);
                    checkFirstRun();
                    dispatchFlag(RTFKeyword::PARD);
                    m_bNeedPap = true;
                    if (nKeyword == RTFKeyword::SHPTXT)
                    {
                        if (!m_aStates.top().getCurrentBuffer())
                            m_pSdrImport->resolve(m_aStates.top().getShape(), false,
                                                  RTFSdrImport::SHAPE);
                        else
                        {
                            auto pValue = new RTFValue(m_aStates.top().getShape());
                            m_aStates.top().getCurrentBuffer()->push_back(
                                Buf_t(BUFFER_STARTSHAPE, pValue, nullptr));
                        }
                    }
                }
            }
            break;
            case RTFKeyword::FORMFIELD:
                if (m_aStates.top().getDestination() == Destination::FIELDINSTRUCTION)
                    m_aStates.top().setDestination(Destination::FORMFIELD);
                break;
            case RTFKeyword::FFNAME:
                m_aStates.top().setDestination(Destination::FORMFIELDNAME);
                break;
            case RTFKeyword::FFL:
                m_aStates.top().setDestination(Destination::FORMFIELDLIST);
                break;
            case RTFKeyword::DATAFIELD:
                m_aStates.top().setDestination(Destination::DATAFIELD);
                break;
            case RTFKeyword::INFO:
                m_aStates.top().setDestination(Destination::INFO);
                break;
            case RTFKeyword::CREATIM:
                m_aStates.top().setDestination(Destination::CREATIONTIME);
                break;
            case RTFKeyword::REVTIM:
                m_aStates.top().setDestination(Destination::REVISIONTIME);
                break;
            case RTFKeyword::PRINTIM:
                m_aStates.top().setDestination(Destination::PRINTTIME);
                break;
            case RTFKeyword::AUTHOR:
                m_aStates.top().setDestination(Destination::AUTHOR);
                break;
            case RTFKeyword::KEYWORDS:
                m_aStates.top().setDestination(Destination::KEYWORDS);
                break;
            case RTFKeyword::OPERATOR:
                m_aStates.top().setDestination(Destination::OPERATOR);
                break;
            case RTFKeyword::COMPANY:
                m_aStates.top().setDestination(Destination::COMPANY);
                break;
            case RTFKeyword::COMMENT:
                m_aStates.top().setDestination(Destination::COMMENT);
                break;
            case RTFKeyword::OBJECT:
            {
                // beginning of an OLE Object
                m_aStates.top().setDestination(Destination::OBJECT);
 
                // check if the object is in a special container (e.g. a table)
                if (!m_aStates.top().getCurrentBuffer())
                {
                    // the object is in a table or another container.
                    // Don't try to treat it as an OLE object (fdo#53594).
                    // Use the \result (RTFKeyword::RESULT) element of the object instead,
                    // the result element contain picture representing the OLE Object.
                    m_bObject = true;
                }
            }
            break;
            case RTFKeyword::OBJDATA:
                // check if the object is in a special container (e.g. a table)
                if (m_aStates.top().getCurrentBuffer())
                {
                    // the object is in a table or another container.
                    // Use the \result (RTFKeyword::RESULT) element of the object instead,
                    // of the \objdata.
                    m_aStates.top().setDestination(Destination::SKIP);
                }
                else
                {
                    m_aStates.top().setDestination(Destination::OBJDATA);
                }
                break;
            case RTFKeyword::OBJCLASS:
                m_aStates.top().setDestination(Destination::OBJCLASS);
                break;
            case RTFKeyword::RESULT:
                m_aStates.top().setDestination(Destination::RESULT);
                break;
            case RTFKeyword::ATNDATE:
                m_aStates.top().setDestination(Destination::ANNOTATIONDATE);
                break;
            case RTFKeyword::ATNAUTHOR:
                m_aStates.top().setDestination(Destination::ANNOTATIONAUTHOR);
                break;
            case RTFKeyword::ATNREF:
                m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCE);
                break;
            case RTFKeyword::FALT:
                m_aStates.top().setDestination(Destination::FALT);
                break;
            case RTFKeyword::FLYMAINCNT:
                m_aStates.top().setDestination(Destination::FLYMAINCONTENT);
                break;
            case RTFKeyword::LISTTEXT:
            // Should be ignored by any reader that understands Word 97 through Word 2007 numbering.
            case RTFKeyword::NONESTTABLES:
                // This destination should be ignored by readers that support nested tables.
                m_aStates.top().setDestination(Destination::SKIP);
                break;
            case RTFKeyword::DO:
                m_aStates.top().setDestination(Destination::DRAWINGOBJECT);
                break;
            case RTFKeyword::PN:
                m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING);
                break;
            case RTFKeyword::PNTEXT:
                // This destination should be ignored by readers that support paragraph numbering.
                m_aStates.top().setDestination(Destination::SKIP);
                break;
            case RTFKeyword::PNTXTA:
                m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTAFTER);
                break;
            case RTFKeyword::PNTXTB:
                m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTBEFORE);
                break;
            case RTFKeyword::TITLE:
                m_aStates.top().setDestination(Destination::TITLE);
                break;
            case RTFKeyword::SUBJECT:
                m_aStates.top().setDestination(Destination::SUBJECT);
                break;
            case RTFKeyword::DOCCOMM:
                m_aStates.top().setDestination(Destination::DOCCOMM);
                break;
            case RTFKeyword::ATRFSTART:
                m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCESTART);
                break;
            case RTFKeyword::ATRFEND:
                m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCEEND);
                break;
            case RTFKeyword::ATNID:
                m_aStates.top().setDestination(Destination::ATNID);
                break;
            case RTFKeyword::MMATH:
            case RTFKeyword::MOMATHPARA:
                // Nothing to do here (just enter the destination) till RTFKeyword::MMATHPR is implemented.
                break;
            case RTFKeyword::MR:
                m_aStates.top().setDestination(Destination::MR);
                break;
            case RTFKeyword::MCHR:
                m_aStates.top().setDestination(Destination::MCHR);
                break;
            case RTFKeyword::MPOS:
                m_aStates.top().setDestination(Destination::MPOS);
                break;
            case RTFKeyword::MVERTJC:
                m_aStates.top().setDestination(Destination::MVERTJC);
                break;
            case RTFKeyword::MSTRIKEH:
                m_aStates.top().setDestination(Destination::MSTRIKEH);
                break;
            case RTFKeyword::MDEGHIDE:
                m_aStates.top().setDestination(Destination::MDEGHIDE);
                break;
            case RTFKeyword::MTYPE:
                m_aStates.top().setDestination(Destination::MTYPE);
                break;
            case RTFKeyword::MGROW:
                m_aStates.top().setDestination(Destination::MGROW);
                break;
            case RTFKeyword::MHIDETOP:
            case RTFKeyword::MHIDEBOT:
            case RTFKeyword::MHIDELEFT:
            case RTFKeyword::MHIDERIGHT:
                // SmOoxmlImport::handleBorderBox will ignore these anyway, so silently ignore for now.
                m_aStates.top().setDestination(Destination::SKIP);
                break;
            case RTFKeyword::MSUBHIDE:
                m_aStates.top().setDestination(Destination::MSUBHIDE);
                break;
            case RTFKeyword::MSUPHIDE:
                m_aStates.top().setDestination(Destination::MSUPHIDE);
                break;
            case RTFKeyword::MBEGCHR:
                m_aStates.top().setDestination(Destination::MBEGCHR);
                break;
            case RTFKeyword::MSEPCHR:
                m_aStates.top().setDestination(Destination::MSEPCHR);
                break;
            case RTFKeyword::MENDCHR:
                m_aStates.top().setDestination(Destination::MENDCHR);
                break;
            case RTFKeyword::UPR:
                m_aStates.top().setDestination(Destination::UPR);
                break;
            case RTFKeyword::UD:
                // Anything inside \ud is just normal Unicode content.
                m_aStates.top().setDestination(Destination::NORMAL);
                break;
            case RTFKeyword::BACKGROUND:
                m_aStates.top().setDestination(Destination::BACKGROUND);
                m_aStates.top().setInBackground(true);
                break;
            case RTFKeyword::SHPGRP:
            {
                RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
                if (!aLookahead.hasTable())
                {
                    uno::Reference<drawing::XShapes> xGroupShape(
                        getTextDocument()->createInstance(u"com.sun.star.drawing.GroupShape"_ustr),
                        uno::UNO_QUERY);
                    if (m_xDstDoc)
                    {
                        uno::Reference<drawing::XShape> xShape(xGroupShape, uno::UNO_QUERY);
                        // set default VertOrient before inserting
                        uno::Reference<beans::XPropertySet>(xShape, uno::UNO_QUERY_THROW)
                            ->setPropertyValue(u"VertOrient"_ustr,
                                               uno::Any(text::VertOrientation::NONE));
                        m_xDstDoc->getDrawPage()->add(xShape);
                    }
                    m_pSdrImport->pushParent(xGroupShape);
                    m_aStates.top().setCreatedShapeGroup(true);
                }
                m_aStates.top().setDestination(Destination::SHAPEGROUP);
                m_aStates.top().setInShapeGroup(true);
            }
            break;
            case RTFKeyword::FTNSEP:
                m_aStates.top().setDestination(Destination::FOOTNOTESEPARATOR);
                m_aStates.top().getCharacterAttributes().set(
                    NS_ooxml::LN_CT_FtnEdn_type,
                    new RTFValue(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator));
                break;
            case RTFKeyword::USERPROPS:
                // Container of all user-defined properties.
                m_aStates.top().setDestination(Destination::USERPROPS);
                if (m_xDocumentProperties.is())
                    // Create a custom document properties to be able to process them later all at once.
                    m_xDocumentProperties = document::DocumentProperties::create(m_xContext);
                break;
            case RTFKeyword::PROPNAME:
                m_aStates.top().setDestination(Destination::PROPNAME);
                break;
            case RTFKeyword::STATICVAL:
                m_aStates.top().setDestination(Destination::STATICVAL);
                break;
            case RTFKeyword::GENERATOR:
                m_aStates.top().setDestination(Destination::GENERATOR);
                break;
            default:
            {
                // Check if it's a math token.
                if (auto pSymbolData = RTFTokenizer::lookupMathKeyword(nKeyword))
                {
                    m_aMathBuffer.appendOpeningTag(pSymbolData->GetToken());
                    m_aStates.top().setDestination(pSymbolData->GetDestination());
                    return RTFError::OK;
                }
 
                SAL_INFO("writerfilter",
                         "TODO handle destination '" << RTFTokenizer::toString(nKeyword) << "'");
                // Make sure we skip destinations (even without \*) till we don't handle them
                m_aStates.top().setDestination(Destination::SKIP);
                aSkip.setParsed(false);
            }
            break;
        }
 
    // new destination => use new destination text
    m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
 
    return RTFError::OK;
}
 
} // namespace writerfilter
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V530 The return value of function 'append' is required to be utilized.

V1037 Two or more case-branches perform the same actions. Check lines: 513, 523, 582