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 <sal/config.h>
22 #include <string_view>
24 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
25 #include <com/sun/star/xml/dom/SAXDocumentBuilder.hpp>
26 #include <com/sun/star/xml/dom/XSAXDocumentBuilder2.hpp>
27 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/beans/XPropertySetInfo.hpp>
30 #include <com/sun/star/document/XDocumentProperties.hpp>
31 #include <comphelper/processfactory.hxx>
32 #include <cppuhelper/exc_hlp.hxx>
33 #include <rtl/character.hxx>
34 #include <rtl/ustrbuf.hxx>
35 #include <xmloff/xmlmetai.hxx>
36 #include <xmloff/xmlimp.hxx>
37 #include <xmloff/xmltoken.hxx>
38 #include <xmloff/xmlnamespace.hxx>
40 using namespace com::sun::star
;
41 using namespace ::xmloff::token
;
45 /// builds a DOM tree from SAX events, by forwarding to SAXDocumentBuilder
46 class XMLDocumentBuilderContext
: public SvXMLImportContext
49 css::uno::Reference
< css::xml::dom::XSAXDocumentBuilder2
> mxDocBuilder
;
50 SvXMLMetaDocumentContext
*const m_pTopLevel
;
53 XMLDocumentBuilderContext(SvXMLImport
& rImport
, sal_Int32 nElement
,
54 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
,
55 const css::uno::Reference
<css::xml::dom::XSAXDocumentBuilder2
>& rDocBuilder
,
56 SvXMLMetaDocumentContext
* pTopLevel
);
58 virtual void SAL_CALL
characters( const OUString
& aChars
) override
;
60 virtual void SAL_CALL
startFastElement( sal_Int32 nElement
,
61 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
63 virtual void SAL_CALL
endFastElement( sal_Int32 nElement
) override
;
65 virtual void SAL_CALL
startUnknownElement( const OUString
& Namespace
, const OUString
& Name
,
66 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& Attribs
) override
;
68 virtual void SAL_CALL
endUnknownElement( const OUString
& Namespace
, const OUString
& Name
) override
;
70 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
71 sal_Int32 nElement
, const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
77 XMLDocumentBuilderContext::XMLDocumentBuilderContext(SvXMLImport
& rImport
,
78 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>&,
79 const uno::Reference
<xml::dom::XSAXDocumentBuilder2
>& rDocBuilder
,
80 SvXMLMetaDocumentContext
*const pTopLevel
)
81 : SvXMLImportContext(rImport
)
82 , mxDocBuilder(rDocBuilder
)
83 , m_pTopLevel(pTopLevel
)
87 void SAL_CALL
XMLDocumentBuilderContext::startFastElement( sal_Int32 nElement
,
88 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttribs
)
90 mxDocBuilder
->startFastElement(nElement
, xAttribs
);
93 void SAL_CALL
XMLDocumentBuilderContext::endFastElement( sal_Int32 nElement
)
95 mxDocBuilder
->endFastElement(nElement
);
98 // call this here because in the flat ODF case the top-level
99 // endFastElement is called only at the very end of the document,
100 // which is too late to init BuildId
101 m_pTopLevel
->FinishMetaElement();
105 void SAL_CALL
XMLDocumentBuilderContext::startUnknownElement( const OUString
& rNamespace
,
106 const OUString
& rName
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
108 mxDocBuilder
->startUnknownElement(rNamespace
, rName
, xAttrList
);
111 void SAL_CALL
XMLDocumentBuilderContext::endUnknownElement( const OUString
& rNamespace
, const OUString
& rName
)
113 mxDocBuilder
->endUnknownElement(rNamespace
, rName
);
116 void SAL_CALL
XMLDocumentBuilderContext::characters( const OUString
& rChars
)
118 mxDocBuilder
->characters(rChars
);
121 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
XMLDocumentBuilderContext::createFastChildContext(
122 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
124 return new XMLDocumentBuilderContext(GetImport(), nElement
, xAttrList
, mxDocBuilder
, nullptr);
128 lcl_initDocumentProperties(SvXMLImport
& rImport
,
129 uno::Reference
<xml::dom::XSAXDocumentBuilder2
> const& xDocBuilder
,
130 uno::Reference
<document::XDocumentProperties
> const& xDocProps
)
132 uno::Sequence
< uno::Any
> aSeq(1);
133 aSeq
[0] <<= xDocBuilder
->getDocument();
134 uno::Reference
< lang::XInitialization
> const xInit(xDocProps
,
135 uno::UNO_QUERY_THROW
);
137 xInit
->initialize(aSeq
);
138 rImport
.SetStatistics(xDocProps
->getDocumentStatistics());
139 // convert all URLs from relative to absolute
140 xDocProps
->setTemplateURL(rImport
.GetAbsoluteReference(
141 xDocProps
->getTemplateURL()));
142 xDocProps
->setAutoloadURL(rImport
.GetAbsoluteReference(
143 xDocProps
->getAutoloadURL()));
144 SvXMLMetaDocumentContext::setBuildId(
145 xDocProps
->getGenerator(), rImport
.getImportInfo());
146 } catch (const uno::RuntimeException
&) {
148 } catch (const uno::Exception
&) {
149 css::uno::Any anyEx
= cppu::getCaughtException();
150 throw lang::WrappedTargetRuntimeException(
151 "SvXMLMetaDocumentContext::initDocumentProperties: "
152 "properties init exception",
158 lcl_initGenerator(SvXMLImport
& rImport
,
159 uno::Reference
<xml::dom::XSAXDocumentBuilder2
> const& xDocBuilder
)
161 uno::Reference
< xml::dom::XDocument
> const xDoc(xDocBuilder
->getDocument(),
164 uno::Reference
< xml::xpath::XXPathAPI
> const xPath
= xml::xpath::XPathAPI::create(
165 rImport
.GetComponentContext() );
166 xPath
->registerNS(GetXMLToken(XML_NP_OFFICE
),GetXMLToken(XML_N_OFFICE
));
167 xPath
->registerNS(GetXMLToken(XML_NP_META
), GetXMLToken(XML_N_META
));
169 uno::Reference
< xml::xpath::XXPathObject
> const xObj(
170 xPath
->eval(xDoc
.get(), "string(/office:document-meta/office:meta/meta:generator)"),
172 OUString
const value(xObj
->getString());
173 SvXMLMetaDocumentContext::setBuildId(value
, rImport
.getImportInfo());
174 } catch (const uno::RuntimeException
&) {
176 } catch (const uno::Exception
&) {
177 css::uno::Any anyEx
= cppu::getCaughtException();
178 throw lang::WrappedTargetRuntimeException(
179 "SvXMLMetaDocumentContext::initGenerator: exception",
184 SvXMLMetaDocumentContext::SvXMLMetaDocumentContext(SvXMLImport
& rImport
,
185 const uno::Reference
<document::XDocumentProperties
>& xDocProps
) :
186 SvXMLImportContext( rImport
),
187 mxDocProps(xDocProps
),
189 xml::dom::SAXDocumentBuilder::create(
190 comphelper::getProcessComponentContext()))
192 // #i103539#: must always read meta.xml for generator, xDocProps unwanted then
193 // OSL_ENSURE(xDocProps.is(), "SvXMLMetaDocumentContext: no document props");
196 SvXMLMetaDocumentContext::~SvXMLMetaDocumentContext()
200 void SAL_CALL
SvXMLMetaDocumentContext::startFastElement(sal_Int32
/*nElement*/,
201 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
203 mxDocBuilder
->startDocument();
204 // hardcode office:document-meta (necessary in case of flat file ODF)
205 mxDocBuilder
->startFastElement(XML_ELEMENT(OFFICE
, XML_DOCUMENT_META
), xAttrList
);
208 void SvXMLMetaDocumentContext::FinishMetaElement()
210 // hardcode office:document-meta (necessary in case of flat file ODF)
211 mxDocBuilder
->endFastElement(XML_ELEMENT(OFFICE
, XML_DOCUMENT_META
));
212 mxDocBuilder
->endDocument();
215 lcl_initDocumentProperties(GetImport(), mxDocBuilder
, mxDocProps
);
219 lcl_initGenerator(GetImport(), mxDocBuilder
);
223 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
SvXMLMetaDocumentContext::createFastChildContext(
224 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
226 if ( nElement
== XML_ELEMENT(OFFICE
, XML_META
) )
227 return new XMLDocumentBuilderContext(
228 GetImport(), nElement
, xAttrList
, mxDocBuilder
, this);
232 void SvXMLMetaDocumentContext::setBuildId(OUString
const& i_rBuildId
, const uno::Reference
<beans::XPropertySet
>& xImportInfo
)
235 // skip to second product
236 sal_Int32 nBegin
= i_rBuildId
.indexOf( ' ' );
239 // skip to build information
240 nBegin
= i_rBuildId
.indexOf( '/', nBegin
);
243 sal_Int32 nEnd
= i_rBuildId
.indexOf( 'm', nBegin
);
246 OUStringBuffer
sBuffer(
247 i_rBuildId
.copy( nBegin
+1, nEnd
-nBegin
-1 ) );
248 const OUString
sBuildCompare(
250 nBegin
= i_rBuildId
.indexOf( sBuildCompare
, nEnd
);
253 sBuffer
.append( '$' );
254 sBuffer
.append( std::u16string_view(i_rBuildId
).substr(
255 nBegin
+ sBuildCompare
.getLength()) );
256 sBuildId
= sBuffer
.makeStringAndClear();
262 if ( sBuildId
.isEmpty() )
264 if ( i_rBuildId
.startsWith("StarOffice 7")
265 || i_rBuildId
.startsWith("StarSuite 7")
266 || i_rBuildId
.startsWith("StarOffice 6")
267 || i_rBuildId
.startsWith("StarSuite 6")
268 || i_rBuildId
.startsWith("OpenOffice.org 1"))
270 sBuildId
= "645$8687";
272 else if (i_rBuildId
.startsWith("NeoOffice/2"))
274 sBuildId
= "680$9134"; // fake NeoOffice as OpenOffice.org 2.2 release
278 // "LibreOffice_project" was hard-coded since LO 3.3.0
279 // see utl::DocInfoHelper::GetGeneratorString()
280 if (i_rBuildId
.indexOf("LibreOffice_project/") != -1)
282 OUStringBuffer sNumber
;
283 auto const firstSlash
= i_rBuildId
.indexOf("/");
284 assert(firstSlash
!= -1);
285 for (sal_Int32 i
= firstSlash
+ 1; i
< i_rBuildId
.getLength(); ++i
)
287 if (rtl::isAsciiDigit(i_rBuildId
[i
]))
289 sNumber
.append(i_rBuildId
[i
]);
291 else if ('.' != i_rBuildId
[i
])
296 if (!sNumber
.isEmpty())
298 sBuildId
+= ";" + sNumber
.makeStringAndClear();
302 if ( sBuildId
.isEmpty() )
307 if( xImportInfo
.is() )
309 const OUString
aPropName("BuildId");
310 uno::Reference
< beans::XPropertySetInfo
> xSetInfo(
311 xImportInfo
->getPropertySetInfo());
312 if( xSetInfo
.is() && xSetInfo
->hasPropertyByName( aPropName
) )
313 xImportInfo
->setPropertyValue( aPropName
, uno::makeAny( sBuildId
) );
316 catch(const uno::Exception
&)
321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */