LibreOffice Module xmloff (master) 1
xmlversion.cxx
Go to the documentation of this file.
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 <com/sun/star/embed/ElementModes.hpp>
21#include <xmlversion.hxx>
23#include <xmloff/xmlmetae.hxx>
24#include <osl/diagnose.h>
25#include <sal/log.hxx>
26#include <o3tl/string_view.hxx>
27
28#include <xmloff/xmltoken.hxx>
30#include <comphelper/string.hxx>
31#include <com/sun/star/beans/XPropertySet.hpp>
32#include <com/sun/star/io/IOException.hpp>
33#include <com/sun/star/io/XOutputStream.hpp>
34#include <com/sun/star/util/DateTime.hpp>
35#include <com/sun/star/util/MeasureUnit.hpp>
36#include <com/sun/star/xml/sax/InputSource.hpp>
37#include <com/sun/star/xml/sax/Writer.hpp>
38#include <com/sun/star/xml/sax/SAXParseException.hpp>
40
41using namespace ::com::sun::star::xml::sax;
42using namespace ::com::sun::star::uno;
43using namespace ::com::sun::star;
44
45constexpr OUStringLiteral XMLN_VERSIONSLIST = u"VersionList.xml";
46
48 const css::uno::Reference< css::uno::XComponentContext >& rContext,
49 const css::uno::Sequence < css::util::RevisionTag >& rVersions,
50 const OUString &rFileName,
51 Reference< XDocumentHandler > const &rHandler )
52: SvXMLExport( rContext, "", rFileName, util::MeasureUnit::CM, rHandler ),
53 maVersions( rVersions )
54{
59}
60
62{
63 GetDocHandler()->startDocument();
64
66
68
69 AddAttribute( XML_NAMESPACE_NONE, GetNamespaceMap_().GetAttrNameByIndex( nPos ),
70 GetNamespaceMap_().GetNameByIndex ( nPos ) );
71
73 AddAttribute( XML_NAMESPACE_NONE, GetNamespaceMap_().GetAttrNameByIndex( nPos ),
74 GetNamespaceMap_().GetNameByIndex ( nPos ) );
75
76 {
77 // the following object will write all collected attributes in its dtor
79
80 for ( const util::RevisionTag& rInfo : maVersions )
81 {
84 rInfo.Identifier );
87 rInfo.Comment );
90 rInfo.Author );
91
92 OUString aDateStr =
94
96
97 // the following object will write all collected attributes in its dtor
99 }
100 }
101 GetDocHandler()->endDocument();
102 return ERRCODE_NONE;
103}
104
106 const css::uno::Reference< css::uno::XComponentContext >& rContext,
107 css::uno::Sequence < css::util::RevisionTag >& rVersions )
108: SvXMLImport(rContext, ""),
109 maVersions( rVersions )
110{
111}
112
114{}
115
117 const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
118{
119 SvXMLImportContext *pContext = nullptr;
120
121 if ( nElement == XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_VERSION_LIST) )
122 {
123 pContext = new XMLVersionListContext( *this );
124 }
125
126 return pContext;
127}
128
130 : SvXMLImportContext( rImport )
131{
132}
133
135{}
136
137css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL
139 const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList)
140{
141 SvXMLImportContext *pContext = nullptr;
142
143 if ( nElement == XML_ELEMENT(FRAMEWORK, xmloff::token::XML_VERSION_ENTRY)
144 || nElement == XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_VERSION_ENTRY) )
145 {
146 pContext = new XMLVersionContext( GetImport(), xAttrList );
147 }
148
149 return pContext;
150}
151
153 const Reference< XFastAttributeList > & xAttrList )
154 : SvXMLImportContext( rImport )
155{
158 if ( rAttribList.getFastAttributeTokens().empty() )
159 return;
160 util::RevisionTag aInfo;
161 for (auto &aIter : rAttribList)
162 {
163 switch( aIter.getToken() )
164 {
165 case XML_ELEMENT(FRAMEWORK, xmloff::token::XML_TITLE):
166 case XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_TITLE):
167 {
168 aInfo.Identifier = aIter.toString();
169 break;
170 }
172 case XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_COMMENT):
173 {
174 aInfo.Comment = aIter.toString();
175 break;
176 }
178 case XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_CREATOR):
179 {
180 aInfo.Author = aIter.toString();
181 break;
182 }
184 {
185 util::DateTime aTime;
186 if ( ParseISODateTimeString( aIter.toString(), aTime ) )
187 aInfo.TimeStamp = aTime;
188 break;
189 }
190 default:
191 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
192 break;
193 }
194 }
195
196 uno::Sequence < util::RevisionTag >& aList = rImport.GetList();
197 sal_Int32 nLength = aList.getLength();
198 aList.realloc( nLength+1 );
199 aList.getArray()[nLength] = aInfo;
200}
201
203{}
204
206 std::u16string_view rString,
207 util::DateTime& rDateTime )
208{
209 bool bSuccess = true;
210
211 std::u16string_view aDateStr, aTimeStr;
212 size_t nPos = rString.find( 'T' );
213 if ( nPos != std::u16string_view::npos )
214 {
215 aDateStr = rString.substr( 0, nPos );
216 aTimeStr = rString.substr( nPos + 1 );
217 }
218 else
219 aDateStr = rString; // no separator: only date part
220
221 sal_Int32 nYear = 0;
222 sal_Int32 nMonth = 1;
223 sal_Int32 nDay = 1;
224 sal_Int32 nHour = 0;
225 sal_Int32 nMin = 0;
226 sal_Int32 nSec = 0;
227
228 auto pStr = aDateStr.begin();
229 sal_Int32 nDateTokens = 1;
230 while ( pStr != aDateStr.end() )
231 {
232 if ( *pStr == '-' )
233 nDateTokens++;
234 pStr++;
235 }
236 if ( nDateTokens > 3 || aDateStr.empty() )
237 bSuccess = false;
238 else
239 {
240 sal_Int32 n = 0;
241 nYear = o3tl::toInt32(o3tl::getToken(aDateStr, 0, '-', n ));
242 if ( nYear > 9999 )
243 bSuccess = false;
244 else if ( nDateTokens >= 2 )
245 {
246 nMonth = o3tl::toInt32(o3tl::getToken(aDateStr, 0, '-', n ));
247 if ( nMonth > 12 )
248 bSuccess = false;
249 else if ( nDateTokens >= 3 )
250 {
251 nDay = o3tl::toInt32(o3tl::getToken(aDateStr, 0, '-', n ));
252 if ( nDay > 31 )
253 bSuccess = false;
254 }
255 }
256 }
257
258 if ( bSuccess && !aTimeStr.empty() ) // time is optional
259 {
260 pStr = aTimeStr.begin();
261 sal_Int32 nTimeTokens = 1;
262 while ( pStr != aTimeStr.end() )
263 {
264 if ( *pStr == ':' )
265 nTimeTokens++;
266 pStr++;
267 }
268 if ( nTimeTokens > 3 )
269 bSuccess = false;
270 else
271 {
272 sal_Int32 n = 0;
273 nHour = o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', n ));
274 if ( nHour > 23 )
275 bSuccess = false;
276 else if ( nTimeTokens >= 2 )
277 {
278 nMin = o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', n ));
279 if ( nMin > 59 )
280 bSuccess = false;
281 else if ( nTimeTokens >= 3 )
282 {
283 nSec = o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', n ));
284 if ( nSec > 59 )
285 bSuccess = false;
286 }
287 }
288 }
289 }
290
291 if ( bSuccess )
292 {
293 rDateTime.Day = sal::static_int_cast< sal_uInt16 >(nDay);
294 rDateTime.Month = sal::static_int_cast< sal_uInt16 >(nMonth);
295 rDateTime.Year = sal::static_int_cast< sal_uInt16 >(nYear);
296 rDateTime.Hours = sal::static_int_cast< sal_uInt16 >(nHour);
297 rDateTime.Minutes = sal::static_int_cast< sal_uInt16 >(nMin);
298 rDateTime.Seconds = sal::static_int_cast< sal_uInt16 >(nSec);
299 }
300
301 return bSuccess;
302}
303
304void SAL_CALL XMLVersionListPersistence::store( const uno::Reference< embed::XStorage >& xRoot, const uno::Sequence< util::RevisionTag >& rVersions )
305{
306 // no storage, no version list!
307 if ( !xRoot.is() )
308 return;
309
310 // get the services needed for writing the xml data
311 Reference< uno::XComponentContext > xContext =
313
314 Reference< XWriter > xWriter = Writer::create(xContext);
315
316 // check whether there's already a sub storage with the version info
317 // and delete it
318 OUString sVerName( XMLN_VERSIONSLIST );
319
320 try {
321 // open (create) the sub storage with the version info
322 uno::Reference< io::XStream > xVerStream = xRoot->openStreamElement(
323 sVerName,
324 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
325 if ( !xVerStream.is() )
326 throw uno::RuntimeException();
327
328 Reference< io::XOutputStream > xOut = xVerStream->getOutputStream();
329 if ( !xOut.is() )
330 throw uno::RuntimeException("The stream was successfully opened for writing already!");
331
332 xWriter->setOutputStream(xOut);
333
334 rtl::Reference< XMLVersionListExport > xExp( new XMLVersionListExport( xContext, rVersions, sVerName, xWriter ) );
335
336 xExp->exportDoc( ::xmloff::token::XML_VERSION );
337
338 xVerStream.clear(); // use refcounting for now to dispose
339 }
340 catch( uno::Exception& )
341 {
342 // TODO: error handling
343 }
344}
345
346uno::Sequence< util::RevisionTag > SAL_CALL XMLVersionListPersistence::load( const uno::Reference< embed::XStorage >& xRoot )
347{
348 css::uno::Sequence < css::util::RevisionTag > aVersions;
349
350 const OUString sDocName( XMLN_VERSIONSLIST );
351
352 try {
353 if ( xRoot.is() && xRoot->hasByName( sDocName ) && xRoot->isStreamElement( sDocName ) )
354 {
355 Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
356
357 InputSource aParserInput;
358
359 uno::Reference< beans::XPropertySet > xProps( xRoot, uno::UNO_QUERY );
360 OSL_ENSURE( xProps.is(), "Storage must implement XPropertySet!" );
361 if ( xProps.is() )
362 {
363 try {
364 xProps->getPropertyValue("URL") >>= aParserInput.sSystemId;
365 }
366 catch( uno::Exception& )
367 {}
368 }
369
370 uno::Reference< io::XStream > xDocStream = xRoot->openStreamElement(
371 sDocName,
372 embed::ElementModes::READ );
373 if ( !xDocStream.is() )
374 throw uno::RuntimeException();
375
376 aParserInput.aInputStream = xDocStream->getInputStream();
377 OSL_ENSURE( aParserInput.aInputStream.is(),
378 "The stream was successfully opened for reading, the input part must be accessible!" );
379 if ( !aParserInput.aInputStream.is() )
380 throw uno::RuntimeException();
381
382 // get filter
383 rtl::Reference< XMLVersionListImport > xImport = new XMLVersionListImport( xContext, aVersions );
384
385 // parse
386 try
387 {
388 xImport->parseStream( aParserInput );
389 }
390 catch( SAXParseException& ) {}
391 catch( SAXException& ) {}
392 catch( io::IOException& ) {}
393 }
394 }
395 catch( uno::Exception& )
396 {
397 // TODO: error handling
398 }
399
400 return aVersions;
401}
402
404{
405 return "XMLVersionListPersistence";
406}
407
409 OUString const & ServiceName)
410{
412}
413
414css::uno::Sequence<OUString>
416{
417 return css::uno::Sequence<OUString>{
418 "com.sun.star.document.DocumentRevisionListPersistence"};
419}
420
421extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
423 css::uno::XComponentContext *,
424 css::uno::Sequence<css::uno::Any> const &)
425{
426 return cppu::acquire(new XMLVersionListPersistence);
427}
428
429/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void AddAttribute(sal_uInt16 nPrefix, const OUString &rName, const OUString &rValue)
Definition: xmlexp.cxx:907
SvXMLNamespaceMap & GetNamespaceMap_()
Definition: xmlexp.hxx:181
void addChaffWhenEncryptedStorage()
Definition: xmlexp.cxx:1185
const css::uno::Reference< css::xml::sax::XDocumentHandler > & GetDocHandler() const
Definition: xmlexp.hxx:379
This class deliberately does not support XWeak, to improve performance when loading large documents.
Definition: xmlictxt.hxx:48
static OUString GetISODateTimeString(const css::util::DateTime &rDateTime)
Definition: xmlmetae.cxx:53
void AddAtIndex(const OUString &rPrefix, const OUString &rName, sal_uInt16 nKey)
static sal_uInt16 GetIndexByKey(sal_uInt16 nKey)
virtual ~XMLVersionContext() override
Definition: xmlversion.cxx:202
static bool ParseISODateTimeString(std::u16string_view rString, css::util::DateTime &rDateTime)
Definition: xmlversion.cxx:205
XMLVersionContext(XMLVersionListImport &rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
Definition: xmlversion.cxx:152
XMLVersionListContext(XMLVersionListImport &rImport)
Definition: xmlversion.cxx:129
virtual ~XMLVersionListContext() override
Definition: xmlversion.cxx:134
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttribs) override
Definition: xmlversion.cxx:138
XMLVersionListImport & GetImport()
Definition: xmlversion.hxx:71
ErrCode exportDoc(enum ::xmloff::token::XMLTokenEnum eClass=::xmloff::token::XML_TOKEN_INVALID) override
Definition: xmlversion.cxx:61
XMLVersionListExport(const css::uno::Reference< css::uno::XComponentContext > &rContext, const css::uno::Sequence< css::util::RevisionTag > &rVersions, const OUString &rFileName, css::uno::Reference< css::xml::sax::XDocumentHandler > const &rHandler)
Definition: xmlversion.cxx:47
const css::uno::Sequence< css::util::RevisionTag > & maVersions
Definition: xmlversion.hxx:35
virtual SvXMLImportContext * CreateFastContext(sal_Int32 Element, const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList > &xAttrList) override
Definition: xmlversion.cxx:116
css::uno::Sequence< css::util::RevisionTag > & GetList()
Definition: xmlversion.hxx:65
virtual ~XMLVersionListImport() noexcept override
Definition: xmlversion.cxx:113
XMLVersionListImport(const css::uno::Reference< css::uno::XComponentContext > &rContext, css::uno::Sequence< css::util::RevisionTag > &rVersions)
Definition: xmlversion.cxx:105
virtual void SAL_CALL store(const css::uno::Reference< css::embed::XStorage > &Storage, const css::uno::Sequence< css::util::RevisionTag > &List) override
Definition: xmlversion.cxx:304
css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: xmlversion.cxx:415
OUString SAL_CALL getImplementationName() override
Definition: xmlversion.cxx:403
sal_Bool SAL_CALL supportsService(OUString const &ServiceName) override
Definition: xmlversion.cxx:408
virtual css::uno::Sequence< css::util::RevisionTag > SAL_CALL load(const css::uno::Reference< css::embed::XStorage > &Storage) override
Definition: xmlversion.cxx:346
const std::vector< sal_Int32 > & getFastAttributeTokens() const
float u
#define ERRCODE_NONE
sal_Int64 n
sal_uInt16 nPos
Reference< XComponentContext > getProcessComponentContext()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
const sal_uInt16 XML_NAMESPACE_NONE
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:50
@ XML_NP_VERSIONS_LIST
Definition: xmltoken.hxx:125
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3541
unsigned char sal_Bool
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:114
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:97
constexpr sal_uInt16 XML_NAMESPACE_DC
constexpr sal_uInt16 XML_NAMESPACE_FRAMEWORK
sal_Int32 nLength
Definition: xmltoken.cxx:38
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * XMLVersionListPersistence_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
Definition: xmlversion.cxx:422
constexpr OUStringLiteral XMLN_VERSIONSLIST
Definition: xmlversion.cxx:45