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>
31 #define STREAM_BUFFER_SIZE 2048
34 using ::com::sun::star::uno::Any
;
36 using namespace ::com::sun::star
;
38 #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.
39 /// Invalid value for date and time to create invalid instance of TimeStamp.
40 #define TIMESTAMP_INVALID_UTILDATETIME (util::DateTime(0, 0, 0, 0, 1, 1, 1601, false))
41 /// Invalid value for date to create invalid instance of TimeStamp.
42 #define TIMESTAMP_INVALID_UTILDATE (util::Date(1, 1, 1601))
46 /** Property representing a signed 32-bit integer value. */
47 class SfxOleInt32Property
: public SfxOlePropertyBase
50 explicit SfxOleInt32Property( sal_Int32 nPropId
, sal_Int32 nValue
= 0 );
52 sal_Int32
GetValue() const { return mnValue
; }
55 virtual void ImplLoad( SvStream
& rStrm
) override
;
56 virtual void ImplSave( SvStream
& rStrm
) override
;
63 /** Property representing a floating-point value. */
64 class SfxOleDoubleProperty
: public SfxOlePropertyBase
67 explicit SfxOleDoubleProperty( sal_Int32 nPropId
, double fValue
= 0.0 );
69 double GetValue() const { return mfValue
; }
72 virtual void ImplLoad( SvStream
& rStrm
) override
;
73 virtual void ImplSave( SvStream
& rStrm
) override
;
80 /** Property representing a boolean value. */
81 class SfxOleBoolProperty
: public SfxOlePropertyBase
84 explicit SfxOleBoolProperty( sal_Int32 nPropId
, bool bValue
= false );
86 bool GetValue() const { return mbValue
; }
89 virtual void ImplLoad( SvStream
& rStrm
) override
;
90 virtual void ImplSave( SvStream
& rStrm
) override
;
97 /** Base class for properties that contain a single string value. */
98 class SfxOleStringPropertyBase
: public SfxOlePropertyBase
, public SfxOleStringHelper
101 explicit SfxOleStringPropertyBase(
102 sal_Int32 nPropId
, sal_Int32 nPropType
,
103 const SfxOleTextEncoding
& rTextEnc
);
104 explicit SfxOleStringPropertyBase(
105 sal_Int32 nPropId
, sal_Int32 nPropType
,
106 const SfxOleTextEncoding
& rTextEnc
, OUString aValue
);
107 explicit SfxOleStringPropertyBase(
108 sal_Int32 nPropId
, sal_Int32 nPropType
,
109 rtl_TextEncoding eTextEnc
);
111 const OUString
& GetValue() const { return maValue
; }
112 void SetValue( const OUString
& rValue
) { maValue
= rValue
; }
119 /** Property representing a bytestring value. */
120 class SfxOleString8Property
: public SfxOleStringPropertyBase
123 explicit SfxOleString8Property(
124 sal_Int32 nPropId
, const SfxOleTextEncoding
& rTextEnc
);
125 explicit SfxOleString8Property(
126 sal_Int32 nPropId
, const SfxOleTextEncoding
& rTextEnc
,
127 const OUString
& rValue
);
130 virtual void ImplLoad( SvStream
& rStrm
) override
;
131 virtual void ImplSave( SvStream
& rStrm
) override
;
135 /** Property representing a Unicode string value. */
136 class SfxOleString16Property
: public SfxOleStringPropertyBase
139 explicit SfxOleString16Property( sal_Int32 nPropId
);
142 virtual void ImplLoad( SvStream
& rStrm
) override
;
143 virtual void ImplSave( SvStream
& rStrm
) override
;
147 /** Property representing a filetime value as defined by the Windows API. */
148 class SfxOleFileTimeProperty
: public SfxOlePropertyBase
151 explicit SfxOleFileTimeProperty( sal_Int32 nPropId
);
152 /** @param rDateTime Date and time as LOCAL time. */
153 explicit SfxOleFileTimeProperty( sal_Int32 nPropId
, const util::DateTime
& rDateTime
);
155 /** Returns the time value as LOCAL time. */
156 const util::DateTime
& GetValue() const { return maDateTime
; }
159 virtual void ImplLoad( SvStream
& rStrm
) override
;
160 virtual void ImplSave( SvStream
& rStrm
) override
;
163 util::DateTime maDateTime
;
166 /** Property representing a filetime value as defined by the Windows API. */
167 class SfxOleDateProperty
: public SfxOlePropertyBase
170 explicit SfxOleDateProperty( sal_Int32 nPropId
);
172 /** Returns the date value as LOCAL time. */
173 const util::Date
& GetValue() const { return maDate
; }
176 virtual void ImplLoad( SvStream
& rStrm
) override
;
177 virtual void ImplSave( SvStream
& rStrm
) override
;
184 /** Property representing a thumbnail picture.
186 Currently, only saving this property is implemented.
188 class SfxOleThumbnailProperty
: public SfxOlePropertyBase
191 explicit SfxOleThumbnailProperty( sal_Int32 nPropId
,
192 const uno::Sequence
<sal_Int8
> & i_rData
);
194 bool IsValid() const { return mData
.hasElements(); }
197 virtual void ImplLoad( SvStream
& rStrm
) override
;
198 virtual void ImplSave( SvStream
& rStrm
) override
;
201 uno::Sequence
<sal_Int8
> mData
;
205 /** Property representing a BLOB (which presumably stands for binary large
208 Currently, only saving this property is implemented.
210 class SfxOleBlobProperty
: public SfxOlePropertyBase
213 explicit SfxOleBlobProperty( sal_Int32 nPropId
,
214 const uno::Sequence
<sal_Int8
> & i_rData
);
215 bool IsValid() const { return mData
.hasElements(); }
218 virtual void ImplLoad( SvStream
& rStrm
) override
;
219 virtual void ImplSave( SvStream
& rStrm
) override
;
222 uno::Sequence
<sal_Int8
> mData
;
227 sal_uInt16
SfxOleTextEncoding::GetCodePage() const
229 sal_uInt16 nCodePage
= IsUnicode() ? CODEPAGE_UNICODE
:
230 static_cast< sal_uInt16
>( rtl_getWindowsCodePageFromTextEncoding( *mxTextEnc
) );
231 return (nCodePage
== CODEPAGE_UNKNOWN
) ? CODEPAGE_UTF8
: nCodePage
;
234 void SfxOleTextEncoding::SetCodePage( sal_uInt16 nCodePage
)
236 if( nCodePage
== CODEPAGE_UNICODE
)
240 rtl_TextEncoding eTextEnc
= rtl_getTextEncodingFromWindowsCodePage( nCodePage
);
241 if( eTextEnc
!= RTL_TEXTENCODING_DONTKNOW
)
242 *mxTextEnc
= eTextEnc
;
247 OUString
SfxOleStringHelper::LoadString8( SvStream
& rStrm
) const
249 return IsUnicode() ? ImplLoadString16( rStrm
) : ImplLoadString8( rStrm
);
252 void SfxOleStringHelper::SaveString8( SvStream
& rStrm
, std::u16string_view rValue
) const
255 ImplSaveString16( rStrm
, rValue
);
257 ImplSaveString8( rStrm
, rValue
);
260 OUString
SfxOleStringHelper::LoadString16( SvStream
& rStrm
)
262 return ImplLoadString16( rStrm
);
265 void SfxOleStringHelper::SaveString16( SvStream
& rStrm
, std::u16string_view rValue
)
267 ImplSaveString16( rStrm
, rValue
);
270 OUString
SfxOleStringHelper::ImplLoadString8( SvStream
& rStrm
) const
272 // read size field (signed 32-bit)
274 rStrm
.ReadInt32( nSize
);
275 // size field includes trailing NUL character
276 SAL_WARN_IF(nSize
< 1 || nSize
> 0xFFFF, "sfx.doc", "SfxOleStringHelper::ImplLoadString8 - invalid string of len " << nSize
);
277 if (nSize
< 1 || nSize
> 0xFFFF)
279 // load character buffer
280 OString
sValue(read_uInt8s_ToOString(rStrm
, nSize
- 1));
281 if (rStrm
.good() && rStrm
.remainingSize())
282 rStrm
.SeekRel(1); // skip null-byte at end
283 return OStringToOUString(sValue
, GetTextEncoding());
286 OUString
SfxOleStringHelper::ImplLoadString16( SvStream
& rStrm
)
288 // read size field (signed 32-bit), may be buffer size or character count
290 rStrm
.ReadInt32(nSize
);
291 SAL_WARN_IF(nSize
< 1 || nSize
> 0xFFFF, "sfx.doc", "SfxOleStringHelper::ImplLoadString16 - invalid string of len " << nSize
);
292 // size field includes trailing NUL character
293 if (nSize
< 1 || nSize
> 0xFFFF)
295 // load character buffer
296 OUString aValue
= read_uInt16s_ToOUString(rStrm
, nSize
- 1);
297 sal_Int32
nSkip(2); // skip null-byte at end
298 // stream is always padded to 32-bit boundary, skip 2 bytes on odd character count
299 if ((nSize
& 1) == 1)
301 nSkip
= std::min
<sal_uInt32
>(nSkip
, rStrm
.remainingSize());
302 if (rStrm
.good() && nSkip
)
303 rStrm
.SeekRel(nSkip
);
307 void SfxOleStringHelper::ImplSaveString8( SvStream
& rStrm
, std::u16string_view rValue
) const
309 // encode to byte string
310 OString
aEncoded(OUStringToOString(rValue
, GetTextEncoding()));
311 // write size field (including trailing NUL character)
312 sal_Int32 nSize
= aEncoded
.getLength() + 1;
313 rStrm
.WriteInt32( nSize
);
314 // write character array with trailing NUL character
315 rStrm
.WriteBytes(aEncoded
.getStr(), aEncoded
.getLength());
316 rStrm
.WriteUChar( 0 );
319 void SfxOleStringHelper::ImplSaveString16( SvStream
& rStrm
, std::u16string_view rValue
)
321 // write size field (including trailing NUL character)
322 sal_Int32 nSize
= static_cast< sal_Int32
>( rValue
.size() + 1 );
323 rStrm
.WriteInt32( nSize
);
324 // write character array with trailing NUL character
325 for( size_t nIdx
= 0; nIdx
< rValue
.size(); ++nIdx
)
326 rStrm
.WriteUInt16( rValue
[ nIdx
] );
327 rStrm
.WriteUInt16( 0 );
328 // stream is always padded to 32-bit boundary, add 2 bytes on odd character count
329 if( (nSize
& 1) == 1 )
330 rStrm
.WriteUInt16( 0 );
334 SfxOleObjectBase::~SfxOleObjectBase()
338 ErrCode
const & SfxOleObjectBase::Load( SvStream
& rStrm
)
340 mnErrCode
= ERRCODE_NONE
;
342 SetError( rStrm
.GetErrorCode() );
346 ErrCode
const & SfxOleObjectBase::Save( SvStream
& rStrm
)
348 mnErrCode
= ERRCODE_NONE
;
350 SetError( rStrm
.GetErrorCode() );
354 void SfxOleObjectBase::LoadObject( SvStream
& rStrm
, SfxOleObjectBase
& rObj
)
356 SetError( rObj
.Load( rStrm
) );
359 void SfxOleObjectBase::SaveObject( SvStream
& rStrm
, SfxOleObjectBase
& rObj
)
361 SetError( rObj
.Save( rStrm
) );
365 SfxOleCodePageProperty::SfxOleCodePageProperty() :
366 SfxOlePropertyBase( PROPID_CODEPAGE
, PROPTYPE_INT16
)
370 void SfxOleCodePageProperty::ImplLoad(SvStream
& rStrm
)
372 // property type is signed int16, but we use always unsigned int16 for codepages
373 sal_uInt16
nCodePage(0);
374 rStrm
.ReadUInt16(nCodePage
);
375 SetCodePage(nCodePage
);
378 void SfxOleCodePageProperty::ImplSave( SvStream
& rStrm
)
380 // property type is signed int16, but we use always unsigned int16 for codepages
381 rStrm
.WriteUInt16( GetCodePage() );
385 SfxOleInt32Property::SfxOleInt32Property( sal_Int32 nPropId
, sal_Int32 nValue
) :
386 SfxOlePropertyBase( nPropId
, PROPTYPE_INT32
),
391 void SfxOleInt32Property::ImplLoad( SvStream
& rStrm
)
393 rStrm
.ReadInt32( mnValue
);
396 void SfxOleInt32Property::ImplSave( SvStream
& rStrm
)
398 rStrm
.WriteInt32( mnValue
);
402 SfxOleDoubleProperty::SfxOleDoubleProperty( sal_Int32 nPropId
, double fValue
) :
403 SfxOlePropertyBase( nPropId
, PROPTYPE_DOUBLE
),
408 void SfxOleDoubleProperty::ImplLoad( SvStream
& rStrm
)
410 rStrm
.ReadDouble( mfValue
);
413 void SfxOleDoubleProperty::ImplSave( SvStream
& rStrm
)
415 rStrm
.WriteDouble( mfValue
);
419 SfxOleBoolProperty::SfxOleBoolProperty( sal_Int32 nPropId
, bool bValue
) :
420 SfxOlePropertyBase( nPropId
, PROPTYPE_BOOL
),
425 void SfxOleBoolProperty::ImplLoad( SvStream
& rStrm
)
428 rStrm
.ReadInt16( nValue
);
429 mbValue
= nValue
!= 0;
432 void SfxOleBoolProperty::ImplSave( SvStream
& rStrm
)
434 rStrm
.WriteInt16( mbValue
? -1 : 0 );
438 SfxOleStringPropertyBase::SfxOleStringPropertyBase(
439 sal_Int32 nPropId
, sal_Int32 nPropType
, const SfxOleTextEncoding
& rTextEnc
) :
440 SfxOlePropertyBase( nPropId
, nPropType
),
441 SfxOleStringHelper( rTextEnc
)
445 SfxOleStringPropertyBase::SfxOleStringPropertyBase(
446 sal_Int32 nPropId
, sal_Int32 nPropType
, const SfxOleTextEncoding
& rTextEnc
, OUString aValue
) :
447 SfxOlePropertyBase( nPropId
, nPropType
),
448 SfxOleStringHelper( rTextEnc
),
449 maValue(std::move( aValue
))
453 SfxOleStringPropertyBase::SfxOleStringPropertyBase(
454 sal_Int32 nPropId
, sal_Int32 nPropType
, rtl_TextEncoding eTextEnc
) :
455 SfxOlePropertyBase( nPropId
, nPropType
),
456 SfxOleStringHelper( eTextEnc
)
461 SfxOleString8Property::SfxOleString8Property(
462 sal_Int32 nPropId
, const SfxOleTextEncoding
& rTextEnc
) :
463 SfxOleStringPropertyBase( nPropId
, PROPTYPE_STRING8
, rTextEnc
)
467 SfxOleString8Property::SfxOleString8Property(
468 sal_Int32 nPropId
, const SfxOleTextEncoding
& rTextEnc
, const OUString
& rValue
) :
469 SfxOleStringPropertyBase( nPropId
, PROPTYPE_STRING8
, rTextEnc
, rValue
)
473 void SfxOleString8Property::ImplLoad( SvStream
& rStrm
)
475 SetValue( LoadString8( rStrm
) );
478 void SfxOleString8Property::ImplSave( SvStream
& rStrm
)
480 SaveString8( rStrm
, GetValue() );
484 SfxOleString16Property::SfxOleString16Property( sal_Int32 nPropId
) :
485 SfxOleStringPropertyBase( nPropId
, PROPTYPE_STRING16
, RTL_TEXTENCODING_UCS2
)
489 void SfxOleString16Property::ImplLoad( SvStream
& rStrm
)
491 SetValue( LoadString16( rStrm
) );
494 void SfxOleString16Property::ImplSave( SvStream
& rStrm
)
496 SaveString16( rStrm
, GetValue() );
500 SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId
) :
501 SfxOlePropertyBase( nPropId
, PROPTYPE_FILETIME
)
505 SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId
, const util::DateTime
& rDateTime
) :
506 SfxOlePropertyBase( nPropId
, PROPTYPE_FILETIME
),
507 maDateTime( rDateTime
)
511 void SfxOleFileTimeProperty::ImplLoad( SvStream
& rStrm
)
513 sal_uInt32
nLower(0), nUpper(0);
514 rStrm
.ReadUInt32( nLower
).ReadUInt32( nUpper
);
515 ::DateTime aDateTime
= DateTime::CreateFromWin32FileDateTime( nLower
, nUpper
);
516 // note: editing duration is stored as offset to TIMESTAMP_INVALID_DATETIME
517 // of course we should not convert the time zone of a duration!
518 // heuristic to detect editing durations (which we assume to be < 1 year):
519 // check only the year, not the entire date
520 if ( aDateTime
.GetYear() != TIMESTAMP_INVALID_DATETIME
.GetYear() )
521 aDateTime
.ConvertToLocalTime();
522 maDateTime
.Year
= aDateTime
.GetYear();
523 maDateTime
.Month
= aDateTime
.GetMonth();
524 maDateTime
.Day
= aDateTime
.GetDay();
525 maDateTime
.Hours
= aDateTime
.GetHour();
526 maDateTime
.Minutes
= aDateTime
.GetMin();
527 maDateTime
.Seconds
= aDateTime
.GetSec();
528 maDateTime
.NanoSeconds
= aDateTime
.GetNanoSec();
529 maDateTime
.IsUTC
= false;
532 void SfxOleFileTimeProperty::ImplSave( SvStream
& rStrm
)
534 DateTime
aDateTimeUtc(
538 static_cast< sal_uInt16
>( maDateTime
.Year
) ),
543 maDateTime
.NanoSeconds
) );
544 // invalid time stamp is not converted to UTC
545 // heuristic to detect editing durations (which we assume to be < 1 year):
546 // check only the year, not the entire date
547 if( aDateTimeUtc
.IsValidAndGregorian()
548 && aDateTimeUtc
.GetYear() != TIMESTAMP_INVALID_DATETIME
.GetYear() ) {
549 aDateTimeUtc
.ConvertToUTC();
551 sal_uInt32 nLower
, nUpper
;
552 aDateTimeUtc
.GetWin32FileDateTime( nLower
, nUpper
);
553 rStrm
.WriteUInt32( nLower
).WriteUInt32( nUpper
);
556 SfxOleDateProperty::SfxOleDateProperty( sal_Int32 nPropId
) :
557 SfxOlePropertyBase( nPropId
, PROPTYPE_DATE
)
561 void SfxOleDateProperty::ImplLoad( SvStream
& rStrm
)
564 rStrm
.ReadDouble( fValue
);
565 //stored as number of days (not seconds) since December 31, 1899
566 sal_Int32 nDays
= fValue
;
567 sal_Int32 nStartDays
= ::Date::DateToDays(31, 12, 1899);
568 if (o3tl::checked_add(nStartDays
, nDays
, nStartDays
))
569 SAL_WARN("sfx.doc", "SfxOleDateProperty::ImplLoad bad date, ignored");
572 ::Date
aDate(31, 12, 1899);
573 aDate
.AddDays(nDays
);
574 maDate
.Day
= aDate
.GetDay();
575 maDate
.Month
= aDate
.GetMonth();
576 maDate
.Year
= aDate
.GetYear();
580 void SfxOleDateProperty::ImplSave( SvStream
& rStrm
)
582 sal_Int32 nDays
= ::Date::DateToDays(maDate
.Day
, maDate
.Month
, maDate
.Year
);
583 //number of days (not seconds) since December 31, 1899
584 sal_Int32 nStartDays
= ::Date::DateToDays(31, 12, 1899);
585 double fValue
= nDays
-nStartDays
;
586 rStrm
.WriteDouble( fValue
);
590 SfxOleThumbnailProperty::SfxOleThumbnailProperty(
591 sal_Int32 nPropId
, const uno::Sequence
<sal_Int8
> & i_rData
) :
592 SfxOlePropertyBase( nPropId
, PROPTYPE_CLIPFMT
),
597 void SfxOleThumbnailProperty::ImplLoad( SvStream
& )
599 SAL_WARN( "sfx.doc", "SfxOleThumbnailProperty::ImplLoad - not implemented" );
600 SetError( SVSTREAM_INVALID_ACCESS
);
603 void SfxOleThumbnailProperty::ImplSave( SvStream
& rStrm
)
606 -----------------------------------------------------------------------
607 int32 size of following data
608 int32 clipboard format tag (see below)
609 byte[] clipboard data (see below)
611 Clipboard format tag:
612 -1 = Windows clipboard format
613 -2 = Macintosh clipboard format
614 -3 = GUID that contains a format identifier (FMTID)
615 >0 = custom clipboard format name plus data (see msdn site below)
619 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/propvariant.asp
620 http://jakarta.apache.org/poi/hpsf/thumbnails.html
621 http://linux.com.hk/docs/poi/org/apache/poi/hpsf/Thumbnail.html
622 https://web.archive.org/web/20060126202945/http://sparks.discreet.com/knowledgebase/public/solutions/ExtractThumbnailImg.htm
626 // clipboard size: clip_format_tag + data_format_tag + bitmap_len
627 sal_Int32 nClipSize
= static_cast< sal_Int32
>( 4 + 4 + mData
.getLength() );
628 rStrm
.WriteInt32( nClipSize
).WriteInt32( CLIPFMT_WIN
).WriteInt32( CLIPDATAFMT_DIB
);
629 rStrm
.WriteBytes(mData
.getConstArray(), mData
.getLength());
633 SAL_WARN( "sfx.doc", "SfxOleThumbnailProperty::ImplSave - invalid thumbnail property" );
634 SetError( SVSTREAM_INVALID_ACCESS
);
639 SfxOleBlobProperty::SfxOleBlobProperty( sal_Int32 nPropId
,
640 const uno::Sequence
<sal_Int8
> & i_rData
) :
641 SfxOlePropertyBase( nPropId
, PROPTYPE_BLOB
),
646 void SfxOleBlobProperty::ImplLoad( SvStream
& )
648 SAL_WARN( "sfx.doc", "SfxOleBlobProperty::ImplLoad - not implemented" );
649 SetError( SVSTREAM_INVALID_ACCESS
);
652 void SfxOleBlobProperty::ImplSave( SvStream
& rStrm
)
655 rStrm
.WriteBytes(mData
.getConstArray(), mData
.getLength());
657 SAL_WARN( "sfx.doc", "SfxOleBlobProperty::ImplSave - invalid BLOB property" );
658 SetError( SVSTREAM_INVALID_ACCESS
);
663 SfxOleDictionaryProperty::SfxOleDictionaryProperty( const SfxOleTextEncoding
& rTextEnc
) :
664 SfxOlePropertyBase( PROPID_DICTIONARY
, 0 ),
665 SfxOleStringHelper( rTextEnc
)
669 OUString
SfxOleDictionaryProperty::GetPropertyName( sal_Int32 nPropId
) const
671 SfxOlePropNameMap::const_iterator aIt
= maPropNameMap
.find( nPropId
);
672 return (aIt
== maPropNameMap
.end()) ? OUString() : aIt
->second
;
675 void SfxOleDictionaryProperty::SetPropertyName( sal_Int32 nPropId
, const OUString
& rPropName
)
677 maPropNameMap
[ nPropId
] = rPropName
;
678 // dictionary property contains number of pairs in property type field
679 SetPropType( static_cast< sal_Int32
>( maPropNameMap
.size() ) );
682 void SfxOleDictionaryProperty::ImplLoad( SvStream
& rStrm
)
684 // dictionary property contains number of pairs in property type field
685 sal_Int32 nNameCount
= GetPropType();
686 // read property ID/name pairs
687 maPropNameMap
.clear();
688 for (sal_Int32 nIdx
= 0; nIdx
< nNameCount
&& rStrm
.good() && rStrm
.remainingSize() >= 4; ++nIdx
)
690 sal_Int32
nPropId(0);
691 rStrm
.ReadInt32(nPropId
);
692 // name always stored as byte string
693 maPropNameMap
[nPropId
] = LoadString8(rStrm
);
697 void SfxOleDictionaryProperty::ImplSave( SvStream
& rStrm
)
699 // write property ID/name pairs
700 for (auto const& propName
: maPropNameMap
)
702 rStrm
.WriteInt32( propName
.first
);
703 // name always stored as byte string
704 SaveString8( rStrm
, propName
.second
);
709 SfxOleSection::SfxOleSection( bool bSupportsDict
) :
710 maDictProp( maCodePageProp
),
712 mbSupportsDict( bSupportsDict
)
716 SfxOlePropertyRef
SfxOleSection::GetProperty( sal_Int32 nPropId
) const
718 SfxOlePropertyRef xProp
;
719 SfxOlePropMap::const_iterator aIt
= maPropMap
.find( nPropId
);
720 if( aIt
!= maPropMap
.end() )
725 bool SfxOleSection::GetInt32Value( sal_Int32
& rnValue
, sal_Int32 nPropId
) const
727 SfxOlePropertyRef xProp
= GetProperty( nPropId
);
728 const SfxOleInt32Property
* pProp
=
729 dynamic_cast< const SfxOleInt32Property
* >( xProp
.get() );
731 rnValue
= pProp
->GetValue();
732 return pProp
!= nullptr;
735 bool SfxOleSection::GetDoubleValue( double& rfValue
, sal_Int32 nPropId
) const
737 SfxOlePropertyRef xProp
= GetProperty( nPropId
);
738 const SfxOleDoubleProperty
* pProp
=
739 dynamic_cast< const SfxOleDoubleProperty
* >( xProp
.get() );
741 rfValue
= pProp
->GetValue();
742 return pProp
!= nullptr;
745 bool SfxOleSection::GetBoolValue( bool& rbValue
, sal_Int32 nPropId
) const
747 SfxOlePropertyRef xProp
= GetProperty( nPropId
);
748 const SfxOleBoolProperty
* pProp
=
749 dynamic_cast< const SfxOleBoolProperty
* >( xProp
.get() );
751 rbValue
= pProp
->GetValue();
752 return pProp
!= nullptr;
755 bool SfxOleSection::GetStringValue( OUString
& rValue
, sal_Int32 nPropId
) const
757 SfxOlePropertyRef xProp
= GetProperty( nPropId
);
758 const SfxOleStringPropertyBase
* pProp
=
759 dynamic_cast< const SfxOleStringPropertyBase
* >( xProp
.get() );
761 rValue
= pProp
->GetValue();
762 return pProp
!= nullptr;
765 bool SfxOleSection::GetFileTimeValue( util::DateTime
& rValue
, sal_Int32 nPropId
) const
767 SfxOlePropertyRef xProp
= GetProperty( nPropId
);
768 const SfxOleFileTimeProperty
* pProp
=
769 dynamic_cast< const SfxOleFileTimeProperty
* >( xProp
.get() );
772 if ( pProp
->GetValue() == TIMESTAMP_INVALID_UTILDATETIME
)
773 rValue
= util::DateTime();
775 rValue
= pProp
->GetValue();
777 return pProp
!= nullptr;
780 bool SfxOleSection::GetDateValue( util::Date
& rValue
, sal_Int32 nPropId
) const
782 SfxOlePropertyRef xProp
= GetProperty( nPropId
);
783 const SfxOleDateProperty
* pProp
=
784 dynamic_cast< const SfxOleDateProperty
* >( xProp
.get() );
787 if ( pProp
->GetValue() == TIMESTAMP_INVALID_UTILDATE
)
788 rValue
= util::Date();
790 rValue
= pProp
->GetValue();
792 return pProp
!= nullptr;
795 void SfxOleSection::SetProperty( const SfxOlePropertyRef
& xProp
)
798 maPropMap
[ xProp
->GetPropId() ] = xProp
;
801 void SfxOleSection::SetInt32Value( sal_Int32 nPropId
, sal_Int32 nValue
)
803 SetProperty( std::make_shared
<SfxOleInt32Property
>( nPropId
, nValue
) );
806 void SfxOleSection::SetDoubleValue( sal_Int32 nPropId
, double fValue
)
808 SetProperty( std::make_shared
<SfxOleDoubleProperty
>( nPropId
, fValue
) );
811 void SfxOleSection::SetBoolValue( sal_Int32 nPropId
, bool bValue
)
813 SetProperty( std::make_shared
<SfxOleBoolProperty
>( nPropId
, bValue
) );
816 bool SfxOleSection::SetStringValue( sal_Int32 nPropId
, const OUString
& rValue
)
818 bool bInserted
= !rValue
.isEmpty();
820 SetProperty( std::make_shared
<SfxOleString8Property
>( nPropId
, maCodePageProp
, rValue
) );
824 void SfxOleSection::SetFileTimeValue( sal_Int32 nPropId
, const util::DateTime
& rValue
)
826 if ( rValue
.Year
== 0 || rValue
.Month
== 0 || rValue
.Day
== 0 )
827 SetProperty( std::make_shared
<SfxOleFileTimeProperty
>( nPropId
, TIMESTAMP_INVALID_UTILDATETIME
) );
829 SetProperty( std::make_shared
<SfxOleFileTimeProperty
>( nPropId
, rValue
) );
832 void SfxOleSection::SetDateValue( sal_Int32 nPropId
, const util::Date
& rValue
)
834 //Annoyingly MS2010 considers VT_DATE apparently as an invalid possibility, so here we use VT_FILETIME
836 if ( rValue
.Year
== 0 || rValue
.Month
== 0 || rValue
.Day
== 0 )
837 SetProperty( std::make_shared
<SfxOleFileTimeProperty
>( nPropId
, TIMESTAMP_INVALID_UTILDATETIME
) );
840 const util::DateTime
aValue(0, 0, 0, 0, rValue
.Day
, rValue
.Month
,
841 rValue
.Year
, false );
842 SetProperty( std::make_shared
<SfxOleFileTimeProperty
>( nPropId
, aValue
) );
846 void SfxOleSection::SetThumbnailValue( sal_Int32 nPropId
,
847 const uno::Sequence
<sal_Int8
> & i_rData
)
849 auto pThumbnail
= std::make_shared
<SfxOleThumbnailProperty
>( nPropId
, i_rData
);
850 if( pThumbnail
->IsValid() )
851 SetProperty( pThumbnail
);
854 void SfxOleSection::SetBlobValue( sal_Int32 nPropId
,
855 const uno::Sequence
<sal_Int8
> & i_rData
)
857 auto pBlob
= std::make_shared
<SfxOleBlobProperty
>( nPropId
, i_rData
);
858 if( pBlob
->IsValid() )
859 SetProperty( pBlob
);
862 Any
SfxOleSection::GetAnyValue( sal_Int32 nPropId
) const
865 sal_Int32 nInt32
= 0;
866 double fDouble
= 0.0;
869 css::util::DateTime aApiDateTime
;
870 css::util::Date aApiDate
;
872 if( GetInt32Value( nInt32
, nPropId
) )
874 else if( GetDoubleValue( fDouble
, nPropId
) )
876 else if( GetBoolValue( bBool
, nPropId
) )
878 else if( GetStringValue( aString
, nPropId
) )
880 else if( GetFileTimeValue( aApiDateTime
, nPropId
) )
882 aValue
<<= aApiDateTime
;
884 else if( GetDateValue( aApiDate
, nPropId
) )
891 bool SfxOleSection::SetAnyValue( sal_Int32 nPropId
, const Any
& rValue
)
893 bool bInserted
= true;
894 sal_Int32 nInt32
= 0;
895 double fDouble
= 0.0;
897 css::util::DateTime aApiDateTime
;
898 css::util::Date aApiDate
;
900 if( rValue
.getValueType() == cppu::UnoType
<bool>::get() )
901 SetBoolValue( nPropId
, ::comphelper::getBOOL( rValue
) );
902 else if( rValue
>>= nInt32
)
903 SetInt32Value( nPropId
, nInt32
);
904 else if( rValue
>>= fDouble
)
905 SetDoubleValue( nPropId
, fDouble
);
906 else if( rValue
>>= aString
)
907 bInserted
= SetStringValue( nPropId
, aString
);
908 else if( rValue
>>= aApiDateTime
)
909 SetFileTimeValue( nPropId
, aApiDateTime
);
910 else if( rValue
>>= aApiDate
)
911 SetDateValue( nPropId
, aApiDate
);
917 OUString
SfxOleSection::GetPropertyName( sal_Int32 nPropId
) const
919 return maDictProp
.GetPropertyName( nPropId
);
922 void SfxOleSection::SetPropertyName( sal_Int32 nPropId
, const OUString
& rPropName
)
924 maDictProp
.SetPropertyName( nPropId
, rPropName
);
927 void SfxOleSection::GetPropertyIds( ::std::vector
< sal_Int32
>& rPropIds
) const
930 for (auto const& prop
: maPropMap
)
931 rPropIds
.push_back(prop
.first
);
934 sal_Int32
SfxOleSection::GetFreePropertyId() const
936 return maPropMap
.empty() ? PROPID_FIRSTCUSTOM
: (maPropMap
.rbegin()->first
+ 1);
939 void SfxOleSection::ImplLoad( SvStream
& rStrm
)
941 // read section header
942 mnStartPos
= rStrm
.Tell();
944 sal_Int32
nPropCount(0);
945 rStrm
.ReadUInt32( nSize
).ReadInt32( nPropCount
);
947 // read property ID/position pairs
948 typedef ::std::map
< sal_Int32
, sal_uInt32
> SfxOlePropPosMap
;
949 SfxOlePropPosMap aPropPosMap
;
950 for (sal_Int32 nPropIdx
= 0; nPropIdx
< nPropCount
&& rStrm
.good(); ++nPropIdx
)
952 sal_Int32
nPropId(0);
953 sal_uInt32
nPropPos(0);
954 rStrm
.ReadInt32( nPropId
).ReadUInt32( nPropPos
);
955 aPropPosMap
[ nPropId
] = nPropPos
;
958 // read codepage property
959 SfxOlePropPosMap::iterator aCodePageIt
= aPropPosMap
.find( PROPID_CODEPAGE
);
960 if( (aCodePageIt
!= aPropPosMap
.end()) && SeekToPropertyPos( rStrm
, aCodePageIt
->second
) )
962 // codepage property must be of type signed int-16
963 sal_Int32
nPropType(0);
964 rStrm
.ReadInt32( nPropType
);
965 if( nPropType
== PROPTYPE_INT16
)
966 LoadObject( rStrm
, maCodePageProp
);
967 // remove property position
968 aPropPosMap
.erase( aCodePageIt
);
971 // read dictionary property
972 SfxOlePropPosMap::iterator aDictIt
= aPropPosMap
.find( PROPID_DICTIONARY
);
973 if( (aDictIt
!= aPropPosMap
.end()) && SeekToPropertyPos( rStrm
, aDictIt
->second
) )
975 // #i66214# #i66428# applications may write broken dictionary properties in wrong sections
978 // dictionary property contains number of pairs in property type field
979 sal_Int32
nNameCount(0);
980 rStrm
.ReadInt32( nNameCount
);
981 maDictProp
.SetNameCount( nNameCount
);
982 LoadObject( rStrm
, maDictProp
);
984 // always remove position of dictionary property (do not try to read it again below)
985 aPropPosMap
.erase( aDictIt
);
988 // read other properties
990 for (auto const& propPos
: aPropPosMap
)
991 if( SeekToPropertyPos( rStrm
, propPos
.second
) )
992 LoadProperty( rStrm
, propPos
.first
);
995 void SfxOleSection::ImplSave( SvStream
& rStrm
)
997 /* Always export with UTF-8 encoding. All dependent properties (bytestring
998 and dictionary) will be updated automatically. */
999 maCodePageProp
.SetTextEncoding( RTL_TEXTENCODING_UTF8
);
1001 // write section header
1002 mnStartPos
= rStrm
.Tell();
1003 sal_Int32 nPropCount
= static_cast< sal_Int32
>( maPropMap
.size() + 1 );
1004 if( maDictProp
.HasPropertyNames() )
1006 rStrm
.WriteUInt32( 0 ).WriteInt32( nPropCount
);
1008 // write placeholders for property ID/position pairs
1009 sal_uInt64 nPropPosPos
= rStrm
.Tell();
1010 rStrm
.SeekRel( static_cast< sal_sSize
>( 8 * nPropCount
) );
1012 // write dictionary property
1013 if( maDictProp
.HasPropertyNames() )
1014 SaveProperty( rStrm
, maDictProp
, nPropPosPos
);
1015 // write codepage property
1016 SaveProperty( rStrm
, maCodePageProp
, nPropPosPos
);
1017 // write other properties
1018 for (auto const& prop
: maPropMap
)
1019 SaveProperty( rStrm
, *prop
.second
, nPropPosPos
);
1021 // write section size (first field in section header)
1022 sal_uInt32 nSectSize
= static_cast< sal_uInt32
>( rStrm
.TellEnd() - 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
;
1042 case PROPTYPE_INT32
:
1043 xProp
= std::make_shared
<SfxOleInt32Property
>( nPropId
);
1045 case PROPTYPE_DOUBLE
:
1046 xProp
= std::make_shared
<SfxOleDoubleProperty
>( nPropId
);
1049 xProp
= std::make_shared
<SfxOleBoolProperty
>( nPropId
);
1051 case PROPTYPE_STRING8
:
1052 xProp
= std::make_shared
<SfxOleString8Property
>( nPropId
, maCodePageProp
);
1054 case PROPTYPE_STRING16
:
1055 xProp
= std::make_shared
<SfxOleString16Property
>( nPropId
);
1057 case PROPTYPE_FILETIME
:
1058 xProp
= std::make_shared
<SfxOleFileTimeProperty
>( nPropId
);
1061 xProp
= std::make_shared
<SfxOleDateProperty
>( nPropId
);
1064 // load property contents
1067 SetError( xProp
->Load( rStrm
) );
1068 maPropMap
[ nPropId
] = std::move(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
);
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
)
1094 rtl::Reference
<SotStorageStream
> xStrm
= pStrg
->OpenSotStream( rStrmName
, StreamMode::STD_READ
);
1095 if( xStrm
.is() && (xStrm
->GetError() == ERRCODE_NONE
) )
1097 xStrm
->SetBufferSize( STREAM_BUFFER_SIZE
);
1101 SetError( ERRCODE_IO_ACCESSDENIED
);
1104 SetError( ERRCODE_IO_ACCESSDENIED
);
1108 ErrCode
const & SfxOlePropertySet::SavePropertySet( SotStorage
* pStrg
, const OUString
& rStrmName
)
1112 rtl::Reference
<SotStorageStream
> xStrm
= pStrg
->OpenSotStream( rStrmName
, StreamMode::TRUNC
| StreamMode::STD_WRITE
);
1113 if (xStrm
.is() && xStrm
->IsWritable())
1116 SetError( ERRCODE_IO_ACCESSDENIED
);
1119 SetError( ERRCODE_IO_ACCESSDENIED
);
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
;
1137 SfxOleSection
& SfxOlePropertySet::AddSection( SfxOleSectionType eSection
)
1139 return AddSection( GetSectionGuid( eSection
) );
1142 SfxOleSection
& SfxOlePropertySet::AddSection( const SvGlobalName
& rSectionGuid
)
1144 SfxOleSectionRef xSection
= GetSection( rSectionGuid
);
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
;
1155 void SfxOlePropertySet::ImplLoad( SvStream
& rStrm
)
1157 // read property set header
1158 sal_uInt16 nByteOrder
;
1159 sal_uInt16 nVersion
;
1160 sal_uInt16 nOsMinor
;
1163 sal_Int32
nSectCount(0);
1164 rStrm
.ReadUInt16( nByteOrder
).ReadUInt16( nVersion
).ReadUInt16( nOsMinor
).ReadUInt16( nOsType
);
1166 rStrm
.ReadInt32( nSectCount
);
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
;
1176 sal_uInt32
nSectPos(0);
1177 rStrm
.ReadUInt32(nSectPos
);
1180 nSectPosPos
= rStrm
.Tell();
1182 if (!checkSeek(rStrm
, nSectPos
))
1184 LoadObject(rStrm
, AddSection(aSectGuid
));
1190 void SfxOlePropertySet::ImplSave( SvStream
& rStrm
)
1192 // write property set header
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
) );
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
;
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" );
1241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */