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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/urlobj.hxx>
21 #include <com/sun/star/document/XGraphicStorageHandler.hpp>
22 #include <com/sun/star/embed/ElementModes.hpp>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
25 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
26 #include <com/sun/star/drawing/LineDash.hpp>
27 #include <com/sun/star/awt/Gradient2.hpp>
28 #include <com/sun/star/awt/XBitmap.hpp>
29 #include <com/sun/star/awt/ColorStop.hpp>
30 #include <com/sun/star/drawing/Hatch.hpp>
31 #include <com/sun/star/io/XSeekable.hpp>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/storagehelper.hxx>
34 #include <sax/tools/converter.hxx>
35 #include <sfx2/docfile.hxx>
37 #include <xmloff/xmlnamespace.hxx>
38 #include <xmloff/namespacemap.hxx>
40 #include <xmloff/xmltoken.hxx>
41 #include <xmloff/DashStyle.hxx>
42 #include <xmloff/GradientStyle.hxx>
43 #include <xmloff/HatchStyle.hxx>
44 #include <xmloff/ImageStyle.hxx>
45 #include <xmloff/MarkerStyle.hxx>
46 #include <xmloff/xmlictxt.hxx>
47 #include <svx/xmlgrhlp.hxx>
49 #include <xmlxtimp.hxx>
50 #include <comphelper/sequence.hxx>
51 #include <comphelper/diagnose_ex.hxx>
53 using namespace com::sun::star
;
54 using namespace com::sun::star::container
;
55 using namespace com::sun::star::document
;
56 using namespace com::sun::star::uno
;
57 using namespace com::sun::star::awt
;
58 using namespace com::sun::star::lang
;
59 using namespace com::sun::star::xml::sax
;
60 using namespace ::xmloff::token
;
65 enum class SvxXMLTableImportContextEnum
{ Color
, Marker
, Dash
, Hatch
, Gradient
, Bitmap
};
67 class SvxXMLTableImportContext
: public SvXMLImportContext
70 SvxXMLTableImportContext( SvXMLImport
& rImport
, SvxXMLTableImportContextEnum eContext
, uno::Reference
< XNameContainer
> xTable
,
73 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
74 createFastChildContext(sal_Int32 Element
,
75 const css::uno::Reference
< css::xml::sax::XFastAttributeList
> & Attribs
) override
;
78 static void importColor( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
);
79 void importMarker( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
);
80 void importDash( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
);
81 void importHatch( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
);
82 void importBitmap( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
);
85 uno::Reference
< XNameContainer
> mxTable
;
86 SvxXMLTableImportContextEnum meContext
;
92 SvxXMLTableImportContext::SvxXMLTableImportContext( SvXMLImport
& rImport
, SvxXMLTableImportContextEnum eContext
, uno::Reference
< XNameContainer
> xTable
, bool bOOoFormat
)
93 : SvXMLImportContext( rImport
), mxTable(std::move( xTable
)), meContext( eContext
),
94 mbOOoFormat( bOOoFormat
)
100 // MCGR: Helper ImportContext to be able to parse sub-content
101 // entries like XMLGradientStopContext which are allowed now
102 // for importing Gradients
103 class XMLGradientHelperContext
: public SvXMLImportContext
106 uno::Reference
< XNameContainer
> mxTable
;
109 std::vector
<css::awt::ColorStop
> maColorStopVec
;
112 XMLGradientHelperContext(
113 SvXMLImport
& rImport
,
114 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
,
115 const css::uno::Reference
< XNameContainer
>& rxTable
);
116 virtual ~XMLGradientHelperContext() override
;
117 virtual css::uno::Reference
<css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
119 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& AttrList
) override
;
120 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
123 XMLGradientHelperContext::XMLGradientHelperContext(
124 SvXMLImport
& rImport
,
125 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
,
126 const uno::Reference
< XNameContainer
>& rxTable
)
127 : SvXMLImportContext(rImport
),
132 // Import GradientStyle
133 XMLGradientStyleImport
aGradientStyle( GetImport() );
134 aGradientStyle
.importXML( xAttrList
, maAny
, maStrName
);
136 catch (const uno::Exception
&)
138 DBG_UNHANDLED_EXCEPTION("svx");
142 XMLGradientHelperContext::~XMLGradientHelperContext()
144 // if GradientStyle was imported, add to List
145 if( !maStrName
.isEmpty() && maAny
.hasValue() )
147 if( mxTable
->hasByName( maStrName
) )
149 mxTable
->replaceByName( maStrName
, maAny
);
153 mxTable
->insertByName( maStrName
, maAny
);
158 css::uno::Reference
<css::xml::sax::XFastContextHandler
> XMLGradientHelperContext::createFastChildContext(
160 const css::uno::Reference
<css::xml::sax::XFastAttributeList
>& xAttrList
)
162 // be prepared & import GradientStop entries
163 if (nElement
== XML_ELEMENT(LO_EXT
, xmloff::token::XML_GRADIENT_STOP
))
165 return new XMLGradientStopContext(GetImport(), nElement
, xAttrList
, maColorStopVec
);
171 void XMLGradientHelperContext::endFastElement(sal_Int32
)
173 // correcting invalid StopOffset values is done at the model. Therefore we import them here
174 // without any change.
175 if (!maColorStopVec
.empty())
177 awt::Gradient2 aGradient
;
179 aGradient
.ColorStops
= comphelper::containerToSequence(maColorStopVec
);
185 css::uno::Reference
< css::xml::sax::XFastContextHandler
>
186 SvxXMLTableImportContext::createFastChildContext(sal_Int32 nElement
,
187 const css::uno::Reference
< css::xml::sax::XFastAttributeList
> & rAttrList
)
189 if( !(IsTokenInNamespace(nElement
, XML_NAMESPACE_DRAW
) ||
190 IsTokenInNamespace(nElement
, XML_NAMESPACE_DRAW_OOO
) ))
193 std::vector
<std::pair
<sal_Int32
, OString
>> aTmpAttrList
;
194 for (auto& aIter
: sax_fastparser::castToFastAttributeList( rAttrList
))
195 aTmpAttrList
.push_back({aIter
.getToken(), OString(aIter
.toCString())});
197 (SvxXMLTableImportContextEnum::Dash
== meContext
|| SvxXMLTableImportContextEnum::Hatch
== meContext
||
198 SvxXMLTableImportContextEnum::Bitmap
== meContext
) )
200 for( auto & aIter
: aTmpAttrList
)
202 sal_Int32 aLocalAttr
= aIter
.first
& TOKEN_MASK
;
203 if( aIter
.first
== XML_ELEMENT(XLINK
, XML_HREF
) &&
204 SvxXMLTableImportContextEnum::Bitmap
== meContext
)
206 OString
& rValue
= aIter
.second
;
207 if( !rValue
.isEmpty() && '#' == rValue
[0] )
208 rValue
= rValue
.copy( 1 );
210 else if( (IsTokenInNamespace(aIter
.first
, XML_NAMESPACE_DRAW
) || IsTokenInNamespace(aIter
.first
, XML_NAMESPACE_DRAW_OOO
)) &&
211 ( ( SvxXMLTableImportContextEnum::Dash
== meContext
&&
212 ( aLocalAttr
== XML_DOTS1_LENGTH
||
213 aLocalAttr
== XML_DOTS2_LENGTH
||
214 aLocalAttr
== XML_DISTANCE
) ) ||
215 ( SvxXMLTableImportContextEnum::Hatch
== meContext
&&
216 ( aLocalAttr
== XML_DISTANCE
) ) ) )
218 OString
& rValue
= aIter
.second
;
219 sal_Int32 nPos
= rValue
.getLength();
220 while( nPos
&& rValue
[nPos
-1] <= ' ' )
223 ('c'==rValue
[nPos
-2] || 'C'==rValue
[nPos
-2]) &&
224 ('h'==rValue
[nPos
-1] || 'H'==rValue
[nPos
-1]) )
226 rValue
= rValue
.copy( 0, nPos
-2 );
232 if (nElement
== XML_ELEMENT(DRAW
, XML_GRADIENT
))
234 // MCGR: for Gradients, no longer use fixed import but use an own
235 // ImportContext to be able to import now possible sub-entries like
237 return new XMLGradientHelperContext( GetImport(), rAttrList
, mxTable
);
242 rtl::Reference
<sax_fastparser::FastAttributeList
> xFastList
= new sax_fastparser::FastAttributeList(nullptr);
243 for (const auto& aIter
: aTmpAttrList
)
244 xFastList
->add(aIter
.first
, aIter
.second
);
251 case SvxXMLTableImportContextEnum::Color
:
252 importColor( xFastList
, aAny
, aName
);
254 case SvxXMLTableImportContextEnum::Marker
:
255 importMarker( xFastList
, aAny
, aName
);
257 case SvxXMLTableImportContextEnum::Dash
:
258 importDash( xFastList
, aAny
, aName
);
260 case SvxXMLTableImportContextEnum::Hatch
:
261 importHatch( xFastList
, aAny
, aName
);
263 case SvxXMLTableImportContextEnum::Bitmap
:
264 importBitmap( xFastList
, aAny
, aName
);
267 // SvxXMLTableImportContextEnum::Gradient
268 // is no longer imported as 'fixed content'
269 // but dynamically using an own ImportContext
273 if( !aName
.isEmpty() && aAny
.hasValue() )
275 if( mxTable
->hasByName( aName
) )
277 mxTable
->replaceByName( aName
, aAny
);
281 mxTable
->insertByName( aName
, aAny
);
285 catch (const uno::Exception
&)
287 DBG_UNHANDLED_EXCEPTION("svx");
289 return new SvXMLImportContext( GetImport() );
292 void SvxXMLTableImportContext::importColor( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
)
294 for (auto& aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
296 switch (aIter
.getToken())
298 case XML_ELEMENT(DRAW
, XML_NAME
):
299 case XML_ELEMENT(DRAW_OOO
, XML_NAME
):
300 rName
= aIter
.toString();
302 case XML_ELEMENT(DRAW
, XML_COLOR
):
303 case XML_ELEMENT(DRAW_OOO
, XML_COLOR
):
306 ::sax::Converter::convertColor(nColor
, aIter
.toView());
311 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
316 void SvxXMLTableImportContext::importMarker( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
)
320 XMLMarkerStyleImport
aMarkerStyle( GetImport() );
321 aMarkerStyle
.importXML( xAttrList
, rAny
, rName
);
323 catch (const Exception
&)
325 TOOLS_WARN_EXCEPTION("svx", "");
329 void SvxXMLTableImportContext::importDash( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
)
333 XMLDashStyleImport
aDashStyle( GetImport() );
334 aDashStyle
.importXML( xAttrList
, rAny
, rName
);
336 catch (const Exception
&)
338 TOOLS_WARN_EXCEPTION("svx", "");
342 void SvxXMLTableImportContext::importHatch( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
)
346 XMLHatchStyleImport
aHatchStyle( GetImport() );
347 aHatchStyle
.importXML( xAttrList
, rAny
, rName
);
349 catch (const Exception
&)
351 TOOLS_WARN_EXCEPTION("svx", "");
355 void SvxXMLTableImportContext::importBitmap( const uno::Reference
< XFastAttributeList
>& xAttrList
, Any
& rAny
, OUString
& rName
)
359 uno::Any aGraphicAny
;
360 XMLImageStyle::importXML(xAttrList
, aGraphicAny
, rName
, GetImport());
361 if (aGraphicAny
.has
<uno::Reference
<graphic::XGraphic
>>())
363 auto xGraphic
= aGraphicAny
.get
<uno::Reference
<graphic::XGraphic
>>();
364 uno::Reference
<awt::XBitmap
> xBitmap(xGraphic
, uno::UNO_QUERY
);
369 catch (const Exception
&)
371 TOOLS_WARN_EXCEPTION("svx", "");
376 SvxXMLXTableImport::SvxXMLXTableImport(
377 const css::uno::Reference
< css::uno::XComponentContext
>& rContext
,
378 const uno::Reference
< XNameContainer
> & rTable
,
379 uno::Reference
<XGraphicStorageHandler
> const & xGraphicStorageHandler
)
380 : SvXMLImport(rContext
, "", SvXMLImportFlags::NONE
),
383 SetGraphicStorageHandler(xGraphicStorageHandler
);
385 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO
), GetXMLToken(XML_N_OOO
), XML_NAMESPACE_OOO
);
386 GetNamespaceMap().Add( GetXMLToken(XML_NP_OFFICE
), GetXMLToken(XML_N_OFFICE
), XML_NAMESPACE_OFFICE
);
387 GetNamespaceMap().Add( GetXMLToken(XML_NP_DRAW
), GetXMLToken(XML_N_DRAW
), XML_NAMESPACE_DRAW
);
388 GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK
), GetXMLToken(XML_N_XLINK
), XML_NAMESPACE_XLINK
);
390 GetNamespaceMap().Add( "__ooo", GetXMLToken(XML_N_OOO
), XML_NAMESPACE_OOO
);
391 GetNamespaceMap().Add( "__xlink", GetXMLToken(XML_N_XLINK
), XML_NAMESPACE_XLINK
);
393 // OOo namespaces for reading OOo 1.1 files
394 GetNamespaceMap().Add( "___office",
395 GetXMLToken(XML_N_OFFICE_OOO
),
396 XML_NAMESPACE_OFFICE
);
397 GetNamespaceMap().Add( "___draw",
398 GetXMLToken(XML_N_DRAW_OOO
),
399 XML_NAMESPACE_DRAW
);
400 GetNamespaceMap().Add( "___loext",
401 GetXMLToken(XML_N_LO_EXT
),
402 XML_NAMESPACE_LO_EXT
);
405 SvxXMLXTableImport::~SvxXMLXTableImport() noexcept
409 static void openStorageStream( xml::sax::InputSource
*pParserInput
,
410 rtl::Reference
<SvXMLGraphicHelper
>& rxGraphicHelper
,
411 const uno::Reference
< embed::XStorage
>& xStorage
)
413 uno::Reference
< io::XStream
> xIStm( xStorage
->openStreamElement( "Content.xml", embed::ElementModes::READ
), uno::UNO_SET_THROW
);
414 pParserInput
->aInputStream
= xIStm
->getInputStream();
415 rxGraphicHelper
= SvXMLGraphicHelper::Create( xStorage
, SvXMLGraphicHelperMode::Read
);
418 bool SvxXMLXTableImport::load( const OUString
&rPath
, const OUString
&rReferer
,
419 const uno::Reference
< embed::XStorage
> &xStorage
,
420 const uno::Reference
< XNameContainer
>& xTable
,
421 bool *bOptLoadedFromStorage
) noexcept
424 rtl::Reference
<SvXMLGraphicHelper
> xGraphicHelper
;
426 INetURLObject
aURLObj( rPath
);
427 bool bUseStorage
= aURLObj
.GetProtocol() == INetProtocol::NotValid
; // a relative path
431 uno::Reference
<uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
433 xml::sax::InputSource aParserInput
;
434 comphelper::LifecycleProxy aNasty
;
436 if( !bUseStorage
|| !xStorage
.is() )
438 SfxMedium
aMedium( rPath
, rReferer
, StreamMode::READ
| StreamMode::NOCREATE
);
439 aParserInput
.sSystemId
= aMedium
.GetName();
441 if( aMedium
.IsStorage() )
443 uno::Reference
< embed::XStorage
> xMediumStorage( aMedium
.GetStorage( false ), uno::UNO_SET_THROW
);
444 openStorageStream( &aParserInput
, xGraphicHelper
, xMediumStorage
);
447 aParserInput
.aInputStream
= aMedium
.GetInputStream();
449 else // relative URL into a storage
451 uno::Reference
< embed::XStorage
> xSubStorage
;
454 xSubStorage
= comphelper::OStorageHelper::GetStorageAtPath(
455 xStorage
, rPath
, embed::ElementModes::READ
, aNasty
);
457 catch (const uno::Exception
&)
460 if( xSubStorage
.is() )
461 openStorageStream( &aParserInput
, xGraphicHelper
, xSubStorage
);
464 css::uno::Reference
< css::io::XStream
> xStream
= comphelper::OStorageHelper::GetStreamAtPath(
465 xStorage
, rPath
, embed::ElementModes::READ
, aNasty
);
468 aParserInput
.aInputStream
= xStream
->getInputStream();
470 if( bOptLoadedFromStorage
)
471 *bOptLoadedFromStorage
= true;
474 uno::Reference
<XGraphicStorageHandler
> xGraphicStorageHandler
;
475 if (xGraphicHelper
.is())
476 xGraphicStorageHandler
= xGraphicHelper
.get();
480 uno::Reference
< io::XSeekable
> xSeek( aParserInput
.aInputStream
, uno::UNO_QUERY_THROW
);
483 catch (const uno::Exception
&)
487 rtl::Reference
<SvxXMLXTableImport
> xImport(new SvxXMLXTableImport(xContext
, xTable
, xGraphicStorageHandler
));
488 xImport
->parseStream( aParserInput
);
491 xGraphicHelper
->dispose();
495 // thrown each time you load a document with property tables that are not
496 // on the current machine. FIXME: would be better to check a file exists
497 // before importing ...
504 SvXMLImportContext
*SvxXMLXTableImport::CreateFastContext( sal_Int32 nElement
,
505 const ::css::uno::Reference
< ::css::xml::sax::XFastAttributeList
>& /*xAttrList*/ )
507 if( IsTokenInNamespace(nElement
, XML_NAMESPACE_OOO
) ||
508 IsTokenInNamespace(nElement
, XML_NAMESPACE_OFFICE
) ||
509 IsTokenInNamespace(nElement
, XML_NAMESPACE_OFFICE_OOO
) )
511 bool bOOoFormat
= IsTokenInNamespace(nElement
, XML_NAMESPACE_OFFICE
) ||
512 IsTokenInNamespace(nElement
, XML_NAMESPACE_OFFICE_OOO
);
513 Type aType
= mrTable
->getElementType();
514 sal_Int32 nToken
= nElement
& TOKEN_MASK
;
516 if ( nToken
== XML_COLOR_TABLE
)
518 if( aType
== ::cppu::UnoType
<sal_Int32
>::get() )
519 return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Color
, mrTable
, bOOoFormat
);
521 else if ( nToken
== XML_MARKER_TABLE
)
523 if( aType
== cppu::UnoType
<drawing::PolyPolygonBezierCoords
>::get())
524 return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Marker
, mrTable
, bOOoFormat
);
526 else if ( nToken
== XML_DASH_TABLE
)
528 if( aType
== cppu::UnoType
<drawing::LineDash
>::get())
529 return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Dash
, mrTable
, bOOoFormat
);
531 else if ( nToken
== XML_HATCH_TABLE
)
533 if( aType
== cppu::UnoType
<drawing::Hatch
>::get())
534 return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Hatch
, mrTable
, bOOoFormat
);
536 else if ( nToken
== XML_GRADIENT_TABLE
)
538 if( aType
== cppu::UnoType
<awt::Gradient
>::get())
539 return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Gradient
, mrTable
, bOOoFormat
);
541 else if ( nToken
== XML_BITMAP_TABLE
)
543 if( aType
== ::cppu::UnoType
<awt::XBitmap
>::get())
544 return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Bitmap
, mrTable
, bOOoFormat
);
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */