1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/embed/ElementModes.hpp>
21 #include <unotools/streamwrap.hxx>
22 #include <xmlversion.hxx>
23 #include <xmloff/xmlmetae.hxx>
25 #include <xmloff/xmltoken.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <com/sun/star/io/XActiveDataSource.hpp>
28 #include <com/sun/star/io/XOutputStream.hpp>
29 #include <com/sun/star/util/DateTime.hpp>
30 #include <com/sun/star/util/MeasureUnit.hpp>
31 #include <com/sun/star/xml/sax/InputSource.hpp>
32 #include <com/sun/star/xml/sax/Parser.hpp>
33 #include <com/sun/star/xml/sax/Writer.hpp>
34 #include <cppuhelper/supportsservice.hxx>
36 using namespace ::com::sun::star::xml::sax
;
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star
;
40 const char XMLN_VERSIONSLIST
[] = "VersionList.xml";
42 XMLVersionListExport::XMLVersionListExport(
43 const css::uno::Reference
< css::uno::XComponentContext
>& rContext
,
44 const css::uno::Sequence
< css::util::RevisionTag
>& rVersions
,
45 const OUString
&rFileName
,
46 Reference
< XDocumentHandler
> &rHandler
)
47 : SvXMLExport( rContext
, "", rFileName
, util::MeasureUnit::CM
, rHandler
),
48 maVersions( rVersions
)
50 GetNamespaceMap_().AddAtIndex( XML_NAMESPACE_DC_IDX
, xmloff::token::GetXMLToken(xmloff::token::XML_NP_DC
),
51 xmloff::token::GetXMLToken(xmloff::token::XML_N_DC
), XML_NAMESPACE_DC
);
52 GetNamespaceMap_().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX
, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST
),
53 xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST
), XML_NAMESPACE_FRAMEWORK
);
56 sal_uInt32
XMLVersionListExport::exportDoc( enum ::xmloff::token::XMLTokenEnum
)
58 GetDocHandler()->startDocument();
60 addChaffWhenEncryptedStorage();
62 sal_uInt16 nPos
= SvXMLNamespaceMap::GetIndexByKey( XML_NAMESPACE_DC
);
64 AddAttribute( XML_NAMESPACE_NONE
, GetNamespaceMap_().GetAttrNameByIndex( nPos
),
65 GetNamespaceMap_().GetNameByIndex ( nPos
) );
67 nPos
= SvXMLNamespaceMap::GetIndexByKey( XML_NAMESPACE_FRAMEWORK
);
68 AddAttribute( XML_NAMESPACE_NONE
, GetNamespaceMap_().GetAttrNameByIndex( nPos
),
69 GetNamespaceMap_().GetNameByIndex ( nPos
) );
72 // the following object will write all collected attributes in its dtor
73 SvXMLElementExport
aRoot( *this, XML_NAMESPACE_FRAMEWORK
, xmloff::token::XML_VERSION_LIST
, true, true );
75 for ( sal_Int32 n
=0; n
<maVersions
.getLength(); n
++ )
77 const util::RevisionTag
& rInfo
= maVersions
[n
];
78 AddAttribute( XML_NAMESPACE_FRAMEWORK
,
79 xmloff::token::XML_TITLE
,
80 OUString( rInfo
.Identifier
) );
81 AddAttribute( XML_NAMESPACE_FRAMEWORK
,
82 xmloff::token::XML_COMMENT
,
83 OUString( rInfo
.Comment
) );
84 AddAttribute( XML_NAMESPACE_FRAMEWORK
,
85 xmloff::token::XML_CREATOR
,
86 OUString( rInfo
.Author
) );
89 SvXMLMetaExport::GetISODateTimeString( rInfo
.TimeStamp
);
91 AddAttribute( XML_NAMESPACE_DC
, xmloff::token::XML_DATE_TIME
, aDateStr
);
93 // the following object will write all collected attributes in its dtor
94 SvXMLElementExport
aEntry( *this, XML_NAMESPACE_FRAMEWORK
, xmloff::token::XML_VERSION_ENTRY
, true, true );
97 GetDocHandler()->endDocument();
101 XMLVersionListImport::XMLVersionListImport(
102 const css::uno::Reference
< css::uno::XComponentContext
>& rContext
,
103 css::uno::Sequence
< css::util::RevisionTag
>& rVersions
)
104 : SvXMLImport(rContext
, ""),
105 maVersions( rVersions
)
107 GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX
, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST
),
108 xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST
), XML_NAMESPACE_FRAMEWORK
);
111 XMLVersionListImport::~XMLVersionListImport() throw()
114 SvXMLImportContext
*XMLVersionListImport::CreateContext(
116 const OUString
& rLocalName
,
117 const Reference
< XAttributeList
> & xAttrList
)
119 SvXMLImportContext
*pContext
= nullptr;
121 if ( XML_NAMESPACE_FRAMEWORK
== nPrefix
&&
122 rLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_LIST
) )
124 pContext
= new XMLVersionListContext( *this, nPrefix
, rLocalName
, xAttrList
);
128 pContext
= SvXMLImport::CreateContext( nPrefix
, rLocalName
, xAttrList
);
134 XMLVersionListContext::XMLVersionListContext( XMLVersionListImport
& rImport
,
136 const OUString
& rLocalName
,
137 const Reference
< XAttributeList
> & )
138 : SvXMLImportContext( rImport
, nPrefix
, rLocalName
)
139 , rLocalRef( rImport
)
143 XMLVersionListContext::~XMLVersionListContext()
146 SvXMLImportContext
*XMLVersionListContext::CreateChildContext( sal_uInt16 nPrefix
,
147 const OUString
& rLocalName
,
148 const Reference
< XAttributeList
> & xAttrList
)
150 SvXMLImportContext
*pContext
= nullptr;
152 if ( nPrefix
== XML_NAMESPACE_FRAMEWORK
&&
153 rLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_ENTRY
) )
155 pContext
= new XMLVersionContext( rLocalRef
, nPrefix
, rLocalName
, xAttrList
);
159 pContext
= new SvXMLImportContext( rLocalRef
, nPrefix
, rLocalName
);
165 XMLVersionContext::XMLVersionContext( XMLVersionListImport
& rImport
,
167 const OUString
& rLocalName
,
168 const Reference
< XAttributeList
> & xAttrList
)
169 : SvXMLImportContext( rImport
, nPref
, rLocalName
)
170 , rLocalRef( rImport
)
172 sal_Int16 nAttrCount
= xAttrList
.is() ? xAttrList
->getLength() : 0;
177 util::RevisionTag aInfo
;
178 for ( sal_Int16 i
=0; i
< nAttrCount
; i
++ )
181 const OUString
& rAttrName
= xAttrList
->getNameByIndex( i
);
182 sal_uInt16 nPrefix
= rImport
.GetNamespaceMap().GetKeyByAttrName( rAttrName
, &aLocalName
);
184 if ( XML_NAMESPACE_FRAMEWORK
== nPrefix
)
186 if ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_TITLE
) )
188 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
189 aInfo
.Identifier
= rAttrValue
;
191 else if ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_COMMENT
) )
193 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
194 aInfo
.Comment
= rAttrValue
;
196 else if ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_CREATOR
) )
198 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
199 aInfo
.Author
= rAttrValue
;
202 else if ( ( XML_NAMESPACE_DC
== nPrefix
) &&
203 ( aLocalName
== xmloff::token::GetXMLToken(xmloff::token::XML_DATE_TIME
) ) )
205 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
206 util::DateTime aTime
;
207 if ( ParseISODateTimeString( rAttrValue
, aTime
) )
208 aInfo
.TimeStamp
= aTime
;
212 uno::Sequence
< util::RevisionTag
>& aList
= rLocalRef
.GetList();
213 sal_Int32 nLength
= aList
.getLength();
214 aList
.realloc( nLength
+1 );
215 aList
[nLength
] = aInfo
;
218 XMLVersionContext::~XMLVersionContext()
221 bool XMLVersionContext::ParseISODateTimeString(
222 const OUString
& rString
,
223 util::DateTime
& rDateTime
)
225 bool bSuccess
= true;
227 OUString aDateStr
, aTimeStr
;
228 sal_Int32 nPos
= rString
.indexOf( (sal_Unicode
) 'T' );
231 aDateStr
= rString
.copy( 0, nPos
);
232 aTimeStr
= rString
.copy( nPos
+ 1 );
235 aDateStr
= rString
; // no separator: only date part
238 sal_Int32 nMonth
= 1;
244 const sal_Unicode
* pStr
= aDateStr
.getStr();
245 sal_Int32 nDateTokens
= 1;
252 if ( nDateTokens
> 3 || aDateStr
.isEmpty() )
257 nYear
= aDateStr
.getToken( 0, '-', n
).toInt32();
260 else if ( nDateTokens
>= 2 )
262 nMonth
= aDateStr
.getToken( 0, '-', n
).toInt32();
265 else if ( nDateTokens
>= 3 )
267 nDay
= aDateStr
.getToken( 0, '-', n
).toInt32();
274 if ( bSuccess
&& !aTimeStr
.isEmpty() ) // time is optional
276 pStr
= aTimeStr
.getStr();
277 sal_Int32 nTimeTokens
= 1;
284 if ( nTimeTokens
> 3 )
289 nHour
= aTimeStr
.getToken( 0, ':', n
).toInt32();
292 else if ( nTimeTokens
>= 2 )
294 nMin
= aTimeStr
.getToken( 0, ':', n
).toInt32();
297 else if ( nTimeTokens
>= 3 )
299 nSec
= aTimeStr
.getToken( 0, ':', n
).toInt32();
309 rDateTime
.Day
= sal::static_int_cast
< sal_uInt16
>(nDay
);
310 rDateTime
.Month
= sal::static_int_cast
< sal_uInt16
>(nMonth
);
311 rDateTime
.Year
= sal::static_int_cast
< sal_uInt16
>(nYear
);
312 rDateTime
.Hours
= sal::static_int_cast
< sal_uInt16
>(nHour
);
313 rDateTime
.Minutes
= sal::static_int_cast
< sal_uInt16
>(nMin
);
314 rDateTime
.Seconds
= sal::static_int_cast
< sal_uInt16
>(nSec
);
320 void SAL_CALL
XMLVersionListPersistence::store( const uno::Reference
< embed::XStorage
>& xRoot
, const uno::Sequence
< util::RevisionTag
>& rVersions
)
321 throw (css::io::IOException
, css::uno::Exception
, css::uno::RuntimeException
, std::exception
)
323 // no storage, no version list!
326 // get the services needed for writing the xml data
327 Reference
< uno::XComponentContext
> xContext
=
328 comphelper::getProcessComponentContext();
330 Reference
< XWriter
> xWriter
= Writer::create(xContext
);
332 // check whether there's already a sub storage with the version info
334 OUString
sVerName( XMLN_VERSIONSLIST
);
337 // open (create) the sub storage with the version info
338 uno::Reference
< io::XStream
> xVerStream
= xRoot
->openStreamElement(
340 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
341 if ( !xVerStream
.is() )
342 throw uno::RuntimeException();
344 Reference
< io::XOutputStream
> xOut
= xVerStream
->getOutputStream();
346 throw uno::RuntimeException(); // the stream was successfully opened for writing already
348 Reference
< io::XActiveDataSource
> xSrc( xWriter
, uno::UNO_QUERY
);
349 xSrc
->setOutputStream(xOut
);
351 Reference
< XDocumentHandler
> xHandler( xWriter
, uno::UNO_QUERY
);
353 rtl::Reference
< XMLVersionListExport
> xExp( new XMLVersionListExport( xContext
, rVersions
, sVerName
, xHandler
) );
355 xExp
->exportDoc( ::xmloff::token::XML_VERSION
);
357 xVerStream
.clear(); // use refcounting for now to dispose
359 catch( uno::Exception
& )
361 // TODO: error handling
366 uno::Sequence
< util::RevisionTag
> SAL_CALL
XMLVersionListPersistence::load( const uno::Reference
< embed::XStorage
>& xRoot
)
367 throw (css::container::NoSuchElementException
, css::io::IOException
, css::uno::Exception
, css::uno::RuntimeException
, std::exception
)
369 css::uno::Sequence
< css::util::RevisionTag
> aVersions
;
371 const OUString
sDocName( XMLN_VERSIONSLIST
);
372 uno::Reference
< container::XNameAccess
> xRootNames( xRoot
, uno::UNO_QUERY
);
375 if ( xRootNames
.is() && xRootNames
->hasByName( sDocName
) && xRoot
->isStreamElement( sDocName
) )
377 Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
379 InputSource aParserInput
;
381 uno::Reference
< beans::XPropertySet
> xProps( xRoot
, uno::UNO_QUERY
);
382 OSL_ENSURE( xProps
.is(), "Storage must implement XPropertySet!\n" );
386 xProps
->getPropertyValue("URL") >>= aParserInput
.sSystemId
;
388 catch( uno::Exception
& )
392 uno::Reference
< io::XStream
> xDocStream
= xRoot
->openStreamElement(
394 embed::ElementModes::READ
);
395 if ( !xDocStream
.is() )
396 throw uno::RuntimeException();
398 aParserInput
.aInputStream
= xDocStream
->getInputStream();
399 OSL_ENSURE( aParserInput
.aInputStream
.is(),
400 "The stream was successfully opened for reading, the input part must be accessible!\n" );
401 if ( !aParserInput
.aInputStream
.is() )
402 throw uno::RuntimeException();
405 Reference
< XDocumentHandler
> xFilter
= new XMLVersionListImport( xContext
, aVersions
);
407 // connect parser and filter
408 Reference
< XParser
> xParser
= xml::sax::Parser::create(xContext
);
409 xParser
->setDocumentHandler( xFilter
);
414 xParser
->parseStream( aParserInput
);
416 catch( SAXParseException
& ) {}
417 catch( SAXException
& ) {}
418 catch( io::IOException
& ) {}
421 catch( uno::Exception
& )
423 // TODO: error handling
429 OUString
XMLVersionListPersistence::getImplementationName()
430 throw (css::uno::RuntimeException
, std::exception
)
432 return OUString("XMLVersionListPersistence");
435 sal_Bool
XMLVersionListPersistence::supportsService(
436 OUString
const & ServiceName
)
437 throw (css::uno::RuntimeException
, std::exception
)
439 return cppu::supportsService(this, ServiceName
);
442 css::uno::Sequence
<OUString
>
443 XMLVersionListPersistence::getSupportedServiceNames()
444 throw (css::uno::RuntimeException
, std::exception
)
446 return css::uno::Sequence
<OUString
>{
447 "com.sun.star.document.DocumentRevisionListPersistence"};
450 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
451 XMLVersionListPersistence_get_implementation(
452 css::uno::XComponentContext
*,
453 css::uno::Sequence
<css::uno::Any
> const &)
455 return cppu::acquire(new XMLVersionListPersistence());
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */