/src/libreoffice/sfx2/source/doc/docinf.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | |
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/bitmap.hxx> |
34 | | #include <vcl/gdimtf.hxx> |
35 | | #include <vcl/dibtools.hxx> |
36 | | #include "oleprops.hxx" |
37 | | |
38 | | |
39 | | // stream names |
40 | | constexpr OUString STREAM_SUMMARYINFO = u"\005SummaryInformation"_ustr; |
41 | | constexpr OUString STREAM_DOCSUMMARYINFO = u"\005DocumentSummaryInformation"_ustr; |
42 | | |
43 | | // usings |
44 | | using namespace ::com::sun::star; |
45 | | |
46 | | |
47 | | namespace sfx2 { |
48 | | |
49 | | ErrCode LoadOlePropertySet( |
50 | | const uno::Reference< document::XDocumentProperties>& i_xDocProps, |
51 | | SotStorage* i_pStorage ) |
52 | 30.4k | { |
53 | | // *** global properties from stream "005SummaryInformation" *** |
54 | | |
55 | | // load the property set |
56 | 30.4k | SfxOlePropertySet aGlobSet; |
57 | 30.4k | ErrCode nGlobError = aGlobSet.LoadPropertySet(i_pStorage, |
58 | 30.4k | STREAM_SUMMARYINFO ); |
59 | | |
60 | | // global section |
61 | 30.4k | SfxOleSectionRef xGlobSect = aGlobSet.GetSection( SECTION_GLOBAL ); |
62 | 30.4k | if( xGlobSect ) |
63 | 6.60k | { |
64 | | // set supported properties |
65 | 6.60k | OUString aStrValue; |
66 | 6.60k | util::DateTime aDateTime; |
67 | | |
68 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_TITLE ) ) |
69 | 4.86k | i_xDocProps->setTitle( aStrValue ); |
70 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_SUBJECT ) ) |
71 | 2.10k | i_xDocProps->setSubject( aStrValue ); |
72 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_KEYWORDS ) ) { |
73 | 2.09k | i_xDocProps->setKeywords( |
74 | 2.09k | ::comphelper::string::convertCommaSeparated(aStrValue) ); |
75 | 2.09k | } |
76 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_TEMPLATE ) ) |
77 | 3.33k | i_xDocProps->setTemplateName( aStrValue ); |
78 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_COMMENTS ) ) |
79 | 1.72k | i_xDocProps->setDescription( aStrValue ); |
80 | | |
81 | 6.60k | util::DateTime aInvalid; |
82 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_AUTHOR) ) |
83 | 5.37k | i_xDocProps->setAuthor( aStrValue ); |
84 | 1.22k | else |
85 | 1.22k | i_xDocProps->setAuthor( OUString() ); |
86 | 6.60k | if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_CREATED ) ) |
87 | 5.29k | i_xDocProps->setCreationDate( aDateTime ); |
88 | 1.30k | else |
89 | 1.30k | i_xDocProps->setCreationDate( aInvalid ); |
90 | | |
91 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_LASTAUTHOR) ) |
92 | 5.43k | i_xDocProps->setModifiedBy( aStrValue ); |
93 | 1.17k | else |
94 | 1.17k | i_xDocProps->setModifiedBy( OUString() ); |
95 | 6.60k | if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_LASTSAVED ) ) |
96 | 5.46k | i_xDocProps->setModificationDate( aDateTime ); |
97 | 1.13k | else |
98 | 1.13k | i_xDocProps->setModificationDate( aInvalid ); |
99 | | |
100 | 6.60k | i_xDocProps->setPrintedBy( OUString() ); |
101 | 6.60k | if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_LASTPRINTED ) ) |
102 | 3.05k | i_xDocProps->setPrintDate( aDateTime ); |
103 | 3.54k | else |
104 | 3.54k | i_xDocProps->setPrintDate( aInvalid ); |
105 | | |
106 | 6.60k | if( xGlobSect->GetStringValue( aStrValue, PROPID_REVNUMBER ) ) |
107 | 5.42k | { |
108 | 5.42k | sal_Int16 nRevision = static_cast< sal_Int16 >( aStrValue.toInt32() ); |
109 | 5.42k | if ( nRevision > 0 ) |
110 | 5.07k | i_xDocProps->setEditingCycles( nRevision ); |
111 | 5.42k | } |
112 | | |
113 | 6.60k | if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_EDITTIME ) |
114 | 5.06k | && !(aDateTime.NanoSeconds == 0 && aDateTime.Seconds == 0 |
115 | 2.32k | && aDateTime.Minutes == 0 && aDateTime.Hours == 0 |
116 | 1.09k | && aDateTime.Day == 0 && aDateTime.Month == 0 |
117 | 1.07k | && aDateTime.Year == 0) ) |
118 | 3.99k | { |
119 | 3.99k | assert(aDateTime.Day <= 31); |
120 | | // subtract offset 1601-01-01 |
121 | 3.99k | aDateTime.Year -= 1601; |
122 | 3.99k | aDateTime.Month -= 1; |
123 | 3.99k | aDateTime.Day -= 1; |
124 | 3.99k | try |
125 | 3.99k | { |
126 | 3.99k | i_xDocProps->setEditingDuration( |
127 | 3.99k | aDateTime.Day * 60*60*24 + |
128 | 3.99k | aDateTime.Hours * 60*60 + |
129 | 3.99k | aDateTime.Minutes * 60 + |
130 | 3.99k | aDateTime.Seconds ); |
131 | 3.99k | } |
132 | 3.99k | catch (const lang::IllegalArgumentException &) |
133 | 3.99k | { |
134 | | // ignore |
135 | 0 | } |
136 | 3.99k | } |
137 | 6.60k | } |
138 | | |
139 | | // *** custom properties from stream "005DocumentSummaryInformation" *** |
140 | | |
141 | | // load the property set |
142 | 30.4k | SfxOlePropertySet aDocSet; |
143 | 30.4k | ErrCode nDocError = aDocSet.LoadPropertySet(i_pStorage, |
144 | 30.4k | STREAM_DOCSUMMARYINFO ); |
145 | | |
146 | | // custom properties |
147 | 30.4k | SfxOleSectionRef xCustomSect = aDocSet.GetSection( SECTION_CUSTOM ); |
148 | 30.4k | if( xCustomSect ) |
149 | 2.31k | { |
150 | 2.31k | uno::Reference < beans::XPropertyContainer > xUserDefined( |
151 | 2.31k | i_xDocProps->getUserDefinedProperties(), uno::UNO_SET_THROW); |
152 | 2.31k | ::std::vector< sal_Int32 > aPropIds; |
153 | 2.31k | xCustomSect->GetPropertyIds( aPropIds ); |
154 | 2.31k | for( const auto& rPropId : aPropIds ) |
155 | 2.32k | { |
156 | 2.32k | const OUString aPropName = xCustomSect->GetPropertyName( rPropId ); |
157 | 2.32k | uno::Any aPropValue = xCustomSect->GetAnyValue( rPropId ); |
158 | 2.32k | if( !aPropName.isEmpty() && aPropValue.hasValue() ) |
159 | 1.10k | { |
160 | 1.10k | try |
161 | 1.10k | { |
162 | 1.10k | xUserDefined->addProperty( aPropName, |
163 | 1.10k | beans::PropertyAttribute::REMOVABLE, aPropValue ); |
164 | 1.10k | } |
165 | 1.10k | catch (const uno::Exception&) |
166 | 1.10k | { |
167 | | //ignore |
168 | 0 | } |
169 | 1.10k | } |
170 | 2.32k | } |
171 | 2.31k | } |
172 | | |
173 | 30.4k | uno::Reference< document::XCompatWriterDocProperties > xWriterProps( i_xDocProps, uno::UNO_QUERY ); |
174 | 30.4k | if ( xWriterProps.is() ) |
175 | 0 | { |
176 | 0 | SfxOleSectionRef xBuiltin = aDocSet.GetSection( SECTION_BUILTIN ); |
177 | 0 | if ( xBuiltin ) |
178 | 0 | { |
179 | 0 | try |
180 | 0 | { |
181 | 0 | OUString aStrValue; |
182 | 0 | if ( xBuiltin->GetStringValue( aStrValue, PROPID_MANAGER ) ) |
183 | 0 | xWriterProps->setManager( aStrValue ); |
184 | 0 | if ( xBuiltin->GetStringValue( aStrValue, PROPID_CATEGORY ) ) |
185 | 0 | xWriterProps->setCategory( aStrValue ); |
186 | 0 | if ( xBuiltin->GetStringValue( aStrValue, PROPID_COMPANY ) ) |
187 | 0 | xWriterProps->setCompany( aStrValue ); |
188 | 0 | } |
189 | 0 | catch (const uno::Exception&) |
190 | 0 | { |
191 | 0 | } |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | // return code |
196 | 30.4k | return (nGlobError != ERRCODE_NONE) ? nGlobError : nDocError; |
197 | 30.4k | } |
198 | | |
199 | | bool SaveOlePropertySet( |
200 | | const uno::Reference< document::XDocumentProperties>& i_xDocProps, |
201 | | SotStorage* i_pStorage, |
202 | | const uno::Sequence<sal_Int8> * i_pThumb, |
203 | | const uno::Sequence<sal_Int8> * i_pGuid, |
204 | | const uno::Sequence<sal_Int8> * i_pHyperlinks) |
205 | 0 | { |
206 | | // *** global properties into stream "005SummaryInformation" *** |
207 | |
|
208 | 0 | SfxOlePropertySet aGlobSet; |
209 | | |
210 | | // set supported properties |
211 | 0 | SfxOleSection& rGlobSect = aGlobSet.AddSection( SECTION_GLOBAL ); |
212 | 0 | rGlobSect.SetStringValue( PROPID_TITLE, i_xDocProps->getTitle() ); |
213 | 0 | rGlobSect.SetStringValue( PROPID_SUBJECT, i_xDocProps->getSubject() ); |
214 | 0 | const OUString aStr = ::comphelper::string::convertCommaSeparated( |
215 | 0 | i_xDocProps->getKeywords() ); |
216 | 0 | rGlobSect.SetStringValue( PROPID_KEYWORDS, aStr ); |
217 | 0 | rGlobSect.SetStringValue( PROPID_TEMPLATE, i_xDocProps->getTemplateName() ); |
218 | 0 | rGlobSect.SetStringValue( PROPID_COMMENTS, i_xDocProps->getDescription() ); |
219 | 0 | rGlobSect.SetStringValue( PROPID_AUTHOR, i_xDocProps->getAuthor() ); |
220 | 0 | rGlobSect.SetFileTimeValue(PROPID_CREATED, i_xDocProps->getCreationDate()); |
221 | 0 | rGlobSect.SetStringValue( PROPID_LASTAUTHOR, i_xDocProps->getModifiedBy() ); |
222 | 0 | rGlobSect.SetFileTimeValue(PROPID_LASTSAVED, |
223 | 0 | i_xDocProps->getModificationDate() ); |
224 | | // note: apparently PrintedBy is not supported in file format |
225 | 0 | rGlobSect.SetFileTimeValue(PROPID_LASTPRINTED, i_xDocProps->getPrintDate()); |
226 | |
|
227 | 0 | sal_Int32 dur = i_xDocProps->getEditingDuration(); |
228 | 0 | util::DateTime aEditTime; |
229 | | // add offset 1601-01-01 |
230 | 0 | aEditTime.Year = 1601; |
231 | 0 | aEditTime.Month = 1; |
232 | 0 | aEditTime.Day = 1; |
233 | 0 | aEditTime.Hours = static_cast<sal_Int16>(dur / 3600); |
234 | 0 | aEditTime.Minutes = static_cast<sal_Int16>((dur % 3600) / 60); |
235 | 0 | aEditTime.Seconds = static_cast<sal_Int16>(dur % 60); |
236 | 0 | rGlobSect.SetFileTimeValue( PROPID_EDITTIME, aEditTime ); |
237 | |
|
238 | 0 | rGlobSect.SetStringValue( PROPID_REVNUMBER, |
239 | 0 | OUString::number( i_xDocProps->getEditingCycles() ) ); |
240 | 0 | if ( i_pThumb && i_pThumb->hasElements() ) |
241 | 0 | rGlobSect.SetThumbnailValue( PROPID_THUMBNAIL, *i_pThumb ); |
242 | | |
243 | | // save the property set |
244 | 0 | ErrCode nGlobError = aGlobSet.SavePropertySet(i_pStorage, |
245 | 0 | STREAM_SUMMARYINFO); |
246 | | |
247 | | // *** custom properties into stream "005DocumentSummaryInformation" *** |
248 | |
|
249 | 0 | SfxOlePropertySet aDocSet; |
250 | | |
251 | | // set builtin properties |
252 | 0 | aDocSet.AddSection( SECTION_BUILTIN ); |
253 | | |
254 | | // set custom properties |
255 | 0 | SfxOleSection& rCustomSect = aDocSet.AddSection( SECTION_CUSTOM ); |
256 | | |
257 | | // write GUID |
258 | 0 | if (i_pGuid) { |
259 | 0 | const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); |
260 | 0 | rCustomSect.SetBlobValue( nPropId, *i_pGuid ); |
261 | 0 | rCustomSect.SetPropertyName( nPropId, |
262 | 0 | u"_PID_GUID"_ustr ); |
263 | 0 | } |
264 | | |
265 | | // write hyperlinks |
266 | 0 | if (i_pHyperlinks) { |
267 | 0 | const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); |
268 | 0 | rCustomSect.SetBlobValue( nPropId, *i_pHyperlinks ); |
269 | 0 | rCustomSect.SetPropertyName( nPropId, |
270 | 0 | u"_PID_HLINKS"_ustr ); |
271 | 0 | } |
272 | |
|
273 | 0 | uno::Reference<beans::XPropertySet> xUserDefinedProps( |
274 | 0 | i_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); |
275 | 0 | uno::Reference<beans::XPropertySetInfo> xPropInfo = |
276 | 0 | xUserDefinedProps->getPropertySetInfo(); |
277 | 0 | DBG_ASSERT(xPropInfo.is(), "UserDefinedProperties Info is null"); |
278 | 0 | const uno::Sequence<beans::Property> props = xPropInfo->getProperties(); |
279 | 0 | for (const auto& rProp : props) |
280 | 0 | { |
281 | 0 | try |
282 | 0 | { |
283 | | // skip transient properties |
284 | 0 | if (~rProp.Attributes & beans::PropertyAttribute::TRANSIENT) |
285 | 0 | { |
286 | 0 | const OUString name = rProp.Name; |
287 | 0 | const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); |
288 | 0 | if (rCustomSect.SetAnyValue( nPropId, |
289 | 0 | xUserDefinedProps->getPropertyValue(name))) { |
290 | 0 | rCustomSect.SetPropertyName( nPropId, name ); |
291 | 0 | } |
292 | 0 | } |
293 | 0 | } |
294 | 0 | catch (const uno::Exception &) |
295 | 0 | { |
296 | | // may happen with concurrent modification... |
297 | 0 | SAL_INFO("sfx", "SavePropertySet: exception"); |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | | // save the property set |
302 | 0 | ErrCode nDocError = aDocSet.SavePropertySet(i_pStorage, |
303 | 0 | STREAM_DOCSUMMARYINFO ); |
304 | | |
305 | | // return code |
306 | 0 | return (nGlobError == ERRCODE_NONE) && (nDocError == ERRCODE_NONE); |
307 | 0 | } |
308 | | |
309 | | uno::Sequence<sal_Int8> convertMetaFile(GDIMetaFile const * i_pThumb) |
310 | 0 | { |
311 | 0 | if (i_pThumb) { |
312 | 0 | Bitmap aBitmap; |
313 | 0 | SvMemoryStream aStream; |
314 | 0 | if (i_pThumb->CreateThumbnail(aBitmap)) |
315 | 0 | { |
316 | 0 | WriteDIB(aBitmap, aStream, false, false); |
317 | 0 | return uno::Sequence<sal_Int8>(static_cast< const sal_Int8* >( aStream.GetData() ), aStream.TellEnd()); |
318 | 0 | } |
319 | 0 | } |
320 | 0 | return uno::Sequence<sal_Int8>(); |
321 | 0 | } |
322 | | |
323 | | } // namespace sfx2 |
324 | | |
325 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |