Line data Source code
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 <tools/debug.hxx>
22 : #include <unotools/streamwrap.hxx>
23 : #include <xmlversion.hxx>
24 : #include <xmloff/xmlmetae.hxx>
25 :
26 : #include <xmloff/xmltoken.hxx>
27 : #include <comphelper/componentcontext.hxx>
28 : #include <comphelper/processfactory.hxx>
29 : #include <com/sun/star/io/XActiveDataSource.hpp>
30 : #include <com/sun/star/io/XOutputStream.hpp>
31 : #include <com/sun/star/util/DateTime.hpp>
32 : #include <com/sun/star/util/MeasureUnit.hpp>
33 : #include <com/sun/star/xml/sax/InputSource.hpp>
34 : #include <com/sun/star/xml/sax/Parser.hpp>
35 : #include <com/sun/star/xml/sax/Writer.hpp>
36 :
37 : using namespace ::com::sun::star::xml::sax;
38 : using namespace ::com::sun::star::uno;
39 : using namespace ::com::sun::star;
40 : using ::rtl::OUString;
41 :
42 : // ------------------------------------------------------------------------
43 :
44 : const char XMLN_VERSIONSLIST[] = "VersionList.xml";
45 :
46 : // ------------------------------------------------------------------------
47 : // #110897#
48 0 : XMLVersionListExport::XMLVersionListExport(
49 : const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory,
50 : const com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag >& rVersions,
51 : const OUString &rFileName,
52 : Reference< XDocumentHandler > &rHandler )
53 : : SvXMLExport( xServiceFactory, rFileName, util::MeasureUnit::CM, rHandler ),
54 0 : maVersions( rVersions )
55 : {
56 0 : _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_DC_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_DC),
57 0 : xmloff::token::GetXMLToken(xmloff::token::XML_N_DC), XML_NAMESPACE_DC );
58 0 : _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST),
59 0 : xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST), XML_NAMESPACE_FRAMEWORK );
60 0 : }
61 :
62 : // ------------------------------------------------------------------------
63 0 : sal_uInt32 XMLVersionListExport::exportDoc( enum ::xmloff::token::XMLTokenEnum )
64 : {
65 0 : GetDocHandler()->startDocument();
66 :
67 0 : addChaffWhenEncryptedStorage();
68 :
69 0 : sal_uInt16 nPos = _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_DC );
70 :
71 0 : AddAttribute( XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByIndex( nPos ),
72 0 : _GetNamespaceMap().GetNameByIndex ( nPos ) );
73 :
74 0 : nPos = _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_FRAMEWORK );
75 0 : AddAttribute( XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByIndex( nPos ),
76 0 : _GetNamespaceMap().GetNameByIndex ( nPos ) );
77 :
78 : {
79 : // the following object will write all collected attributes in its dtor
80 0 : SvXMLElementExport aRoot( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_LIST, sal_True, sal_True );
81 :
82 0 : for ( sal_Int32 n=0; n<maVersions.getLength(); n++ )
83 : {
84 0 : const util::RevisionTag& rInfo = maVersions[n];
85 : AddAttribute( XML_NAMESPACE_FRAMEWORK,
86 : xmloff::token::XML_TITLE,
87 0 : OUString( rInfo.Identifier ) );
88 : AddAttribute( XML_NAMESPACE_FRAMEWORK,
89 : xmloff::token::XML_COMMENT,
90 0 : OUString( rInfo.Comment ) );
91 : AddAttribute( XML_NAMESPACE_FRAMEWORK,
92 : xmloff::token::XML_CREATOR,
93 0 : OUString( rInfo.Author ) );
94 :
95 : OUString aDateStr =
96 0 : SvXMLMetaExport::GetISODateTimeString( rInfo.TimeStamp );
97 :
98 0 : AddAttribute( XML_NAMESPACE_DC, xmloff::token::XML_DATE_TIME, aDateStr );
99 :
100 : // the following object will write all collected attributes in its dtor
101 0 : SvXMLElementExport aEntry( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_ENTRY, sal_True, sal_True );
102 0 : }
103 : }
104 0 : GetDocHandler()->endDocument();
105 0 : return 0;
106 : }
107 :
108 : // ------------------------------------------------------------------------
109 : // #110897#
110 0 : XMLVersionListImport::XMLVersionListImport(
111 : const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory,
112 : com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag >& rVersions )
113 : : SvXMLImport(xServiceFactory),
114 0 : maVersions( rVersions )
115 : {
116 0 : GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST),
117 0 : xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST), XML_NAMESPACE_FRAMEWORK );
118 0 : }
119 :
120 : // ------------------------------------------------------------------------
121 0 : XMLVersionListImport::~XMLVersionListImport( void ) throw()
122 0 : {}
123 :
124 : // ------------------------------------------------------------------------
125 0 : SvXMLImportContext *XMLVersionListImport::CreateContext(
126 : sal_uInt16 nPrefix,
127 : const OUString& rLocalName,
128 : const Reference< XAttributeList > & xAttrList )
129 : {
130 0 : SvXMLImportContext *pContext = 0;
131 :
132 0 : if ( XML_NAMESPACE_FRAMEWORK == nPrefix &&
133 0 : rLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_LIST) )
134 : {
135 0 : pContext = new XMLVersionListContext( *this, nPrefix, rLocalName, xAttrList );
136 : }
137 : else
138 : {
139 0 : pContext = SvXMLImport::CreateContext( nPrefix, rLocalName, xAttrList );
140 : }
141 :
142 0 : return pContext;
143 : }
144 :
145 :
146 : // ------------------------------------------------------------------------
147 0 : XMLVersionListContext::XMLVersionListContext( XMLVersionListImport& rImport,
148 : sal_uInt16 nPrefix,
149 : const OUString& rLocalName,
150 : const Reference< XAttributeList > & )
151 : : SvXMLImportContext( rImport, nPrefix, rLocalName )
152 0 : , rLocalRef( rImport )
153 : {
154 0 : }
155 :
156 : // ------------------------------------------------------------------------
157 0 : XMLVersionListContext::~XMLVersionListContext( void )
158 0 : {}
159 :
160 : // ------------------------------------------------------------------------
161 0 : SvXMLImportContext *XMLVersionListContext::CreateChildContext( sal_uInt16 nPrefix,
162 : const OUString& rLocalName,
163 : const Reference< XAttributeList > & xAttrList )
164 : {
165 0 : SvXMLImportContext *pContext = 0;
166 :
167 0 : if ( nPrefix == XML_NAMESPACE_FRAMEWORK &&
168 0 : rLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_ENTRY) )
169 : {
170 0 : pContext = new XMLVersionContext( rLocalRef, nPrefix, rLocalName, xAttrList );
171 : }
172 : else
173 : {
174 0 : pContext = new SvXMLImportContext( rLocalRef, nPrefix, rLocalName );
175 : }
176 :
177 0 : return pContext;
178 : }
179 :
180 : // ------------------------------------------------------------------------
181 0 : XMLVersionContext::XMLVersionContext( XMLVersionListImport& rImport,
182 : sal_uInt16 nPref,
183 : const OUString& rLocalName,
184 : const Reference< XAttributeList > & xAttrList )
185 : : SvXMLImportContext( rImport, nPref, rLocalName )
186 0 : , rLocalRef( rImport )
187 : {
188 0 : sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
189 :
190 0 : if ( !nAttrCount )
191 0 : return;
192 :
193 0 : util::RevisionTag aInfo;
194 0 : for ( sal_Int16 i=0; i < nAttrCount; i++ )
195 : {
196 0 : OUString aLocalName;
197 0 : const OUString& rAttrName = xAttrList->getNameByIndex( i );
198 0 : sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName );
199 :
200 0 : if ( XML_NAMESPACE_FRAMEWORK == nPrefix )
201 : {
202 0 : if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_TITLE) )
203 : {
204 0 : const OUString& rAttrValue = xAttrList->getValueByIndex( i );
205 0 : aInfo.Identifier = rAttrValue;
206 : }
207 0 : else if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_COMMENT) )
208 : {
209 0 : const OUString& rAttrValue = xAttrList->getValueByIndex( i );
210 0 : aInfo.Comment = rAttrValue;
211 : }
212 0 : else if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_CREATOR) )
213 : {
214 0 : const OUString& rAttrValue = xAttrList->getValueByIndex( i );
215 0 : aInfo.Author = rAttrValue;
216 : }
217 : }
218 0 : else if ( ( XML_NAMESPACE_DC == nPrefix ) &&
219 0 : ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_DATE_TIME) ) )
220 : {
221 0 : const OUString& rAttrValue = xAttrList->getValueByIndex( i );
222 0 : util::DateTime aTime;
223 0 : if ( ParseISODateTimeString( rAttrValue, aTime ) )
224 0 : aInfo.TimeStamp = aTime;
225 : }
226 0 : }
227 :
228 0 : uno::Sequence < util::RevisionTag >& aList = rLocalRef.GetList();
229 0 : sal_Int32 nLength = aList.getLength();
230 0 : aList.realloc( nLength+1 );
231 0 : aList[nLength] = aInfo;
232 : }
233 :
234 :
235 : // ------------------------------------------------------------------------
236 0 : XMLVersionContext::~XMLVersionContext( void )
237 0 : {}
238 :
239 : // ------------------------------------------------------------------------
240 0 : sal_Bool XMLVersionContext::ParseISODateTimeString(
241 : const rtl::OUString& rString,
242 : util::DateTime& rDateTime )
243 : {
244 0 : sal_Bool bSuccess = sal_True;
245 :
246 0 : OUString aDateStr, aTimeStr;
247 0 : sal_Int32 nPos = rString.indexOf( (sal_Unicode) 'T' );
248 0 : if ( nPos >= 0 )
249 : {
250 0 : aDateStr = rString.copy( 0, nPos );
251 0 : aTimeStr = rString.copy( nPos + 1 );
252 : }
253 : else
254 0 : aDateStr = rString; // no separator: only date part
255 :
256 0 : sal_Int32 nYear = 0;
257 0 : sal_Int32 nMonth = 1;
258 0 : sal_Int32 nDay = 1;
259 0 : sal_Int32 nHour = 0;
260 0 : sal_Int32 nMin = 0;
261 0 : sal_Int32 nSec = 0;
262 :
263 0 : const sal_Unicode* pStr = aDateStr.getStr();
264 0 : sal_Int32 nDateTokens = 1;
265 0 : while ( *pStr )
266 : {
267 0 : if ( *pStr == '-' )
268 0 : nDateTokens++;
269 0 : pStr++;
270 : }
271 0 : if ( nDateTokens > 3 || aDateStr.isEmpty() )
272 0 : bSuccess = sal_False;
273 : else
274 : {
275 0 : sal_Int32 n = 0;
276 0 : nYear = aDateStr.getToken( 0, '-', n ).toInt32();
277 0 : if ( nYear > 9999 )
278 0 : bSuccess = sal_False;
279 0 : else if ( nDateTokens >= 2 )
280 : {
281 0 : nMonth = aDateStr.getToken( 0, '-', n ).toInt32();
282 0 : if ( nMonth > 12 )
283 0 : bSuccess = sal_False;
284 0 : else if ( nDateTokens >= 3 )
285 : {
286 0 : nDay = aDateStr.getToken( 0, '-', n ).toInt32();
287 0 : if ( nDay > 31 )
288 0 : bSuccess = sal_False;
289 : }
290 : }
291 : }
292 :
293 0 : if ( bSuccess && !aTimeStr.isEmpty() ) // time is optional
294 : {
295 0 : pStr = aTimeStr.getStr();
296 0 : sal_Int32 nTimeTokens = 1;
297 0 : while ( *pStr )
298 : {
299 0 : if ( *pStr == ':' )
300 0 : nTimeTokens++;
301 0 : pStr++;
302 : }
303 0 : if ( nTimeTokens > 3 )
304 0 : bSuccess = sal_False;
305 : else
306 : {
307 0 : sal_Int32 n = 0;
308 0 : nHour = aTimeStr.getToken( 0, ':', n ).toInt32();
309 0 : if ( nHour > 23 )
310 0 : bSuccess = sal_False;
311 0 : else if ( nTimeTokens >= 2 )
312 : {
313 0 : nMin = aTimeStr.getToken( 0, ':', n ).toInt32();
314 0 : if ( nMin > 59 )
315 0 : bSuccess = sal_False;
316 0 : else if ( nTimeTokens >= 3 )
317 : {
318 0 : nSec = aTimeStr.getToken( 0, ':', n ).toInt32();
319 0 : if ( nSec > 59 )
320 0 : bSuccess = sal_False;
321 : }
322 : }
323 : }
324 : }
325 :
326 0 : if ( bSuccess )
327 : {
328 0 : rDateTime.Day = sal::static_int_cast< sal_uInt16 >(nDay);
329 0 : rDateTime.Month = sal::static_int_cast< sal_uInt16 >(nMonth);
330 0 : rDateTime.Year = sal::static_int_cast< sal_uInt16 >(nYear);
331 0 : rDateTime.Hours = sal::static_int_cast< sal_uInt16 >(nHour);
332 0 : rDateTime.Minutes = sal::static_int_cast< sal_uInt16 >(nMin);
333 0 : rDateTime.Seconds = sal::static_int_cast< sal_uInt16 >(nSec);
334 : }
335 :
336 0 : return bSuccess;
337 : }
338 :
339 :
340 : // ------------------------------------------------------------------------
341 0 : void SAL_CALL XMLVersionListPersistence::store( const uno::Reference< embed::XStorage >& xRoot, const uno::Sequence< util::RevisionTag >& rVersions )
342 : throw (::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
343 : {
344 : // no storage, no version list!
345 0 : if ( xRoot.is() )
346 : {
347 : // get the services needed for writing the xml data
348 : Reference< lang::XMultiServiceFactory > xServiceFactory =
349 0 : comphelper::getProcessServiceFactory();
350 : DBG_ASSERT( xServiceFactory.is(), "XMLReader::Read: got no service manager" );
351 : Reference< uno::XComponentContext > xContext =
352 0 : comphelper::getProcessComponentContext();
353 :
354 0 : Reference< XWriter > xWriter = Writer::create(xContext);
355 :
356 : // check whether there's already a sub storage with the version info
357 : // and delete it
358 0 : OUString sVerName( XMLN_VERSIONSLIST );
359 :
360 : try {
361 : // open (create) the sub storage with the version info
362 0 : uno::Reference< io::XStream > xVerStream = xRoot->openStreamElement(
363 : sVerName,
364 0 : embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
365 0 : if ( !xVerStream.is() )
366 0 : throw uno::RuntimeException();
367 :
368 0 : Reference< io::XOutputStream > xOut = xVerStream->getOutputStream();
369 0 : if ( !xOut.is() )
370 0 : throw uno::RuntimeException(); // the stream was successfuly opened for writing already
371 :
372 0 : Reference< io::XActiveDataSource > xSrc( xWriter, uno::UNO_QUERY );
373 0 : xSrc->setOutputStream(xOut);
374 :
375 0 : Reference< XDocumentHandler > xHandler( xWriter, uno::UNO_QUERY );
376 :
377 0 : XMLVersionListExport aExp( xServiceFactory, rVersions, sVerName, xHandler );
378 :
379 0 : aExp.exportDoc( ::xmloff::token::XML_VERSION );
380 :
381 0 : xVerStream = uno::Reference< io::XStream >(); // use refcounting for now to dispose
382 : }
383 0 : catch( uno::Exception& )
384 : {
385 : // TODO: error handling
386 0 : }
387 : }
388 0 : }
389 :
390 : // ------------------------------------------------------------------------
391 6 : uno::Sequence< util::RevisionTag > SAL_CALL XMLVersionListPersistence::load( const uno::Reference< embed::XStorage >& xRoot )
392 : throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
393 : {
394 6 : com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag > aVersions;
395 :
396 6 : const OUString sDocName( XMLN_VERSIONSLIST );
397 6 : uno::Reference< container::XNameAccess > xRootNames( xRoot, uno::UNO_QUERY );
398 :
399 : try {
400 6 : if ( xRootNames.is() && xRootNames->hasByName( sDocName ) && xRoot->isStreamElement( sDocName ) )
401 : {
402 : Reference< lang::XMultiServiceFactory > xServiceFactory =
403 0 : comphelper::getProcessServiceFactory();
404 : DBG_ASSERT( xServiceFactory.is(), "XMLReader::Read: got no service manager" );
405 :
406 0 : InputSource aParserInput;
407 :
408 0 : uno::Reference< beans::XPropertySet > xProps( xRoot, uno::UNO_QUERY );
409 : OSL_ENSURE( xProps.is(), "Storage must implement XPropertySet!\n" );
410 0 : if ( xProps.is() )
411 : {
412 : try {
413 0 : xProps->getPropertyValue( ::rtl::OUString("URL") ) >>= aParserInput.sSystemId;
414 : }
415 0 : catch( uno::Exception& )
416 : {}
417 : }
418 :
419 0 : uno::Reference< io::XStream > xDocStream = xRoot->openStreamElement(
420 : sDocName,
421 0 : embed::ElementModes::READ );
422 0 : if ( !xDocStream.is() )
423 0 : throw uno::RuntimeException();
424 :
425 0 : aParserInput.aInputStream = xDocStream->getInputStream();
426 : OSL_ENSURE( aParserInput.aInputStream.is(),
427 : "The stream was successfuly opened for reading, the input part must be accessible!\n" );
428 0 : if ( !aParserInput.aInputStream.is() )
429 0 : throw uno::RuntimeException();
430 :
431 : // get filter
432 0 : Reference< XDocumentHandler > xFilter = new XMLVersionListImport( xServiceFactory, aVersions );
433 :
434 : // connect parser and filter
435 0 : Reference< XParser > xParser = xml::sax::Parser::create(comphelper::getComponentContext(xServiceFactory));
436 0 : xParser->setDocumentHandler( xFilter );
437 :
438 : // parse
439 : try
440 : {
441 0 : xParser->parseStream( aParserInput );
442 : }
443 0 : catch( SAXParseException& ) {}
444 0 : catch( SAXException& ) {}
445 0 : catch( io::IOException& ) {}
446 : }
447 : }
448 4 : catch( uno::Exception& )
449 : {
450 : // TODO: error handling
451 : }
452 :
453 6 : return aVersions;
454 : }
455 :
456 2 : uno::Sequence< rtl::OUString > SAL_CALL XMLVersionListPersistence_getSupportedServiceNames()
457 : throw()
458 : {
459 : const rtl::OUString aServiceName(
460 2 : "com.sun.star.document.DocumentRevisionListPersistence" );
461 2 : const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 );
462 2 : return aSeq;
463 : }
464 :
465 4 : rtl::OUString SAL_CALL XMLVersionListPersistence_getImplementationName() throw()
466 : {
467 4 : return rtl::OUString( "XMLVersionListPersistence" );
468 : }
469 :
470 6 : uno::Reference< uno::XInterface > SAL_CALL XMLVersionListPersistence_createInstance(
471 : const uno::Reference< lang::XMultiServiceFactory > &)
472 : throw( uno::Exception )
473 : {
474 6 : return (cppu::OWeakObject*)new XMLVersionListPersistence;
475 : }
476 :
477 0 : uno::Sequence< rtl::OUString > SAL_CALL XMLVersionImExportOOO_getSupportedServiceNames()
478 : throw()
479 : {
480 : const rtl::OUString aServiceName(
481 0 : "com.sun.star.document.DocumentRevisionListPersistence" );
482 0 : const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 );
483 0 : return aSeq;
484 : }
485 :
486 0 : rtl::OUString SAL_CALL XMLVersionImExportOOO_getImplementationName() throw()
487 : {
488 0 : return rtl::OUString( "XMLVersionImExportOOo" );
489 : }
490 :
491 0 : uno::Reference< uno::XInterface > SAL_CALL XMLVersionImExportOOO_createInstance(
492 : const uno::Reference< lang::XMultiServiceFactory > &)
493 : throw( uno::Exception )
494 : {
495 0 : return (cppu::OWeakObject*)new XMLVersionListPersistence;
496 : }
497 :
498 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|