xref: /trunk/main/xmloff/source/meta/xmlversion.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include <com/sun/star/embed/ElementModes.hpp>
31 #include <tools/debug.hxx>
32 #include <unotools/streamwrap.hxx>
33 #include <xmlversion.hxx>
34 #include <xmloff/xmlmetae.hxx>
35 
36 #include <xmloff/xmltoken.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <com/sun/star/io/XActiveDataSource.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/util/DateTime.hpp>
41 #include <com/sun/star/xml/sax/InputSource.hpp>
42 #include <com/sun/star/xml/sax/XParser.hpp>
43 
44 #include <tools/string.hxx>
45 class SvStringsDtor;
46 
47 using namespace ::com::sun::star::xml::sax;
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star;
50 using ::rtl::OUString;
51 
52 // ------------------------------------------------------------------------
53 
54 sal_Char __FAR_DATA XMLN_VERSIONSLIST[] = "VersionList.xml";
55 
56 // ------------------------------------------------------------------------
57 
58 // #110897#
59 XMLVersionListExport::XMLVersionListExport(
60 	const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory,
61     const com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag >& rVersions,
62     const OUString &rFileName,
63     Reference< XDocumentHandler > &rHandler )
64 :   SvXMLExport( xServiceFactory, rFileName, rHandler ),
65 	maVersions( rVersions )
66 {
67     _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_DC_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_DC),
68                                    xmloff::token::GetXMLToken(xmloff::token::XML_N_DC), XML_NAMESPACE_DC );
69     _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST),
70                                    xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST), XML_NAMESPACE_FRAMEWORK );
71 }
72 
73 // ------------------------------------------------------------------------
74 sal_uInt32 XMLVersionListExport::exportDoc( enum ::xmloff::token::XMLTokenEnum )
75 {
76     GetDocHandler()->startDocument();
77 
78     sal_uInt16 nPos = _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_DC );
79 
80     AddAttribute( XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByIndex( nPos ),
81                              _GetNamespaceMap().GetNameByIndex ( nPos ) );
82 
83     nPos = _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_FRAMEWORK );
84     AddAttribute( XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByIndex( nPos ),
85                              _GetNamespaceMap().GetNameByIndex ( nPos ) );
86 
87     {
88         // the following object will write all collected attributes in its dtor
89         SvXMLElementExport aRoot( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_LIST, sal_True, sal_True );
90 
91         for ( sal_Int32 n=0; n<maVersions.getLength(); n++ )
92         {
93             const util::RevisionTag& rInfo = maVersions[n];
94             AddAttribute( XML_NAMESPACE_FRAMEWORK,
95                           xmloff::token::XML_TITLE,
96                           OUString( rInfo.Identifier ) );
97             AddAttribute( XML_NAMESPACE_FRAMEWORK,
98                           xmloff::token::XML_COMMENT,
99                           OUString( rInfo.Comment ) );
100             AddAttribute( XML_NAMESPACE_FRAMEWORK,
101                           xmloff::token::XML_CREATOR,
102                           OUString( rInfo.Author ) );
103 
104             OUString aDateStr =
105                 SvXMLMetaExport::GetISODateTimeString( rInfo.TimeStamp );
106 
107             AddAttribute( XML_NAMESPACE_DC, xmloff::token::XML_DATE_TIME, aDateStr );
108 
109             // the following object will write all collected attributes in its dtor
110             SvXMLElementExport aEntry( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_ENTRY, sal_True, sal_True );
111         }
112     }
113     GetDocHandler()->endDocument();
114     return 0;
115 }
116 
117 // ------------------------------------------------------------------------
118 // ------------------------------------------------------------------------
119 
120 // #110897#
121 XMLVersionListImport::XMLVersionListImport(
122 	const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory,
123     com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag >& rVersions )
124 :	SvXMLImport(xServiceFactory),
125     maVersions( rVersions )
126 {
127     GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST),
128                                   xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST), XML_NAMESPACE_FRAMEWORK );
129 }
130 
131 // ------------------------------------------------------------------------
132 XMLVersionListImport::~XMLVersionListImport( void ) throw()
133 {}
134 
135 // ------------------------------------------------------------------------
136 SvXMLImportContext *XMLVersionListImport::CreateContext(
137         sal_uInt16 nPrefix,
138         const OUString& rLocalName,
139         const Reference< XAttributeList > & xAttrList )
140 {
141     SvXMLImportContext *pContext = 0;
142 
143     if ( XML_NAMESPACE_FRAMEWORK == nPrefix &&
144         rLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_LIST) )
145     {
146         pContext = new XMLVersionListContext( *this, nPrefix, rLocalName, xAttrList );
147     }
148     else
149     {
150         pContext = SvXMLImport::CreateContext( nPrefix, rLocalName, xAttrList );
151     }
152 
153     return pContext;
154 }
155 
156 
157 // ------------------------------------------------------------------------
158 // ------------------------------------------------------------------------
159 
160 XMLVersionListContext::XMLVersionListContext( XMLVersionListImport& rImport,
161                                         sal_uInt16 nPrefix,
162                                         const OUString& rLocalName,
163                                         const Reference< XAttributeList > & )
164     : SvXMLImportContext( rImport, nPrefix, rLocalName )
165     , rLocalRef( rImport )
166 {
167 }
168 
169 // ------------------------------------------------------------------------
170 XMLVersionListContext::~XMLVersionListContext( void )
171 {}
172 
173 // ------------------------------------------------------------------------
174 SvXMLImportContext *XMLVersionListContext::CreateChildContext( sal_uInt16 nPrefix,
175                                         const OUString& rLocalName,
176                                         const Reference< XAttributeList > & xAttrList )
177 {
178     SvXMLImportContext *pContext = 0;
179 
180     if ( nPrefix == XML_NAMESPACE_FRAMEWORK &&
181          rLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_ENTRY) )
182     {
183         pContext = new XMLVersionContext( rLocalRef, nPrefix, rLocalName, xAttrList );
184     }
185     else
186     {
187         pContext = new SvXMLImportContext( rLocalRef, nPrefix, rLocalName );
188     }
189 
190     return pContext;
191 }
192 
193 // ------------------------------------------------------------------------
194 // ------------------------------------------------------------------------
195 
196 XMLVersionContext::XMLVersionContext( XMLVersionListImport& rImport,
197                                         sal_uInt16 nPref,
198                                         const OUString& rLocalName,
199                                         const Reference< XAttributeList > & xAttrList )
200     : SvXMLImportContext( rImport, nPref, rLocalName )
201     , rLocalRef( rImport )
202 {
203     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
204 
205     if ( !nAttrCount )
206         return;
207 
208     util::RevisionTag aInfo;
209     for ( sal_Int16 i=0; i < nAttrCount; i++ )
210     {
211         OUString        aLocalName;
212         const OUString& rAttrName   = xAttrList->getNameByIndex( i );
213         sal_uInt16      nPrefix     = rImport.GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName );
214 
215         if ( XML_NAMESPACE_FRAMEWORK == nPrefix )
216         {
217             if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_TITLE) )
218             {
219                 const OUString& rAttrValue = xAttrList->getValueByIndex( i );
220                 aInfo.Identifier = rAttrValue;
221             }
222             else if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_COMMENT) )
223             {
224                 const OUString& rAttrValue = xAttrList->getValueByIndex( i );
225                 aInfo.Comment = rAttrValue;
226             }
227             else if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_CREATOR) )
228             {
229                 const OUString& rAttrValue = xAttrList->getValueByIndex( i );
230                 aInfo.Author = rAttrValue;
231             }
232         }
233         else if ( ( XML_NAMESPACE_DC == nPrefix ) &&
234                   ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_DATE_TIME) ) )
235         {
236             const OUString& rAttrValue = xAttrList->getValueByIndex( i );
237             util::DateTime aTime;
238             if ( ParseISODateTimeString( rAttrValue, aTime ) )
239                 aInfo.TimeStamp = aTime;
240         }
241     }
242 
243     uno::Sequence < util::RevisionTag >& aList = rLocalRef.GetList();
244     sal_Int32 nLength = aList.getLength();
245     aList.realloc( nLength+1 );
246     aList[nLength] = aInfo;
247 }
248 
249 
250 // ------------------------------------------------------------------------
251 XMLVersionContext::~XMLVersionContext( void )
252 {}
253 
254 // ------------------------------------------------------------------------
255 // static
256 sal_Bool XMLVersionContext::ParseISODateTimeString(
257                                 const rtl::OUString& rString,
258                                 util::DateTime& rDateTime )
259 {
260     sal_Bool bSuccess = sal_True;
261 
262     OUString aDateStr, aTimeStr;
263     sal_Int32 nPos = rString.indexOf( (sal_Unicode) 'T' );
264     if ( nPos >= 0 )
265     {
266         aDateStr = rString.copy( 0, nPos );
267         aTimeStr = rString.copy( nPos + 1 );
268     }
269     else
270         aDateStr = rString;         // no separator: only date part
271 
272     sal_Int32 nYear  = 0;
273     sal_Int32 nMonth = 1;
274     sal_Int32 nDay   = 1;
275     sal_Int32 nHour  = 0;
276     sal_Int32 nMin   = 0;
277     sal_Int32 nSec   = 0;
278 
279     const sal_Unicode* pStr = aDateStr.getStr();
280     sal_Int32 nDateTokens = 1;
281     while ( *pStr )
282     {
283         if ( *pStr == '-' )
284             nDateTokens++;
285         pStr++;
286     }
287     if ( nDateTokens > 3 || aDateStr.getLength() == 0 )
288         bSuccess = sal_False;
289     else
290     {
291         sal_Int32 n = 0;
292         nYear = aDateStr.getToken( 0, '-', n ).toInt32();
293         if ( nYear > 9999 )
294             bSuccess = sal_False;
295         else if ( nDateTokens >= 2 )
296         {
297             nMonth = aDateStr.getToken( 0, '-', n ).toInt32();
298             if ( nMonth > 12 )
299                 bSuccess = sal_False;
300             else if ( nDateTokens >= 3 )
301             {
302                 nDay = aDateStr.getToken( 0, '-', n ).toInt32();
303                 if ( nDay > 31 )
304                     bSuccess = sal_False;
305             }
306         }
307     }
308 
309     if ( bSuccess && aTimeStr.getLength() > 0 )         // time is optional
310     {
311         pStr = aTimeStr.getStr();
312         sal_Int32 nTimeTokens = 1;
313         while ( *pStr )
314         {
315             if ( *pStr == ':' )
316                 nTimeTokens++;
317             pStr++;
318         }
319         if ( nTimeTokens > 3 )
320             bSuccess = sal_False;
321         else
322         {
323             sal_Int32 n = 0;
324             nHour = aTimeStr.getToken( 0, ':', n ).toInt32();
325             if ( nHour > 23 )
326                 bSuccess = sal_False;
327             else if ( nTimeTokens >= 2 )
328             {
329                 nMin = aTimeStr.getToken( 0, ':', n ).toInt32();
330                 if ( nMin > 59 )
331                     bSuccess = sal_False;
332                 else if ( nTimeTokens >= 3 )
333                 {
334                     nSec = aTimeStr.getToken( 0, ':', n ).toInt32();
335                     if ( nSec > 59 )
336                         bSuccess = sal_False;
337                 }
338             }
339         }
340     }
341 
342     if ( bSuccess )
343     {
344         rDateTime.Day = sal::static_int_cast< sal_uInt16 >(nDay);
345         rDateTime.Month = sal::static_int_cast< sal_uInt16 >(nMonth);
346         rDateTime.Year = sal::static_int_cast< sal_uInt16 >(nYear);
347         rDateTime.Hours = sal::static_int_cast< sal_uInt16 >(nHour);
348         rDateTime.Minutes = sal::static_int_cast< sal_uInt16 >(nMin);
349         rDateTime.Seconds = sal::static_int_cast< sal_uInt16 >(nSec);
350     }
351 
352     return bSuccess;
353 }
354 
355 
356 // ------------------------------------------------------------------------
357 // ------------------------------------------------------------------------
358 
359 void SAL_CALL XMLVersionListPersistence::store( const uno::Reference< embed::XStorage >& xRoot, const uno::Sequence< util::RevisionTag >& rVersions )
360     throw (::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
361 {
362     // no storage, no version list!
363     if ( xRoot.is() )
364     {
365         // get the services needed for writing the xml data
366         Reference< lang::XMultiServiceFactory > xServiceFactory =
367                 comphelper::getProcessServiceFactory();
368         DBG_ASSERT( xServiceFactory.is(), "XMLReader::Read: got no service manager" );
369 
370         Reference< XInterface > xWriter (xServiceFactory->createInstance(
371                 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer"))));
372         DBG_ASSERT( xWriter.is(), "com.sun.star.xml.sax.Writer service missing" );
373 
374         // check wether there's already a sub storage with the version info
375         // and delete it
376         OUString sVerName( RTL_CONSTASCII_USTRINGPARAM( XMLN_VERSIONSLIST ) );
377 
378         // is this really needed, we set the size to zero before doing
379         // anything with this stream?
380 /*      if ( xRoot->IsContained( sVerName ) )
381         {
382             xRoot->Remove( sVerName );
383             xRoot->Commit();
384         }
385 */
386 		try {
387         	// open (create) the sub storage with the version info
388         	uno::Reference< io::XStream > xVerStream = xRoot->openStreamElement(
389 											sVerName,
390 											embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
391 			if ( !xVerStream.is() )
392 				throw uno::RuntimeException();
393 
394 //REMOVE	        	// SetSize should not be neccessary because OpenStream( WRITE|TRUNC ) should already
395 //REMOVE	        	// have set the size to zero
396 //REMOVE		//      xVerStream->SetSize ( 0L );
397 //REMOVE	        	xVerStream->SetBufferSize( 16*1024 );
398 
399         	Reference< io::XOutputStream > xOut = xVerStream->getOutputStream();
400 			if ( !xOut.is() )
401 				throw uno::RuntimeException(); // the stream was successfuly opened for writing already
402 
403         	Reference< io::XActiveDataSource > xSrc( xWriter, uno::UNO_QUERY );
404         	xSrc->setOutputStream(xOut);
405 
406         	Reference< XDocumentHandler > xHandler( xWriter, uno::UNO_QUERY );
407 
408             // XMLVersionListExport aExp( pList, sVerName, xHandler );
409             XMLVersionListExport aExp( xServiceFactory, rVersions, sVerName, xHandler );
410 
411         	aExp.exportDoc( ::xmloff::token::XML_VERSION );
412 
413 //REMOVE	        	xVerStream->Commit();
414 			xVerStream = uno::Reference< io::XStream >(); // use refcounting for now to dispose
415 	//      xRoot->Commit();
416 		}
417 		catch( uno::Exception& )
418 		{
419             // TODO: error handling
420 		}
421     }
422 }
423 
424 // ------------------------------------------------------------------------
425 uno::Sequence< util::RevisionTag > SAL_CALL XMLVersionListPersistence::load( const uno::Reference< embed::XStorage >& xRoot )
426         throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
427 {
428     com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag > aVersions;
429 
430     const OUString sDocName( RTL_CONSTASCII_USTRINGPARAM( XMLN_VERSIONSLIST ) );
431 	uno::Reference< container::XNameAccess > xRootNames( xRoot, uno::UNO_QUERY );
432 
433 	try {
434     	if ( xRootNames.is() && xRootNames->hasByName( sDocName ) && xRoot->isStreamElement( sDocName ) )
435     	{
436         	Reference< lang::XMultiServiceFactory > xServiceFactory =
437                 	comphelper::getProcessServiceFactory();
438         	DBG_ASSERT( xServiceFactory.is(), "XMLReader::Read: got no service manager" );
439 
440         	InputSource aParserInput;
441 
442 			uno::Reference< beans::XPropertySet > xProps( xRoot, uno::UNO_QUERY );
443 			OSL_ENSURE( xProps.is(), "Storage must implement XPropertySet!\n" );
444 			if ( xProps.is() )
445 			{
446 				try {
447 					xProps->getPropertyValue( ::rtl::OUString::createFromAscii( "URL" ) ) >>= aParserInput.sSystemId;
448 				}
449 				catch( uno::Exception& )
450 				{}
451 			}
452 
453         	uno::Reference< io::XStream > xDocStream = xRoot->openStreamElement(
454 															sDocName,
455 															embed::ElementModes::READ );
456 			if ( !xDocStream.is() )
457 				throw uno::RuntimeException();
458 
459 //REMOVE	        	xDocStream->Seek( 0L );
460 //REMOVE	        	xDocStream->SetBufferSize( 16*1024 );
461 
462         	aParserInput.aInputStream = xDocStream->getInputStream();
463 			OSL_ENSURE( aParserInput.aInputStream.is(),
464 						"The stream was successfuly opened for reading, the input part must be accessible!\n" );
465 			if ( !aParserInput.aInputStream.is() )
466 				throw uno::RuntimeException();
467 
468         	// get parser
469         	Reference< XInterface > xXMLParser = xServiceFactory->createInstance(
470             	OUString::createFromAscii("com.sun.star.xml.sax.Parser") );
471         	DBG_ASSERT( xXMLParser.is(),
472             		"XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
473 
474         	// get filter
475             // Reference< XDocumentHandler > xFilter = new XMLVersionListImport( pList );
476             Reference< XDocumentHandler > xFilter = new XMLVersionListImport( xServiceFactory, aVersions );
477 
478         	// connect parser and filter
479         	Reference< XParser > xParser( xXMLParser, UNO_QUERY );
480         	xParser->setDocumentHandler( xFilter );
481 
482         	// parse
483         	try
484         	{
485             	xParser->parseStream( aParserInput );
486         	}
487         	catch( SAXParseException&  ) {}
488         	catch( SAXException&  )      {}
489         	catch( io::IOException& )    {}
490     	}
491 	}
492 	catch( uno::Exception& )
493 	{
494         // TODO: error handling
495 	}
496 
497     return aVersions;
498 }
499 
500 uno::Sequence< rtl::OUString > SAL_CALL XMLVersionListPersistence_getSupportedServiceNames()
501 	throw()
502 {
503 	const rtl::OUString aServiceName(
504         RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.DocumentRevisionListPersistence" ) );
505 	const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 );
506 	return aSeq;
507 }
508 
509 rtl::OUString SAL_CALL XMLVersionListPersistence_getImplementationName() throw()
510 {
511     return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XMLVersionListPersistence" ) );
512 }
513 
514 uno::Reference< uno::XInterface > SAL_CALL XMLVersionListPersistence_createInstance(
515 		const uno::Reference< lang::XMultiServiceFactory > &)
516 	throw( uno::Exception )
517 {
518     return (cppu::OWeakObject*)new XMLVersionListPersistence;
519 }
520 
521 uno::Sequence< rtl::OUString > SAL_CALL XMLVersionImExportOOO_getSupportedServiceNames()
522 	throw()
523 {
524 	const rtl::OUString aServiceName(
525         RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.DocumentRevisionListPersistence" ) );
526 	const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 );
527 	return aSeq;
528 }
529 
530 rtl::OUString SAL_CALL XMLVersionImExportOOO_getImplementationName() throw()
531 {
532     return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XMLVersionImExportOOo" ) );
533 }
534 
535 uno::Reference< uno::XInterface > SAL_CALL XMLVersionImExportOOO_createInstance(
536 		const uno::Reference< lang::XMultiServiceFactory > &)
537 	throw( uno::Exception )
538 {
539     return (cppu::OWeakObject*)new XMLVersionListPersistence;
540 }
541 
542