Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / doc / oleprops.cxx
blob65145a21a96d05953eeb5b90f3265620f6249426
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 .
21 #include "oleprops.hxx"
23 #include <comphelper/types.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <tools/datetime.hxx>
26 #include <rtl/tencinfo.h>
27 #include <sal/log.hxx>
30 #define STREAM_BUFFER_SIZE 2048
32 // usings
33 using ::com::sun::star::uno::Any;
35 using namespace ::com::sun::star;
37 #define TIMESTAMP_INVALID_DATETIME ( DateTime ( Date ( 1, 1, 1601 ), tools::Time ( 0, 0, 0 ) ) ) /// Invalid value for date and time to create invalid instance of TimeStamp.
38 /// Invalid value for date and time to create invalid instance of TimeStamp.
39 #define TIMESTAMP_INVALID_UTILDATETIME (util::DateTime(0, 0, 0, 0, 1, 1, 1601, false))
40 /// Invalid value for date to create invalid instance of TimeStamp.
41 #define TIMESTAMP_INVALID_UTILDATE (util::Date(1, 1, 1601))
43 namespace {
45 /** Property representing a signed 32-bit integer value. */
46 class SfxOleInt32Property : public SfxOlePropertyBase
48 public:
49 explicit SfxOleInt32Property( sal_Int32 nPropId, sal_Int32 nValue = 0 );
51 sal_Int32 GetValue() const { return mnValue; }
53 private:
54 virtual void ImplLoad( SvStream& rStrm ) override;
55 virtual void ImplSave( SvStream& rStrm ) override;
57 private:
58 sal_Int32 mnValue;
62 /** Property representing a floating-point value. */
63 class SfxOleDoubleProperty : public SfxOlePropertyBase
65 public:
66 explicit SfxOleDoubleProperty( sal_Int32 nPropId, double fValue = 0.0 );
68 double GetValue() const { return mfValue; }
70 private:
71 virtual void ImplLoad( SvStream& rStrm ) override;
72 virtual void ImplSave( SvStream& rStrm ) override;
74 private:
75 double mfValue;
79 /** Property representing a boolean value. */
80 class SfxOleBoolProperty : public SfxOlePropertyBase
82 public:
83 explicit SfxOleBoolProperty( sal_Int32 nPropId, bool bValue = false );
85 bool GetValue() const { return mbValue; }
87 private:
88 virtual void ImplLoad( SvStream& rStrm ) override;
89 virtual void ImplSave( SvStream& rStrm ) override;
91 private:
92 bool mbValue;
96 /** Base class for properties that contain a single string value. */
97 class SfxOleStringPropertyBase : public SfxOlePropertyBase, public SfxOleStringHelper
99 public:
100 explicit SfxOleStringPropertyBase(
101 sal_Int32 nPropId, sal_Int32 nPropType,
102 const SfxOleTextEncoding& rTextEnc );
103 explicit SfxOleStringPropertyBase(
104 sal_Int32 nPropId, sal_Int32 nPropType,
105 const SfxOleTextEncoding& rTextEnc, const OUString& rValue );
106 explicit SfxOleStringPropertyBase(
107 sal_Int32 nPropId, sal_Int32 nPropType,
108 rtl_TextEncoding eTextEnc );
110 const OUString& GetValue() const { return maValue; }
111 void SetValue( const OUString& rValue ) { maValue = rValue; }
113 private:
114 OUString maValue;
118 /** Property representing a bytestring value. */
119 class SfxOleString8Property : public SfxOleStringPropertyBase
121 public:
122 explicit SfxOleString8Property(
123 sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc );
124 explicit SfxOleString8Property(
125 sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc,
126 const OUString& rValue );
128 private:
129 virtual void ImplLoad( SvStream& rStrm ) override;
130 virtual void ImplSave( SvStream& rStrm ) override;
134 /** Property representing a Unicode string value. */
135 class SfxOleString16Property : public SfxOleStringPropertyBase
137 public:
138 explicit SfxOleString16Property( sal_Int32 nPropId );
140 private:
141 virtual void ImplLoad( SvStream& rStrm ) override;
142 virtual void ImplSave( SvStream& rStrm ) override;
146 /** Property representing a filetime value as defined by the Windows API. */
147 class SfxOleFileTimeProperty : public SfxOlePropertyBase
149 public:
150 explicit SfxOleFileTimeProperty( sal_Int32 nPropId );
151 /** @param rDateTime Date and time as LOCAL time. */
152 explicit SfxOleFileTimeProperty( sal_Int32 nPropId, const util::DateTime& rDateTime );
154 /** Returns the time value as LOCAL time. */
155 const util::DateTime& GetValue() const { return maDateTime; }
157 private:
158 virtual void ImplLoad( SvStream& rStrm ) override;
159 virtual void ImplSave( SvStream& rStrm ) override;
161 private:
162 util::DateTime maDateTime;
165 /** Property representing a filetime value as defined by the Windows API. */
166 class SfxOleDateProperty : public SfxOlePropertyBase
168 public:
169 explicit SfxOleDateProperty( sal_Int32 nPropId );
171 /** Returns the date value as LOCAL time. */
172 const util::Date& GetValue() const { return maDate; }
174 private:
175 virtual void ImplLoad( SvStream& rStrm ) override;
176 virtual void ImplSave( SvStream& rStrm ) override;
178 private:
179 util::Date maDate;
183 /** Property representing a thumbnail picture.
185 Currently, only saving this property is implemented.
187 class SfxOleThumbnailProperty : public SfxOlePropertyBase
189 public:
190 explicit SfxOleThumbnailProperty( sal_Int32 nPropId,
191 const uno::Sequence<sal_Int8> & i_rData);
193 bool IsValid() const { return mData.hasElements(); }
195 private:
196 virtual void ImplLoad( SvStream& rStrm ) override;
197 virtual void ImplSave( SvStream& rStrm ) override;
199 private:
200 uno::Sequence<sal_Int8> mData;
204 /** Property representing a BLOB (which presumably stands for binary large
205 object).
207 Currently, only saving this property is implemented.
209 class SfxOleBlobProperty : public SfxOlePropertyBase
211 public:
212 explicit SfxOleBlobProperty( sal_Int32 nPropId,
213 const uno::Sequence<sal_Int8> & i_rData);
214 bool IsValid() const { return mData.hasElements(); }
216 private:
217 virtual void ImplLoad( SvStream& rStrm ) override;
218 virtual void ImplSave( SvStream& rStrm ) override;
220 private:
221 uno::Sequence<sal_Int8> mData;
226 sal_uInt16 SfxOleTextEncoding::GetCodePage() const
228 sal_uInt16 nCodePage = IsUnicode() ? CODEPAGE_UNICODE :
229 static_cast< sal_uInt16 >( rtl_getWindowsCodePageFromTextEncoding( *mxTextEnc ) );
230 return (nCodePage == CODEPAGE_UNKNOWN) ? CODEPAGE_UTF8 : nCodePage;
233 void SfxOleTextEncoding::SetCodePage( sal_uInt16 nCodePage )
235 if( nCodePage == CODEPAGE_UNICODE )
236 SetUnicode();
237 else
239 rtl_TextEncoding eTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
240 if( eTextEnc != RTL_TEXTENCODING_DONTKNOW )
241 *mxTextEnc = eTextEnc;
246 OUString SfxOleStringHelper::LoadString8( SvStream& rStrm ) const
248 return IsUnicode() ? ImplLoadString16( rStrm ) : ImplLoadString8( rStrm );
251 void SfxOleStringHelper::SaveString8( SvStream& rStrm, const OUString& rValue ) const
253 if( IsUnicode() )
254 ImplSaveString16( rStrm, rValue );
255 else
256 ImplSaveString8( rStrm, rValue );
259 OUString SfxOleStringHelper::LoadString16( SvStream& rStrm )
261 return ImplLoadString16( rStrm );
264 void SfxOleStringHelper::SaveString16( SvStream& rStrm, const OUString& rValue )
266 ImplSaveString16( rStrm, rValue );
269 OUString SfxOleStringHelper::ImplLoadString8( SvStream& rStrm ) const
271 // read size field (signed 32-bit)
272 sal_Int32 nSize(0);
273 rStrm.ReadInt32( nSize );
274 // size field includes trailing NUL character
275 SAL_WARN_IF(nSize < 1 || nSize > 0xFFFF, "sfx.doc", "SfxOleStringHelper::ImplLoadString8 - invalid string of len " << nSize);
276 if (nSize < 1 || nSize > 0xFFFF)
277 return OUString();
278 // load character buffer
279 OString sValue(read_uInt8s_ToOString(rStrm, nSize - 1));
280 if (rStrm.good() && rStrm.remainingSize())
281 rStrm.SeekRel(1); // skip null-byte at end
282 return OStringToOUString(sValue, GetTextEncoding());
285 OUString SfxOleStringHelper::ImplLoadString16( SvStream& rStrm )
287 // read size field (signed 32-bit), may be buffer size or character count
288 sal_Int32 nSize(0);
289 rStrm.ReadInt32(nSize);
290 SAL_WARN_IF(nSize < 1 || nSize > 0xFFFF, "sfx.doc", "SfxOleStringHelper::ImplLoadString16 - invalid string of len " << nSize);
291 // size field includes trailing NUL character
292 if (nSize < 1 || nSize > 0xFFFF)
293 return OUString();
294 // load character buffer
295 OUString aValue = read_uInt16s_ToOUString(rStrm, nSize - 1);
296 sal_Int32 nSkip(2); // skip null-byte at end
297 // stream is always padded to 32-bit boundary, skip 2 bytes on odd character count
298 if ((nSize & 1) == 1)
299 nSkip += 2;
300 nSkip = std::min<sal_uInt32>(nSkip, rStrm.remainingSize());
301 if (rStrm.good() && nSkip)
302 rStrm.SeekRel(nSkip);
303 return aValue;
306 void SfxOleStringHelper::ImplSaveString8( SvStream& rStrm, const OUString& rValue ) const
308 // encode to byte string
309 OString aEncoded(OUStringToOString(rValue, GetTextEncoding()));
310 // write size field (including trailing NUL character)
311 sal_Int32 nSize = aEncoded.getLength() + 1;
312 rStrm.WriteInt32( nSize );
313 // write character array with trailing NUL character
314 rStrm.WriteBytes(aEncoded.getStr(), aEncoded.getLength());
315 rStrm.WriteUChar( 0 );
318 void SfxOleStringHelper::ImplSaveString16( SvStream& rStrm, const OUString& rValue )
320 // write size field (including trailing NUL character)
321 sal_Int32 nSize = static_cast< sal_Int32 >( rValue.getLength() + 1 );
322 rStrm.WriteInt32( nSize );
323 // write character array with trailing NUL character
324 for( sal_Int32 nIdx = 0; nIdx < rValue.getLength(); ++nIdx )
325 rStrm.WriteUInt16( rValue[ nIdx ] );
326 rStrm.WriteUInt16( 0 );
327 // stream is always padded to 32-bit boundary, add 2 bytes on odd character count
328 if( (nSize & 1) == 1 )
329 rStrm.WriteUInt16( 0 );
333 SfxOleObjectBase::~SfxOleObjectBase()
337 ErrCode const & SfxOleObjectBase::Load( SvStream& rStrm )
339 mnErrCode = ERRCODE_NONE;
340 ImplLoad( rStrm );
341 SetError( rStrm.GetErrorCode() );
342 return GetError();
345 ErrCode const & SfxOleObjectBase::Save( SvStream& rStrm )
347 mnErrCode = ERRCODE_NONE;
348 ImplSave( rStrm );
349 SetError( rStrm.GetErrorCode() );
350 return GetError();
353 void SfxOleObjectBase::LoadObject( SvStream& rStrm, SfxOleObjectBase& rObj )
355 SetError( rObj.Load( rStrm ) );
358 void SfxOleObjectBase::SaveObject( SvStream& rStrm, SfxOleObjectBase& rObj )
360 SetError( rObj.Save( rStrm ) );
364 SfxOleCodePageProperty::SfxOleCodePageProperty() :
365 SfxOlePropertyBase( PROPID_CODEPAGE, PROPTYPE_INT16 )
369 void SfxOleCodePageProperty::ImplLoad(SvStream& rStrm)
371 // property type is signed int16, but we use always unsigned int16 for codepages
372 sal_uInt16 nCodePage(0);
373 rStrm.ReadUInt16(nCodePage);
374 SetCodePage(nCodePage);
377 void SfxOleCodePageProperty::ImplSave( SvStream& rStrm )
379 // property type is signed int16, but we use always unsigned int16 for codepages
380 rStrm.WriteUInt16( GetCodePage() );
384 SfxOleInt32Property::SfxOleInt32Property( sal_Int32 nPropId, sal_Int32 nValue ) :
385 SfxOlePropertyBase( nPropId, PROPTYPE_INT32 ),
386 mnValue( nValue )
390 void SfxOleInt32Property::ImplLoad( SvStream& rStrm )
392 rStrm.ReadInt32( mnValue );
395 void SfxOleInt32Property::ImplSave( SvStream& rStrm )
397 rStrm.WriteInt32( mnValue );
401 SfxOleDoubleProperty::SfxOleDoubleProperty( sal_Int32 nPropId, double fValue ) :
402 SfxOlePropertyBase( nPropId, PROPTYPE_DOUBLE ),
403 mfValue( fValue )
407 void SfxOleDoubleProperty::ImplLoad( SvStream& rStrm )
409 rStrm.ReadDouble( mfValue );
412 void SfxOleDoubleProperty::ImplSave( SvStream& rStrm )
414 rStrm.WriteDouble( mfValue );
418 SfxOleBoolProperty::SfxOleBoolProperty( sal_Int32 nPropId, bool bValue ) :
419 SfxOlePropertyBase( nPropId, PROPTYPE_BOOL ),
420 mbValue( bValue )
424 void SfxOleBoolProperty::ImplLoad( SvStream& rStrm )
426 sal_Int16 nValue(0);
427 rStrm.ReadInt16( nValue );
428 mbValue = nValue != 0;
431 void SfxOleBoolProperty::ImplSave( SvStream& rStrm )
433 rStrm.WriteInt16( mbValue ? -1 : 0 );
437 SfxOleStringPropertyBase::SfxOleStringPropertyBase(
438 sal_Int32 nPropId, sal_Int32 nPropType, const SfxOleTextEncoding& rTextEnc ) :
439 SfxOlePropertyBase( nPropId, nPropType ),
440 SfxOleStringHelper( rTextEnc )
444 SfxOleStringPropertyBase::SfxOleStringPropertyBase(
445 sal_Int32 nPropId, sal_Int32 nPropType, const SfxOleTextEncoding& rTextEnc, const OUString& rValue ) :
446 SfxOlePropertyBase( nPropId, nPropType ),
447 SfxOleStringHelper( rTextEnc ),
448 maValue( rValue )
452 SfxOleStringPropertyBase::SfxOleStringPropertyBase(
453 sal_Int32 nPropId, sal_Int32 nPropType, rtl_TextEncoding eTextEnc ) :
454 SfxOlePropertyBase( nPropId, nPropType ),
455 SfxOleStringHelper( eTextEnc )
460 SfxOleString8Property::SfxOleString8Property(
461 sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc ) :
462 SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING8, rTextEnc )
466 SfxOleString8Property::SfxOleString8Property(
467 sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc, const OUString& rValue ) :
468 SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING8, rTextEnc, rValue )
472 void SfxOleString8Property::ImplLoad( SvStream& rStrm )
474 SetValue( LoadString8( rStrm ) );
477 void SfxOleString8Property::ImplSave( SvStream& rStrm )
479 SaveString8( rStrm, GetValue() );
483 SfxOleString16Property::SfxOleString16Property( sal_Int32 nPropId ) :
484 SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING16, RTL_TEXTENCODING_UCS2 )
488 void SfxOleString16Property::ImplLoad( SvStream& rStrm )
490 SetValue( LoadString16( rStrm ) );
493 void SfxOleString16Property::ImplSave( SvStream& rStrm )
495 SaveString16( rStrm, GetValue() );
499 SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId ) :
500 SfxOlePropertyBase( nPropId, PROPTYPE_FILETIME )
504 SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId, const util::DateTime& rDateTime ) :
505 SfxOlePropertyBase( nPropId, PROPTYPE_FILETIME ),
506 maDateTime( rDateTime )
510 void SfxOleFileTimeProperty::ImplLoad( SvStream& rStrm )
512 sal_uInt32 nLower(0), nUpper(0);
513 rStrm.ReadUInt32( nLower ).ReadUInt32( nUpper );
514 ::DateTime aDateTime = DateTime::CreateFromWin32FileDateTime( nLower, nUpper );
515 // note: editing duration is stored as offset to TIMESTAMP_INVALID_DATETIME
516 // of course we should not convert the time zone of a duration!
517 // heuristic to detect editing durations (which we assume to be < 1 year):
518 // check only the year, not the entire date
519 if ( aDateTime.GetYear() != TIMESTAMP_INVALID_DATETIME.GetYear() )
520 aDateTime.ConvertToLocalTime();
521 maDateTime.Year = aDateTime.GetYear();
522 maDateTime.Month = aDateTime.GetMonth();
523 maDateTime.Day = aDateTime.GetDay();
524 maDateTime.Hours = aDateTime.GetHour();
525 maDateTime.Minutes = aDateTime.GetMin();
526 maDateTime.Seconds = aDateTime.GetSec();
527 maDateTime.NanoSeconds = aDateTime.GetNanoSec();
528 maDateTime.IsUTC = false;
531 void SfxOleFileTimeProperty::ImplSave( SvStream& rStrm )
533 DateTime aDateTimeUtc(
534 Date(
535 maDateTime.Day,
536 maDateTime.Month,
537 static_cast< sal_uInt16 >( maDateTime.Year ) ),
538 tools::Time(
539 maDateTime.Hours,
540 maDateTime.Minutes,
541 maDateTime.Seconds,
542 maDateTime.NanoSeconds ) );
543 // invalid time stamp is not converted to UTC
544 // heuristic to detect editing durations (which we assume to be < 1 year):
545 // check only the year, not the entire date
546 if( aDateTimeUtc.IsValidAndGregorian()
547 && aDateTimeUtc.GetYear() != TIMESTAMP_INVALID_DATETIME.GetYear() ) {
548 aDateTimeUtc.ConvertToUTC();
550 sal_uInt32 nLower, nUpper;
551 aDateTimeUtc.GetWin32FileDateTime( nLower, nUpper );
552 rStrm.WriteUInt32( nLower ).WriteUInt32( nUpper );
555 SfxOleDateProperty::SfxOleDateProperty( sal_Int32 nPropId ) :
556 SfxOlePropertyBase( nPropId, PROPTYPE_DATE )
560 void SfxOleDateProperty::ImplLoad( SvStream& rStrm )
562 double fValue(0.0);
563 rStrm.ReadDouble( fValue );
564 //stored as number of days (not seconds) since December 31, 1899
565 sal_Int32 nDays = fValue;
566 sal_Int32 nStartDays = ::Date::DateToDays(31, 12, 1899);
567 if (o3tl::checked_add(nStartDays, nDays, nStartDays))
568 SAL_WARN("sfx.doc", "SfxOleDateProperty::ImplLoad bad date, ignored");
569 else
571 ::Date aDate(31, 12, 1899);
572 aDate.AddDays(nDays);
573 maDate.Day = aDate.GetDay();
574 maDate.Month = aDate.GetMonth();
575 maDate.Year = aDate.GetYear();
579 void SfxOleDateProperty::ImplSave( SvStream& rStrm )
581 sal_Int32 nDays = ::Date::DateToDays(maDate.Day, maDate.Month, maDate.Year);
582 //number of days (not seconds) since December 31, 1899
583 sal_Int32 nStartDays = ::Date::DateToDays(31, 12, 1899);
584 double fValue = nDays-nStartDays;
585 rStrm.WriteDouble( fValue );
589 SfxOleThumbnailProperty::SfxOleThumbnailProperty(
590 sal_Int32 nPropId, const uno::Sequence<sal_Int8> & i_rData) :
591 SfxOlePropertyBase( nPropId, PROPTYPE_CLIPFMT ),
592 mData(i_rData)
596 void SfxOleThumbnailProperty::ImplLoad( SvStream& )
598 SAL_WARN( "sfx.doc", "SfxOleThumbnailProperty::ImplLoad - not implemented" );
599 SetError( SVSTREAM_INVALID_ACCESS );
602 void SfxOleThumbnailProperty::ImplSave( SvStream& rStrm )
604 /* Type Contents
605 -----------------------------------------------------------------------
606 int32 size of following data
607 int32 clipboard format tag (see below)
608 byte[] clipboard data (see below)
610 Clipboard format tag:
611 -1 = Windows clipboard format
612 -2 = Macintosh clipboard format
613 -3 = GUID that contains a format identifier (FMTID)
614 >0 = custom clipboard format name plus data (see msdn site below)
615 0 = no data
617 References:
618 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/propvariant.asp
619 http://jakarta.apache.org/poi/hpsf/thumbnails.html
620 http://linux.com.hk/docs/poi/org/apache/poi/hpsf/Thumbnail.html
621 https://web.archive.org/web/20060126202945/http://sparks.discreet.com/knowledgebase/public/solutions/ExtractThumbnailImg.htm
623 if( IsValid() )
625 // clipboard size: clip_format_tag + data_format_tag + bitmap_len
626 sal_Int32 nClipSize = static_cast< sal_Int32 >( 4 + 4 + mData.getLength() );
627 rStrm.WriteInt32( nClipSize ).WriteInt32( CLIPFMT_WIN ).WriteInt32( CLIPDATAFMT_DIB );
628 rStrm.WriteBytes(mData.getConstArray(), mData.getLength());
630 else
632 SAL_WARN( "sfx.doc", "SfxOleThumbnailProperty::ImplSave - invalid thumbnail property" );
633 SetError( SVSTREAM_INVALID_ACCESS );
638 SfxOleBlobProperty::SfxOleBlobProperty( sal_Int32 nPropId,
639 const uno::Sequence<sal_Int8> & i_rData) :
640 SfxOlePropertyBase( nPropId, PROPTYPE_BLOB ),
641 mData(i_rData)
645 void SfxOleBlobProperty::ImplLoad( SvStream& )
647 SAL_WARN( "sfx.doc", "SfxOleBlobProperty::ImplLoad - not implemented" );
648 SetError( SVSTREAM_INVALID_ACCESS );
651 void SfxOleBlobProperty::ImplSave( SvStream& rStrm )
653 if (IsValid()) {
654 rStrm.WriteBytes(mData.getConstArray(), mData.getLength());
655 } else {
656 SAL_WARN( "sfx.doc", "SfxOleBlobProperty::ImplSave - invalid BLOB property" );
657 SetError( SVSTREAM_INVALID_ACCESS );
662 SfxOleDictionaryProperty::SfxOleDictionaryProperty( const SfxOleTextEncoding& rTextEnc ) :
663 SfxOlePropertyBase( PROPID_DICTIONARY, 0 ),
664 SfxOleStringHelper( rTextEnc )
668 OUString SfxOleDictionaryProperty::GetPropertyName( sal_Int32 nPropId ) const
670 SfxOlePropNameMap::const_iterator aIt = maPropNameMap.find( nPropId );
671 return (aIt == maPropNameMap.end()) ? OUString() : aIt->second;
674 void SfxOleDictionaryProperty::SetPropertyName( sal_Int32 nPropId, const OUString& rPropName )
676 maPropNameMap[ nPropId ] = rPropName;
677 // dictionary property contains number of pairs in property type field
678 SetPropType( static_cast< sal_Int32 >( maPropNameMap.size() ) );
681 void SfxOleDictionaryProperty::ImplLoad( SvStream& rStrm )
683 // dictionary property contains number of pairs in property type field
684 sal_Int32 nNameCount = GetPropType();
685 // read property ID/name pairs
686 maPropNameMap.clear();
687 for (sal_Int32 nIdx = 0; nIdx < nNameCount && rStrm.good(); ++nIdx)
689 sal_Int32 nPropId(0);
690 rStrm.ReadInt32(nPropId);
691 // name always stored as byte string
692 maPropNameMap[nPropId] = LoadString8(rStrm);
696 void SfxOleDictionaryProperty::ImplSave( SvStream& rStrm )
698 // write property ID/name pairs
699 for (auto const& propName : maPropNameMap)
701 rStrm.WriteInt32( propName.first );
702 // name always stored as byte string
703 SaveString8( rStrm, propName.second );
708 SfxOleSection::SfxOleSection( bool bSupportsDict ) :
709 maDictProp( maCodePageProp ),
710 mnStartPos( 0 ),
711 mbSupportsDict( bSupportsDict )
715 SfxOlePropertyRef SfxOleSection::GetProperty( sal_Int32 nPropId ) const
717 SfxOlePropertyRef xProp;
718 SfxOlePropMap::const_iterator aIt = maPropMap.find( nPropId );
719 if( aIt != maPropMap.end() )
720 xProp = aIt->second;
721 return xProp;
724 bool SfxOleSection::GetInt32Value( sal_Int32& rnValue, sal_Int32 nPropId ) const
726 SfxOlePropertyRef xProp = GetProperty( nPropId );
727 const SfxOleInt32Property* pProp =
728 dynamic_cast< const SfxOleInt32Property* >( xProp.get() );
729 if( pProp )
730 rnValue = pProp->GetValue();
731 return pProp != nullptr;
734 bool SfxOleSection::GetDoubleValue( double& rfValue, sal_Int32 nPropId ) const
736 SfxOlePropertyRef xProp = GetProperty( nPropId );
737 const SfxOleDoubleProperty* pProp =
738 dynamic_cast< const SfxOleDoubleProperty* >( xProp.get() );
739 if( pProp )
740 rfValue = pProp->GetValue();
741 return pProp != nullptr;
744 bool SfxOleSection::GetBoolValue( bool& rbValue, sal_Int32 nPropId ) const
746 SfxOlePropertyRef xProp = GetProperty( nPropId );
747 const SfxOleBoolProperty* pProp =
748 dynamic_cast< const SfxOleBoolProperty* >( xProp.get() );
749 if( pProp )
750 rbValue = pProp->GetValue();
751 return pProp != nullptr;
754 bool SfxOleSection::GetStringValue( OUString& rValue, sal_Int32 nPropId ) const
756 SfxOlePropertyRef xProp = GetProperty( nPropId );
757 const SfxOleStringPropertyBase* pProp =
758 dynamic_cast< const SfxOleStringPropertyBase* >( xProp.get() );
759 if( pProp )
760 rValue = pProp->GetValue();
761 return pProp != nullptr;
764 bool SfxOleSection::GetFileTimeValue( util::DateTime& rValue, sal_Int32 nPropId ) const
766 SfxOlePropertyRef xProp = GetProperty( nPropId );
767 const SfxOleFileTimeProperty* pProp =
768 dynamic_cast< const SfxOleFileTimeProperty* >( xProp.get() );
769 if( pProp )
771 if ( pProp->GetValue() == TIMESTAMP_INVALID_UTILDATETIME )
772 rValue = util::DateTime();
773 else
774 rValue = pProp->GetValue();
776 return pProp != nullptr;
779 bool SfxOleSection::GetDateValue( util::Date& rValue, sal_Int32 nPropId ) const
781 SfxOlePropertyRef xProp = GetProperty( nPropId );
782 const SfxOleDateProperty* pProp =
783 dynamic_cast< const SfxOleDateProperty* >( xProp.get() );
784 if( pProp )
786 if ( pProp->GetValue() == TIMESTAMP_INVALID_UTILDATE )
787 rValue = util::Date();
788 else
789 rValue = pProp->GetValue();
791 return pProp != nullptr;
794 void SfxOleSection::SetProperty( const SfxOlePropertyRef& xProp )
796 if( xProp )
797 maPropMap[ xProp->GetPropId() ] = xProp;
800 void SfxOleSection::SetInt32Value( sal_Int32 nPropId, sal_Int32 nValue )
802 SetProperty( std::make_shared<SfxOleInt32Property>( nPropId, nValue ) );
805 void SfxOleSection::SetDoubleValue( sal_Int32 nPropId, double fValue )
807 SetProperty( std::make_shared<SfxOleDoubleProperty>( nPropId, fValue ) );
810 void SfxOleSection::SetBoolValue( sal_Int32 nPropId, bool bValue )
812 SetProperty( std::make_shared<SfxOleBoolProperty>( nPropId, bValue ) );
815 bool SfxOleSection::SetStringValue( sal_Int32 nPropId, const OUString& rValue )
817 bool bInserted = !rValue.isEmpty();
818 if( bInserted )
819 SetProperty( std::make_shared<SfxOleString8Property>( nPropId, maCodePageProp, rValue ) );
820 return bInserted;
823 void SfxOleSection::SetFileTimeValue( sal_Int32 nPropId, const util::DateTime& rValue )
825 if ( rValue.Year == 0 || rValue.Month == 0 || rValue.Day == 0 )
826 SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, TIMESTAMP_INVALID_UTILDATETIME ) );
827 else
828 SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, rValue ) );
831 void SfxOleSection::SetDateValue( sal_Int32 nPropId, const util::Date& rValue )
833 //Annoyingly MS2010 considers VT_DATE apparently as an invalid possibility, so here we use VT_FILETIME
834 //instead :-(
835 if ( rValue.Year == 0 || rValue.Month == 0 || rValue.Day == 0 )
836 SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, TIMESTAMP_INVALID_UTILDATETIME ) );
837 else
839 const util::DateTime aValue(0, 0, 0, 0, rValue.Day, rValue.Month,
840 rValue.Year, false );
841 SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, aValue ) );
845 void SfxOleSection::SetThumbnailValue( sal_Int32 nPropId,
846 const uno::Sequence<sal_Int8> & i_rData)
848 auto pThumbnail = std::make_shared<SfxOleThumbnailProperty>( nPropId, i_rData );
849 if( pThumbnail->IsValid() )
850 SetProperty( pThumbnail );
853 void SfxOleSection::SetBlobValue( sal_Int32 nPropId,
854 const uno::Sequence<sal_Int8> & i_rData)
856 auto pBlob = std::make_shared<SfxOleBlobProperty>( nPropId, i_rData );
857 if( pBlob->IsValid() )
858 SetProperty( pBlob );
861 Any SfxOleSection::GetAnyValue( sal_Int32 nPropId ) const
863 Any aValue;
864 sal_Int32 nInt32 = 0;
865 double fDouble = 0.0;
866 bool bBool = false;
867 OUString aString;
868 css::util::DateTime aApiDateTime;
869 css::util::Date aApiDate;
871 if( GetInt32Value( nInt32, nPropId ) )
872 aValue <<= nInt32;
873 else if( GetDoubleValue( fDouble, nPropId ) )
874 aValue <<= fDouble;
875 else if( GetBoolValue( bBool, nPropId ) )
876 aValue <<= bBool;
877 else if( GetStringValue( aString, nPropId ) )
878 aValue <<= aString;
879 else if( GetFileTimeValue( aApiDateTime, nPropId ) )
881 aValue <<= aApiDateTime;
883 else if( GetDateValue( aApiDate, nPropId ) )
885 aValue <<= aApiDate;
887 return aValue;
890 bool SfxOleSection::SetAnyValue( sal_Int32 nPropId, const Any& rValue )
892 bool bInserted = true;
893 sal_Int32 nInt32 = 0;
894 double fDouble = 0.0;
895 OUString aString;
896 css::util::DateTime aApiDateTime;
897 css::util::Date aApiDate;
899 if( rValue.getValueType() == cppu::UnoType<bool>::get() )
900 SetBoolValue( nPropId, ::comphelper::getBOOL( rValue ) );
901 else if( rValue >>= nInt32 )
902 SetInt32Value( nPropId, nInt32 );
903 else if( rValue >>= fDouble )
904 SetDoubleValue( nPropId, fDouble );
905 else if( rValue >>= aString )
906 bInserted = SetStringValue( nPropId, aString );
907 else if( rValue >>= aApiDateTime )
908 SetFileTimeValue( nPropId, aApiDateTime );
909 else if( rValue >>= aApiDate )
910 SetDateValue( nPropId, aApiDate );
911 else
912 bInserted = false;
913 return bInserted;
916 OUString SfxOleSection::GetPropertyName( sal_Int32 nPropId ) const
918 return maDictProp.GetPropertyName( nPropId );
921 void SfxOleSection::SetPropertyName( sal_Int32 nPropId, const OUString& rPropName )
923 maDictProp.SetPropertyName( nPropId, rPropName );
926 void SfxOleSection::GetPropertyIds( ::std::vector< sal_Int32 >& rPropIds ) const
928 rPropIds.clear();
929 for (auto const& prop : maPropMap)
930 rPropIds.push_back(prop.first);
933 sal_Int32 SfxOleSection::GetFreePropertyId() const
935 return maPropMap.empty() ? PROPID_FIRSTCUSTOM : (maPropMap.rbegin()->first + 1);
938 void SfxOleSection::ImplLoad( SvStream& rStrm )
940 // read section header
941 mnStartPos = rStrm.Tell();
942 sal_uInt32 nSize(0);
943 sal_Int32 nPropCount(0);
944 rStrm.ReadUInt32( nSize ).ReadInt32( nPropCount );
946 // read property ID/position pairs
947 typedef ::std::map< sal_Int32, sal_uInt32 > SfxOlePropPosMap;
948 SfxOlePropPosMap aPropPosMap;
949 for (sal_Int32 nPropIdx = 0; nPropIdx < nPropCount && rStrm.good(); ++nPropIdx)
951 sal_Int32 nPropId(0);
952 sal_uInt32 nPropPos(0);
953 rStrm.ReadInt32( nPropId ).ReadUInt32( nPropPos );
954 aPropPosMap[ nPropId ] = nPropPos;
957 // read codepage property
958 SfxOlePropPosMap::iterator aCodePageIt = aPropPosMap.find( PROPID_CODEPAGE );
959 if( (aCodePageIt != aPropPosMap.end()) && SeekToPropertyPos( rStrm, aCodePageIt->second ) )
961 // codepage property must be of type signed int-16
962 sal_Int32 nPropType(0);
963 rStrm.ReadInt32( nPropType );
964 if( nPropType == PROPTYPE_INT16 )
965 LoadObject( rStrm, maCodePageProp );
966 // remove property position
967 aPropPosMap.erase( aCodePageIt );
970 // read dictionary property
971 SfxOlePropPosMap::iterator aDictIt = aPropPosMap.find( PROPID_DICTIONARY );
972 if( (aDictIt != aPropPosMap.end()) && SeekToPropertyPos( rStrm, aDictIt->second ) )
974 // #i66214# #i66428# applications may write broken dictionary properties in wrong sections
975 if( mbSupportsDict )
977 // dictionary property contains number of pairs in property type field
978 sal_Int32 nNameCount(0);
979 rStrm.ReadInt32( nNameCount );
980 maDictProp.SetNameCount( nNameCount );
981 LoadObject( rStrm, maDictProp );
983 // always remove position of dictionary property (do not try to read it again below)
984 aPropPosMap.erase( aDictIt );
987 // read other properties
988 maPropMap.clear();
989 for (auto const& propPos : aPropPosMap)
990 if( SeekToPropertyPos( rStrm, propPos.second ) )
991 LoadProperty( rStrm, propPos.first );
994 void SfxOleSection::ImplSave( SvStream& rStrm )
996 /* Always export with UTF-8 encoding. All dependent properties (bytestring
997 and dictionary) will be updated automatically. */
998 maCodePageProp.SetTextEncoding( RTL_TEXTENCODING_UTF8 );
1000 // write section header
1001 mnStartPos = rStrm.Tell();
1002 sal_Int32 nPropCount = static_cast< sal_Int32 >( maPropMap.size() + 1 );
1003 if( maDictProp.HasPropertyNames() )
1004 ++nPropCount;
1005 rStrm.WriteUInt32( 0 ).WriteInt32( nPropCount );
1007 // write placeholders for property ID/position pairs
1008 sal_uInt64 nPropPosPos = rStrm.Tell();
1009 rStrm.SeekRel( static_cast< sal_sSize >( 8 * nPropCount ) );
1011 // write dictionary property
1012 if( maDictProp.HasPropertyNames() )
1013 SaveProperty( rStrm, maDictProp, nPropPosPos );
1014 // write codepage property
1015 SaveProperty( rStrm, maCodePageProp, nPropPosPos );
1016 // write other properties
1017 for (auto const& prop : maPropMap)
1018 SaveProperty( rStrm, *prop.second, nPropPosPos );
1020 // write section size (first field in section header)
1021 rStrm.Seek( STREAM_SEEK_TO_END );
1022 sal_uInt32 nSectSize = static_cast< sal_uInt32 >( rStrm.Tell() - mnStartPos );
1023 rStrm.Seek( mnStartPos );
1024 rStrm.WriteUInt32( nSectSize );
1027 bool SfxOleSection::SeekToPropertyPos( SvStream& rStrm, sal_uInt32 nPropPos ) const
1029 return checkSeek(rStrm, static_cast<std::size_t>(mnStartPos + nPropPos)) &&
1030 rStrm.GetErrorCode() == ERRCODE_NONE;
1033 void SfxOleSection::LoadProperty( SvStream& rStrm, sal_Int32 nPropId )
1035 // property data type
1036 sal_Int32 nPropType(0);
1037 rStrm.ReadInt32( nPropType );
1038 // create empty property object
1039 SfxOlePropertyRef xProp;
1040 switch( nPropType )
1042 case PROPTYPE_INT32:
1043 xProp = std::make_shared<SfxOleInt32Property>( nPropId );
1044 break;
1045 case PROPTYPE_DOUBLE:
1046 xProp = std::make_shared<SfxOleDoubleProperty>( nPropId );
1047 break;
1048 case PROPTYPE_BOOL:
1049 xProp = std::make_shared<SfxOleBoolProperty>( nPropId );
1050 break;
1051 case PROPTYPE_STRING8:
1052 xProp = std::make_shared<SfxOleString8Property>( nPropId, maCodePageProp );
1053 break;
1054 case PROPTYPE_STRING16:
1055 xProp = std::make_shared<SfxOleString16Property>( nPropId );
1056 break;
1057 case PROPTYPE_FILETIME:
1058 xProp = std::make_shared<SfxOleFileTimeProperty>( nPropId );
1059 break;
1060 case PROPTYPE_DATE:
1061 xProp = std::make_shared<SfxOleDateProperty>( nPropId );
1062 break;
1064 // load property contents
1065 if( xProp )
1067 SetError( xProp->Load( rStrm ) );
1068 maPropMap[ nPropId ] = xProp;
1072 void SfxOleSection::SaveProperty( SvStream& rStrm, SfxOlePropertyBase& rProp, sal_uInt64 & rnPropPosPos )
1074 rStrm.Seek( STREAM_SEEK_TO_END );
1075 sal_uInt32 nPropPos = static_cast< sal_uInt32 >( rStrm.Tell() - mnStartPos );
1076 // property data type
1077 rStrm.WriteInt32( rProp.GetPropType() );
1078 // write property contents
1079 SaveObject( rStrm, rProp );
1080 // align to 32-bit
1081 while( (rStrm.Tell() & 3) != 0 )
1082 rStrm.WriteUChar( 0 );
1083 // write property ID/position pair
1084 rStrm.Seek( rnPropPosPos );
1085 rStrm.WriteInt32( rProp.GetPropId() ).WriteUInt32( nPropPos );
1086 rnPropPosPos = rStrm.Tell();
1090 ErrCode const & SfxOlePropertySet::LoadPropertySet( SotStorage* pStrg, const OUString& rStrmName )
1092 if( pStrg )
1094 tools::SvRef<SotStorageStream> xStrm = pStrg->OpenSotStream( rStrmName, StreamMode::STD_READ );
1095 if( xStrm.is() && (xStrm->GetError() == ERRCODE_NONE) )
1097 xStrm->SetBufferSize( STREAM_BUFFER_SIZE );
1098 Load( *xStrm );
1100 else
1101 SetError( ERRCODE_IO_ACCESSDENIED );
1103 else
1104 SetError( ERRCODE_IO_ACCESSDENIED );
1105 return GetError();
1108 ErrCode const & SfxOlePropertySet::SavePropertySet( SotStorage* pStrg, const OUString& rStrmName )
1110 if( pStrg )
1112 tools::SvRef<SotStorageStream> xStrm = pStrg->OpenSotStream( rStrmName, StreamMode::TRUNC | StreamMode::STD_WRITE );
1113 if( xStrm.is() )
1114 Save( *xStrm );
1115 else
1116 SetError( ERRCODE_IO_ACCESSDENIED );
1118 else
1119 SetError( ERRCODE_IO_ACCESSDENIED );
1120 return GetError();
1123 SfxOleSectionRef SfxOlePropertySet::GetSection( SfxOleSectionType eSection ) const
1125 return GetSection( GetSectionGuid( eSection ) );
1128 SfxOleSectionRef SfxOlePropertySet::GetSection( const SvGlobalName& rSectionGuid ) const
1130 SfxOleSectionRef xSection;
1131 SfxOleSectionMap::const_iterator aIt = maSectionMap.find( rSectionGuid );
1132 if( aIt != maSectionMap.end() )
1133 xSection = aIt->second;
1134 return xSection;
1137 SfxOleSection& SfxOlePropertySet::AddSection( SfxOleSectionType eSection )
1139 return AddSection( GetSectionGuid( eSection ) );
1142 SfxOleSection& SfxOlePropertySet::AddSection( const SvGlobalName& rSectionGuid )
1144 SfxOleSectionRef xSection = GetSection( rSectionGuid );
1145 if( !xSection )
1147 // #i66214# #i66428# applications may write broken dictionary properties in wrong sections
1148 bool bSupportsDict = rSectionGuid == GetSectionGuid( SECTION_CUSTOM );
1149 xSection = std::make_shared<SfxOleSection>( bSupportsDict );
1150 maSectionMap[ rSectionGuid ] = xSection;
1152 return *xSection;
1155 void SfxOlePropertySet::ImplLoad( SvStream& rStrm )
1157 // read property set header
1158 sal_uInt16 nByteOrder;
1159 sal_uInt16 nVersion;
1160 sal_uInt16 nOsMinor;
1161 sal_uInt16 nOsType;
1162 SvGlobalName aGuid;
1163 sal_Int32 nSectCount(0);
1164 rStrm.ReadUInt16( nByteOrder ).ReadUInt16( nVersion ).ReadUInt16( nOsMinor ).ReadUInt16( nOsType );
1165 rStrm >> aGuid;
1166 rStrm.ReadInt32( nSectCount );
1168 // read sections
1169 sal_uInt64 nSectPosPos = rStrm.Tell();
1170 for (sal_Int32 nSectIdx = 0; nSectIdx < nSectCount; ++nSectIdx)
1172 // read section guid/position pair
1173 rStrm.Seek(nSectPosPos);
1174 SvGlobalName aSectGuid;
1175 rStrm >> aSectGuid;
1176 sal_uInt32 nSectPos(0);
1177 rStrm.ReadUInt32(nSectPos);
1178 if (!rStrm.good())
1179 break;
1180 nSectPosPos = rStrm.Tell();
1181 // read section
1182 if (!checkSeek(rStrm, nSectPos))
1183 break;
1184 LoadObject(rStrm, AddSection(aSectGuid));
1185 if (!rStrm.good())
1186 break;
1190 void SfxOlePropertySet::ImplSave( SvStream& rStrm )
1192 // write property set header
1193 SvGlobalName aGuid;
1194 sal_Int32 nSectCount = static_cast< sal_Int32 >( maSectionMap.size() );
1195 rStrm .WriteUInt16( 0xFFFE ) // byte order
1196 .WriteUInt16( 0 ) // version
1197 .WriteUInt16( 1 ) // OS minor version
1198 .WriteUInt16( 2 ); // OS type always windows for text encoding
1199 WriteSvGlobalName( rStrm, aGuid ); // unused guid
1200 rStrm .WriteInt32( nSectCount ); // number of sections
1202 // write placeholders for section guid/position pairs
1203 sal_uInt64 nSectPosPos = rStrm.Tell();
1204 rStrm.SeekRel( static_cast< sal_sSize >( 20 * nSectCount ) );
1206 // write sections
1207 for (auto const& section : maSectionMap)
1209 SfxOleSection& rSection = *section.second;
1210 rStrm.Seek( STREAM_SEEK_TO_END );
1211 sal_uInt32 nSectPos = static_cast< sal_uInt32 >( rStrm.Tell() );
1212 // write the section
1213 SaveObject( rStrm, rSection );
1214 // write section guid/position pair
1215 rStrm.Seek( nSectPosPos );
1216 WriteSvGlobalName( rStrm, section.first );
1217 rStrm.WriteUInt32( nSectPos );
1218 nSectPosPos = rStrm.Tell();
1222 const SvGlobalName& SfxOlePropertySet::GetSectionGuid( SfxOleSectionType eSection )
1224 static const SvGlobalName saGlobalGuid( 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 );
1225 static const SvGlobalName saBuiltInGuid( 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE );
1226 static const SvGlobalName saCustomGuid( 0xD5CDD505, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE );
1227 static const SvGlobalName saEmptyGuid;
1228 switch( eSection )
1230 case SECTION_GLOBAL: return saGlobalGuid;
1231 case SECTION_BUILTIN: return saBuiltInGuid;
1232 case SECTION_CUSTOM: return saCustomGuid;
1233 default: SAL_WARN( "sfx.doc", "SfxOlePropertySet::GetSectionGuid - unknown section type" );
1235 return saEmptyGuid;
1239 //} // namespace
1241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */