/src/libreoffice/xmloff/source/meta/xmlmetai.cxx
Line | Count | Source (jump to first uncovered line) |
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 | | |
20 | | #include <sal/config.h> |
21 | | |
22 | | #include <string_view> |
23 | | |
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> |
36 | | #include <utility> |
37 | | #include <xmloff/xmlmetai.hxx> |
38 | | #include <xmloff/xmlimp.hxx> |
39 | | #include <xmloff/xmltoken.hxx> |
40 | | #include <xmloff/xmlnamespace.hxx> |
41 | | |
42 | | using namespace com::sun::star; |
43 | | using namespace ::xmloff::token; |
44 | | |
45 | | namespace { |
46 | | |
47 | | /// builds a DOM tree from SAX events, by forwarding to SAXDocumentBuilder |
48 | | class XMLDocumentBuilderContext : public SvXMLImportContext |
49 | | { |
50 | | private: |
51 | | css::uno::Reference< css::xml::dom::XSAXDocumentBuilder2> mxDocBuilder; |
52 | | SvXMLMetaDocumentContext *const m_pTopLevel; |
53 | | |
54 | | public: |
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); |
59 | | |
60 | | virtual void SAL_CALL characters( const OUString& aChars ) override; |
61 | | |
62 | | virtual void SAL_CALL startFastElement( sal_Int32 nElement, |
63 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; |
64 | | |
65 | | virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; |
66 | | |
67 | | virtual void SAL_CALL startUnknownElement( const OUString& Namespace, const OUString& Name, |
68 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; |
69 | | |
70 | | virtual void SAL_CALL endUnknownElement( const OUString& Namespace, const OUString& Name ) override; |
71 | | |
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; |
74 | | |
75 | | }; |
76 | | |
77 | | } |
78 | | |
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 | 436k | : SvXMLImportContext(rImport) |
84 | 436k | , mxDocBuilder(std::move(xDocBuilder)) |
85 | 436k | , m_pTopLevel(pTopLevel) |
86 | 436k | { |
87 | 436k | } |
88 | | |
89 | | void SAL_CALL XMLDocumentBuilderContext::startFastElement( sal_Int32 nElement, |
90 | | const uno::Reference< xml::sax::XFastAttributeList >& xAttribs ) |
91 | 436k | { |
92 | 436k | mxDocBuilder->startFastElement(nElement, xAttribs); |
93 | 436k | } |
94 | | |
95 | | void SAL_CALL XMLDocumentBuilderContext::endFastElement( sal_Int32 nElement ) |
96 | 253k | { |
97 | 253k | mxDocBuilder->endFastElement(nElement); |
98 | 253k | if (m_pTopLevel) |
99 | 16.7k | { |
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 | 16.7k | m_pTopLevel->FinishMetaElement(); |
104 | 16.7k | } |
105 | 253k | } |
106 | | |
107 | | void SAL_CALL XMLDocumentBuilderContext::startUnknownElement( const OUString& rNamespace, |
108 | | const OUString& rName, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) |
109 | 1.67M | { |
110 | 1.67M | mxDocBuilder->startUnknownElement(rNamespace, rName, xAttrList); |
111 | 1.67M | } |
112 | | |
113 | | void SAL_CALL XMLDocumentBuilderContext::endUnknownElement( const OUString& rNamespace, const OUString& rName ) |
114 | 161k | { |
115 | 161k | mxDocBuilder->endUnknownElement(rNamespace, rName); |
116 | 161k | } |
117 | | |
118 | | void SAL_CALL XMLDocumentBuilderContext::characters( const OUString& rChars ) |
119 | 705k | { |
120 | 705k | mxDocBuilder->characters(rChars); |
121 | 705k | } |
122 | | |
123 | | uno::Reference< xml::sax::XFastContextHandler > SAL_CALL XMLDocumentBuilderContext::createFastChildContext( |
124 | | sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) |
125 | 413k | { |
126 | 413k | return new XMLDocumentBuilderContext(GetImport(), nElement, xAttrList, mxDocBuilder, nullptr); |
127 | 413k | } |
128 | | |
129 | | static void |
130 | | lcl_initDocumentProperties(SvXMLImport & rImport, |
131 | | uno::Reference<xml::dom::XSAXDocumentBuilder2> const& xDocBuilder, |
132 | | uno::Reference<document::XDocumentProperties> const& xDocProps) |
133 | 16.7k | { |
134 | 16.7k | uno::Reference< lang::XInitialization > const xInit(xDocProps, |
135 | 16.7k | uno::UNO_QUERY_THROW); |
136 | 16.7k | try { |
137 | 16.7k | xInit->initialize({ uno::Any(xDocBuilder->getDocument()) }); |
138 | 16.7k | rImport.SetStatistics(xDocProps->getDocumentStatistics()); |
139 | | // convert all URLs from relative to absolute |
140 | 16.7k | xDocProps->setTemplateURL(rImport.GetAbsoluteReference( |
141 | 16.7k | xDocProps->getTemplateURL())); |
142 | 16.7k | xDocProps->setAutoloadURL(rImport.GetAbsoluteReference( |
143 | 16.7k | xDocProps->getAutoloadURL())); |
144 | 16.7k | SvXMLMetaDocumentContext::setBuildId( |
145 | 16.7k | xDocProps->getGenerator(), rImport.getImportInfo()); |
146 | 16.7k | } catch (const uno::RuntimeException&) { |
147 | 0 | throw; |
148 | 0 | } catch (const uno::Exception&) { |
149 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
150 | 0 | throw lang::WrappedTargetRuntimeException( |
151 | 0 | u"SvXMLMetaDocumentContext::initDocumentProperties: " |
152 | 0 | "properties init exception"_ustr, |
153 | 0 | rImport, anyEx); |
154 | 0 | } |
155 | 16.7k | } |
156 | | |
157 | | static void |
158 | | lcl_initGenerator(SvXMLImport & rImport, |
159 | | uno::Reference<xml::dom::XSAXDocumentBuilder2> const& xDocBuilder) |
160 | 0 | { |
161 | 0 | uno::Reference< xml::dom::XDocument > const xDoc(xDocBuilder->getDocument(), |
162 | 0 | uno::UNO_SET_THROW); |
163 | 0 | try { |
164 | 0 | uno::Reference< xml::xpath::XXPathAPI > const xPath = xml::xpath::XPathAPI::create( |
165 | 0 | rImport.GetComponentContext() ); |
166 | 0 | xPath->registerNS(GetXMLToken(XML_NP_OFFICE),GetXMLToken(XML_N_OFFICE)); |
167 | 0 | xPath->registerNS(GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META)); |
168 | |
|
169 | 0 | uno::Reference< xml::xpath::XXPathObject > const xObj( |
170 | 0 | xPath->eval(xDoc, u"string(/office:document-meta/office:meta/meta:generator)"_ustr), |
171 | 0 | uno::UNO_SET_THROW); |
172 | 0 | OUString const value(xObj->getString()); |
173 | 0 | SvXMLMetaDocumentContext::setBuildId(value, rImport.getImportInfo()); |
174 | 0 | } catch (const uno::RuntimeException&) { |
175 | 0 | throw; |
176 | 0 | } catch (const uno::Exception&) { |
177 | 0 | css::uno::Any anyEx = cppu::getCaughtException(); |
178 | 0 | throw lang::WrappedTargetRuntimeException( |
179 | 0 | u"SvXMLMetaDocumentContext::initGenerator: exception"_ustr, |
180 | 0 | rImport, anyEx); |
181 | 0 | } |
182 | 0 | } |
183 | | |
184 | | SvXMLMetaDocumentContext::SvXMLMetaDocumentContext(SvXMLImport& rImport, |
185 | | uno::Reference<document::XDocumentProperties> xDocProps) : |
186 | 47.4k | SvXMLImportContext( rImport ), |
187 | 47.4k | mxDocProps(std::move(xDocProps)), |
188 | | mxDocBuilder( |
189 | 47.4k | xml::dom::SAXDocumentBuilder::create( |
190 | 47.4k | comphelper::getProcessComponentContext())) |
191 | 47.4k | { |
192 | | // #i103539#: must always read meta.xml for generator, xDocProps unwanted then |
193 | | // OSL_ENSURE(xDocProps.is(), "SvXMLMetaDocumentContext: no document props"); |
194 | 47.4k | } SvXMLMetaDocumentContext::SvXMLMetaDocumentContext(SvXMLImport&, com::sun::star::uno::Reference<com::sun::star::document::XDocumentProperties>) Line | Count | Source | 186 | 47.4k | SvXMLImportContext( rImport ), | 187 | 47.4k | mxDocProps(std::move(xDocProps)), | 188 | | mxDocBuilder( | 189 | 47.4k | xml::dom::SAXDocumentBuilder::create( | 190 | 47.4k | comphelper::getProcessComponentContext())) | 191 | 47.4k | { | 192 | | // #i103539#: must always read meta.xml for generator, xDocProps unwanted then | 193 | | // OSL_ENSURE(xDocProps.is(), "SvXMLMetaDocumentContext: no document props"); | 194 | 47.4k | } |
Unexecuted instantiation: SvXMLMetaDocumentContext::SvXMLMetaDocumentContext(SvXMLImport&, com::sun::star::uno::Reference<com::sun::star::document::XDocumentProperties>) |
195 | | |
196 | | SvXMLMetaDocumentContext::~SvXMLMetaDocumentContext() |
197 | 47.4k | { |
198 | 47.4k | } |
199 | | |
200 | | void SAL_CALL SvXMLMetaDocumentContext::startFastElement(sal_Int32 /*nElement*/, |
201 | | const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) |
202 | 47.4k | { |
203 | 47.4k | mxDocBuilder->startDocument(); |
204 | | // hardcode office:document-meta (necessary in case of flat file ODF) |
205 | 47.4k | mxDocBuilder->startFastElement(XML_ELEMENT(OFFICE, XML_DOCUMENT_META), xAttrList); |
206 | 47.4k | } |
207 | | |
208 | | void SvXMLMetaDocumentContext::FinishMetaElement() |
209 | 16.7k | { |
210 | | // hardcode office:document-meta (necessary in case of flat file ODF) |
211 | 16.7k | mxDocBuilder->endFastElement(XML_ELEMENT(OFFICE, XML_DOCUMENT_META)); |
212 | 16.7k | mxDocBuilder->endDocument(); |
213 | 16.7k | if (mxDocProps.is()) |
214 | 16.7k | { |
215 | 16.7k | lcl_initDocumentProperties(GetImport(), mxDocBuilder, mxDocProps); |
216 | 16.7k | } |
217 | 0 | else |
218 | 0 | { |
219 | 0 | lcl_initGenerator(GetImport(), mxDocBuilder); |
220 | 0 | } |
221 | 16.7k | } |
222 | | |
223 | | uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SvXMLMetaDocumentContext::createFastChildContext( |
224 | | sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) |
225 | 23.1k | { |
226 | 23.1k | if ( nElement == XML_ELEMENT(OFFICE, XML_META) ) |
227 | 23.1k | return new XMLDocumentBuilderContext( |
228 | 23.1k | GetImport(), nElement, xAttrList, mxDocBuilder, this); |
229 | 0 | return nullptr; |
230 | 23.1k | } |
231 | | |
232 | | void SvXMLMetaDocumentContext::setBuildId(std::u16string_view i_rBuildId, const uno::Reference<beans::XPropertySet>& xImportInfo ) |
233 | 16.7k | { |
234 | 16.7k | OUString sBuildId; |
235 | | // skip to second product |
236 | 16.7k | size_t nBegin = i_rBuildId.find( ' ' ); |
237 | 16.7k | if ( nBegin != std::u16string_view::npos ) |
238 | 10.0k | { |
239 | | // skip to build information |
240 | 10.0k | nBegin = i_rBuildId.find( '/', nBegin ); |
241 | 10.0k | if ( nBegin != std::u16string_view::npos ) |
242 | 10.0k | { |
243 | 10.0k | size_t nEnd = i_rBuildId.find( 'm', nBegin ); |
244 | 10.0k | if ( nEnd != std::u16string_view::npos ) |
245 | 2.67k | { |
246 | 2.67k | OUStringBuffer sBuffer( |
247 | 2.67k | i_rBuildId.substr( nBegin+1, nEnd-nBegin-1 ) ); |
248 | 2.67k | static constexpr OUString sBuildCompare( |
249 | 2.67k | u"$Build-"_ustr ); |
250 | 2.67k | nBegin = i_rBuildId.find( sBuildCompare, nEnd ); |
251 | 2.67k | if ( nBegin != std::u16string_view::npos ) |
252 | 2.58k | { |
253 | 2.58k | sBuffer.append( '$' ); |
254 | 2.58k | sBuffer.append( i_rBuildId.substr(nBegin + sBuildCompare.getLength()) ); |
255 | 2.58k | sBuildId = sBuffer.makeStringAndClear(); |
256 | 2.58k | } |
257 | 2.67k | } |
258 | 10.0k | } |
259 | 10.0k | } |
260 | | |
261 | 16.7k | if ( sBuildId.isEmpty() ) |
262 | 14.2k | { |
263 | 14.2k | if ( o3tl::starts_with(i_rBuildId, u"StarOffice 7") |
264 | 14.2k | || o3tl::starts_with(i_rBuildId, u"StarSuite 7") |
265 | 14.2k | || o3tl::starts_with(i_rBuildId, u"StarOffice 6") |
266 | 14.2k | || o3tl::starts_with(i_rBuildId, u"StarSuite 6") |
267 | 14.2k | || o3tl::starts_with(i_rBuildId, u"OpenOffice.org 1")) |
268 | 0 | { |
269 | 0 | sBuildId = "645$8687"; |
270 | 0 | } |
271 | 14.2k | else if (o3tl::starts_with(i_rBuildId, u"NeoOffice/2")) |
272 | 0 | { |
273 | 0 | sBuildId = "680$9134"; // fake NeoOffice as OpenOffice.org 2.2 release |
274 | 0 | } |
275 | 14.2k | } |
276 | | |
277 | | // "LibreOffice_project" was hard-coded since LO 3.3.0 |
278 | | // see utl::DocInfoHelper::GetGeneratorString() |
279 | 16.7k | if (i_rBuildId.find(u"LibreOffice_project/") != std::u16string_view::npos) |
280 | 8.71k | { |
281 | 8.71k | OUStringBuffer sNumber; |
282 | 8.71k | size_t const firstSlash = i_rBuildId.find('/'); |
283 | 8.71k | assert(firstSlash != std::u16string_view::npos); |
284 | 51.5k | for (size_t i = firstSlash + 1; i < i_rBuildId.size(); ++i) |
285 | 51.5k | { |
286 | 51.5k | if (rtl::isAsciiDigit(i_rBuildId[i]) || '.' == i_rBuildId[i]) |
287 | 42.7k | { |
288 | 42.7k | sNumber.append(i_rBuildId[i]); |
289 | 42.7k | } |
290 | 8.71k | else |
291 | 8.71k | { |
292 | 8.71k | break; |
293 | 8.71k | } |
294 | 51.5k | } |
295 | 8.71k | if (!sNumber.isEmpty()) |
296 | 8.67k | { |
297 | 8.67k | sBuildId += ";" + sNumber; |
298 | 8.67k | } |
299 | 8.71k | } |
300 | | |
301 | 16.7k | if ( sBuildId.isEmpty() ) |
302 | 7.99k | return; |
303 | | |
304 | 8.78k | try |
305 | 8.78k | { |
306 | 8.78k | if( xImportInfo.is() ) |
307 | 8.76k | { |
308 | 8.76k | static constexpr OUString aPropName(u"BuildId"_ustr); |
309 | 8.76k | uno::Reference< beans::XPropertySetInfo > xSetInfo( |
310 | 8.76k | xImportInfo->getPropertySetInfo()); |
311 | 8.76k | if( xSetInfo.is() && xSetInfo->hasPropertyByName( aPropName ) ) |
312 | 8.76k | xImportInfo->setPropertyValue( aPropName, uno::Any( sBuildId ) ); |
313 | 8.76k | } |
314 | 8.78k | } |
315 | 8.78k | catch(const uno::Exception&) |
316 | 8.78k | { |
317 | 0 | } |
318 | 8.78k | } |
319 | | |
320 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |