update credits
[LibreOffice.git] / oox / source / docprop / docprophandler.cxx
blobe7ecd973e7801fb1a2548eead3e8ee30fc7d07d1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 "docprophandler.hxx"
22 #include <com/sun/star/beans/PropertyAttribute.hpp>
23 #include <com/sun/star/beans/PropertyExistException.hpp>
24 #include <com/sun/star/lang/Locale.hpp>
26 #include <osl/time.h>
28 #include <vector>
29 #include <boost/algorithm/string.hpp>
31 #include "oox/helper/attributelist.hxx"
33 using namespace ::com::sun::star;
35 namespace oox {
36 namespace docprop {
38 // ------------------------------------------------
39 OOXMLDocPropHandler::OOXMLDocPropHandler( const uno::Reference< uno::XComponentContext >& xContext,
40 const uno::Reference< document::XDocumentProperties > xDocProp )
41 : m_xContext( xContext )
42 , m_xDocProp( xDocProp )
43 , m_nState( 0 )
44 , m_nBlock( 0 )
45 , m_nType( 0 )
46 , m_nInBlock( 0 )
48 if ( !xContext.is() || !xDocProp.is() )
49 throw uno::RuntimeException();
52 // ------------------------------------------------
53 OOXMLDocPropHandler::~OOXMLDocPropHandler()
57 // ------------------------------------------------
58 void OOXMLDocPropHandler::InitNew()
60 m_nState = 0;
61 m_nBlock = 0;
62 m_aCustomPropertyName = "";
63 m_nType = 0;
64 m_nInBlock = 0;
67 // ------------------------------------------------
68 void OOXMLDocPropHandler::AddCustomProperty( const uno::Any& aAny )
70 if ( !m_aCustomPropertyName.isEmpty() )
72 const uno::Reference< beans::XPropertyContainer > xUserProps =
73 m_xDocProp->getUserDefinedProperties();
74 if ( !xUserProps.is() )
75 throw uno::RuntimeException();
77 try
79 xUserProps->addProperty( m_aCustomPropertyName,
80 beans::PropertyAttribute::REMOVABLE, aAny );
82 catch( beans::PropertyExistException& )
84 // conflicts with core and extended properties are possible
86 catch( uno::Exception& )
88 OSL_FAIL( "Can not add custom property!" );
93 // ------------------------------------------------
94 util::DateTime OOXMLDocPropHandler::GetDateTimeFromW3CDTF( const OUString& aChars )
96 oslDateTime aOslDTime = { 0, 0, 0, 0, 0, 0, 0, 0 };
97 sal_Int32 nLen = aChars.getLength();
98 if ( nLen >= 4 )
100 aOslDTime.Year = (sal_Int16)aChars.copy( 0, 4 ).toInt32();
102 if ( nLen >= 7 && aChars.getStr()[4] == (sal_Unicode)'-' )
104 aOslDTime.Month = (sal_uInt16)aChars.copy( 5, 2 ).toInt32();
106 if ( nLen >= 10 && aChars.getStr()[7] == (sal_Unicode)'-' )
108 aOslDTime.Day = (sal_uInt16)aChars.copy( 8, 2 ).toInt32();
110 if ( nLen >= 16 && aChars.getStr()[10] == (sal_Unicode)'T' && aChars.getStr()[13] == (sal_Unicode)':' )
112 aOslDTime.Hours = (sal_uInt16)aChars.copy( 11, 2 ).toInt32();
113 aOslDTime.Minutes = (sal_uInt16)aChars.copy( 14, 2 ).toInt32();
115 sal_Int32 nOptTime = 0;
116 if ( nLen >= 19 && aChars.getStr()[16] == (sal_Unicode)':' )
118 aOslDTime.Seconds = (sal_uInt16)aChars.copy( 17, 2 ).toInt32();
119 nOptTime += 3;
120 if ( nLen >= 21 && aChars.getStr()[19] == (sal_Unicode)'.' )
122 aOslDTime.NanoSeconds = (sal_uInt32)(aChars.copy( 20, 1 ).toInt32() * 10e8);
123 nOptTime += 2;
127 sal_Int32 nModif = 0;
128 if ( nLen >= 16 + nOptTime + 6 )
130 if ( ( aChars.getStr()[16 + nOptTime] == (sal_Unicode)'+' || aChars.getStr()[16 + nOptTime] == (sal_Unicode)'-' )
131 && aChars.getStr()[16 + nOptTime + 3] == (sal_Unicode)':' )
134 nModif = aChars.copy( 16 + nOptTime + 1, 2 ).toInt32() * 3600;
135 nModif += aChars.copy( 16 + nOptTime + 4, 2 ).toInt32() * 60;
136 if ( aChars.getStr()[16 + nOptTime] == (sal_Unicode)'-' )
137 nModif *= -1;
141 if ( nModif )
143 // convert to UTC time
144 TimeValue aTmp;
145 if ( osl_getTimeValueFromDateTime( &aOslDTime, &aTmp ) )
147 aTmp.Seconds += nModif;
148 osl_getDateTimeFromTimeValue( &aTmp, &aOslDTime );
156 return util::DateTime( aOslDTime.NanoSeconds, aOslDTime.Seconds,
157 aOslDTime.Minutes, aOslDTime.Hours,
158 aOslDTime.Day, aOslDTime.Month, aOslDTime.Year, false);
161 // ------------------------------------------------
162 uno::Sequence< OUString > OOXMLDocPropHandler::GetKeywordsSet( const OUString& aChars )
164 if ( !aChars.isEmpty() )
166 std::string aUtf8Chars = OUStringToOString( aChars, RTL_TEXTENCODING_UTF8 ).getStr();
167 std::vector<std::string> aUtf8Result;
168 boost::split( aUtf8Result, aUtf8Chars, boost::is_any_of(" ,;:\t"), boost::token_compress_on );
170 if (!aUtf8Result.empty())
172 uno::Sequence< OUString > aResult( aUtf8Result.size() );
173 OUString* pResultValues = aResult.getArray();
174 for ( std::vector< std::string >::const_iterator i = aUtf8Result.begin();
175 i != aUtf8Result.end(); ++i, ++pResultValues )
176 *pResultValues = OUString( i->c_str(), static_cast< sal_Int32 >( i->size() ),RTL_TEXTENCODING_UTF8 );
178 return aResult;
181 return uno::Sequence< OUString >();
183 // ------------------------------------------------
184 lang::Locale OOXMLDocPropHandler::GetLanguage( const OUString& aChars )
186 lang::Locale aResult;
187 if ( aChars.getLength() >= 2 )
189 aResult.Language = aChars.copy( 0, 2 );
190 if ( aChars.getLength() >= 5 && aChars.getStr()[2] == (sal_Unicode)'-' )
191 aResult.Country = aChars.copy( 3, 2 );
193 // TODO/LATER: the variant could be also detected
196 return aResult;
199 // ------------------------------------------------
200 void OOXMLDocPropHandler::UpdateDocStatistic( const OUString& aChars )
202 uno::Sequence< beans::NamedValue > aSet = m_xDocProp->getDocumentStatistics();
203 OUString aName;
205 switch( m_nBlock )
207 case EXTPR_TOKEN( Characters ):
208 aName = "CharacterCount";
209 break;
211 case EXTPR_TOKEN( Pages ):
212 aName = "PageCount";
213 break;
215 case EXTPR_TOKEN( Words ):
216 aName = "WordCount";
217 break;
219 case EXTPR_TOKEN( Paragraphs ):
220 aName = "ParagraphCount";
221 break;
223 default:
224 OSL_FAIL( "Unexpected statistic!" );
225 break;
228 if ( !aName.isEmpty() )
230 sal_Bool bFound = sal_False;
231 sal_Int32 nLen = aSet.getLength();
232 for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ )
233 if ( aSet[nInd].Name.equals( aName ) )
235 aSet[nInd].Value = uno::makeAny( aChars.toInt32() );
236 bFound = sal_True;
237 break;
240 if ( !bFound )
242 aSet.realloc( nLen + 1 );
243 aSet[nLen].Name = aName;
244 aSet[nLen].Value = uno::makeAny( aChars.toInt32() );
247 m_xDocProp->setDocumentStatistics( aSet );
251 // ------------------------------------------------
252 // com.sun.star.xml.sax.XFastDocumentHandler
253 // ------------------------------------------------
254 void SAL_CALL OOXMLDocPropHandler::startDocument()
255 throw (xml::sax::SAXException, uno::RuntimeException)
259 // ------------------------------------------------
260 void SAL_CALL OOXMLDocPropHandler::endDocument()
261 throw (xml::sax::SAXException, uno::RuntimeException)
263 InitNew();
266 // ------------------------------------------------
267 void SAL_CALL OOXMLDocPropHandler::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& )
268 throw (xml::sax::SAXException, uno::RuntimeException)
273 // com.sun.star.xml.sax.XFastContextHandler
274 // ------------------------------------------------
275 void SAL_CALL OOXMLDocPropHandler::startFastElement( ::sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttribs )
276 throw (xml::sax::SAXException, uno::RuntimeException)
278 if ( !m_nInBlock && !m_nState )
280 if ( nElement == COREPR_TOKEN( coreProperties )
281 || nElement == EXTPR_TOKEN( Properties )
282 || nElement == CUSTPR_TOKEN( Properties ) )
284 m_nState = nElement;
286 else
288 OSL_FAIL( "Unexpected file format!" );
291 else if ( m_nState && m_nInBlock == 1 ) // that tag should contain the property name
293 // Currently the attributes are ignored for the core properties since the only
294 // known attribute is xsi:type that can only be used with dcterms:created and
295 // dcterms:modified, and this element is allowed currently to have only one value dcterms:W3CDTF
296 m_nBlock = nElement;
298 if ( xAttribs.is() && xAttribs->hasAttribute( XML_name ) )
299 m_aCustomPropertyName = xAttribs->getValue( XML_name );
301 else if ( m_nState && m_nInBlock && m_nInBlock == 2 && getNamespace( nElement ) == NMSP_officeDocPropsVT )
303 m_nType = nElement;
305 else
307 OSL_FAIL( "For now unexpected tags are ignored!" );
310 if ( m_nInBlock == SAL_MAX_INT32 )
311 throw uno::RuntimeException();
313 m_nInBlock++;
316 // ------------------------------------------------
317 void SAL_CALL OOXMLDocPropHandler::startUnknownElement( const OUString& aNamespace, const OUString& aName, const uno::Reference< xml::sax::XFastAttributeList >& )
318 throw (xml::sax::SAXException, uno::RuntimeException)
320 OUString aUnknown = "Unknown element" + aNamespace + ":" + aName;
321 OSL_FAIL( OUStringToOString( aUnknown, RTL_TEXTENCODING_UTF8 ).getStr() );
323 if ( m_nInBlock == SAL_MAX_INT32 )
324 throw uno::RuntimeException();
326 m_nInBlock++;
329 // ------------------------------------------------
330 void SAL_CALL OOXMLDocPropHandler::endFastElement( ::sal_Int32 )
331 throw (xml::sax::SAXException, uno::RuntimeException)
333 if ( m_nInBlock )
335 m_nInBlock--;
337 if ( !m_nInBlock )
338 m_nState = 0;
339 else if ( m_nInBlock == 1 )
341 m_nBlock = 0;
342 m_aCustomPropertyName = "";
344 else if ( m_nInBlock == 2 )
345 m_nType = 0;
349 // ------------------------------------------------
350 void SAL_CALL OOXMLDocPropHandler::endUnknownElement( const OUString&, const OUString& )
351 throw (xml::sax::SAXException, uno::RuntimeException)
353 if ( m_nInBlock )
354 m_nInBlock--;
357 // ------------------------------------------------
358 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL OOXMLDocPropHandler::createFastChildContext( ::sal_Int32, const uno::Reference< xml::sax::XFastAttributeList >& )
359 throw (xml::sax::SAXException, uno::RuntimeException)
361 // Should the arguments be parsed?
362 return uno::Reference< xml::sax::XFastContextHandler >( static_cast< xml::sax::XFastContextHandler* >( this ) );
365 // ------------------------------------------------
366 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL OOXMLDocPropHandler::createUnknownChildContext( const OUString&, const OUString&, const uno::Reference< xml::sax::XFastAttributeList >& )
367 throw (xml::sax::SAXException, uno::RuntimeException)
369 return uno::Reference< xml::sax::XFastContextHandler >( static_cast< xml::sax::XFastContextHandler* >( this ) );
372 // ------------------------------------------------
373 void SAL_CALL OOXMLDocPropHandler::characters( const OUString& aChars )
374 throw (xml::sax::SAXException, uno::RuntimeException)
378 if ( (m_nInBlock == 2) || ((m_nInBlock == 3) && m_nType) )
380 if ( m_nState == COREPR_TOKEN( coreProperties ) )
382 switch( m_nBlock )
384 case COREPR_TOKEN( category ):
385 m_aCustomPropertyName = "category";
386 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
387 break;
389 case COREPR_TOKEN( contentStatus ):
390 m_aCustomPropertyName = "contentStatus";
391 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
392 break;
394 case COREPR_TOKEN( contentType ):
395 m_aCustomPropertyName = "contentType";
396 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
397 break;
399 case COREPR_TOKEN( identifier ):
400 m_aCustomPropertyName = "identifier";
401 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
402 break;
404 case COREPR_TOKEN( version ):
405 m_aCustomPropertyName = "version";
406 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
407 break;
409 case DCT_TOKEN( created ):
410 if ( aChars.getLength() >= 4 )
411 m_xDocProp->setCreationDate( GetDateTimeFromW3CDTF( aChars ) );
412 break;
414 case DC_TOKEN( creator ):
415 m_xDocProp->setAuthor( aChars );
416 break;
418 case DC_TOKEN( description ):
419 m_xDocProp->setDescription( aChars );
420 break;
422 case COREPR_TOKEN( keywords ):
423 m_xDocProp->setKeywords( GetKeywordsSet( aChars ) );
424 break;
426 case DC_TOKEN( language ):
427 if ( aChars.getLength() >= 2 )
428 m_xDocProp->setLanguage( GetLanguage( aChars ) );
429 break;
431 case COREPR_TOKEN( lastModifiedBy ):
432 m_xDocProp->setModifiedBy( aChars );
433 break;
435 case COREPR_TOKEN( lastPrinted ):
436 if ( aChars.getLength() >= 4 )
437 m_xDocProp->setPrintDate( GetDateTimeFromW3CDTF( aChars ) );
438 break;
440 case DCT_TOKEN( modified ):
441 if ( aChars.getLength() >= 4 )
442 m_xDocProp->setModificationDate( GetDateTimeFromW3CDTF( aChars ) );
443 break;
445 case COREPR_TOKEN( revision ):
448 m_xDocProp->setEditingCycles(
449 static_cast<sal_Int16>(aChars.toInt32()) );
451 catch (lang::IllegalArgumentException &)
453 // ignore
455 break;
457 case DC_TOKEN( subject ):
458 m_xDocProp->setSubject( aChars );
459 break;
461 case DC_TOKEN( title ):
462 m_xDocProp->setTitle( aChars );
463 break;
465 default:
466 OSL_FAIL( "Unexpected core property!" );
469 else if ( m_nState == EXTPR_TOKEN( Properties ) )
471 switch( m_nBlock )
473 case EXTPR_TOKEN( Application ):
474 m_xDocProp->setGenerator( aChars );
475 break;
477 case EXTPR_TOKEN( Template ):
478 m_xDocProp->setTemplateName( aChars );
479 break;
481 case EXTPR_TOKEN( TotalTime ):
484 m_xDocProp->setEditingDuration( aChars.toInt32() );
486 catch (lang::IllegalArgumentException &)
488 // ignore
490 break;
492 case EXTPR_TOKEN( Characters ):
493 case EXTPR_TOKEN( Pages ):
494 case EXTPR_TOKEN( Words ):
495 case EXTPR_TOKEN( Paragraphs ):
496 UpdateDocStatistic( aChars );
497 break;
499 case EXTPR_TOKEN( HyperlinksChanged ):
500 m_aCustomPropertyName = "HyperlinksChanged";
501 AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
502 break;
504 case EXTPR_TOKEN( LinksUpToDate ):
505 m_aCustomPropertyName = "LinksUpToDate";
506 AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
507 break;
509 case EXTPR_TOKEN( ScaleCrop ):
510 m_aCustomPropertyName = "ScaleCrop";
511 AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
512 break;
514 case EXTPR_TOKEN( SharedDoc ):
515 m_aCustomPropertyName = "ShareDoc";
516 AddCustomProperty( uno::makeAny( aChars.toBoolean() ) ); // the property has boolean type
517 break;
519 case EXTPR_TOKEN( DocSecurity ):
520 m_aCustomPropertyName = "DocSecurity";
521 AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
522 break;
524 case EXTPR_TOKEN( HiddenSlides ):
525 m_aCustomPropertyName = "HiddenSlides";
526 AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
527 break;
529 case EXTPR_TOKEN( MMClips ):
530 m_aCustomPropertyName = "MMClips";
531 AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
532 break;
534 case EXTPR_TOKEN( Notes ):
535 m_aCustomPropertyName = "Notes";
536 AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
537 break;
539 case EXTPR_TOKEN( Slides ):
540 m_aCustomPropertyName = "Slides";
541 AddCustomProperty( uno::makeAny( aChars.toInt32() ) ); // the property has sal_Int32 type
542 break;
544 case EXTPR_TOKEN( AppVersion ):
545 m_aCustomPropertyName = "AppVersion";
546 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
547 break;
549 case EXTPR_TOKEN( Company ):
550 m_aCustomPropertyName = "Company";
551 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
552 break;
554 case EXTPR_TOKEN( HyperlinkBase ):
555 m_aCustomPropertyName = "HyperlinkBase";
556 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
557 break;
559 case EXTPR_TOKEN( Manager ):
560 m_aCustomPropertyName = "Manager";
561 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
562 break;
564 case EXTPR_TOKEN( PresentationFormat ):
565 m_aCustomPropertyName = "PresentationFormat";
566 AddCustomProperty( uno::makeAny( aChars ) ); // the property has string type
567 break;
569 case EXTPR_TOKEN( CharactersWithSpaces ):
570 case EXTPR_TOKEN( Lines ):
571 case EXTPR_TOKEN( DigSig ):
572 case EXTPR_TOKEN( HeadingPairs ):
573 case EXTPR_TOKEN( HLinks ):
574 case EXTPR_TOKEN( TitlesOfParts ):
575 // ignored during the import currently
576 break;
578 default:
579 OSL_FAIL( "Unexpected extended property!" );
582 else if ( m_nState == CUSTPR_TOKEN( Properties ) )
584 if ( m_nBlock == CUSTPR_TOKEN( property ) )
586 // this is a custom property
587 switch( m_nType )
589 case VT_TOKEN( bool ):
590 AddCustomProperty( uno::makeAny( aChars.toBoolean() ) );
591 break;
593 case VT_TOKEN( bstr ):
594 case VT_TOKEN( lpstr ):
595 case VT_TOKEN( lpwstr ):
596 // the property has string type
597 AddCustomProperty( uno::makeAny( AttributeConversion::decodeXString( aChars ) ) );
598 break;
600 case VT_TOKEN( date ):
601 case VT_TOKEN( filetime ):
602 AddCustomProperty( uno::makeAny( GetDateTimeFromW3CDTF( aChars ) ) );
603 break;
605 case VT_TOKEN( i1 ):
606 case VT_TOKEN( i2 ):
607 AddCustomProperty( uno::makeAny( (sal_Int16)aChars.toInt32() ) );
608 break;
610 case VT_TOKEN( i4 ):
611 case VT_TOKEN( int ):
612 AddCustomProperty( uno::makeAny( aChars.toInt32() ) );
613 break;
615 case VT_TOKEN( i8 ):
616 AddCustomProperty( uno::makeAny( aChars.toInt64() ) );
617 break;
619 case VT_TOKEN( r4 ):
620 AddCustomProperty( uno::makeAny( aChars.toFloat() ) );
621 break;
623 case VT_TOKEN( r8 ):
624 AddCustomProperty( uno::makeAny( aChars.toDouble() ) );
625 break;
627 default:
628 // all the other types are ignored;
629 break;
632 else
634 OSL_FAIL( "Unexpected tag in custom property!" );
639 catch( uno::RuntimeException& )
641 throw;
643 catch( xml::sax::SAXException& )
645 throw;
647 catch( uno::Exception& e )
649 throw xml::sax::SAXException(
650 OUString("Error while setting document property!"),
651 uno::Reference< uno::XInterface >(),
652 uno::makeAny( e ) );
656 // ------------------------------------------------
657 void SAL_CALL OOXMLDocPropHandler::ignorableWhitespace( const OUString& )
658 throw (xml::sax::SAXException, uno::RuntimeException)
662 // ------------------------------------------------
663 void SAL_CALL OOXMLDocPropHandler::processingInstruction( const OUString&, const OUString& )
664 throw (xml::sax::SAXException, uno::RuntimeException)
668 } // namespace docprop
669 } // namespace oox
671 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */