LibreOffice Module oox (master) 1
contexthandler2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
23#include <oox/token/namespaces.hxx>
24#include <oox/token/tokens.hxx>
25#include <rtl/ustrbuf.hxx>
26#include <o3tl/safeint.hxx>
27#include <osl/diagnose.h>
28#include <com/sun/star/frame/XModel.hpp>
29#include <com/sun/star/lang/XServiceInfo.hpp>
30
31namespace oox::core {
32
33using namespace ::com::sun::star::uno;
34using namespace ::com::sun::star::lang;
35using namespace ::com::sun::star::xml::sax;
36
39{
40 OUStringBuffer maChars;
41 sal_Int32 mnElement;
43
45};
46
48 mxContextStack( std::make_shared<ContextStack>() ),
49 mnRootStackSize( 0 ),
50 mbEnableTrimSpace( bEnableTrimSpace ),
51 mrFilter( rFilter )
52{
54}
55
57 mxContextStack( rParent.mxContextStack ),
58 mnRootStackSize( rParent.mxContextStack->size() ),
59 mbEnableTrimSpace( rParent.mbEnableTrimSpace ),
60 mrFilter(rParent.mrFilter)
61{
62}
63
65{
66}
67
69{
70 return mxContextStack->empty() ? XML_ROOT_CONTEXT : mxContextStack->back().mnElement;
71}
72
74{
75 auto It = std::find_if(mxContextStack->rbegin(), mxContextStack->rend(),
76 [](const ElementInfo& rItem) { return getNamespace(rItem.mnElement) != NMSP_mce; });
77 if (It != mxContextStack->rend())
78 return It->mnElement;
79 return XML_ROOT_CONTEXT;
80}
81
82sal_Int32 ContextHandler2Helper::getParentElement( sal_Int32 nCountBack ) const
83{
84 if( (nCountBack < 0) || (mxContextStack->size() < o3tl::make_unsigned( nCountBack )) )
85 return XML_TOKEN_INVALID;
86 return (mxContextStack->size() == static_cast< size_t >( nCountBack )) ?
87 XML_ROOT_CONTEXT : (*mxContextStack)[ mxContextStack->size() - nCountBack - 1 ].mnElement;
88}
89
91{
92 return mxContextStack->size() == mnRootStackSize + 1;
93}
94
95Reference< XFastContextHandler > ContextHandler2Helper::implCreateChildContext(
96 sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs )
97{
98 // #i76091# process collected characters (calls onCharacters() if needed)
100 ContextHandlerRef xContext = onCreateContext( nElement, AttributeList( rxAttribs ) );
101 return xContext;
102}
103
104void ContextHandler2Helper::implStartElement( sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs )
105{
106 AttributeList aAttribs( rxAttribs );
107 pushElementInfo( nElement ).mbTrimSpaces = aAttribs.getToken( XML_TOKEN( space ), XML_TOKEN_INVALID ) != XML_preserve;
108 onStartElement( aAttribs );
109}
110
111void ContextHandler2Helper::implCharacters( std::u16string_view rChars )
112{
113 // #i76091# collect characters until new element starts or this element ends
114 if( !mxContextStack->empty() )
115 mxContextStack->back().maChars.append(rChars);
116}
117
119{
120 OSL_ENSURE( getCurrentElementWithMce() == nElement, "ContextHandler2Helper::implEndElement - context stack broken" );
121 if( !mxContextStack->empty() )
122 {
123 // #i76091# process collected characters (calls onCharacters() if needed)
125 onEndElement();
127 }
128}
129
131{
132 return onCreateRecordContext( nRecId, rStrm );
133}
134
136{
137 pushElementInfo( nRecId );
139}
140
142{
143 OSL_ENSURE( getCurrentElementWithMce() == nRecId, "ContextHandler2Helper::implEndRecord - context stack broken" );
144 if( !mxContextStack->empty() )
145 {
146 onEndRecord();
148 }
149}
150
152{
153 mxContextStack->emplace_back();
154 ElementInfo& rInfo = mxContextStack->back();
155 rInfo.mnElement = nElement;
156 return rInfo;
157}
158
160{
161 OSL_ENSURE( !mxContextStack->empty(), "ContextHandler2Helper::popElementInfo - context stack broken" );
162 if( !mxContextStack->empty() )
163 mxContextStack->pop_back();
164}
165
167{
168 OSL_ENSURE( !mxContextStack->empty(), "ContextHandler2Helper::processCollectedChars - no context info" );
169 if (mxContextStack->empty())
170 return;
171 ElementInfo& rInfo = mxContextStack->back();
172 if( !rInfo.maChars.isEmpty() )
173 {
174 OUString aChars = rInfo.maChars.makeStringAndClear();
175 if( mbEnableTrimSpace && rInfo.mbTrimSpaces )
176 aChars = aChars.trim();
177 if( !aChars.isEmpty() )
178 onCharacters( aChars );
179 }
180}
181
183 ContextHandler( dynamic_cast< ContextHandler const & >( rParent ) ),
184 ContextHandler2Helper( rParent )
185{
186}
187
189{
190}
191
192// com.sun.star.xml.sax.XFastContextHandler interface -------------------------
193
194Reference< XFastContextHandler > SAL_CALL ContextHandler2::createFastChildContext(
195 sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs )
196{
197 if( getNamespace( nElement ) == NMSP_mce ) // TODO for checking 'Ignorable'
198 {
199 if( prepareMceContext( nElement, AttributeList( rxAttribs ) ) )
200 return this;
201 return nullptr;
202 }
203
204 return implCreateChildContext( nElement, rxAttribs );
205}
206
208 sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs )
209{
210 implStartElement( nElement, rxAttribs );
211}
212
213void SAL_CALL ContextHandler2::characters( const OUString& rChars )
214{
215 implCharacters( rChars );
216}
217
218void SAL_CALL ContextHandler2::endFastElement( sal_Int32 nElement )
219{
220 implEndElement( nElement );
221}
222
223bool ContextHandler2Helper::prepareMceContext( sal_Int32 nElement, const AttributeList& rAttribs )
224{
225 switch( nElement )
226 {
227 case MCE_TOKEN( AlternateContent ):
229 break;
230
231 case MCE_TOKEN( Choice ):
232 {
234 return false;
235
236 OUString aRequires = rAttribs.getString( XML_Requires, "none" );
237
238 // At this point we can't access namespaces as the correct xml filter
239 // is long gone. For now let's decide depending on a list of supported
240 // namespaces like we do in writerfilter
241
242 std::vector<OUString> aSupportedNS =
243 {
244 "a14", // Impress needs this to import math formulas.
245 "p14",
246 "p15",
247 "x12ac",
248 "v"
249 };
250
251 Reference<XServiceInfo> xModel(getDocFilter().getModel(), UNO_QUERY);
252 if (xModel.is() && xModel->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
253 {
254 // No a14 for Calc documents, it would cause duplicated shapes as-is.
255 auto it = std::find(aSupportedNS.begin(), aSupportedNS.end(), "a14");
256 if (it != aSupportedNS.end())
257 {
258 aSupportedNS.erase(it);
259 }
260 }
261
262 if (std::find(aSupportedNS.begin(), aSupportedNS.end(), aRequires) != aSupportedNS.end())
264 else
265 return false;
266 }
267 break;
268
269 case MCE_TOKEN( Fallback ):
271 break;
272 return false;
273 default:
274 {
275 OUString str = rAttribs.getStringDefaulted( MCE_TOKEN( Ignorable ));
276 if( !str.isEmpty() )
277 {
278 // Sequence< css::xml::FastAttribute > attrs = rAttribs.getFastAttributeList()->getFastAttributes();
279 // printf("MCE: %s\n", OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
280 // TODO: Check & Get the namespaces in "Ignorable"
281 // printf("NS: %d : %s\n", attrs.getLength(), OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
282 }
283 }
284 return false;
285 }
286 return true;
287}
288
289// oox.core.RecordContext interface -------------------------------------------
290
292{
293 return implCreateRecordContext( nRecId, rStrm );
294}
295
296void ContextHandler2::startRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
297{
298 implStartRecord( nRecId, rStrm );
299}
300
301void ContextHandler2::endRecord( sal_Int32 nRecId )
302{
303 implEndRecord( nRecId );
304}
305
306// oox.core.ContextHandler2Helper interface -----------------------------------
307
309{
310 return nullptr;
311}
312
314{
315}
316
317void ContextHandler2::onCharacters( const OUString& )
318{
319}
320
322{
323}
324
326{
327 return nullptr;
328}
329
331{
332}
333
335{
336}
337
338} // namespace oox::core
339
340/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Provides access to attribute values of an element.
OUString getStringDefaulted(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute, returns an empty string if attribute not present...
std::optional< OUString > getString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
std::optional< sal_Int32 > getToken(sal_Int32 nAttrToken) const
Returns the token identifier of the value of the specified attribute.
Wraps a StreamDataSequence and provides convenient access functions.
Helper class that provides a context stack.
ContextHandler2Helper(bool bEnableTrimSpace, XmlFilterBase &rFilter)
virtual void onCharacters(const OUString &rChars)=0
Will be called before a new child element starts, or if the current element is about to be left.
void implCharacters(std::u16string_view rChars)
Must be called from characters() in derived classes.
bool prepareMceContext(sal_Int32 nElement, const AttributeList &rAttribs)
sal_Int32 getParentElement(sal_Int32 nCountBack=1) const
Returns the identifier of the specified parent element.
void setMCEState(MCE_STATE aState)
void implEndRecord(sal_Int32 nRecId)
Must be called from endRecord() in derived classes.
bool mbEnableTrimSpace
True = trim whitespace in characters().
std::vector< ElementInfo > ContextStack
virtual void onStartRecord(SequenceInputStream &rStrm)=0
Will be called when a new record block in a binary stream has been started.
ContextStackRef mxContextStack
Stack of all processed elements.
virtual void onEndElement()=0
Will be called when the current element is about to be left.
void implStartElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &rxAttribs)
Must be called from startFastElement() in derived classes.
void implStartRecord(sal_Int32 nRecId, SequenceInputStream &rStrm)
Must be called from startRecord() in derived classes.
size_t mnRootStackSize
Stack size on construction time.
XmlFilterBase & getDocFilter() const
void addMCEState(MCE_STATE aState)
css::uno::Reference< css::xml::sax::XFastContextHandler > implCreateChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &rxAttribs)
Must be called from createFastChildContext() in derived classes.
ContextHandlerRef implCreateRecordContext(sal_Int32 nRecId, SequenceInputStream &rStrm)
Must be called from createRecordContext() in derived classes.
sal_Int32 getCurrentElement() const
Returns the identifier of the currently processed element.
virtual ContextHandlerRef onCreateContext(sal_Int32 nElement, const AttributeList &rAttribs)=0
Will be called to create a context handler for the passed element.
bool isRootElement() const
Returns true, if the element currently processed is the root element of the context or fragment handl...
sal_Int32 getCurrentElementWithMce() const
Returns the identifier of the currently processed element - Including MCE root elements.
virtual void onStartElement(const AttributeList &rAttribs)=0
Will be called when a new element has been started.
virtual void onEndRecord()=0
Will be called when the current record block is about to be left.
ElementInfo & pushElementInfo(sal_Int32 nElement)
virtual ContextHandlerRef onCreateRecordContext(sal_Int32 nRecId, SequenceInputStream &rStrm)=0
Will be called to create a context handler for the passed record.
void implEndElement(sal_Int32 nElement)
Must be called from endFastElement() in derived classes.
ContextHandler2(ContextHandler2Helper const &rParent)
virtual void onCharacters(const OUString &rChars) override
Will be called before a new child element starts, or if the current element is about to be left.
virtual void SAL_CALL characters(const OUString &rChars) final override
virtual void onEndElement() override
Will be called when the current element is about to be left.
virtual ~ContextHandler2() override
virtual void onStartRecord(SequenceInputStream &rStrm) override
Will be called when a new record block in a binary stream has been started.
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &rxAttribs) final override
virtual ContextHandlerRef onCreateContext(sal_Int32 nElement, const AttributeList &rAttribs) override
Will be called to create a context handler for the passed element.
virtual void onStartElement(const AttributeList &rAttribs) override
Will be called when a new element has been started.
virtual ContextHandlerRef createRecordContext(sal_Int32 nRecId, SequenceInputStream &rStrm) override
virtual void startRecord(sal_Int32 nRecId, SequenceInputStream &rStrm) override
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &rxAttribs) final override
virtual void onEndRecord() override
Will be called when the current record block is about to be left.
virtual void SAL_CALL endFastElement(sal_Int32 nElement) final override
virtual void endRecord(sal_Int32 nRecId) override
virtual ContextHandlerRef onCreateRecordContext(sal_Int32 nRecId, SequenceInputStream &rStrm) override
Will be called to create a context handler for the passed record.
ScModelObj * getModel(const ScDocShell &rDocShell)
size
void SvStream & rStrm
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
std::shared_ptr< T > make_shared(Args &&... args)
const sal_Int32 XML_ROOT_CONTEXT
XML_TOKEN_INVALID
const PowerPointImport & mrFilter
Definition: pptimport.cxx:264
Information about a processed element.
ElementInfo()
True = trims leading/trailing spaces from text data.
sal_Int32 mnElement
Collected element characters.
bool mbTrimSpaces
The element identifier.
Reference< XModel > xModel