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 <vcl/errinf.hxx>
21 #include <sal/log.hxx>
22 #include <com/sun/star/container/XChild.hpp>
23 #include <com/sun/star/beans/XPropertySetInfo.hpp>
24 #include <com/sun/star/embed/ElementModes.hpp>
25 #include <com/sun/star/xml/sax/SAXParseException.hpp>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/propertysequence.hxx>
28 #include <editeng/outlobj.hxx>
29 #include <sfx2/docfile.hxx>
30 #include <sfx2/docfilt.hxx>
31 #include <sfx2/sfxsids.hrc>
32 #include <sot/storage.hxx>
33 #include <drawdoc.hxx>
35 #include <Outliner.hxx>
36 #include <unotools/streamwrap.hxx>
37 #include <svx/dialmgr.hxx>
38 #include <svx/strings.hrc>
39 #include <svx/xmlgrhlp.hxx>
41 #include <DrawDocShell.hxx>
43 #include <sdxmlwrp.hxx>
44 #include <svx/xmleohlp.hxx>
45 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
46 #include <com/sun/star/xml/sax/XFastParser.hpp>
47 #include <com/sun/star/document/XFilter.hpp>
48 #include <com/sun/star/document/XImporter.hpp>
49 #include <com/sun/star/document/XExporter.hpp>
50 #include <com/sun/star/lang/XInitialization.hpp>
51 #include <com/sun/star/lang/XServiceInfo.hpp>
52 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
53 #include <com/sun/star/beans/PropertyAttribute.hpp>
54 #include <com/sun/star/packages/WrongPasswordException.hpp>
55 #include <com/sun/star/packages/zip/ZipIOException.hpp>
57 #include <com/sun/star/xml/sax/InputSource.hpp>
58 #include <com/sun/star/xml/sax/Parser.hpp>
59 #include <com/sun/star/xml/sax/Writer.hpp>
60 #include <com/sun/star/io/XActiveDataSource.hpp>
61 #include <comphelper/genericpropertyset.hxx>
62 #include <comphelper/propertysetinfo.hxx>
63 #include <editeng/eeitem.hxx>
64 #include <unotools/saveopt.hxx>
66 // include necessary for XML progress bar at load time
67 #include <svl/itemset.hxx>
68 #include <svl/stritem.hxx>
69 #include <svtools/sfxecode.hxx>
72 #include <sderror.hxx>
73 #include <sdresid.hxx>
74 #include "sdtransform.hxx"
75 #include <strings.hrc>
77 #include <sfx2/frame.hxx>
78 #include <tools/diagnose_ex.h>
80 using namespace com::sun::star
;
81 using namespace com::sun::star::uno
;
82 using namespace com::sun::star::lang
;
83 using namespace com::sun::star::document
;
84 using namespace comphelper
;
86 #define SD_XML_READERROR ErrCode(1234)
88 char const sXML_export_impress_meta_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisMetaExporter";
89 char const sXML_export_impress_styles_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisStylesExporter";
90 char const sXML_export_impress_content_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisContentExporter";
91 char const sXML_export_impress_settings_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisSettingsExporter";
93 char const sXML_export_draw_meta_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisMetaExporter";
94 char const sXML_export_draw_styles_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisStylesExporter";
95 char const sXML_export_draw_content_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisContentExporter";
96 char const sXML_export_draw_settings_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisSettingsExporter";
98 char const sXML_import_impress_meta_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisMetaImporter";
99 char const sXML_import_impress_styles_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisStylesImporter";
100 char const sXML_import_impress_content_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisContentImporter";
101 char const sXML_import_impress_settings_oasis_service
[] = "com.sun.star.comp.Impress.XMLOasisSettingsImporter";
103 char const sXML_import_draw_meta_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisMetaImporter";
104 char const sXML_import_draw_styles_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisStylesImporter";
105 char const sXML_import_draw_content_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisContentImporter";
106 char const sXML_import_draw_settings_oasis_service
[] = "com.sun.star.comp.Draw.XMLOasisSettingsImporter";
109 char const sXML_export_impress_meta_ooo_service
[] = "com.sun.star.comp.Impress.XMLMetaExporter";
110 char const sXML_export_impress_styles_ooo_service
[] = "com.sun.star.comp.Impress.XMLStylesExporter";
111 char const sXML_export_impress_content_ooo_service
[] = "com.sun.star.comp.Impress.XMLContentExporter";
112 char const sXML_export_impress_settings_ooo_service
[] = "com.sun.star.comp.Impress.XMLSettingsExporter";
114 char const sXML_export_draw_meta_ooo_service
[] = "com.sun.star.comp.Draw.XMLMetaExporter";
115 char const sXML_export_draw_styles_ooo_service
[] = "com.sun.star.comp.Draw.XMLStylesExporter";
116 char const sXML_export_draw_content_ooo_service
[] = "com.sun.star.comp.Draw.XMLContentExporter";
117 char const sXML_export_draw_settings_ooo_service
[] = "com.sun.star.comp.Draw.XMLSettingsExporter";
119 char const sXML_import_impress_meta_ooo_service
[] = "com.sun.star.comp.Impress.XMLMetaImporter";
120 char const sXML_import_impress_styles_ooo_service
[] = "com.sun.star.comp.Impress.XMLStylesImporter";
121 char const sXML_import_impress_content_ooo_service
[] = "com.sun.star.comp.Impress.XMLContentImporter";
122 char const sXML_import_impress_settings_ooo_service
[] = "com.sun.star.comp.Impress.XMLSettingsImporter";
124 char const sXML_import_draw_meta_ooo_service
[] = "com.sun.star.comp.Draw.XMLMetaImporter";
125 char const sXML_import_draw_styles_ooo_service
[] = "com.sun.star.comp.Draw.XMLStylesImporter";
126 char const sXML_import_draw_content_ooo_service
[] = "com.sun.star.comp.Draw.XMLContentImporter";
127 char const sXML_import_draw_settings_ooo_service
[] = "com.sun.star.comp.Draw.XMLSettingsImporter";
129 struct XML_SERVICEMAP
131 const sal_Char
* mpService
;
132 const sal_Char
* mpStream
;
137 const sal_Char
* mpMeta
;
138 const sal_Char
* mpStyles
;
139 const sal_Char
* mpContent
;
140 const sal_Char
* mpSettings
;
143 static XML_SERVICES
const * getServices( bool bImport
, bool bDraw
, sal_uLong nStoreVer
)
145 static XML_SERVICES
const gServices
[] =
147 { sXML_export_impress_meta_oasis_service
, sXML_export_impress_styles_oasis_service
, sXML_export_impress_content_oasis_service
, sXML_export_impress_settings_oasis_service
},
148 { sXML_export_draw_meta_oasis_service
, sXML_export_draw_styles_oasis_service
, sXML_export_draw_content_oasis_service
, sXML_export_draw_settings_oasis_service
},
149 { sXML_import_impress_meta_oasis_service
, sXML_import_impress_styles_oasis_service
, sXML_import_impress_content_oasis_service
, sXML_import_impress_settings_oasis_service
},
150 { sXML_import_draw_meta_oasis_service
, sXML_import_draw_styles_oasis_service
, sXML_import_draw_content_oasis_service
, sXML_import_draw_settings_oasis_service
},
152 { sXML_export_impress_meta_ooo_service
, sXML_export_impress_styles_ooo_service
, sXML_export_impress_content_ooo_service
, sXML_export_impress_settings_ooo_service
},
153 { sXML_export_draw_meta_ooo_service
, sXML_export_draw_styles_ooo_service
, sXML_export_draw_content_ooo_service
, sXML_export_draw_settings_ooo_service
},
154 { sXML_import_impress_meta_ooo_service
, sXML_import_impress_styles_ooo_service
, sXML_import_impress_content_ooo_service
, sXML_import_impress_settings_ooo_service
},
155 { sXML_import_draw_meta_ooo_service
, sXML_import_draw_styles_ooo_service
, sXML_import_draw_content_ooo_service
, sXML_import_draw_settings_ooo_service
},
158 return &gServices
[ (bImport
? 2 : 0) + ((nStoreVer
== SOFFICE_FILEFORMAT_60
) ? 4 : 0) + (bDraw
? 1 : 0 ) ];
162 SdXMLFilter::SdXMLFilter( SfxMedium
& rMedium
, ::sd::DrawDocShell
& rDocShell
, SdXMLFilterMode eFilterMode
, sal_uLong nStoreVer
) :
163 SdFilter( rMedium
, rDocShell
), meFilterMode( eFilterMode
), mnStoreVer( nStoreVer
)
167 SdXMLFilter::~SdXMLFilter()
174 ErrCode
ReadThroughComponent(
175 const Reference
<io::XInputStream
>& xInputStream
,
176 const Reference
<XComponent
>& xModelComponent
,
177 const OUString
& rStreamName
,
178 Reference
<uno::XComponentContext
> const & rxContext
,
179 const sal_Char
* pFilterName
,
180 const Sequence
<Any
>& rFilterArguments
,
181 const OUString
& rName
,
182 bool bMustBeSuccessfull
,
185 DBG_ASSERT(xInputStream
.is(), "input stream missing");
186 DBG_ASSERT(xModelComponent
.is(), "document missing");
187 DBG_ASSERT(rxContext
.is(), "factory missing");
188 DBG_ASSERT(nullptr != pFilterName
,"I need a service name for the component!");
190 SAL_INFO( "sd.filter", "ReadThroughComponent" );
192 // prepare ParserInputSrouce
193 xml::sax::InputSource aParserInput
;
194 aParserInput
.sSystemId
= rName
;
195 aParserInput
.aInputStream
= xInputStream
;
198 Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create(rxContext
);
199 SAL_INFO( "sd.filter", "parser created" );
202 OUString
aFilterName(OUString::createFromAscii(pFilterName
));
203 Reference
< xml::sax::XDocumentHandler
> xFilter(
204 rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(aFilterName
, rFilterArguments
, rxContext
),
206 SAL_WARN_IF(!xFilter
.is(), "sd.filter", "Can't instantiate filter component: " << aFilterName
);
208 return SD_XML_READERROR
;
209 SAL_INFO( "sd.filter", "" << pFilterName
<< " created" );
211 // connect parser and filter
212 xParser
->setDocumentHandler( xFilter
);
214 // connect model and filter
215 Reference
< XImporter
> xImporter( xFilter
, UNO_QUERY
);
216 xImporter
->setTargetDocument( xModelComponent
);
218 uno::Reference
< xml::sax::XFastParser
> xFastParser
= dynamic_cast<
219 xml::sax::XFastParser
* >( xFilter
.get() );
221 // finally, parser the stream
222 SAL_INFO( "sd.filter", "parsing stream" );
225 if( xFastParser
.is() )
226 xFastParser
->parseStream( aParserInput
);
228 xParser
->parseStream( aParserInput
);
230 catch (const xml::sax::SAXParseException
& r
)
232 css::uno::Any
ex( cppu::getCaughtException() );
233 // sax parser sends wrapped exceptions,
234 // try to find the original one
235 xml::sax::SAXException aSaxEx
= *static_cast<xml::sax::SAXException
const *>(&r
);
236 bool bTryChild
= true;
240 xml::sax::SAXException aTmp
;
241 if ( aSaxEx
.WrappedException
>>= aTmp
)
247 packages::zip::ZipIOException aBrokenPackage
;
248 if ( aSaxEx
.WrappedException
>>= aBrokenPackage
)
249 return ERRCODE_IO_BROKENPACKAGE
;
252 return ERRCODE_SFX_WRONGPASSWORD
;
254 SAL_WARN( "sd.filter", "SAX parse exception caught while importing: " << exceptionToString(ex
));
256 OUString
sErr( OUString::number( r
.LineNumber
));
258 sErr
+= OUString::number( r
.ColumnNumber
);
260 if (!rStreamName
.isEmpty())
262 return *new TwoStringErrorInfo(
263 (bMustBeSuccessfull
? ERR_FORMAT_FILE_ROWCOL
264 : WARN_FORMAT_FILE_ROWCOL
),
266 DialogMask::ButtonsOk
| DialogMask::MessageError
);
270 DBG_ASSERT( bMustBeSuccessfull
, "Warnings are not supported" );
271 return *new StringErrorInfo( ERR_FORMAT_ROWCOL
, sErr
,
272 DialogMask::ButtonsOk
| DialogMask::MessageError
);
275 catch (const xml::sax::SAXException
& r
)
277 css::uno::Any
ex( cppu::getCaughtException() );
278 packages::zip::ZipIOException aBrokenPackage
;
279 if ( r
.WrappedException
>>= aBrokenPackage
)
280 return ERRCODE_IO_BROKENPACKAGE
;
283 return ERRCODE_SFX_WRONGPASSWORD
;
285 SAL_WARN( "sd.filter", "SAX exception caught while importing: " << exceptionToString(ex
));
286 return SD_XML_READERROR
;
288 catch (const packages::zip::ZipIOException
&)
290 css::uno::Any
ex( cppu::getCaughtException() );
291 SAL_WARN( "sd.filter", "Zip exception caught while importing: " << exceptionToString(ex
));
292 return ERRCODE_IO_BROKENPACKAGE
;
294 catch (const io::IOException
&)
296 css::uno::Any
ex( cppu::getCaughtException() );
297 SAL_WARN( "sd.filter", "IO exception caught while importing: " << exceptionToString(ex
));
298 return SD_XML_READERROR
;
300 catch (const uno::Exception
&)
302 css::uno::Any
ex( cppu::getCaughtException() );
303 SAL_WARN( "sd.filter", "uno exception caught while importing: " << exceptionToString(ex
));
304 return SD_XML_READERROR
;
311 ErrCode
ReadThroughComponent(
312 const uno::Reference
< embed::XStorage
>& xStorage
,
313 const Reference
<XComponent
>& xModelComponent
,
314 const sal_Char
* pStreamName
,
315 const sal_Char
* pCompatibilityStreamName
,
316 Reference
<uno::XComponentContext
> const & rxContext
,
317 const sal_Char
* pFilterName
,
318 const Sequence
<Any
>& rFilterArguments
,
319 const OUString
& rName
,
320 bool bMustBeSuccessfull
)
322 DBG_ASSERT(xStorage
.is(), "Need storage!");
323 DBG_ASSERT(nullptr != pStreamName
, "Please, please, give me a name!");
325 // open stream (and set parser input)
326 OUString sStreamName
= OUString::createFromAscii(pStreamName
);
327 bool bContainsStream
= false;
330 bContainsStream
= xStorage
->isStreamElement(sStreamName
);
332 catch (const container::NoSuchElementException
&)
336 if (!bContainsStream
)
338 // stream name not found! Then try the compatibility name.
339 // if no stream can be opened, return immediately with OK signal
341 // do we even have an alternative name?
342 if ( nullptr == pCompatibilityStreamName
)
345 // if so, does the stream exist?
346 sStreamName
= OUString::createFromAscii(pCompatibilityStreamName
);
349 bContainsStream
= xStorage
->isStreamElement(sStreamName
);
351 catch (const container::NoSuchElementException
&)
355 if (! bContainsStream
)
360 uno::Reference
< beans::XPropertySet
> xInfoSet
;
361 if( rFilterArguments
.hasElements() )
362 rFilterArguments
.getConstArray()[0] >>= xInfoSet
;
363 DBG_ASSERT( xInfoSet
.is(), "missing property set" );
366 xInfoSet
->setPropertyValue( "StreamName", makeAny( sStreamName
) );
372 Reference
<io::XStream
> xStream
=
373 xStorage
->openStreamElement( sStreamName
, embed::ElementModes::READ
);
374 Reference
<beans::XPropertySet
> xProps( xStream
, uno::UNO_QUERY
);
375 if ( !xStream
.is() || ! xProps
.is() )
376 return SD_XML_READERROR
;
378 Any aAny
= xProps
->getPropertyValue( "Encrypted" );
380 bool bEncrypted
= false;
383 Reference
<io::XInputStream
> xInputStream
= xStream
->getInputStream();
385 // read from the stream
386 return ReadThroughComponent(
387 xInputStream
, xModelComponent
, sStreamName
, rxContext
,
388 pFilterName
, rFilterArguments
,
389 rName
, bMustBeSuccessfull
, bEncrypted
);
391 catch (const packages::WrongPasswordException
&)
393 return ERRCODE_SFX_WRONGPASSWORD
;
395 catch (const packages::zip::ZipIOException
&)
397 return ERRCODE_IO_BROKENPACKAGE
;
399 catch (const uno::Exception
&)
402 return SD_XML_READERROR
;
407 //PRESOBJ_OUTLINEs in master pages are the preview of the outline styles
408 //numbering format. Since fdo#78151 toggling bullets on and off changes
409 //the style they are a preview of, previously toggling bullets on and off
410 //would only affect the preview paragraph itself without an effect on the
411 //style. i.e. previews of numbering which don't match the real numbering
412 //they are supposed to be a preview of.
414 //But there exist documents which were saved previous to that modification
415 //so here we detect such cases and fix them up to ensure the previews
416 //numbering level matches that of the outline level it previews
417 static void fixupOutlinePlaceholderNumberingDepths(SdDrawDocument
* pDoc
)
419 for (sal_uInt16 i
= 0; i
< pDoc
->GetMasterSdPageCount(PageKind::Standard
); ++i
)
421 SdPage
*pMasterPage
= pDoc
->GetMasterSdPage(i
, PageKind::Standard
);
422 SdrObject
* pMasterOutline
= pMasterPage
->GetPresObj(PRESOBJ_OUTLINE
);
425 OutlinerParaObject
* pOutlParaObj
= pMasterOutline
->GetOutlinerParaObject();
428 SdOutliner
* pOutliner
= pDoc
->GetInternalOutliner();
430 pOutliner
->SetText(*pOutlParaObj
);
431 bool bInconsistent
= false;
432 const sal_Int32 nParaCount
= pOutliner
->GetParagraphCount();
433 for (sal_Int32 j
= 0; j
< nParaCount
; ++j
)
435 //Make sure the depth of the paragraph matches that of the outline style it previews
436 const sal_Int16 nExpectedDepth
= j
;
437 if (nExpectedDepth
!= pOutliner
->GetDepth(j
))
439 Paragraph
* p
= pOutliner
->GetParagraph(j
);
440 pOutliner
->SetDepth(p
, nExpectedDepth
);
441 bInconsistent
= true;
444 //If the preview has hard-coded bullets/numbering then they must
445 //be stripped to reveal the true underlying styles attributes
446 SfxItemSet
aAttrs(pOutliner
->GetParaAttribs(j
));
447 if (aAttrs
.GetItemState(EE_PARA_NUMBULLET
) == SfxItemState::SET
)
449 aAttrs
.ClearItem(EE_PARA_NUMBULLET
);
450 pOutliner
->SetParaAttribs(j
, aAttrs
);
451 bInconsistent
= true;
457 SAL_WARN("sd.filter", "Fixing inconsistent outline numbering placeholder preview");
458 pMasterOutline
->SetOutlinerParaObject(pOutliner
->CreateParaObject(0, nParaCount
));
464 bool SdXMLFilter::Import( ErrCode
& nError
)
466 ErrCode nRet
= ERRCODE_NONE
;
468 // Get service factory
469 Reference
< uno::XComponentContext
> rxContext
=
470 comphelper::getProcessComponentContext();
472 SdDrawDocument
* pDoc
= mrDocShell
.GetDoc();
473 bool const bWasUndo(pDoc
->IsUndoEnabled());
474 pDoc
->EnableUndo(false);
475 pDoc
->NewOrLoadCompleted( NEW_DOC
);
476 pDoc
->CreateFirstPages();
477 pDoc
->StopWorkStartupDelay();
479 mxModel
->lockControllers();
481 /** property map for import info set */
482 PropertyMapEntry
const aImportInfoMap
[] =
484 // necessary properties for XML progress bar at load time
485 { OUString("ProgressRange"), 0, cppu::UnoType
<sal_Int32
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
486 { OUString("ProgressMax"), 0, cppu::UnoType
<sal_Int32
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
487 { OUString("ProgressCurrent"), 0, cppu::UnoType
<sal_Int32
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
488 { OUString("Preview"), 0, cppu::UnoType
<sal_Bool
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
489 { OUString("PageLayouts"), 0, cppu::UnoType
<container::XNameAccess
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
490 { OUString("PrivateData"), 0, cppu::UnoType
<XInterface
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
491 { OUString("BaseURI"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
492 { OUString("StreamRelPath"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
493 { OUString("StreamName"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
494 { OUString("BuildId"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
495 { OUString("OrganizerMode"), 0, cppu::UnoType
<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
496 { OUString("SourceStorage"), 0, cppu::UnoType
<embed::XStorage
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
497 { OUString(), 0, css::uno::Type(), 0, 0 }
500 uno::Reference
< beans::XPropertySet
> xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aImportInfoMap
) ) );
501 xInfoSet
->setPropertyValue( "Preview" , uno::makeAny( mrDocShell
.GetDoc()->IsStarDrawPreviewMode() ) );
503 // ---- get BuildId from parent container if available
505 uno::Reference
< container::XChild
> xChild( mxModel
, uno::UNO_QUERY
);
508 uno::Reference
< beans::XPropertySet
> xParentSet( xChild
->getParent(), uno::UNO_QUERY
);
509 if( xParentSet
.is() )
511 uno::Reference
< beans::XPropertySetInfo
> xPropSetInfo( xParentSet
->getPropertySetInfo() );
512 OUString
sPropName( "BuildId" );
513 if( xPropSetInfo
.is() && xPropSetInfo
->hasPropertyByName(sPropName
) )
515 xInfoSet
->setPropertyValue( sPropName
, xParentSet
->getPropertyValue(sPropName
) );
520 uno::Reference
<document::XGraphicStorageHandler
> xGraphicStorageHandler
;
521 rtl::Reference
<SvXMLGraphicHelper
> xGraphicHelper
;
522 Reference
< document::XEmbeddedObjectResolver
> xObjectResolver
;
523 rtl::Reference
<SvXMLEmbeddedObjectHelper
> xObjectHelper
;
525 Reference
< lang::XComponent
> xModelComp( mxModel
, uno::UNO_QUERY
);
527 // try to get an XStatusIndicator from the Medium
529 SfxItemSet
* pSet
= mrMedium
.GetItemSet();
532 const SfxUnoAnyItem
* pItem
= static_cast<const SfxUnoAnyItem
*>(
533 pSet
->GetItem(SID_PROGRESS_STATUSBAR_CONTROL
) );
536 pItem
->GetValue() >>= mxStatusIndicator
;
540 if(mxStatusIndicator
.is())
542 sal_Int32
nProgressRange(1000000);
543 OUString
aMsg(SvxResId(RID_SVXSTR_DOC_LOAD
));
544 mxStatusIndicator
->start(aMsg
, nProgressRange
);
548 aProgRange
<<= nProgressRange
;
549 xInfoSet
->setPropertyValue( "ProgressRange" , aProgRange
);
551 // set ProgressCurrent
552 uno::Any aProgCurrent
;
553 aProgCurrent
<<= sal_Int32(0);
554 xInfoSet
->setPropertyValue( "ProgressCurrent" , aProgCurrent
);
558 // get the input stream (storage or stream)
560 tools::SvRef
<SotStorageStream
> xDocStream
;
561 uno::Reference
< embed::XStorage
> xStorage
= mrMedium
.GetStorage();
563 xInfoSet
->setPropertyValue( "SourceStorage", Any( xStorage
) );
566 nRet
= SD_XML_READERROR
;
568 if( ERRCODE_NONE
== nRet
)
570 xGraphicHelper
= SvXMLGraphicHelper::Create( xStorage
,
571 SvXMLGraphicHelperMode::Read
);
572 xGraphicStorageHandler
= xGraphicHelper
.get();
573 xObjectHelper
= SvXMLEmbeddedObjectHelper::Create(
574 xStorage
, *pDoc
->GetPersist(),
575 SvXMLEmbeddedObjectHelperMode::Read
);
576 xObjectResolver
= xObjectHelper
.get();
580 OUString
const baseURI(mrMedium
.GetBaseURL());
581 // needed for relative URLs, but in clipboard copy/paste there may be none
582 SAL_INFO_IF(baseURI
.isEmpty(), "sd.filter", "SdXMLFilter: no base URL");
583 xInfoSet
->setPropertyValue("BaseURI", makeAny(baseURI
));
585 if( ERRCODE_NONE
== nRet
&& SfxObjectCreateMode::EMBEDDED
== mrDocShell
.GetCreateMode() )
588 if ( mrMedium
.GetItemSet() )
590 const SfxStringItem
* pDocHierarchItem
= static_cast<const SfxStringItem
*>(
591 mrMedium
.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME
) );
592 if ( pDocHierarchItem
)
593 aName
= pDocHierarchItem
->GetValue();
596 aName
= "dummyObjectName" ;
598 if( !aName
.isEmpty() )
599 xInfoSet
->setPropertyValue( "StreamRelPath", Any( aName
) );
602 if (SDXMLMODE_Organizer
== meFilterMode
)
603 xInfoSet
->setPropertyValue("OrganizerMode", uno::makeAny(true));
605 if( ERRCODE_NONE
== nRet
)
608 // prepare filter arguments
609 Sequence
<Any
> aFilterArgs( 4 );
610 Any
*pArgs
= aFilterArgs
.getArray();
611 *pArgs
++ <<= xInfoSet
;
612 *pArgs
++ <<= xGraphicStorageHandler
;
613 *pArgs
++ <<= xObjectResolver
;
614 *pArgs
++ <<= mxStatusIndicator
;
616 Sequence
<Any
> aEmptyArgs( 2 );
617 pArgs
= aEmptyArgs
.getArray();
618 *pArgs
++ <<= xInfoSet
;
619 *pArgs
++ <<= mxStatusIndicator
;
621 const OUString
aName( mrMedium
.GetName() );
623 XML_SERVICES
const * pServices
= getServices( true, IsDraw(), mnStoreVer
);
625 ErrCode nWarn
= ERRCODE_NONE
;
626 ErrCode nWarn2
= ERRCODE_NONE
;
627 // read storage streams
628 // #i103539#: always read meta.xml for generator
629 nWarn
= ReadThroughComponent(
630 xStorage
, xModelComp
, "meta.xml", "Meta.xml", rxContext
,
632 aEmptyArgs
, aName
, false );
634 if( meFilterMode
!= SDXMLMODE_Organizer
)
636 nWarn2
= ReadThroughComponent(
637 xStorage
, xModelComp
, "settings.xml", nullptr, rxContext
,
638 pServices
->mpSettings
,
639 aFilterArgs
, aName
, false );
642 nRet
= ReadThroughComponent(
643 xStorage
, xModelComp
, "styles.xml", nullptr, rxContext
,
645 aFilterArgs
, aName
, true );
647 if( !nRet
&& (meFilterMode
!= SDXMLMODE_Organizer
) )
648 nRet
= ReadThroughComponent(
649 xStorage
, xModelComp
, "content.xml", "Content.xml", rxContext
,
650 pServices
->mpContent
,
651 aFilterArgs
, aName
, true );
663 xGraphicHelper
->dispose();
664 xGraphicHelper
.clear();
665 xGraphicStorageHandler
= nullptr;
666 if( xObjectHelper
.is() )
667 xObjectHelper
->dispose();
668 xObjectHelper
.clear();
669 xObjectResolver
= nullptr;
671 if( mxStatusIndicator
.is() )
672 mxStatusIndicator
->end();
675 mxModel
->unlockControllers();
677 if( nRet
== ERRCODE_NONE
)
678 pDoc
->UpdateAllLinks();
680 if( nRet
.anyOf( ERRCODE_NONE
, SD_XML_READERROR
) )
682 else if( nRet
== ERRCODE_IO_BROKENPACKAGE
&& xStorage
.is() )
683 nError
= ERRCODE_IO_BROKENPACKAGE
;
686 // TODO/LATER: this is completely wrong! Filter code should never call ErrorHandler directly!
687 ErrorHandler::HandleError( nRet
);
688 if( nRet
.IsWarning() )
692 // clear unused named items from item pool
694 uno::Reference
< lang::XMultiServiceFactory
> xModelFactory( mxModel
, uno::UNO_QUERY
);
695 if( xModelFactory
.is() )
699 const OUString
aName("~clear~" );
700 uno::Reference
< container::XNameContainer
> xGradient( xModelFactory
->createInstance( "com.sun.star.drawing.GradientTable" ), uno::UNO_QUERY
);
702 xGradient
->removeByName( aName
);
704 uno::Reference
< container::XNameContainer
> xHatch( xModelFactory
->createInstance( "com.sun.star.drawing.HatchTable" ), uno::UNO_QUERY
);
706 xHatch
->removeByName( aName
);
708 uno::Reference
< container::XNameContainer
> xBitmap( xModelFactory
->createInstance( "com.sun.star.drawing.BitmapTable" ), uno::UNO_QUERY
);
710 xBitmap
->removeByName( aName
);
712 uno::Reference
< container::XNameContainer
> xTransGradient( xModelFactory
->createInstance( "com.sun.star.drawing.TransparencyGradientTable" ), uno::UNO_QUERY
);
713 if( xTransGradient
.is() )
714 xTransGradient
->removeByName( aName
);
716 uno::Reference
< container::XNameContainer
> xMarker( xModelFactory
->createInstance( "com.sun.star.drawing.MarkerTable" ), uno::UNO_QUERY
);
718 xMarker
->removeByName( aName
);
720 uno::Reference
< container::XNameContainer
> xDashes( xModelFactory
->createInstance( "com.sun.star.drawing.DashTable" ), uno::UNO_QUERY
);
722 xDashes
->removeByName( aName
);
724 catch (const Exception
&)
726 css::uno::Any
ex( cppu::getCaughtException() );
727 SAL_WARN( "sd.filter","sd::SdXMLFilter::Import(), exception during clearing of unused named items " << exceptionToString(ex
));
731 // set BuildId on XModel for later OLE object loading
734 uno::Reference
< beans::XPropertySet
> xModelSet( mxModel
, uno::UNO_QUERY
);
737 uno::Reference
< beans::XPropertySetInfo
> xModelSetInfo( xModelSet
->getPropertySetInfo() );
738 const OUString
sPropName( "BuildId" );
741 xInfoSet
->getPropertyValue(sPropName
) >>= sBuildId
;
743 if( xModelSetInfo
.is() && xModelSetInfo
->hasPropertyByName(sPropName
) )
745 xModelSet
->setPropertyValue( sPropName
, Any( sBuildId
) );
748 bool bTransform
= false;
750 if( nRet
== ERRCODE_NONE
)
752 if( !sBuildId
.isEmpty() )
754 sal_Int32 nIndex
= sBuildId
.indexOf('$');
757 sal_Int32 nUPD
= sBuildId
.copy( 0, nIndex
).toInt32();
761 sal_Int32 nBuildId
= sBuildId
.copy( nIndex
+1 ).toInt32();
762 if( (nBuildId
> 0) && (nBuildId
< 9316) )
763 bTransform
= true; // treat OOo 3.0 beta1 as OOo 2.x
765 else if( (nUPD
== 680) || ( nUPD
>= 640 && nUPD
<= 645 ) )
771 // check for binary formats
772 std::shared_ptr
<const SfxFilter
> pFilter
= mrMedium
.GetFilter();
775 OUString
typeName(pFilter
->GetRealTypeName());
776 if( typeName
.startsWith( "impress_StarImpress" ) ||
777 typeName
.startsWith( "draw_StarDraw" ) )
786 TransformOOo2xDocument( pDoc
);
790 fixupOutlinePlaceholderNumberingDepths(pDoc
);
792 pDoc
->EnableUndo(bWasUndo
);
793 mrDocShell
.ClearUndoBuffer();
794 return nRet
== ERRCODE_NONE
;
797 bool SdXMLFilter::Export()
799 rtl::Reference
<SvXMLEmbeddedObjectHelper
> xObjectHelper
;
800 rtl::Reference
<SvXMLGraphicHelper
> xGraphicHelper
;
801 bool bDocRet
= false;
805 SAL_WARN( "sd.filter","Got NO Model in XMLExport");
809 bool bLocked
= mxModel
->hasControllersLocked();
813 mxModel
->lockControllers();
815 uno::Reference
< lang::XServiceInfo
> xServiceInfo( mxModel
, uno::UNO_QUERY
);
817 if( !xServiceInfo
.is() || !xServiceInfo
->supportsService( "com.sun.star.drawing.GenericDrawingDocument" ) )
819 SAL_WARN( "sd.filter", "Model is no DrawingDocument in XMLExport" );
823 uno::Reference
<uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
825 uno::Reference
< xml::sax::XWriter
> xWriter
= xml::sax::Writer::create( xContext
);
827 /** property map for export info set */
828 PropertyMapEntry
const aExportInfoMap
[] =
830 { OUString("ProgressRange"), 0, cppu::UnoType
<sal_Int32
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
831 { OUString("ProgressMax"), 0, cppu::UnoType
<sal_Int32
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
832 { OUString("ProgressCurrent"), 0, cppu::UnoType
<sal_Int32
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
833 { OUString("UsePrettyPrinting"),0, cppu::UnoType
<bool>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
834 { OUString("PageLayoutNames"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0},
835 { OUString("BaseURI"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
836 { OUString("StreamRelPath"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
837 { OUString("StreamName"), 0, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
838 { OUString("StyleNames"), 0, cppu::UnoType
<Sequence
<OUString
>>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
839 { OUString("StyleFamilies"), 0, cppu::UnoType
<Sequence
<sal_Int32
>>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
840 { OUString("TargetStorage"), 0, cppu::UnoType
<embed::XStorage
>::get(), css::beans::PropertyAttribute::MAYBEVOID
, 0 },
841 { OUString(), 0, css::uno::Type(), 0, 0 }
844 uno::Reference
< beans::XPropertySet
> xInfoSet( GenericPropertySet_CreateInstance( new PropertySetInfo( aExportInfoMap
) ) );
846 SvtSaveOptions aSaveOpt
;
847 bool bUsePrettyPrinting( aSaveOpt
.IsPrettyPrinting() );
848 xInfoSet
->setPropertyValue( "UsePrettyPrinting", makeAny( bUsePrettyPrinting
) );
850 const uno::Reference
< embed::XStorage
>& xStorage
= mrMedium
.GetOutputStorage();
853 OUString
sPropName( "BaseURI" );
854 xInfoSet
->setPropertyValue( sPropName
, makeAny( mrMedium
.GetBaseURL( true ) ) );
856 xInfoSet
->setPropertyValue( "TargetStorage", Any( xStorage
) );
858 if( SfxObjectCreateMode::EMBEDDED
== mrDocShell
.GetCreateMode() )
861 if ( mrMedium
.GetItemSet() )
863 const SfxStringItem
* pDocHierarchItem
= static_cast<const SfxStringItem
*>(
864 mrMedium
.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME
) );
865 if ( pDocHierarchItem
)
866 aName
= pDocHierarchItem
->GetValue();
869 if( !aName
.isEmpty() )
871 sPropName
= "StreamRelPath";
872 xInfoSet
->setPropertyValue( sPropName
, makeAny( aName
) );
876 // initialize descriptor
877 uno::Sequence
< beans::PropertyValue
> aDescriptor( 1 );
878 beans::PropertyValue
* pProps
= aDescriptor
.getArray();
880 pProps
[0].Name
= "FileName";
881 pProps
[0].Value
<<= mrMedium
.GetName();
884 uno::Reference
< document::XEmbeddedObjectResolver
> xObjectResolver
;
885 uno::Reference
<document::XGraphicStorageHandler
> xGraphicStorageHandler
;
887 // create helper for graphic and ole export if we have a storage
890 xObjectHelper
= SvXMLEmbeddedObjectHelper::Create( xStorage
, *mrDocShell
.GetDoc()->GetPersist(), SvXMLEmbeddedObjectHelperMode::Write
);
891 xObjectResolver
= xObjectHelper
.get();
893 xGraphicHelper
= SvXMLGraphicHelper::Create( xStorage
, SvXMLGraphicHelperMode::Write
);
894 xGraphicStorageHandler
= xGraphicHelper
.get();
897 CreateStatusIndicator();
898 if(mxStatusIndicator
.is())
900 sal_Int32
nProgressRange(1000000);
901 OUString
aMsg(SdResId(STR_SAVE_DOC
));
902 mxStatusIndicator
->start(aMsg
, nProgressRange
);
906 aProgRange
<<= nProgressRange
;
907 xInfoSet
->setPropertyValue( "ProgressRange" , aProgRange
);
909 // set ProgressCurrent
910 uno::Any aProgCurrent
;
911 aProgCurrent
<<= sal_Int32(0);
912 xInfoSet
->setPropertyValue( "ProgressCurrent" , aProgCurrent
);
915 uno::Reference
< lang::XComponent
> xComponent( mxModel
, uno::UNO_QUERY
);
917 XML_SERVICES
const * pServiceNames
= getServices( false, IsDraw(), mnStoreVer
);
919 XML_SERVICEMAP aServices
[5]; sal_uInt16 i
= 0;
920 aServices
[i
].mpService
= pServiceNames
->mpStyles
;
921 aServices
[i
++].mpStream
= "styles.xml";
923 aServices
[i
].mpService
= pServiceNames
->mpContent
;
924 aServices
[i
++].mpStream
= "content.xml";
926 aServices
[i
].mpService
= pServiceNames
->mpSettings
;
927 aServices
[i
++].mpStream
= "settings.xml";
929 if( mrDocShell
.GetCreateMode() != SfxObjectCreateMode::EMBEDDED
)
931 aServices
[i
].mpService
= pServiceNames
->mpMeta
;
932 aServices
[i
++].mpStream
= "meta.xml";
935 aServices
[i
].mpService
= nullptr;
936 aServices
[i
].mpStream
= nullptr;
938 XML_SERVICEMAP
* pServices
= aServices
;
943 SAL_INFO( "sd.filter", "exporting substream " << pServices
->mpStream
);
945 uno::Reference
<io::XOutputStream
> xDocOut
;
948 const OUString
sDocName( OUString::createFromAscii( pServices
->mpStream
) );
949 uno::Reference
<io::XStream
> xStream
=
950 xStorage
->openStreamElement( sDocName
,
951 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
953 DBG_ASSERT(xStream
.is(), "Can't create output stream in package!");
957 xDocOut
= xStream
->getOutputStream();
958 Reference
<beans::XPropertySet
> xProps( xStream
, uno::UNO_QUERY
);
959 if( !xDocOut
.is() || !xProps
.is() )
962 xProps
->setPropertyValue( "MediaType", Any(OUString( "text/xml")));
964 // encrypt all streams
965 xProps
->setPropertyValue( "UseCommonStoragePasswordEncryption",
966 uno::makeAny( true ) );
968 const OUString
sStreamName( "StreamName");
969 xInfoSet
->setPropertyValue( sStreamName
, Any( sDocName
) );
972 uno::Reference
< io::XActiveDataSource
> xDocSrc( xWriter
, uno::UNO_QUERY
);
973 xDocSrc
->setOutputStream( xDocOut
);
975 uno::Sequence
< uno::Any
> aArgs( 2 + ( mxStatusIndicator
.is() ? 1 : 0 ) + ( xGraphicStorageHandler
.is() ? 1 : 0 ) + ( xObjectResolver
.is() ? 1 : 0 ) );
976 uno::Any
* pArgs
= aArgs
.getArray();
977 *pArgs
++ <<= xInfoSet
;
978 if (xGraphicStorageHandler
.is())
979 *pArgs
++ <<= xGraphicStorageHandler
;
980 if (xObjectResolver
.is())
981 *pArgs
++ <<= xObjectResolver
;
982 if (mxStatusIndicator
.is())
983 *pArgs
++ <<= mxStatusIndicator
;
987 uno::Reference
< document::XFilter
> xFilter( xContext
->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii( pServices
->mpService
), aArgs
, xContext
), uno::UNO_QUERY
);
990 uno::Reference
< document::XExporter
> xExporter( xFilter
, uno::UNO_QUERY
);
993 xExporter
->setSourceDocument( xComponent
);
994 // outputstream will be closed by SAX parser
995 bDocRet
= xFilter
->filter( aDescriptor
);
1001 while( bDocRet
&& pServices
->mpService
);
1003 if(mxStatusIndicator
.is())
1004 mxStatusIndicator
->end();
1007 catch (const uno::Exception
&e
)
1009 SAL_WARN( "sd.filter", "uno Exception caught while exporting:" << e
);
1013 mxModel
->unlockControllers();
1015 if( xGraphicHelper
)
1016 xGraphicHelper
->dispose();
1017 xGraphicHelper
.clear();
1020 xObjectHelper
->dispose();
1021 xObjectHelper
.clear();
1026 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportFODP(SvStream
&rStream
)
1030 sd::DrawDocShellRef
xDocSh(new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED
, false, DocumentType::Impress
));
1031 xDocSh
->DoInitNew();
1032 uno::Reference
<frame::XModel
> xModel(xDocSh
->GetModel());
1034 uno::Reference
<lang::XMultiServiceFactory
> xMultiServiceFactory(comphelper::getProcessServiceFactory());
1035 uno::Reference
<io::XInputStream
> xStream(new ::utl::OSeekableInputStreamWrapper(rStream
));
1036 uno::Reference
<uno::XInterface
> xInterface(xMultiServiceFactory
->createInstance("com.sun.star.comp.Writer.XmlFilterAdaptor"), uno::UNO_SET_THROW
);
1038 css::uno::Sequence
<OUString
> aUserData(7);
1039 aUserData
[0] = "com.sun.star.comp.filter.OdfFlatXml";
1040 aUserData
[2] = "com.sun.star.comp.Impress.XMLOasisImporter";
1041 aUserData
[3] = "com.sun.star.comp.Impress.XMLOasisExporter";
1042 aUserData
[6] = "true";
1043 uno::Sequence
<beans::PropertyValue
> aAdaptorArgs(comphelper::InitPropertySequence(
1045 { "UserData", uno::Any(aUserData
) },
1047 css::uno::Sequence
<uno::Any
> aOuterArgs(1);
1048 aOuterArgs
[0] <<= aAdaptorArgs
;
1050 uno::Reference
<lang::XInitialization
> xInit(xInterface
, uno::UNO_QUERY_THROW
);
1051 xInit
->initialize(aOuterArgs
);
1053 uno::Reference
<document::XImporter
> xImporter(xInterface
, uno::UNO_QUERY_THROW
);
1054 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
1056 { "InputStream", uno::Any(xStream
) },
1057 { "URL", uno::Any(OUString("private:stream")) },
1059 xImporter
->setTargetDocument(xModel
);
1061 uno::Reference
<document::XFilter
> xFilter(xInterface
, uno::UNO_QUERY_THROW
);
1062 //SetLoading hack because the document properties will be re-initted
1063 //by the xml filter and during the init, while its considered uninitialized,
1064 //setting a property will inform the document its modified, which attempts
1065 //to update the properties, which throws cause the properties are uninitialized
1066 xDocSh
->SetLoading(SfxLoadedFlags::NONE
);
1067 bool ret
= xFilter
->filter(aArgs
);
1068 xDocSh
->SetLoading(SfxLoadedFlags::ALL
);
1075 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportPPTX(SvStream
&rStream
)
1079 sd::DrawDocShellRef
xDocSh(new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED
, false, DocumentType::Impress
));
1080 xDocSh
->DoInitNew();
1081 uno::Reference
<frame::XModel
> xModel(xDocSh
->GetModel());
1083 uno::Reference
<lang::XMultiServiceFactory
> xMultiServiceFactory(comphelper::getProcessServiceFactory());
1084 uno::Reference
<io::XInputStream
> xStream(new utl::OSeekableInputStreamWrapper(rStream
));
1086 uno::Reference
<document::XFilter
> xFilter(xMultiServiceFactory
->createInstance("com.sun.star.comp.oox.ppt.PowerPointImport"), uno::UNO_QUERY_THROW
);
1088 uno::Reference
<document::XImporter
> xImporter(xFilter
, uno::UNO_QUERY_THROW
);
1089 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
1091 { "InputStream", uno::makeAny(xStream
) },
1092 { "InputMode", uno::makeAny(true) },
1094 xImporter
->setTargetDocument(xModel
);
1096 //SetLoading hack because the document properties will be re-initted
1097 //by the xml filter and during the init, while its considered uninitialized,
1098 //setting a property will inform the document its modified, which attempts
1099 //to update the properties, which throws cause the properties are uninitialized
1100 xDocSh
->SetLoading(SfxLoadedFlags::NONE
);
1104 ret
= xFilter
->filter(aArgs
);
1109 xDocSh
->SetLoading(SfxLoadedFlags::ALL
);
1117 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */