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 <o3tl/string_view.hxx>
34 #include <rtl/character.hxx>
35 #include <rtl/ustrbuf.hxx>
37 #include <xmloff/xmlmetai.hxx>
38 #include <xmloff/xmlimp.hxx>
39 #include <xmloff/xmltoken.hxx>
40 #include <xmloff/xmlnamespace.hxx>
42 using namespace com::sun::star
;
43 using namespace ::xmloff::token
;
47 /// builds a DOM tree from SAX events, by forwarding to SAXDocumentBuilder
48 class XMLDocumentBuilderContext
: public SvXMLImportContext
51 css::uno::Reference
< css::xml::dom::XSAXDocumentBuilder2
> mxDocBuilder
;
52 SvXMLMetaDocumentContext
*const m_pTopLevel
;
55 XMLDocumentBuilderContext(SvXMLImport
& rImport
, sal_Int32 nElement
,
56 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
,
57 css::uno::Reference
<css::xml::dom::XSAXDocumentBuilder2
> xDocBuilder
,
58 SvXMLMetaDocumentContext
* pTopLevel
);
60 virtual void SAL_CALL
characters( const OUString
& aChars
) override
;
62 virtual void SAL_CALL
startFastElement( sal_Int32 nElement
,
63 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
65 virtual void SAL_CALL
endFastElement( sal_Int32 nElement
) override
;
67 virtual void SAL_CALL
startUnknownElement( const OUString
& Namespace
, const OUString
& Name
,
68 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& Attribs
) override
;
70 virtual void SAL_CALL
endUnknownElement( const OUString
& Namespace
, const OUString
& Name
) override
;
72 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
73 sal_Int32 nElement
, const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
79 XMLDocumentBuilderContext::XMLDocumentBuilderContext(SvXMLImport
& rImport
,
80 sal_Int32
/*nElement*/, const uno::Reference
<xml::sax::XFastAttributeList
>&,
81 uno::Reference
<xml::dom::XSAXDocumentBuilder2
> xDocBuilder
,
82 SvXMLMetaDocumentContext
*const pTopLevel
)
83 : SvXMLImportContext(rImport
)
84 , mxDocBuilder(std::move(xDocBuilder
))
85 , m_pTopLevel(pTopLevel
)
89 void SAL_CALL
XMLDocumentBuilderContext::startFastElement( sal_Int32 nElement
,
90 const uno::Reference
< xml::sax::XFastAttributeList
>& xAttribs
)
92 mxDocBuilder
->startFastElement(nElement
, xAttribs
);
95 void SAL_CALL
XMLDocumentBuilderContext::endFastElement( sal_Int32 nElement
)
97 mxDocBuilder
->endFastElement(nElement
);
100 // call this here because in the flat ODF case the top-level
101 // endFastElement is called only at the very end of the document,
102 // which is too late to init BuildId
103 m_pTopLevel
->FinishMetaElement();
107 void SAL_CALL
XMLDocumentBuilderContext::startUnknownElement( const OUString
& rNamespace
,
108 const OUString
& rName
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
110 mxDocBuilder
->startUnknownElement(rNamespace
, rName
, xAttrList
);
113 void SAL_CALL
XMLDocumentBuilderContext::endUnknownElement( const OUString
& rNamespace
, const OUString
& rName
)
115 mxDocBuilder
->endUnknownElement(rNamespace
, rName
);
118 void SAL_CALL
XMLDocumentBuilderContext::characters( const OUString
& rChars
)
120 mxDocBuilder
->characters(rChars
);
123 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
XMLDocumentBuilderContext::createFastChildContext(
124 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
126 return new XMLDocumentBuilderContext(GetImport(), nElement
, xAttrList
, mxDocBuilder
, nullptr);
130 lcl_initDocumentProperties(SvXMLImport
& rImport
,
131 uno::Reference
<xml::dom::XSAXDocumentBuilder2
> const& xDocBuilder
,
132 uno::Reference
<document::XDocumentProperties
> const& xDocProps
)
134 uno::Reference
< lang::XInitialization
> const xInit(xDocProps
,
135 uno::UNO_QUERY_THROW
);
137 xInit
->initialize({ uno::Any(xDocBuilder
->getDocument()) });
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 u
"SvXMLMetaDocumentContext::initDocumentProperties: "
152 "properties init exception"_ustr
,
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
, u
"string(/office:document-meta/office:meta/meta:generator)"_ustr
),
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 u
"SvXMLMetaDocumentContext::initGenerator: exception"_ustr
,
184 SvXMLMetaDocumentContext::SvXMLMetaDocumentContext(SvXMLImport
& rImport
,
185 uno::Reference
<document::XDocumentProperties
> xDocProps
) :
186 SvXMLImportContext( rImport
),
187 mxDocProps(std::move(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(std::u16string_view i_rBuildId
, const uno::Reference
<beans::XPropertySet
>& xImportInfo
)
235 // skip to second product
236 size_t nBegin
= i_rBuildId
.find( ' ' );
237 if ( nBegin
!= std::u16string_view::npos
)
239 // skip to build information
240 nBegin
= i_rBuildId
.find( '/', nBegin
);
241 if ( nBegin
!= std::u16string_view::npos
)
243 size_t nEnd
= i_rBuildId
.find( 'm', nBegin
);
244 if ( nEnd
!= std::u16string_view::npos
)
246 OUStringBuffer
sBuffer(
247 i_rBuildId
.substr( nBegin
+1, nEnd
-nBegin
-1 ) );
248 static constexpr OUString
sBuildCompare(
250 nBegin
= i_rBuildId
.find( sBuildCompare
, nEnd
);
251 if ( nBegin
!= std::u16string_view::npos
)
253 sBuffer
.append( '$' );
254 sBuffer
.append( i_rBuildId
.substr(nBegin
+ sBuildCompare
.getLength()) );
255 sBuildId
= sBuffer
.makeStringAndClear();
261 if ( sBuildId
.isEmpty() )
263 if ( o3tl::starts_with(i_rBuildId
, u
"StarOffice 7")
264 || o3tl::starts_with(i_rBuildId
, u
"StarSuite 7")
265 || o3tl::starts_with(i_rBuildId
, u
"StarOffice 6")
266 || o3tl::starts_with(i_rBuildId
, u
"StarSuite 6")
267 || o3tl::starts_with(i_rBuildId
, u
"OpenOffice.org 1"))
269 sBuildId
= "645$8687";
271 else if (o3tl::starts_with(i_rBuildId
, u
"NeoOffice/2"))
273 sBuildId
= "680$9134"; // fake NeoOffice as OpenOffice.org 2.2 release
277 // "LibreOffice_project" was hard-coded since LO 3.3.0
278 // see utl::DocInfoHelper::GetGeneratorString()
279 if (i_rBuildId
.find(u
"LibreOffice_project/") != std::u16string_view::npos
)
281 OUStringBuffer sNumber
;
282 size_t const firstSlash
= i_rBuildId
.find('/');
283 assert(firstSlash
!= std::u16string_view::npos
);
284 for (size_t i
= firstSlash
+ 1; i
< i_rBuildId
.size(); ++i
)
286 if (rtl::isAsciiDigit(i_rBuildId
[i
]) || '.' == i_rBuildId
[i
])
288 sNumber
.append(i_rBuildId
[i
]);
295 if (!sNumber
.isEmpty())
297 sBuildId
+= ";" + sNumber
;
301 if ( sBuildId
.isEmpty() )
306 if( xImportInfo
.is() )
308 static constexpr OUString
aPropName(u
"BuildId"_ustr
);
309 uno::Reference
< beans::XPropertySetInfo
> xSetInfo(
310 xImportInfo
->getPropertySetInfo());
311 if( xSetInfo
.is() && xSetInfo
->hasPropertyByName( aPropName
) )
312 xImportInfo
->setPropertyValue( aPropName
, uno::Any( sBuildId
) );
315 catch(const uno::Exception
&)
320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */