/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "oleprops.hxx"
#include <comphelper/types.hxx>
#include <o3tl/safeint.hxx>
#include <tools/datetime.hxx>
#include <rtl/tencinfo.h>
#include <sal/log.hxx>
#include <utility>
#define STREAM_BUFFER_SIZE 2048
// usings
using ::com::sun::star::uno::Any;
using namespace ::com::sun::star;
#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.
/// Invalid value for date and time to create invalid instance of TimeStamp.
#define TIMESTAMP_INVALID_UTILDATETIME (util::DateTime(0, 0, 0, 0, 1, 1, 1601, false))
/// Invalid value for date to create invalid instance of TimeStamp.
#define TIMESTAMP_INVALID_UTILDATE (util::Date(1, 1, 1601))
namespace {
/** Property representing a signed 32-bit integer value. */
class SfxOleInt32Property : public SfxOlePropertyBase
{
public:
explicit SfxOleInt32Property( sal_Int32 nPropId, sal_Int32 nValue = 0 );
sal_Int32 GetValue() const { return mnValue; }
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
private:
sal_Int32 mnValue;
};
/** Property representing a floating-point value. */
class SfxOleDoubleProperty : public SfxOlePropertyBase
{
public:
explicit SfxOleDoubleProperty( sal_Int32 nPropId, double fValue = 0.0 );
double GetValue() const { return mfValue; }
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
private:
double mfValue;
};
/** Property representing a boolean value. */
class SfxOleBoolProperty : public SfxOlePropertyBase
{
public:
explicit SfxOleBoolProperty( sal_Int32 nPropId, bool bValue = false );
bool GetValue() const { return mbValue; }
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
private:
bool mbValue;
};
/** Base class for properties that contain a single string value. */
class SfxOleStringPropertyBase : public SfxOlePropertyBase, public SfxOleStringHelper
{
public:
explicit SfxOleStringPropertyBase(
sal_Int32 nPropId, sal_Int32 nPropType,
const SfxOleTextEncoding& rTextEnc );
explicit SfxOleStringPropertyBase(
sal_Int32 nPropId, sal_Int32 nPropType,
const SfxOleTextEncoding& rTextEnc, OUString aValue );
explicit SfxOleStringPropertyBase(
sal_Int32 nPropId, sal_Int32 nPropType,
rtl_TextEncoding eTextEnc );
const OUString& GetValue() const { return maValue; }
void SetValue( const OUString& rValue ) { maValue = rValue; }
private:
OUString maValue;
};
/** Property representing a bytestring value. */
class SfxOleString8Property : public SfxOleStringPropertyBase
{
public:
explicit SfxOleString8Property(
sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc );
explicit SfxOleString8Property(
sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc,
const OUString& rValue );
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
};
/** Property representing a Unicode string value. */
class SfxOleString16Property : public SfxOleStringPropertyBase
{
public:
explicit SfxOleString16Property( sal_Int32 nPropId );
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
};
/** Property representing a filetime value as defined by the Windows API. */
class SfxOleFileTimeProperty : public SfxOlePropertyBase
{
public:
explicit SfxOleFileTimeProperty( sal_Int32 nPropId );
/** @param rDateTime Date and time as LOCAL time. */
explicit SfxOleFileTimeProperty( sal_Int32 nPropId, const util::DateTime& rDateTime );
/** Returns the time value as LOCAL time. */
const util::DateTime& GetValue() const { return maDateTime; }
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
private:
util::DateTime maDateTime;
};
/** Property representing a filetime value as defined by the Windows API. */
class SfxOleDateProperty : public SfxOlePropertyBase
{
public:
explicit SfxOleDateProperty( sal_Int32 nPropId );
/** Returns the date value as LOCAL time. */
const util::Date& GetValue() const { return maDate; }
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
private:
util::Date maDate;
};
/** Property representing a thumbnail picture.
Currently, only saving this property is implemented.
*/
class SfxOleThumbnailProperty : public SfxOlePropertyBase
{
public:
explicit SfxOleThumbnailProperty( sal_Int32 nPropId,
const uno::Sequence<sal_Int8> & i_rData);
bool IsValid() const { return mData.hasElements(); }
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
private:
uno::Sequence<sal_Int8> mData;
};
/** Property representing a BLOB (which presumably stands for binary large
object).
Currently, only saving this property is implemented.
*/
class SfxOleBlobProperty : public SfxOlePropertyBase
{
public:
explicit SfxOleBlobProperty( sal_Int32 nPropId,
const uno::Sequence<sal_Int8> & i_rData);
bool IsValid() const { return mData.hasElements(); }
private:
virtual void ImplLoad( SvStream& rStrm ) override;
virtual void ImplSave( SvStream& rStrm ) override;
private:
uno::Sequence<sal_Int8> mData;
};
}
sal_uInt16 SfxOleTextEncoding::GetCodePage() const
{
sal_uInt16 nCodePage = IsUnicode() ? CODEPAGE_UNICODE :
static_cast< sal_uInt16 >( rtl_getWindowsCodePageFromTextEncoding( *mxTextEnc ) );
return (nCodePage == CODEPAGE_UNKNOWN) ? CODEPAGE_UTF8 : nCodePage;
}
void SfxOleTextEncoding::SetCodePage( sal_uInt16 nCodePage )
{
if( nCodePage == CODEPAGE_UNICODE )
SetUnicode();
else
{
rtl_TextEncoding eTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
if( eTextEnc != RTL_TEXTENCODING_DONTKNOW )
*mxTextEnc = eTextEnc;
}
}
OUString SfxOleStringHelper::LoadString8( SvStream& rStrm ) const
{
return IsUnicode() ? ImplLoadString16( rStrm ) : ImplLoadString8( rStrm );
}
void SfxOleStringHelper::SaveString8( SvStream& rStrm, std::u16string_view rValue ) const
{
if( IsUnicode() )
ImplSaveString16( rStrm, rValue );
else
ImplSaveString8( rStrm, rValue );
}
OUString SfxOleStringHelper::LoadString16( SvStream& rStrm )
{
return ImplLoadString16( rStrm );
}
void SfxOleStringHelper::SaveString16( SvStream& rStrm, std::u16string_view rValue )
{
ImplSaveString16( rStrm, rValue );
}
OUString SfxOleStringHelper::ImplLoadString8( SvStream& rStrm ) const
{
// read size field (signed 32-bit)
sal_Int32 nSize(0);
rStrm.ReadInt32( nSize );
// size field includes trailing NUL character
SAL_WARN_IF(nSize < 1 || nSize > 0xFFFF, "sfx.doc", "SfxOleStringHelper::ImplLoadString8 - invalid string of len " << nSize);
if (nSize < 1 || nSize > 0xFFFF)
return OUString();
// load character buffer
OString sValue(read_uInt8s_ToOString(rStrm, nSize - 1));
if (rStrm.good() && rStrm.remainingSize())
rStrm.SeekRel(1); // skip null-byte at end
return OStringToOUString(sValue, GetTextEncoding());
}
OUString SfxOleStringHelper::ImplLoadString16( SvStream& rStrm )
{
// read size field (signed 32-bit), may be buffer size or character count
sal_Int32 nSize(0);
rStrm.ReadInt32(nSize);
SAL_WARN_IF(nSize < 1 || nSize > 0xFFFF, "sfx.doc", "SfxOleStringHelper::ImplLoadString16 - invalid string of len " << nSize);
// size field includes trailing NUL character
if (nSize < 1 || nSize > 0xFFFF)
return OUString();
// load character buffer
OUString aValue = read_uInt16s_ToOUString(rStrm, nSize - 1);
sal_Int32 nSkip(2); // skip null-byte at end
// stream is always padded to 32-bit boundary, skip 2 bytes on odd character count
if ((nSize & 1) == 1)
nSkip += 2;
nSkip = std::min<sal_uInt32>(nSkip, rStrm.remainingSize());
if (rStrm.good() && nSkip)
rStrm.SeekRel(nSkip);
return aValue;
}
void SfxOleStringHelper::ImplSaveString8( SvStream& rStrm, std::u16string_view rValue ) const
{
// encode to byte string
OString aEncoded(OUStringToOString(rValue, GetTextEncoding()));
// write size field (including trailing NUL character)
sal_Int32 nSize = aEncoded.getLength() + 1;
rStrm.WriteInt32( nSize );
// write character array with trailing NUL character
rStrm.WriteBytes(aEncoded.getStr(), aEncoded.getLength());
rStrm.WriteUChar( 0 );
}
void SfxOleStringHelper::ImplSaveString16( SvStream& rStrm, std::u16string_view rValue )
{
// write size field (including trailing NUL character)
sal_Int32 nSize = static_cast< sal_Int32 >( rValue.size() + 1 );
rStrm.WriteInt32( nSize );
// write character array with trailing NUL character
for( size_t nIdx = 0; nIdx < rValue.size(); ++nIdx )
rStrm.WriteUInt16( rValue[ nIdx ] );
rStrm.WriteUInt16( 0 );
// stream is always padded to 32-bit boundary, add 2 bytes on odd character count
if( (nSize & 1) == 1 )
rStrm.WriteUInt16( 0 );
}
SfxOleObjectBase::~SfxOleObjectBase()
{
}
ErrCode const & SfxOleObjectBase::Load( SvStream& rStrm )
{
mnErrCode = ERRCODE_NONE;
ImplLoad( rStrm );
SetError( rStrm.GetErrorCode() );
return GetError();
}
ErrCode const & SfxOleObjectBase::Save( SvStream& rStrm )
{
mnErrCode = ERRCODE_NONE;
ImplSave( rStrm );
SetError( rStrm.GetErrorCode() );
return GetError();
}
void SfxOleObjectBase::LoadObject( SvStream& rStrm, SfxOleObjectBase& rObj )
{
SetError( rObj.Load( rStrm ) );
}
void SfxOleObjectBase::SaveObject( SvStream& rStrm, SfxOleObjectBase& rObj )
{
SetError( rObj.Save( rStrm ) );
}
SfxOleCodePageProperty::SfxOleCodePageProperty() :
SfxOlePropertyBase( PROPID_CODEPAGE, PROPTYPE_INT16 )
{
}
void SfxOleCodePageProperty::ImplLoad(SvStream& rStrm)
{
// property type is signed int16, but we use always unsigned int16 for codepages
sal_uInt16 nCodePage(0);
rStrm.ReadUInt16(nCodePage);
SetCodePage(nCodePage);
}
void SfxOleCodePageProperty::ImplSave( SvStream& rStrm )
{
// property type is signed int16, but we use always unsigned int16 for codepages
rStrm.WriteUInt16( GetCodePage() );
}
SfxOleInt32Property::SfxOleInt32Property( sal_Int32 nPropId, sal_Int32 nValue ) :
SfxOlePropertyBase( nPropId, PROPTYPE_INT32 ),
mnValue( nValue )
{
}
void SfxOleInt32Property::ImplLoad( SvStream& rStrm )
{
rStrm.ReadInt32( mnValue );
}
void SfxOleInt32Property::ImplSave( SvStream& rStrm )
{
rStrm.WriteInt32( mnValue );
}
SfxOleDoubleProperty::SfxOleDoubleProperty( sal_Int32 nPropId, double fValue ) :
SfxOlePropertyBase( nPropId, PROPTYPE_DOUBLE ),
mfValue( fValue )
{
}
void SfxOleDoubleProperty::ImplLoad( SvStream& rStrm )
{
rStrm.ReadDouble( mfValue );
}
void SfxOleDoubleProperty::ImplSave( SvStream& rStrm )
{
rStrm.WriteDouble( mfValue );
}
SfxOleBoolProperty::SfxOleBoolProperty( sal_Int32 nPropId, bool bValue ) :
SfxOlePropertyBase( nPropId, PROPTYPE_BOOL ),
mbValue( bValue )
{
}
void SfxOleBoolProperty::ImplLoad( SvStream& rStrm )
{
sal_Int16 nValue(0);
rStrm.ReadInt16( nValue );
mbValue = nValue != 0;
}
void SfxOleBoolProperty::ImplSave( SvStream& rStrm )
{
rStrm.WriteInt16( mbValue ? -1 : 0 );
}
SfxOleStringPropertyBase::SfxOleStringPropertyBase(
sal_Int32 nPropId, sal_Int32 nPropType, const SfxOleTextEncoding& rTextEnc ) :
SfxOlePropertyBase( nPropId, nPropType ),
SfxOleStringHelper( rTextEnc )
{
}
SfxOleStringPropertyBase::SfxOleStringPropertyBase(
sal_Int32 nPropId, sal_Int32 nPropType, const SfxOleTextEncoding& rTextEnc, OUString aValue ) :
SfxOlePropertyBase( nPropId, nPropType ),
SfxOleStringHelper( rTextEnc ),
maValue(std::move( aValue ))
{
}
SfxOleStringPropertyBase::SfxOleStringPropertyBase(
sal_Int32 nPropId, sal_Int32 nPropType, rtl_TextEncoding eTextEnc ) :
SfxOlePropertyBase( nPropId, nPropType ),
SfxOleStringHelper( eTextEnc )
{
}
SfxOleString8Property::SfxOleString8Property(
sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc ) :
SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING8, rTextEnc )
{
}
SfxOleString8Property::SfxOleString8Property(
sal_Int32 nPropId, const SfxOleTextEncoding& rTextEnc, const OUString& rValue ) :
SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING8, rTextEnc, rValue )
{
}
void SfxOleString8Property::ImplLoad( SvStream& rStrm )
{
SetValue( LoadString8( rStrm ) );
}
void SfxOleString8Property::ImplSave( SvStream& rStrm )
{
SaveString8( rStrm, GetValue() );
}
SfxOleString16Property::SfxOleString16Property( sal_Int32 nPropId ) :
SfxOleStringPropertyBase( nPropId, PROPTYPE_STRING16, RTL_TEXTENCODING_UCS2 )
{
}
void SfxOleString16Property::ImplLoad( SvStream& rStrm )
{
SetValue( LoadString16( rStrm ) );
}
void SfxOleString16Property::ImplSave( SvStream& rStrm )
{
SaveString16( rStrm, GetValue() );
}
SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId ) :
SfxOlePropertyBase( nPropId, PROPTYPE_FILETIME )
{
}
SfxOleFileTimeProperty::SfxOleFileTimeProperty( sal_Int32 nPropId, const util::DateTime& rDateTime ) :
SfxOlePropertyBase( nPropId, PROPTYPE_FILETIME ),
maDateTime( rDateTime )
{
}
void SfxOleFileTimeProperty::ImplLoad( SvStream& rStrm )
{
sal_uInt32 nLower(0), nUpper(0);
rStrm.ReadUInt32( nLower ).ReadUInt32( nUpper );
::DateTime aDateTime = DateTime::CreateFromWin32FileDateTime( nLower, nUpper );
// note: editing duration is stored as offset to TIMESTAMP_INVALID_DATETIME
// of course we should not convert the time zone of a duration!
// heuristic to detect editing durations (which we assume to be < 1 year):
// check only the year, not the entire date
if ( aDateTime.GetYear() != TIMESTAMP_INVALID_DATETIME.GetYear() )
aDateTime.ConvertToLocalTime();
maDateTime.Year = aDateTime.GetYear();
maDateTime.Month = aDateTime.GetMonth();
maDateTime.Day = aDateTime.GetDay();
maDateTime.Hours = aDateTime.GetHour();
maDateTime.Minutes = aDateTime.GetMin();
maDateTime.Seconds = aDateTime.GetSec();
maDateTime.NanoSeconds = aDateTime.GetNanoSec();
maDateTime.IsUTC = false;
}
void SfxOleFileTimeProperty::ImplSave( SvStream& rStrm )
{
DateTime aDateTimeUtc(
Date(
maDateTime.Day,
maDateTime.Month,
static_cast< sal_uInt16 >( maDateTime.Year ) ),
tools::Time(
maDateTime.Hours,
maDateTime.Minutes,
maDateTime.Seconds,
maDateTime.NanoSeconds ) );
// invalid time stamp is not converted to UTC
// heuristic to detect editing durations (which we assume to be < 1 year):
// check only the year, not the entire date
if( aDateTimeUtc.IsValidAndGregorian()
&& aDateTimeUtc.GetYear() != TIMESTAMP_INVALID_DATETIME.GetYear() ) {
aDateTimeUtc.ConvertToUTC();
}
sal_uInt32 nLower, nUpper;
aDateTimeUtc.GetWin32FileDateTime( nLower, nUpper );
rStrm.WriteUInt32( nLower ).WriteUInt32( nUpper );
}
SfxOleDateProperty::SfxOleDateProperty( sal_Int32 nPropId ) :
SfxOlePropertyBase( nPropId, PROPTYPE_DATE )
{
}
void SfxOleDateProperty::ImplLoad( SvStream& rStrm )
{
double fValue(0.0);
rStrm.ReadDouble( fValue );
//stored as number of days (not seconds) since December 31, 1899
sal_Int32 nDays = fValue;
sal_Int32 nStartDays = ::Date::DateToDays(31, 12, 1899);
if (o3tl::checked_add(nStartDays, nDays, nStartDays))
SAL_WARN("sfx.doc", "SfxOleDateProperty::ImplLoad bad date, ignored");
else
{
::Date aDate(31, 12, 1899);
aDate.AddDays(nDays);
maDate.Day = aDate.GetDay();
maDate.Month = aDate.GetMonth();
maDate.Year = aDate.GetYear();
}
}
void SfxOleDateProperty::ImplSave( SvStream& rStrm )
{
sal_Int32 nDays = ::Date::DateToDays(maDate.Day, maDate.Month, maDate.Year);
//number of days (not seconds) since December 31, 1899
sal_Int32 nStartDays = ::Date::DateToDays(31, 12, 1899);
double fValue = nDays-nStartDays;
rStrm.WriteDouble( fValue );
}
SfxOleThumbnailProperty::SfxOleThumbnailProperty(
sal_Int32 nPropId, const uno::Sequence<sal_Int8> & i_rData) :
SfxOlePropertyBase( nPropId, PROPTYPE_CLIPFMT ),
mData(i_rData)
{
}
void SfxOleThumbnailProperty::ImplLoad( SvStream& )
{
SAL_WARN( "sfx.doc", "SfxOleThumbnailProperty::ImplLoad - not implemented" );
SetError( SVSTREAM_INVALID_ACCESS );
}
void SfxOleThumbnailProperty::ImplSave( SvStream& rStrm )
{
/* Type Contents
-----------------------------------------------------------------------
int32 size of following data
int32 clipboard format tag (see below)
byte[] clipboard data (see below)
Clipboard format tag:
-1 = Windows clipboard format
-2 = Macintosh clipboard format
-3 = GUID that contains a format identifier (FMTID)
>0 = custom clipboard format name plus data (see msdn site below)
0 = no data
References:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/propvariant.asp
http://jakarta.apache.org/poi/hpsf/thumbnails.html
http://linux.com.hk/docs/poi/org/apache/poi/hpsf/Thumbnail.html
https://web.archive.org/web/20060126202945/http://sparks.discreet.com/knowledgebase/public/solutions/ExtractThumbnailImg.htm
*/
if( IsValid() )
{
// clipboard size: clip_format_tag + data_format_tag + bitmap_len
sal_Int32 nClipSize = static_cast< sal_Int32 >( 4 + 4 + mData.getLength() );
rStrm.WriteInt32( nClipSize ).WriteInt32( CLIPFMT_WIN ).WriteInt32( CLIPDATAFMT_DIB );
rStrm.WriteBytes(mData.getConstArray(), mData.getLength());
}
else
{
SAL_WARN( "sfx.doc", "SfxOleThumbnailProperty::ImplSave - invalid thumbnail property" );
SetError( SVSTREAM_INVALID_ACCESS );
}
}
SfxOleBlobProperty::SfxOleBlobProperty( sal_Int32 nPropId,
const uno::Sequence<sal_Int8> & i_rData) :
SfxOlePropertyBase( nPropId, PROPTYPE_BLOB ),
mData(i_rData)
{
}
void SfxOleBlobProperty::ImplLoad( SvStream& )
{
SAL_WARN( "sfx.doc", "SfxOleBlobProperty::ImplLoad - not implemented" );
SetError( SVSTREAM_INVALID_ACCESS );
}
void SfxOleBlobProperty::ImplSave( SvStream& rStrm )
{
if (IsValid()) {
rStrm.WriteBytes(mData.getConstArray(), mData.getLength());
} else {
SAL_WARN( "sfx.doc", "SfxOleBlobProperty::ImplSave - invalid BLOB property" );
SetError( SVSTREAM_INVALID_ACCESS );
}
}
SfxOleDictionaryProperty::SfxOleDictionaryProperty( const SfxOleTextEncoding& rTextEnc ) :
SfxOlePropertyBase( PROPID_DICTIONARY, 0 ),
SfxOleStringHelper( rTextEnc )
{
}
OUString SfxOleDictionaryProperty::GetPropertyName( sal_Int32 nPropId ) const
{
SfxOlePropNameMap::const_iterator aIt = maPropNameMap.find( nPropId );
return (aIt == maPropNameMap.end()) ? OUString() : aIt->second;
}
void SfxOleDictionaryProperty::SetPropertyName( sal_Int32 nPropId, const OUString& rPropName )
{
maPropNameMap[ nPropId ] = rPropName;
// dictionary property contains number of pairs in property type field
SetPropType( static_cast< sal_Int32 >( maPropNameMap.size() ) );
}
void SfxOleDictionaryProperty::ImplLoad( SvStream& rStrm )
{
// dictionary property contains number of pairs in property type field
sal_Int32 nNameCount = GetPropType();
// read property ID/name pairs
maPropNameMap.clear();
for (sal_Int32 nIdx = 0; nIdx < nNameCount && rStrm.good() && rStrm.remainingSize() >= 4; ++nIdx)
{
sal_Int32 nPropId(0);
rStrm.ReadInt32(nPropId);
// name always stored as byte string
maPropNameMap[nPropId] = LoadString8(rStrm);
}
}
void SfxOleDictionaryProperty::ImplSave( SvStream& rStrm )
{
// write property ID/name pairs
for (auto const& propName : maPropNameMap)
{
rStrm.WriteInt32( propName.first );
// name always stored as byte string
SaveString8( rStrm, propName.second );
}
}
SfxOleSection::SfxOleSection( bool bSupportsDict ) :
maDictProp( maCodePageProp ),
mnStartPos( 0 ),
mbSupportsDict( bSupportsDict )
{
}
SfxOlePropertyRef SfxOleSection::GetProperty( sal_Int32 nPropId ) const
{
SfxOlePropertyRef xProp;
SfxOlePropMap::const_iterator aIt = maPropMap.find( nPropId );
if( aIt != maPropMap.end() )
xProp = aIt->second;
return xProp;
}
bool SfxOleSection::GetInt32Value( sal_Int32& rnValue, sal_Int32 nPropId ) const
{
SfxOlePropertyRef xProp = GetProperty( nPropId );
const SfxOleInt32Property* pProp =
dynamic_cast< const SfxOleInt32Property* >( xProp.get() );
if( pProp )
rnValue = pProp->GetValue();
return pProp != nullptr;
}
bool SfxOleSection::GetDoubleValue( double& rfValue, sal_Int32 nPropId ) const
{
SfxOlePropertyRef xProp = GetProperty( nPropId );
const SfxOleDoubleProperty* pProp =
dynamic_cast< const SfxOleDoubleProperty* >( xProp.get() );
if( pProp )
rfValue = pProp->GetValue();
return pProp != nullptr;
}
bool SfxOleSection::GetBoolValue( bool& rbValue, sal_Int32 nPropId ) const
{
SfxOlePropertyRef xProp = GetProperty( nPropId );
const SfxOleBoolProperty* pProp =
dynamic_cast< const SfxOleBoolProperty* >( xProp.get() );
if( pProp )
rbValue = pProp->GetValue();
return pProp != nullptr;
}
bool SfxOleSection::GetStringValue( OUString& rValue, sal_Int32 nPropId ) const
{
SfxOlePropertyRef xProp = GetProperty( nPropId );
const SfxOleStringPropertyBase* pProp =
dynamic_cast< const SfxOleStringPropertyBase* >( xProp.get() );
if( pProp )
rValue = pProp->GetValue();
return pProp != nullptr;
}
bool SfxOleSection::GetFileTimeValue( util::DateTime& rValue, sal_Int32 nPropId ) const
{
SfxOlePropertyRef xProp = GetProperty( nPropId );
const SfxOleFileTimeProperty* pProp =
dynamic_cast< const SfxOleFileTimeProperty* >( xProp.get() );
if( pProp )
{
if ( pProp->GetValue() == TIMESTAMP_INVALID_UTILDATETIME )
rValue = util::DateTime();
else
rValue = pProp->GetValue();
}
return pProp != nullptr;
}
bool SfxOleSection::GetDateValue( util::Date& rValue, sal_Int32 nPropId ) const
{
SfxOlePropertyRef xProp = GetProperty( nPropId );
const SfxOleDateProperty* pProp =
dynamic_cast< const SfxOleDateProperty* >( xProp.get() );
if( pProp )
{
if ( pProp->GetValue() == TIMESTAMP_INVALID_UTILDATE )
rValue = util::Date();
else
rValue = pProp->GetValue();
}
return pProp != nullptr;
}
void SfxOleSection::SetProperty( const SfxOlePropertyRef& xProp )
{
if( xProp )
maPropMap[ xProp->GetPropId() ] = xProp;
}
void SfxOleSection::SetInt32Value( sal_Int32 nPropId, sal_Int32 nValue )
{
SetProperty( std::make_shared<SfxOleInt32Property>( nPropId, nValue ) );
}
void SfxOleSection::SetDoubleValue( sal_Int32 nPropId, double fValue )
{
SetProperty( std::make_shared<SfxOleDoubleProperty>( nPropId, fValue ) );
}
void SfxOleSection::SetBoolValue( sal_Int32 nPropId, bool bValue )
{
SetProperty( std::make_shared<SfxOleBoolProperty>( nPropId, bValue ) );
}
bool SfxOleSection::SetStringValue( sal_Int32 nPropId, const OUString& rValue )
{
bool bInserted = !rValue.isEmpty();
if( bInserted )
SetProperty( std::make_shared<SfxOleString8Property>( nPropId, maCodePageProp, rValue ) );
return bInserted;
}
void SfxOleSection::SetFileTimeValue( sal_Int32 nPropId, const util::DateTime& rValue )
{
if ( rValue.Year == 0 || rValue.Month == 0 || rValue.Day == 0 )
SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, TIMESTAMP_INVALID_UTILDATETIME ) );
else
SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, rValue ) );
}
void SfxOleSection::SetDateValue( sal_Int32 nPropId, const util::Date& rValue )
{
//Annoyingly MS2010 considers VT_DATE apparently as an invalid possibility, so here we use VT_FILETIME
//instead :-(
if ( rValue.Year == 0 || rValue.Month == 0 || rValue.Day == 0 )
SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, TIMESTAMP_INVALID_UTILDATETIME ) );
else
{
const util::DateTime aValue(0, 0, 0, 0, rValue.Day, rValue.Month,
rValue.Year, false );
SetProperty( std::make_shared<SfxOleFileTimeProperty>( nPropId, aValue ) );
}
}
void SfxOleSection::SetThumbnailValue( sal_Int32 nPropId,
const uno::Sequence<sal_Int8> & i_rData)
{
auto pThumbnail = std::make_shared<SfxOleThumbnailProperty>( nPropId, i_rData );
if( pThumbnail->IsValid() )
SetProperty( pThumbnail );
}
void SfxOleSection::SetBlobValue( sal_Int32 nPropId,
const uno::Sequence<sal_Int8> & i_rData)
{
auto pBlob = std::make_shared<SfxOleBlobProperty>( nPropId, i_rData );
if( pBlob->IsValid() )
SetProperty( pBlob );
}
Any SfxOleSection::GetAnyValue( sal_Int32 nPropId ) const
{
Any aValue;
sal_Int32 nInt32 = 0;
double fDouble = 0.0;
bool bBool = false;
OUString aString;
css::util::DateTime aApiDateTime;
css::util::Date aApiDate;
if( GetInt32Value( nInt32, nPropId ) )
aValue <<= nInt32;
else if( GetDoubleValue( fDouble, nPropId ) )
aValue <<= fDouble;
else if( GetBoolValue( bBool, nPropId ) )
aValue <<= bBool;
else if( GetStringValue( aString, nPropId ) )
aValue <<= aString;
else if( GetFileTimeValue( aApiDateTime, nPropId ) )
{
aValue <<= aApiDateTime;
}
else if( GetDateValue( aApiDate, nPropId ) )
{
aValue <<= aApiDate;
}
return aValue;
}
bool SfxOleSection::SetAnyValue( sal_Int32 nPropId, const Any& rValue )
{
bool bInserted = true;
sal_Int32 nInt32 = 0;
double fDouble = 0.0;
OUString aString;
css::util::DateTime aApiDateTime;
css::util::Date aApiDate;
if( rValue.getValueType() == cppu::UnoType<bool>::get() )
SetBoolValue( nPropId, ::comphelper::getBOOL( rValue ) );
else if( rValue >>= nInt32 )
SetInt32Value( nPropId, nInt32 );
else if( rValue >>= fDouble )
SetDoubleValue( nPropId, fDouble );
else if( rValue >>= aString )
bInserted = SetStringValue( nPropId, aString );
else if( rValue >>= aApiDateTime )
SetFileTimeValue( nPropId, aApiDateTime );
else if( rValue >>= aApiDate )
SetDateValue( nPropId, aApiDate );
else
bInserted = false;
return bInserted;
}
OUString SfxOleSection::GetPropertyName( sal_Int32 nPropId ) const
{
return maDictProp.GetPropertyName( nPropId );
}
void SfxOleSection::SetPropertyName( sal_Int32 nPropId, const OUString& rPropName )
{
maDictProp.SetPropertyName( nPropId, rPropName );
}
void SfxOleSection::GetPropertyIds( ::std::vector< sal_Int32 >& rPropIds ) const
{
rPropIds.clear();
for (auto const& prop : maPropMap)
rPropIds.push_back(prop.first);
}
sal_Int32 SfxOleSection::GetFreePropertyId() const
{
return maPropMap.empty() ? PROPID_FIRSTCUSTOM : (maPropMap.rbegin()->first + 1);
}
void SfxOleSection::ImplLoad( SvStream& rStrm )
{
// read section header
mnStartPos = rStrm.Tell();
sal_uInt32 nSize(0);
sal_Int32 nPropCount(0);
rStrm.ReadUInt32( nSize ).ReadInt32( nPropCount );
// read property ID/position pairs
typedef ::std::map< sal_Int32, sal_uInt32 > SfxOlePropPosMap;
SfxOlePropPosMap aPropPosMap;
for (sal_Int32 nPropIdx = 0; nPropIdx < nPropCount && rStrm.good(); ++nPropIdx)
{
sal_Int32 nPropId(0);
sal_uInt32 nPropPos(0);
rStrm.ReadInt32( nPropId ).ReadUInt32( nPropPos );
aPropPosMap[ nPropId ] = nPropPos;
}
// read codepage property
SfxOlePropPosMap::iterator aCodePageIt = aPropPosMap.find( PROPID_CODEPAGE );
if( (aCodePageIt != aPropPosMap.end()) && SeekToPropertyPos( rStrm, aCodePageIt->second ) )
{
// codepage property must be of type signed int-16
sal_Int32 nPropType(0);
rStrm.ReadInt32( nPropType );
if( nPropType == PROPTYPE_INT16 )
LoadObject( rStrm, maCodePageProp );
// remove property position
aPropPosMap.erase( aCodePageIt );
}
// read dictionary property
SfxOlePropPosMap::iterator aDictIt = aPropPosMap.find( PROPID_DICTIONARY );
if( (aDictIt != aPropPosMap.end()) && SeekToPropertyPos( rStrm, aDictIt->second ) )
{
// #i66214# #i66428# applications may write broken dictionary properties in wrong sections
if( mbSupportsDict )
{
// dictionary property contains number of pairs in property type field
sal_Int32 nNameCount(0);
rStrm.ReadInt32( nNameCount );
maDictProp.SetNameCount( nNameCount );
LoadObject( rStrm, maDictProp );
}
// always remove position of dictionary property (do not try to read it again below)
aPropPosMap.erase( aDictIt );
}
// read other properties
maPropMap.clear();
for (auto const& propPos : aPropPosMap)
if( SeekToPropertyPos( rStrm, propPos.second ) )
LoadProperty( rStrm, propPos.first );
}
void SfxOleSection::ImplSave( SvStream& rStrm )
{
/* Always export with UTF-8 encoding. All dependent properties (bytestring
and dictionary) will be updated automatically. */
maCodePageProp.SetTextEncoding( RTL_TEXTENCODING_UTF8 );
// write section header
mnStartPos = rStrm.Tell();
sal_Int32 nPropCount = static_cast< sal_Int32 >( maPropMap.size() + 1 );
if( maDictProp.HasPropertyNames() )
++nPropCount;
rStrm.WriteUInt32( 0 ).WriteInt32( nPropCount );
// write placeholders for property ID/position pairs
sal_uInt64 nPropPosPos = rStrm.Tell();
rStrm.SeekRel( static_cast< sal_sSize >( 8 * nPropCount ) );
// write dictionary property
if( maDictProp.HasPropertyNames() )
SaveProperty( rStrm, maDictProp, nPropPosPos );
// write codepage property
SaveProperty( rStrm, maCodePageProp, nPropPosPos );
// write other properties
for (auto const& prop : maPropMap)
SaveProperty( rStrm, *prop.second, nPropPosPos );
// write section size (first field in section header)
sal_uInt32 nSectSize = static_cast< sal_uInt32 >( rStrm.TellEnd() - mnStartPos );
rStrm.Seek( mnStartPos );
rStrm.WriteUInt32( nSectSize );
}
bool SfxOleSection::SeekToPropertyPos( SvStream& rStrm, sal_uInt32 nPropPos ) const
{
return checkSeek(rStrm, static_cast<std::size_t>(mnStartPos + nPropPos)) &&
rStrm.GetErrorCode() == ERRCODE_NONE;
}
void SfxOleSection::LoadProperty( SvStream& rStrm, sal_Int32 nPropId )
{
// property data type
sal_Int32 nPropType(0);
rStrm.ReadInt32( nPropType );
// create empty property object
SfxOlePropertyRef xProp;
switch( nPropType )
{
case PROPTYPE_INT32:
xProp = std::make_shared<SfxOleInt32Property>( nPropId );
break;
case PROPTYPE_DOUBLE:
xProp = std::make_shared<SfxOleDoubleProperty>( nPropId );
break;
case PROPTYPE_BOOL:
xProp = std::make_shared<SfxOleBoolProperty>( nPropId );
break;
case PROPTYPE_STRING8:
xProp = std::make_shared<SfxOleString8Property>( nPropId, maCodePageProp );
break;
case PROPTYPE_STRING16:
xProp = std::make_shared<SfxOleString16Property>( nPropId );
break;
case PROPTYPE_FILETIME:
xProp = std::make_shared<SfxOleFileTimeProperty>( nPropId );
break;
case PROPTYPE_DATE:
xProp = std::make_shared<SfxOleDateProperty>( nPropId );
break;
}
// load property contents
if( xProp )
{
SetError( xProp->Load( rStrm ) );
maPropMap[ nPropId ] = std::move(xProp);
}
}
void SfxOleSection::SaveProperty( SvStream& rStrm, SfxOlePropertyBase& rProp, sal_uInt64 & rnPropPosPos )
{
rStrm.Seek( STREAM_SEEK_TO_END );
sal_uInt32 nPropPos = static_cast< sal_uInt32 >( rStrm.Tell() - mnStartPos );
// property data type
rStrm.WriteInt32( rProp.GetPropType() );
// write property contents
SaveObject( rStrm, rProp );
// align to 32-bit
while( (rStrm.Tell() & 3) != 0 )
rStrm.WriteUChar( 0 );
// write property ID/position pair
rStrm.Seek( rnPropPosPos );
rStrm.WriteInt32( rProp.GetPropId() ).WriteUInt32( nPropPos );
rnPropPosPos = rStrm.Tell();
}
ErrCode const & SfxOlePropertySet::LoadPropertySet( SotStorage* pStrg, const OUString& rStrmName )
{
if( pStrg )
{
rtl::Reference<SotStorageStream> xStrm = pStrg->OpenSotStream( rStrmName, StreamMode::STD_READ );
if( xStrm.is() && (xStrm->GetError() == ERRCODE_NONE) )
{
xStrm->SetBufferSize( STREAM_BUFFER_SIZE );
Load( *xStrm );
}
else
SetError( ERRCODE_IO_ACCESSDENIED );
}
else
SetError( ERRCODE_IO_ACCESSDENIED );
return GetError();
}
ErrCode const & SfxOlePropertySet::SavePropertySet( SotStorage* pStrg, const OUString& rStrmName )
{
if( pStrg )
{
rtl::Reference<SotStorageStream> xStrm = pStrg->OpenSotStream( rStrmName, StreamMode::TRUNC | StreamMode::STD_WRITE );
if (xStrm.is() && xStrm->IsWritable())
Save( *xStrm );
else
SetError( ERRCODE_IO_ACCESSDENIED );
}
else
SetError( ERRCODE_IO_ACCESSDENIED );
return GetError();
}
SfxOleSectionRef SfxOlePropertySet::GetSection( SfxOleSectionType eSection ) const
{
return GetSection( GetSectionGuid( eSection ) );
}
SfxOleSectionRef SfxOlePropertySet::GetSection( const SvGlobalName& rSectionGuid ) const
{
SfxOleSectionRef xSection;
SfxOleSectionMap::const_iterator aIt = maSectionMap.find( rSectionGuid );
if( aIt != maSectionMap.end() )
xSection = aIt->second;
return xSection;
}
SfxOleSection& SfxOlePropertySet::AddSection( SfxOleSectionType eSection )
{
return AddSection( GetSectionGuid( eSection ) );
}
SfxOleSection& SfxOlePropertySet::AddSection( const SvGlobalName& rSectionGuid )
{
SfxOleSectionRef xSection = GetSection( rSectionGuid );
if( !xSection )
{
// #i66214# #i66428# applications may write broken dictionary properties in wrong sections
bool bSupportsDict = rSectionGuid == GetSectionGuid( SECTION_CUSTOM );
xSection = std::make_shared<SfxOleSection>( bSupportsDict );
maSectionMap[ rSectionGuid ] = xSection;
}
return *xSection;
}
void SfxOlePropertySet::ImplLoad( SvStream& rStrm )
{
// read property set header
sal_uInt16 nByteOrder;
sal_uInt16 nVersion;
sal_uInt16 nOsMinor;
sal_uInt16 nOsType;
SvGlobalName aGuid;
sal_Int32 nSectCount(0);
rStrm.ReadUInt16( nByteOrder ).ReadUInt16( nVersion ).ReadUInt16( nOsMinor ).ReadUInt16( nOsType );
rStrm >> aGuid;
rStrm.ReadInt32( nSectCount );
// read sections
sal_uInt64 nSectPosPos = rStrm.Tell();
for (sal_Int32 nSectIdx = 0; nSectIdx < nSectCount; ++nSectIdx)
{
// read section guid/position pair
rStrm.Seek(nSectPosPos);
SvGlobalName aSectGuid;
rStrm >> aSectGuid;
sal_uInt32 nSectPos(0);
rStrm.ReadUInt32(nSectPos);
if (!rStrm.good())
break;
nSectPosPos = rStrm.Tell();
// read section
if (!checkSeek(rStrm, nSectPos))
break;
LoadObject(rStrm, AddSection(aSectGuid));
if (!rStrm.good())
break;
}
}
void SfxOlePropertySet::ImplSave( SvStream& rStrm )
{
// write property set header
SvGlobalName aGuid;
sal_Int32 nSectCount = static_cast< sal_Int32 >( maSectionMap.size() );
rStrm .WriteUInt16( 0xFFFE ) // byte order
.WriteUInt16( 0 ) // version
.WriteUInt16( 1 ) // OS minor version
.WriteUInt16( 2 ); // OS type always windows for text encoding
WriteSvGlobalName( rStrm, aGuid ); // unused guid
rStrm .WriteInt32( nSectCount ); // number of sections
// write placeholders for section guid/position pairs
sal_uInt64 nSectPosPos = rStrm.Tell();
rStrm.SeekRel( static_cast< sal_sSize >( 20 * nSectCount ) );
// write sections
for (auto const& section : maSectionMap)
{
SfxOleSection& rSection = *section.second;
rStrm.Seek( STREAM_SEEK_TO_END );
sal_uInt32 nSectPos = static_cast< sal_uInt32 >( rStrm.Tell() );
// write the section
SaveObject( rStrm, rSection );
// write section guid/position pair
rStrm.Seek( nSectPosPos );
WriteSvGlobalName( rStrm, section.first );
rStrm.WriteUInt32( nSectPos );
nSectPosPos = rStrm.Tell();
}
}
const SvGlobalName& SfxOlePropertySet::GetSectionGuid( SfxOleSectionType eSection )
{
static const SvGlobalName saGlobalGuid( 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 );
static const SvGlobalName saBuiltInGuid( 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE );
static const SvGlobalName saCustomGuid( 0xD5CDD505, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE );
static const SvGlobalName saEmptyGuid;
switch( eSection )
{
case SECTION_GLOBAL: return saGlobalGuid;
case SECTION_BUILTIN: return saBuiltInGuid;
case SECTION_CUSTOM: return saCustomGuid;
default: SAL_WARN( "sfx.doc", "SfxOlePropertySet::GetSectionGuid - unknown section type" );
}
return saEmptyGuid;
}
//} // namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'Load' is required to be utilized.
↑ V530 The return value of function 'Save' is required to be utilized.
↑ V1028 Possible overflow. Consider casting operands, not the result.
↑ V1028 Possible overflow. Consider casting operands, not the result.
↑ V1051 Consider checking for misprints. It's possible that the 'nSectPosPos' should be used inside 'checkSeek' function.