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 .
21 #include <sfx2/docinf.hxx>
22 #include <com/sun/star/beans/PropertyAttribute.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/beans/XPropertyContainer.hpp>
25 #include <com/sun/star/document/XDocumentProperties.hpp>
26 #include <com/sun/star/document/XCompatWriterDocProperties.hpp>
27 #include <com/sun/star/uno/Exception.hpp>
28 #include <rtl/ustring.hxx>
29 #include <sal/log.hxx>
30 #include <tools/debug.hxx>
31 #include <comphelper/string.hxx>
32 #include <sot/storage.hxx>
33 #include <vcl/bitmapex.hxx>
34 #include <vcl/gdimtf.hxx>
35 #include <vcl/dibtools.hxx>
36 #include "oleprops.hxx"
40 constexpr OUStringLiteral STREAM_SUMMARYINFO
= u
"\005SummaryInformation";
41 constexpr OUStringLiteral STREAM_DOCSUMMARYINFO
= u
"\005DocumentSummaryInformation";
44 using namespace ::com::sun::star
;
49 ErrCode
LoadOlePropertySet(
50 const uno::Reference
< document::XDocumentProperties
>& i_xDocProps
,
51 SotStorage
* i_pStorage
)
53 // *** global properties from stream "005SummaryInformation" ***
55 // load the property set
56 SfxOlePropertySet aGlobSet
;
57 ErrCode nGlobError
= aGlobSet
.LoadPropertySet(i_pStorage
,
61 SfxOleSectionRef xGlobSect
= aGlobSet
.GetSection( SECTION_GLOBAL
);
64 // set supported properties
66 util::DateTime aDateTime
;
68 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_TITLE
) )
69 i_xDocProps
->setTitle( aStrValue
);
70 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_SUBJECT
) )
71 i_xDocProps
->setSubject( aStrValue
);
72 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_KEYWORDS
) ) {
73 i_xDocProps
->setKeywords(
74 ::comphelper::string::convertCommaSeparated(aStrValue
) );
76 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_TEMPLATE
) )
77 i_xDocProps
->setTemplateName( aStrValue
);
78 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_COMMENTS
) )
79 i_xDocProps
->setDescription( aStrValue
);
81 util::DateTime aInvalid
;
82 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_AUTHOR
) )
83 i_xDocProps
->setAuthor( aStrValue
);
85 i_xDocProps
->setAuthor( OUString() );
86 if( xGlobSect
->GetFileTimeValue( aDateTime
, PROPID_CREATED
) )
87 i_xDocProps
->setCreationDate( aDateTime
);
89 i_xDocProps
->setCreationDate( aInvalid
);
91 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_LASTAUTHOR
) )
92 i_xDocProps
->setModifiedBy( aStrValue
);
94 i_xDocProps
->setModifiedBy( OUString() );
95 if( xGlobSect
->GetFileTimeValue( aDateTime
, PROPID_LASTSAVED
) )
96 i_xDocProps
->setModificationDate( aDateTime
);
98 i_xDocProps
->setModificationDate( aInvalid
);
100 i_xDocProps
->setPrintedBy( OUString() );
101 if( xGlobSect
->GetFileTimeValue( aDateTime
, PROPID_LASTPRINTED
) )
102 i_xDocProps
->setPrintDate( aDateTime
);
104 i_xDocProps
->setPrintDate( aInvalid
);
106 if( xGlobSect
->GetStringValue( aStrValue
, PROPID_REVNUMBER
) )
108 sal_Int16 nRevision
= static_cast< sal_Int16
>( aStrValue
.toInt32() );
110 i_xDocProps
->setEditingCycles( nRevision
);
113 if( xGlobSect
->GetFileTimeValue( aDateTime
, PROPID_EDITTIME
)
114 && !(aDateTime
.NanoSeconds
== 0 && aDateTime
.Seconds
== 0
115 && aDateTime
.Minutes
== 0 && aDateTime
.Hours
== 0
116 && aDateTime
.Day
== 0 && aDateTime
.Month
== 0
117 && aDateTime
.Year
== 0) )
119 // subtract offset 1601-01-01
120 aDateTime
.Year
-= 1601;
121 aDateTime
.Month
-= 1;
125 i_xDocProps
->setEditingDuration(
126 aDateTime
.Day
* 60*60*24 +
127 aDateTime
.Hours
* 60*60 +
128 aDateTime
.Minutes
* 60 +
131 catch (const lang::IllegalArgumentException
&)
138 // *** custom properties from stream "005DocumentSummaryInformation" ***
140 // load the property set
141 SfxOlePropertySet aDocSet
;
142 ErrCode nDocError
= aDocSet
.LoadPropertySet(i_pStorage
,
143 STREAM_DOCSUMMARYINFO
);
146 SfxOleSectionRef xCustomSect
= aDocSet
.GetSection( SECTION_CUSTOM
);
149 uno::Reference
< beans::XPropertyContainer
> xUserDefined(
150 i_xDocProps
->getUserDefinedProperties(), uno::UNO_SET_THROW
);
151 ::std::vector
< sal_Int32
> aPropIds
;
152 xCustomSect
->GetPropertyIds( aPropIds
);
153 for( const auto& rPropId
: aPropIds
)
155 const OUString aPropName
= xCustomSect
->GetPropertyName( rPropId
);
156 uno::Any aPropValue
= xCustomSect
->GetAnyValue( rPropId
);
157 if( !aPropName
.isEmpty() && aPropValue
.hasValue() )
161 xUserDefined
->addProperty( aPropName
,
162 beans::PropertyAttribute::REMOVABLE
, aPropValue
);
164 catch (const uno::Exception
&)
172 uno::Reference
< document::XCompatWriterDocProperties
> xWriterProps( i_xDocProps
, uno::UNO_QUERY
);
173 if ( xWriterProps
.is() )
175 SfxOleSectionRef xBuiltin
= aDocSet
.GetSection( SECTION_BUILTIN
);
181 if ( xBuiltin
->GetStringValue( aStrValue
, PROPID_MANAGER
) )
182 xWriterProps
->setManager( aStrValue
);
183 if ( xBuiltin
->GetStringValue( aStrValue
, PROPID_CATEGORY
) )
184 xWriterProps
->setCategory( aStrValue
);
185 if ( xBuiltin
->GetStringValue( aStrValue
, PROPID_COMPANY
) )
186 xWriterProps
->setCompany( aStrValue
);
188 catch (const uno::Exception
&)
195 return (nGlobError
!= ERRCODE_NONE
) ? nGlobError
: nDocError
;
198 bool SaveOlePropertySet(
199 const uno::Reference
< document::XDocumentProperties
>& i_xDocProps
,
200 SotStorage
* i_pStorage
,
201 const uno::Sequence
<sal_Int8
> * i_pThumb
,
202 const uno::Sequence
<sal_Int8
> * i_pGuid
,
203 const uno::Sequence
<sal_Int8
> * i_pHyperlinks
)
205 // *** global properties into stream "005SummaryInformation" ***
207 SfxOlePropertySet aGlobSet
;
209 // set supported properties
210 SfxOleSection
& rGlobSect
= aGlobSet
.AddSection( SECTION_GLOBAL
);
211 rGlobSect
.SetStringValue( PROPID_TITLE
, i_xDocProps
->getTitle() );
212 rGlobSect
.SetStringValue( PROPID_SUBJECT
, i_xDocProps
->getSubject() );
213 const OUString aStr
= ::comphelper::string::convertCommaSeparated(
214 i_xDocProps
->getKeywords() );
215 rGlobSect
.SetStringValue( PROPID_KEYWORDS
, aStr
);
216 rGlobSect
.SetStringValue( PROPID_TEMPLATE
, i_xDocProps
->getTemplateName() );
217 rGlobSect
.SetStringValue( PROPID_COMMENTS
, i_xDocProps
->getDescription() );
218 rGlobSect
.SetStringValue( PROPID_AUTHOR
, i_xDocProps
->getAuthor() );
219 rGlobSect
.SetFileTimeValue(PROPID_CREATED
, i_xDocProps
->getCreationDate());
220 rGlobSect
.SetStringValue( PROPID_LASTAUTHOR
, i_xDocProps
->getModifiedBy() );
221 rGlobSect
.SetFileTimeValue(PROPID_LASTSAVED
,
222 i_xDocProps
->getModificationDate() );
223 // note: apparently PrintedBy is not supported in file format
224 rGlobSect
.SetFileTimeValue(PROPID_LASTPRINTED
, i_xDocProps
->getPrintDate());
226 sal_Int32 dur
= i_xDocProps
->getEditingDuration();
227 util::DateTime aEditTime
;
228 // add offset 1601-01-01
229 aEditTime
.Year
= 1601;
232 aEditTime
.Hours
= static_cast<sal_Int16
>(dur
/ 3600);
233 aEditTime
.Minutes
= static_cast<sal_Int16
>((dur
% 3600) / 60);
234 aEditTime
.Seconds
= static_cast<sal_Int16
>(dur
% 60);
235 rGlobSect
.SetFileTimeValue( PROPID_EDITTIME
, aEditTime
);
237 rGlobSect
.SetStringValue( PROPID_REVNUMBER
,
238 OUString::number( i_xDocProps
->getEditingCycles() ) );
239 if ( i_pThumb
&& i_pThumb
->hasElements() )
240 rGlobSect
.SetThumbnailValue( PROPID_THUMBNAIL
, *i_pThumb
);
242 // save the property set
243 ErrCode nGlobError
= aGlobSet
.SavePropertySet(i_pStorage
,
246 // *** custom properties into stream "005DocumentSummaryInformation" ***
248 SfxOlePropertySet aDocSet
;
250 // set builtin properties
251 aDocSet
.AddSection( SECTION_BUILTIN
);
253 // set custom properties
254 SfxOleSection
& rCustomSect
= aDocSet
.AddSection( SECTION_CUSTOM
);
258 const sal_Int32 nPropId
= rCustomSect
.GetFreePropertyId();
259 rCustomSect
.SetBlobValue( nPropId
, *i_pGuid
);
260 rCustomSect
.SetPropertyName( nPropId
,
266 const sal_Int32 nPropId
= rCustomSect
.GetFreePropertyId();
267 rCustomSect
.SetBlobValue( nPropId
, *i_pHyperlinks
);
268 rCustomSect
.SetPropertyName( nPropId
,
272 uno::Reference
<beans::XPropertySet
> xUserDefinedProps(
273 i_xDocProps
->getUserDefinedProperties(), uno::UNO_QUERY_THROW
);
274 uno::Reference
<beans::XPropertySetInfo
> xPropInfo
=
275 xUserDefinedProps
->getPropertySetInfo();
276 DBG_ASSERT(xPropInfo
.is(), "UserDefinedProperties Info is null");
277 const uno::Sequence
<beans::Property
> props
= xPropInfo
->getProperties();
278 for (const auto& rProp
: props
)
282 // skip transient properties
283 if (~rProp
.Attributes
& beans::PropertyAttribute::TRANSIENT
)
285 const OUString name
= rProp
.Name
;
286 const sal_Int32 nPropId
= rCustomSect
.GetFreePropertyId();
287 if (rCustomSect
.SetAnyValue( nPropId
,
288 xUserDefinedProps
->getPropertyValue(name
))) {
289 rCustomSect
.SetPropertyName( nPropId
, name
);
293 catch (const uno::Exception
&)
295 // may happen with concurrent modification...
296 SAL_INFO("sfx", "SavePropertySet: exception");
300 // save the property set
301 ErrCode nDocError
= aDocSet
.SavePropertySet(i_pStorage
,
302 STREAM_DOCSUMMARYINFO
);
305 return (nGlobError
== ERRCODE_NONE
) && (nDocError
== ERRCODE_NONE
);
308 uno::Sequence
<sal_Int8
> convertMetaFile(GDIMetaFile
const * i_pThumb
)
312 SvMemoryStream aStream
;
313 if (i_pThumb
->CreateThumbnail(aBitmap
))
315 WriteDIB(aBitmap
.GetBitmap(), aStream
, false, false);
316 return uno::Sequence
<sal_Int8
>(static_cast< const sal_Int8
* >( aStream
.GetData() ), aStream
.TellEnd());
319 return uno::Sequence
<sal_Int8
>();
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */