1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xmlversion.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmloff.hxx"
33 #include <com/sun/star/embed/ElementModes.hpp>
34 #include <tools/debug.hxx>
35 #include <unotools/streamwrap.hxx>
36 #include <xmlversion.hxx>
37 #include <xmloff/xmlmetae.hxx>
39 #include <xmloff/xmltoken.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <com/sun/star/io/XActiveDataSource.hpp>
42 #include <com/sun/star/io/XOutputStream.hpp>
43 #include <com/sun/star/util/DateTime.hpp>
44 #include <com/sun/star/xml/sax/InputSource.hpp>
45 #include <com/sun/star/xml/sax/XParser.hpp>
47 #include <tools/string.hxx>
50 using namespace ::com::sun::star::xml::sax
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star
;
53 using ::rtl::OUString
;
55 // ------------------------------------------------------------------------
57 sal_Char __FAR_DATA XMLN_VERSIONSLIST
[] = "VersionList.xml";
59 // ------------------------------------------------------------------------
62 XMLVersionListExport::XMLVersionListExport(
63 const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
> xServiceFactory
,
64 const com::sun::star::uno::Sequence
< com::sun::star::util::RevisionTag
>& rVersions
,
65 const OUString
&rFileName
,
66 Reference
< XDocumentHandler
> &rHandler
)
67 : SvXMLExport( xServiceFactory
, rFileName
, rHandler
),
68 maVersions( rVersions
)
70 _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_DC_IDX
, xmloff::token::GetXMLToken(xmloff::token::XML_NP_DC
),
71 xmloff::token::GetXMLToken(xmloff::token::XML_N_DC
), XML_NAMESPACE_DC
);
72 _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX
, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST
),
73 xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST
), XML_NAMESPACE_FRAMEWORK
);
76 // ------------------------------------------------------------------------
77 sal_uInt32
XMLVersionListExport::exportDoc( enum ::xmloff::token::XMLTokenEnum
)
79 GetDocHandler()->startDocument();
81 sal_uInt16 nPos
= _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_DC
);
83 AddAttribute( XML_NAMESPACE_NONE
, _GetNamespaceMap().GetAttrNameByIndex( nPos
),
84 _GetNamespaceMap().GetNameByIndex ( nPos
) );
86 nPos
= _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_FRAMEWORK
);
87 AddAttribute( XML_NAMESPACE_NONE
, _GetNamespaceMap().GetAttrNameByIndex( nPos
),
88 _GetNamespaceMap().GetNameByIndex ( nPos
) );
91 // the following object will write all collected attributes in its dtor
92 SvXMLElementExport
aRoot( *this, XML_NAMESPACE_FRAMEWORK
, xmloff::token::XML_VERSION_LIST
, sal_True
, sal_True
);
94 for ( sal_Int32 n
=0; n
<maVersions
.getLength(); n
++ )
96 const util::RevisionTag
& rInfo
= maVersions
[n
];
97 AddAttribute( XML_NAMESPACE_FRAMEWORK
,
98 xmloff::token::XML_TITLE
,
99 OUString( rInfo
.Identifier
) );
100 AddAttribute( XML_NAMESPACE_FRAMEWORK
,
101 xmloff::token::XML_COMMENT
,
102 OUString( rInfo
.Comment
) );
103 AddAttribute( XML_NAMESPACE_FRAMEWORK
,
104 xmloff::token::XML_CREATOR
,
105 OUString( rInfo
.Author
) );
108 SvXMLMetaExport::GetISODateTimeString( rInfo
.TimeStamp
);
110 AddAttribute( XML_NAMESPACE_DC
, xmloff::token::XML_DATE_TIME
, aDateStr
);
112 // the following object will write all collected attributes in its dtor
113 SvXMLElementExport
aEntry( *this, XML_NAMESPACE_FRAMEWORK
, xmloff::token::XML_VERSION_ENTRY
, sal_True
, sal_True
);
116 GetDocHandler()->endDocument();
120 // ------------------------------------------------------------------------
121 // ------------------------------------------------------------------------
124 XMLVersionListImport::XMLVersionListImport(
125 const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
> xServiceFactory
,
126 com::sun::star::uno::Sequence
< com::sun::star::util::RevisionTag
>& rVersions
)
127 : SvXMLImport(xServiceFactory
),
128 maVersions( rVersions
)
130 GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX
, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST
),
131 xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST
), XML_NAMESPACE_FRAMEWORK
);
134 // ------------------------------------------------------------------------
135 XMLVersionListImport::~XMLVersionListImport( void ) throw()
138 // ------------------------------------------------------------------------
139 SvXMLImportContext
*XMLVersionListImport::CreateContext(
141 const OUString
& rLocalName
,
142 const Reference
< XAttributeList
> & xAttrList
)
144 SvXMLImportContext
*pContext
= 0;
146 if ( XML_NAMESPACE_FRAMEWORK
== nPrefix
&&
147 rLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_LIST
) )
149 pContext
= new XMLVersionListContext( *this, nPrefix
, rLocalName
, xAttrList
);
153 pContext
= SvXMLImport::CreateContext( nPrefix
, rLocalName
, xAttrList
);
160 // ------------------------------------------------------------------------
161 // ------------------------------------------------------------------------
163 XMLVersionListContext::XMLVersionListContext( XMLVersionListImport
& rImport
,
165 const OUString
& rLocalName
,
166 const Reference
< XAttributeList
> & )
167 : SvXMLImportContext( rImport
, nPrefix
, rLocalName
)
168 , rLocalRef( rImport
)
172 // ------------------------------------------------------------------------
173 XMLVersionListContext::~XMLVersionListContext( void )
176 // ------------------------------------------------------------------------
177 SvXMLImportContext
*XMLVersionListContext::CreateChildContext( sal_uInt16 nPrefix
,
178 const OUString
& rLocalName
,
179 const Reference
< XAttributeList
> & xAttrList
)
181 SvXMLImportContext
*pContext
= 0;
183 if ( nPrefix
== XML_NAMESPACE_FRAMEWORK
&&
184 rLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_ENTRY
) )
186 pContext
= new XMLVersionContext( rLocalRef
, nPrefix
, rLocalName
, xAttrList
);
190 pContext
= new SvXMLImportContext( rLocalRef
, nPrefix
, rLocalName
);
196 // ------------------------------------------------------------------------
197 // ------------------------------------------------------------------------
199 XMLVersionContext::XMLVersionContext( XMLVersionListImport
& rImport
,
201 const OUString
& rLocalName
,
202 const Reference
< XAttributeList
> & xAttrList
)
203 : SvXMLImportContext( rImport
, nPref
, rLocalName
)
204 , rLocalRef( rImport
)
206 sal_Int16 nAttrCount
= xAttrList
.is() ? xAttrList
->getLength() : 0;
211 util::RevisionTag aInfo
;
212 for ( sal_Int16 i
=0; i
< nAttrCount
; i
++ )
215 const OUString
& rAttrName
= xAttrList
->getNameByIndex( i
);
216 sal_uInt16 nPrefix
= rImport
.GetNamespaceMap().GetKeyByAttrName( rAttrName
, &aLocalName
);
218 if ( XML_NAMESPACE_FRAMEWORK
== nPrefix
)
220 if ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_TITLE
) )
222 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
223 aInfo
.Identifier
= rAttrValue
;
225 else if ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_COMMENT
) )
227 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
228 aInfo
.Comment
= rAttrValue
;
230 else if ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_CREATOR
) )
232 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
233 aInfo
.Author
= rAttrValue
;
236 else if ( ( XML_NAMESPACE_DC
== nPrefix
) &&
237 ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_DATE_TIME
) ) )
239 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
240 util::DateTime aTime
;
241 if ( ParseISODateTimeString( rAttrValue
, aTime
) )
242 aInfo
.TimeStamp
= aTime
;
246 uno::Sequence
< util::RevisionTag
>& aList
= rLocalRef
.GetList();
247 sal_Int32 nLength
= aList
.getLength();
248 aList
.realloc( nLength
+1 );
249 aList
[nLength
] = aInfo
;
253 // ------------------------------------------------------------------------
254 XMLVersionContext::~XMLVersionContext( void )
257 // ------------------------------------------------------------------------
259 sal_Bool
XMLVersionContext::ParseISODateTimeString(
260 const rtl::OUString
& rString
,
261 util::DateTime
& rDateTime
)
263 sal_Bool bSuccess
= sal_True
;
265 OUString aDateStr
, aTimeStr
;
266 sal_Int32 nPos
= rString
.indexOf( (sal_Unicode
) 'T' );
269 aDateStr
= rString
.copy( 0, nPos
);
270 aTimeStr
= rString
.copy( nPos
+ 1 );
273 aDateStr
= rString
; // no separator: only date part
276 sal_Int32 nMonth
= 1;
282 const sal_Unicode
* pStr
= aDateStr
.getStr();
283 sal_Int32 nDateTokens
= 1;
290 if ( nDateTokens
> 3 || aDateStr
.getLength() == 0 )
291 bSuccess
= sal_False
;
295 nYear
= aDateStr
.getToken( 0, '-', n
).toInt32();
297 bSuccess
= sal_False
;
298 else if ( nDateTokens
>= 2 )
300 nMonth
= aDateStr
.getToken( 0, '-', n
).toInt32();
302 bSuccess
= sal_False
;
303 else if ( nDateTokens
>= 3 )
305 nDay
= aDateStr
.getToken( 0, '-', n
).toInt32();
307 bSuccess
= sal_False
;
312 if ( bSuccess
&& aTimeStr
.getLength() > 0 ) // time is optional
314 pStr
= aTimeStr
.getStr();
315 sal_Int32 nTimeTokens
= 1;
322 if ( nTimeTokens
> 3 )
323 bSuccess
= sal_False
;
327 nHour
= aTimeStr
.getToken( 0, ':', n
).toInt32();
329 bSuccess
= sal_False
;
330 else if ( nTimeTokens
>= 2 )
332 nMin
= aTimeStr
.getToken( 0, ':', n
).toInt32();
334 bSuccess
= sal_False
;
335 else if ( nTimeTokens
>= 3 )
337 nSec
= aTimeStr
.getToken( 0, ':', n
).toInt32();
339 bSuccess
= sal_False
;
347 rDateTime
.Day
= sal::static_int_cast
< sal_uInt16
>(nDay
);
348 rDateTime
.Month
= sal::static_int_cast
< sal_uInt16
>(nMonth
);
349 rDateTime
.Year
= sal::static_int_cast
< sal_uInt16
>(nYear
);
350 rDateTime
.Hours
= sal::static_int_cast
< sal_uInt16
>(nHour
);
351 rDateTime
.Minutes
= sal::static_int_cast
< sal_uInt16
>(nMin
);
352 rDateTime
.Seconds
= sal::static_int_cast
< sal_uInt16
>(nSec
);
359 // ------------------------------------------------------------------------
360 // ------------------------------------------------------------------------
362 void SAL_CALL
XMLVersionListPersistence::store( const uno::Reference
< embed::XStorage
>& xRoot
, const uno::Sequence
< util::RevisionTag
>& rVersions
)
363 throw (::com::sun::star::io::IOException
, ::com::sun::star::uno::Exception
, ::com::sun::star::uno::RuntimeException
)
365 // no storage, no version list!
368 // get the services needed for writing the xml data
369 Reference
< lang::XMultiServiceFactory
> xServiceFactory
=
370 comphelper::getProcessServiceFactory();
371 DBG_ASSERT( xServiceFactory
.is(), "XMLReader::Read: got no service manager" );
373 Reference
< XInterface
> xWriter (xServiceFactory
->createInstance(
374 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer"))));
375 DBG_ASSERT( xWriter
.is(), "com.sun.star.xml.sax.Writer service missing" );
377 // check wether there's already a sub storage with the version info
379 OUString
sVerName( RTL_CONSTASCII_USTRINGPARAM( XMLN_VERSIONSLIST
) );
381 // is this really needed, we set the size to zero before doing
382 // anything with this stream?
383 /* if ( xRoot->IsContained( sVerName ) )
385 xRoot->Remove( sVerName );
390 // open (create) the sub storage with the version info
391 uno::Reference
< io::XStream
> xVerStream
= xRoot
->openStreamElement(
393 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
394 if ( !xVerStream
.is() )
395 throw uno::RuntimeException();
397 //REMOVE // SetSize should not be neccessary because OpenStream( WRITE|TRUNC ) should already
398 //REMOVE // have set the size to zero
399 //REMOVE // xVerStream->SetSize ( 0L );
400 //REMOVE xVerStream->SetBufferSize( 16*1024 );
402 Reference
< io::XOutputStream
> xOut
= xVerStream
->getOutputStream();
404 throw uno::RuntimeException(); // the stream was successfuly opened for writing already
406 Reference
< io::XActiveDataSource
> xSrc( xWriter
, uno::UNO_QUERY
);
407 xSrc
->setOutputStream(xOut
);
409 Reference
< XDocumentHandler
> xHandler( xWriter
, uno::UNO_QUERY
);
411 // XMLVersionListExport aExp( pList, sVerName, xHandler );
412 XMLVersionListExport
aExp( xServiceFactory
, rVersions
, sVerName
, xHandler
);
414 aExp
.exportDoc( ::xmloff::token::XML_VERSION
);
416 //REMOVE xVerStream->Commit();
417 xVerStream
= uno::Reference
< io::XStream
>(); // use refcounting for now to dispose
420 catch( uno::Exception
& )
422 // TODO: error handling
427 // ------------------------------------------------------------------------
428 uno::Sequence
< util::RevisionTag
> SAL_CALL
XMLVersionListPersistence::load( const uno::Reference
< embed::XStorage
>& xRoot
)
429 throw (::com::sun::star::container::NoSuchElementException
, ::com::sun::star::io::IOException
, ::com::sun::star::uno::Exception
, ::com::sun::star::uno::RuntimeException
)
431 com::sun::star::uno::Sequence
< com::sun::star::util::RevisionTag
> aVersions
;
433 const OUString
sDocName( RTL_CONSTASCII_USTRINGPARAM( XMLN_VERSIONSLIST
) );
434 uno::Reference
< container::XNameAccess
> xRootNames( xRoot
, uno::UNO_QUERY
);
437 if ( xRootNames
.is() && xRootNames
->hasByName( sDocName
) && xRoot
->isStreamElement( sDocName
) )
439 Reference
< lang::XMultiServiceFactory
> xServiceFactory
=
440 comphelper::getProcessServiceFactory();
441 DBG_ASSERT( xServiceFactory
.is(), "XMLReader::Read: got no service manager" );
443 InputSource aParserInput
;
445 uno::Reference
< beans::XPropertySet
> xProps( xRoot
, uno::UNO_QUERY
);
446 OSL_ENSURE( xProps
.is(), "Storage must implement XPropertySet!\n" );
450 xProps
->getPropertyValue( ::rtl::OUString::createFromAscii( "URL" ) ) >>= aParserInput
.sSystemId
;
452 catch( uno::Exception
& )
456 uno::Reference
< io::XStream
> xDocStream
= xRoot
->openStreamElement(
458 embed::ElementModes::READ
);
459 if ( !xDocStream
.is() )
460 throw uno::RuntimeException();
462 //REMOVE xDocStream->Seek( 0L );
463 //REMOVE xDocStream->SetBufferSize( 16*1024 );
465 aParserInput
.aInputStream
= xDocStream
->getInputStream();
466 OSL_ENSURE( aParserInput
.aInputStream
.is(),
467 "The stream was successfuly opened for reading, the input part must be accessible!\n" );
468 if ( !aParserInput
.aInputStream
.is() )
469 throw uno::RuntimeException();
472 Reference
< XInterface
> xXMLParser
= xServiceFactory
->createInstance(
473 OUString::createFromAscii("com.sun.star.xml.sax.Parser") );
474 DBG_ASSERT( xXMLParser
.is(),
475 "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
478 // Reference< XDocumentHandler > xFilter = new XMLVersionListImport( pList );
479 Reference
< XDocumentHandler
> xFilter
= new XMLVersionListImport( xServiceFactory
, aVersions
);
481 // connect parser and filter
482 Reference
< XParser
> xParser( xXMLParser
, UNO_QUERY
);
483 xParser
->setDocumentHandler( xFilter
);
488 xParser
->parseStream( aParserInput
);
490 catch( SAXParseException
& ) {}
491 catch( SAXException
& ) {}
492 catch( io::IOException
& ) {}
495 catch( uno::Exception
& )
497 // TODO: error handling
503 uno::Sequence
< rtl::OUString
> SAL_CALL
XMLVersionListPersistence_getSupportedServiceNames()
506 const rtl::OUString
aServiceName(
507 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.DocumentRevisionListPersistence" ) );
508 const uno::Sequence
< rtl::OUString
> aSeq( &aServiceName
, 1 );
512 rtl::OUString SAL_CALL
XMLVersionListPersistence_getImplementationName() throw()
514 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XMLVersionListPersistence" ) );
517 uno::Reference
< uno::XInterface
> SAL_CALL
XMLVersionListPersistence_createInstance(
518 const uno::Reference
< lang::XMultiServiceFactory
> &)
519 throw( uno::Exception
)
521 return (cppu::OWeakObject
*)new XMLVersionListPersistence
;
524 uno::Sequence
< rtl::OUString
> SAL_CALL
XMLVersionImExportOOO_getSupportedServiceNames()
527 const rtl::OUString
aServiceName(
528 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.DocumentRevisionListPersistence" ) );
529 const uno::Sequence
< rtl::OUString
> aSeq( &aServiceName
, 1 );
533 rtl::OUString SAL_CALL
XMLVersionImExportOOO_getImplementationName() throw()
535 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XMLVersionImExportOOo" ) );
538 uno::Reference
< uno::XInterface
> SAL_CALL
XMLVersionImExportOOO_createInstance(
539 const uno::Reference
< lang::XMultiServiceFactory
> &)
540 throw( uno::Exception
)
542 return (cppu::OWeakObject
*)new XMLVersionListPersistence
;