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 "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
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))
45 /** Property representing a signed 32-bit integer value. */
46 class SfxOleInt32Property
: public SfxOlePropertyBase
49 explicit SfxOleInt32Property( sal_Int32 nPropId
, sal_Int32 nValue
= 0 );
51 sal_Int32
GetValue() const { return mnValue
; }
54 virtual void ImplLoad( SvStream
& rStrm
) override
;
55 virtual void ImplSave( SvStream
& rStrm
) override
;
62 /** Property representing a floating-point value. */
63 class SfxOleDoubleProperty
: public SfxOlePropertyBase
66 explicit SfxOleDoubleProperty( sal_Int32 nPropId
, double fValue
= 0.0 );
68 double GetValue() const { return mfValue
; }
71 virtual void ImplLoad( SvStream
& rStrm
) override
;
72 virtual void ImplSave( SvStream
& rStrm
) override
;
79 /** Property representing a boolean value. */
80 class SfxOleBoolProperty
: public SfxOlePropertyBase
83 explicit SfxOleBoolProperty( sal_Int32 nPropId
, bool bValue
= false );
85 bool GetValue() const { return mbValue
; }
88 virtual void ImplLoad( SvStream
& rStrm
) override
;
89 virtual void ImplSave( SvStream
& rStrm
) override
;
96 /** Base class for properties that contain a single string value. */
97 class SfxOleStringPropertyBase
: public SfxOlePropertyBase
, public SfxOleStringHelper
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
; }
118 /** Property representing a bytestring value. */
119 class SfxOleString8Property
: public SfxOleStringPropertyBase
122 explicit SfxOleString8Property(
123 sal_Int32 nPropId
, const SfxOleTextEncoding
& rTextEnc
);
124 explicit SfxOleString8Property(
125 sal_Int32 nPropId
, const SfxOleTextEncoding
& rTextEnc
,
126 const OUString
& rValue
);
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
138 explicit SfxOleString16Property( sal_Int32 nPropId
);
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
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
; }
158 virtual void ImplLoad( SvStream
& rStrm
) override
;
159 virtual void ImplSave( SvStream
& rStrm
) override
;
162 util::DateTime maDateTime
;
165 /** Property representing a filetime value as defined by the Windows API. */
166 class SfxOleDateProperty
: public SfxOlePropertyBase
169 explicit SfxOleDateProperty( sal_Int32 nPropId
);
171 /** Returns the date value as LOCAL time. */
172 const util::Date
& GetValue() const { return maDate
; }
175 virtual void ImplLoad( SvStream
& rStrm
) override
;
176 virtual void ImplSave( SvStream
& rStrm
) override
;
183 /** Property representing a thumbnail picture.
185 Currently, only saving this property is implemented.
187 class SfxOleThumbnailProperty
: public SfxOlePropertyBase
190 explicit SfxOleThumbnailProperty( sal_Int32 nPropId
,
191 const uno::Sequence
<sal_Int8
> & i_rData
);
193 bool IsValid() const { return mData
.hasElements(); }
196 virtual void ImplLoad( SvStream
& rStrm
) override
;
197 virtual void ImplSave( SvStream
& rStrm
) override
;
200 uno::Sequence
<sal_Int8
> mData
;
204 /** Property representing a BLOB (which presumably stands for binary large
207 Currently, only saving this property is implemented.
209 class SfxOleBlobProperty
: public SfxOlePropertyBase
212 explicit SfxOleBlobProperty( sal_Int32 nPropId
,
213 const uno::Sequence
<sal_Int8
> & i_rData
);
214 bool IsValid() const { return mData
.hasElements(); }
217 virtual void ImplLoad( SvStream
& rStrm
) override
;
218 virtual void ImplSave( SvStream
& rStrm
) override
;
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
)
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
254 ImplSaveString16( rStrm
, rValue
);
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)
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)
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
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)
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)
300 nSkip
= std::min
<sal_uInt32
>(nSkip
, rStrm
.remainingSize());
301 if (rStrm
.good() && nSkip
)
302 rStrm
.SeekRel(nSkip
);
306 void SfxOleStringHelper::ImplSaveString8( SvStream
& rStrm
, std::u16string_view 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
;
341 SetError( rStrm
.GetErrorCode() );
345 ErrCode
const & SfxOleObjectBase::Save( SvStream
& rStrm
)
347 mnErrCode
= ERRCODE_NONE
;
349 SetError( rStrm
.GetErrorCode() );
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
),
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
),
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
),
424 void SfxOleBoolProperty::ImplLoad( SvStream
& rStrm
)
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
),
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(
537 static_cast< sal_uInt16
>( maDateTime
.Year
) ),
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
)
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");
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
),
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
)
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)
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
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());
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
),
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
)
654 rStrm
.WriteBytes(mData
.getConstArray(), mData
.getLength());
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() && rStrm
.remainingSize() >= 4; ++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
),
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() )
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() );
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() );
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() );
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() );
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() );
771 if ( pProp
->GetValue() == TIMESTAMP_INVALID_UTILDATETIME
)
772 rValue
= util::DateTime();
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() );
786 if ( pProp
->GetValue() == TIMESTAMP_INVALID_UTILDATE
)
787 rValue
= util::Date();
789 rValue
= pProp
->GetValue();
791 return pProp
!= nullptr;
794 void SfxOleSection::SetProperty( const SfxOlePropertyRef
& 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();
819 SetProperty( std::make_shared
<SfxOleString8Property
>( nPropId
, maCodePageProp
, rValue
) );
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
) );
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
835 if ( rValue
.Year
== 0 || rValue
.Month
== 0 || rValue
.Day
== 0 )
836 SetProperty( std::make_shared
<SfxOleFileTimeProperty
>( nPropId
, TIMESTAMP_INVALID_UTILDATETIME
) );
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
864 sal_Int32 nInt32
= 0;
865 double fDouble
= 0.0;
868 css::util::DateTime aApiDateTime
;
869 css::util::Date aApiDate
;
871 if( GetInt32Value( nInt32
, nPropId
) )
873 else if( GetDoubleValue( fDouble
, nPropId
) )
875 else if( GetBoolValue( bBool
, nPropId
) )
877 else if( GetStringValue( aString
, nPropId
) )
879 else if( GetFileTimeValue( aApiDateTime
, nPropId
) )
881 aValue
<<= aApiDateTime
;
883 else if( GetDateValue( aApiDate
, nPropId
) )
890 bool SfxOleSection::SetAnyValue( sal_Int32 nPropId
, const Any
& rValue
)
892 bool bInserted
= true;
893 sal_Int32 nInt32
= 0;
894 double fDouble
= 0.0;
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
);
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
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();
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
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
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() )
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 sal_uInt32 nSectSize
= static_cast< sal_uInt32
>( rStrm
.TellEnd() - mnStartPos
);
1022 rStrm
.Seek( mnStartPos
);
1023 rStrm
.WriteUInt32( nSectSize
);
1026 bool SfxOleSection::SeekToPropertyPos( SvStream
& rStrm
, sal_uInt32 nPropPos
) const
1028 return checkSeek(rStrm
, static_cast<std::size_t>(mnStartPos
+ nPropPos
)) &&
1029 rStrm
.GetErrorCode() == ERRCODE_NONE
;
1032 void SfxOleSection::LoadProperty( SvStream
& rStrm
, sal_Int32 nPropId
)
1034 // property data type
1035 sal_Int32
nPropType(0);
1036 rStrm
.ReadInt32( nPropType
);
1037 // create empty property object
1038 SfxOlePropertyRef xProp
;
1041 case PROPTYPE_INT32
:
1042 xProp
= std::make_shared
<SfxOleInt32Property
>( nPropId
);
1044 case PROPTYPE_DOUBLE
:
1045 xProp
= std::make_shared
<SfxOleDoubleProperty
>( nPropId
);
1048 xProp
= std::make_shared
<SfxOleBoolProperty
>( nPropId
);
1050 case PROPTYPE_STRING8
:
1051 xProp
= std::make_shared
<SfxOleString8Property
>( nPropId
, maCodePageProp
);
1053 case PROPTYPE_STRING16
:
1054 xProp
= std::make_shared
<SfxOleString16Property
>( nPropId
);
1056 case PROPTYPE_FILETIME
:
1057 xProp
= std::make_shared
<SfxOleFileTimeProperty
>( nPropId
);
1060 xProp
= std::make_shared
<SfxOleDateProperty
>( nPropId
);
1063 // load property contents
1066 SetError( xProp
->Load( rStrm
) );
1067 maPropMap
[ nPropId
] = xProp
;
1071 void SfxOleSection::SaveProperty( SvStream
& rStrm
, SfxOlePropertyBase
& rProp
, sal_uInt64
& rnPropPosPos
)
1073 rStrm
.Seek( STREAM_SEEK_TO_END
);
1074 sal_uInt32 nPropPos
= static_cast< sal_uInt32
>( rStrm
.Tell() - mnStartPos
);
1075 // property data type
1076 rStrm
.WriteInt32( rProp
.GetPropType() );
1077 // write property contents
1078 SaveObject( rStrm
, rProp
);
1080 while( (rStrm
.Tell() & 3) != 0 )
1081 rStrm
.WriteUChar( 0 );
1082 // write property ID/position pair
1083 rStrm
.Seek( rnPropPosPos
);
1084 rStrm
.WriteInt32( rProp
.GetPropId() ).WriteUInt32( nPropPos
);
1085 rnPropPosPos
= rStrm
.Tell();
1089 ErrCode
const & SfxOlePropertySet::LoadPropertySet( SotStorage
* pStrg
, const OUString
& rStrmName
)
1093 tools::SvRef
<SotStorageStream
> xStrm
= pStrg
->OpenSotStream( rStrmName
, StreamMode::STD_READ
);
1094 if( xStrm
.is() && (xStrm
->GetError() == ERRCODE_NONE
) )
1096 xStrm
->SetBufferSize( STREAM_BUFFER_SIZE
);
1100 SetError( ERRCODE_IO_ACCESSDENIED
);
1103 SetError( ERRCODE_IO_ACCESSDENIED
);
1107 ErrCode
const & SfxOlePropertySet::SavePropertySet( SotStorage
* pStrg
, const OUString
& rStrmName
)
1111 tools::SvRef
<SotStorageStream
> xStrm
= pStrg
->OpenSotStream( rStrmName
, StreamMode::TRUNC
| StreamMode::STD_WRITE
);
1115 SetError( ERRCODE_IO_ACCESSDENIED
);
1118 SetError( ERRCODE_IO_ACCESSDENIED
);
1122 SfxOleSectionRef
SfxOlePropertySet::GetSection( SfxOleSectionType eSection
) const
1124 return GetSection( GetSectionGuid( eSection
) );
1127 SfxOleSectionRef
SfxOlePropertySet::GetSection( const SvGlobalName
& rSectionGuid
) const
1129 SfxOleSectionRef xSection
;
1130 SfxOleSectionMap::const_iterator aIt
= maSectionMap
.find( rSectionGuid
);
1131 if( aIt
!= maSectionMap
.end() )
1132 xSection
= aIt
->second
;
1136 SfxOleSection
& SfxOlePropertySet::AddSection( SfxOleSectionType eSection
)
1138 return AddSection( GetSectionGuid( eSection
) );
1141 SfxOleSection
& SfxOlePropertySet::AddSection( const SvGlobalName
& rSectionGuid
)
1143 SfxOleSectionRef xSection
= GetSection( rSectionGuid
);
1146 // #i66214# #i66428# applications may write broken dictionary properties in wrong sections
1147 bool bSupportsDict
= rSectionGuid
== GetSectionGuid( SECTION_CUSTOM
);
1148 xSection
= std::make_shared
<SfxOleSection
>( bSupportsDict
);
1149 maSectionMap
[ rSectionGuid
] = xSection
;
1154 void SfxOlePropertySet::ImplLoad( SvStream
& rStrm
)
1156 // read property set header
1157 sal_uInt16 nByteOrder
;
1158 sal_uInt16 nVersion
;
1159 sal_uInt16 nOsMinor
;
1162 sal_Int32
nSectCount(0);
1163 rStrm
.ReadUInt16( nByteOrder
).ReadUInt16( nVersion
).ReadUInt16( nOsMinor
).ReadUInt16( nOsType
);
1165 rStrm
.ReadInt32( nSectCount
);
1168 sal_uInt64 nSectPosPos
= rStrm
.Tell();
1169 for (sal_Int32 nSectIdx
= 0; nSectIdx
< nSectCount
; ++nSectIdx
)
1171 // read section guid/position pair
1172 rStrm
.Seek(nSectPosPos
);
1173 SvGlobalName aSectGuid
;
1175 sal_uInt32
nSectPos(0);
1176 rStrm
.ReadUInt32(nSectPos
);
1179 nSectPosPos
= rStrm
.Tell();
1181 if (!checkSeek(rStrm
, nSectPos
))
1183 LoadObject(rStrm
, AddSection(aSectGuid
));
1189 void SfxOlePropertySet::ImplSave( SvStream
& rStrm
)
1191 // write property set header
1193 sal_Int32 nSectCount
= static_cast< sal_Int32
>( maSectionMap
.size() );
1194 rStrm
.WriteUInt16( 0xFFFE ) // byte order
1195 .WriteUInt16( 0 ) // version
1196 .WriteUInt16( 1 ) // OS minor version
1197 .WriteUInt16( 2 ); // OS type always windows for text encoding
1198 WriteSvGlobalName( rStrm
, aGuid
); // unused guid
1199 rStrm
.WriteInt32( nSectCount
); // number of sections
1201 // write placeholders for section guid/position pairs
1202 sal_uInt64 nSectPosPos
= rStrm
.Tell();
1203 rStrm
.SeekRel( static_cast< sal_sSize
>( 20 * nSectCount
) );
1206 for (auto const& section
: maSectionMap
)
1208 SfxOleSection
& rSection
= *section
.second
;
1209 rStrm
.Seek( STREAM_SEEK_TO_END
);
1210 sal_uInt32 nSectPos
= static_cast< sal_uInt32
>( rStrm
.Tell() );
1211 // write the section
1212 SaveObject( rStrm
, rSection
);
1213 // write section guid/position pair
1214 rStrm
.Seek( nSectPosPos
);
1215 WriteSvGlobalName( rStrm
, section
.first
);
1216 rStrm
.WriteUInt32( nSectPos
);
1217 nSectPosPos
= rStrm
.Tell();
1221 const SvGlobalName
& SfxOlePropertySet::GetSectionGuid( SfxOleSectionType eSection
)
1223 static const SvGlobalName
saGlobalGuid( 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 );
1224 static const SvGlobalName
saBuiltInGuid( 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE );
1225 static const SvGlobalName
saCustomGuid( 0xD5CDD505, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE );
1226 static const SvGlobalName saEmptyGuid
;
1229 case SECTION_GLOBAL
: return saGlobalGuid
;
1230 case SECTION_BUILTIN
: return saBuiltInGuid
;
1231 case SECTION_CUSTOM
: return saCustomGuid
;
1232 default: SAL_WARN( "sfx.doc", "SfxOlePropertySet::GetSectionGuid - unknown section type" );
1240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */