blob: 7b45e69ea9f4ea4385cbeed74381d8e3784e12cd [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include <propread.hxx>
#include <tools/bigint.hxx>
#include "tools/debug.hxx"
#include "rtl/tencinfo.h"
#include "rtl/textenc.h"
// ------------------------------------------------------------------------
struct PropEntry
{
sal_uInt32 mnId;
sal_uInt32 mnSize;
sal_uInt16 mnTextEnc;
sal_uInt8* mpBuf;
PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize, sal_uInt16 nTextEnc );
PropEntry( const PropEntry& rProp );
~PropEntry() { delete[] mpBuf; } ;
const PropEntry& operator=(const PropEntry& rPropEntry);
};
PropEntry::PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize, sal_uInt16 nTextEnc ) :
mnId ( nId ),
mnSize ( nBufSize ),
mnTextEnc ( nTextEnc ),
mpBuf ( new sal_uInt8[ nBufSize ] )
{
memcpy( (void*)mpBuf, (void*)pBuf, nBufSize );
};
PropEntry::PropEntry( const PropEntry& rProp ) :
mnId ( rProp.mnId ),
mnSize ( rProp.mnSize ),
mnTextEnc ( rProp.mnTextEnc ),
mpBuf ( new sal_uInt8[ mnSize ] )
{
memcpy( (void*)mpBuf, (void*)rProp.mpBuf, mnSize );
};
const PropEntry& PropEntry::operator=(const PropEntry& rPropEntry)
{
if ( this != &rPropEntry )
{
delete[] mpBuf;
mnId = rPropEntry.mnId;
mnSize = rPropEntry.mnSize;
mnTextEnc = rPropEntry.mnTextEnc;
mpBuf = new sal_uInt8[ mnSize ];
memcpy( (void*)mpBuf, (void*)rPropEntry.mpBuf, mnSize );
}
return *this;
}
// -----------------------------------------------------------------------
void PropItem::Clear()
{
Seek( STREAM_SEEK_TO_BEGIN );
delete[] (sal_uInt8*)SwitchBuffer();
}
// -----------------------------------------------------------------------
static xub_StrLen lcl_getMaxSafeStrLen(sal_uInt32 nSize)
{
nSize -= 1; //Drop NULL terminator
//If it won't fit in a string, clip it to the max size that does
if (nSize > STRING_MAXLEN)
nSize = STRING_MAXLEN;
return static_cast< xub_StrLen >( nSize );
}
sal_Bool PropItem::Read( String& rString, sal_uInt32 nStringType, sal_Bool bAlign )
{
sal_uInt32 i, nItemSize, nType, nItemPos;
sal_Bool bRetValue = sal_False;
nItemPos = Tell();
if ( nStringType == VT_EMPTY )
*this >> nType;
else
nType = nStringType & VT_TYPEMASK;
*this >> nItemSize;
switch( nType )
{
case VT_LPSTR :
{
if ( nItemSize )
{
try
{
sal_Char* pString = new sal_Char[ nItemSize ];
if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
{
nItemSize >>= 1;
if ( nItemSize > 1 )
{
sal_Unicode* pWString = (sal_Unicode*)pString;
for ( i = 0; i < nItemSize; i++ )
*this >> pWString[ i ];
rString = String( pWString, lcl_getMaxSafeStrLen(nItemSize) );
}
else
rString = String();
bRetValue = sal_True;
}
else
{
SvMemoryStream::Read( pString, nItemSize );
if ( pString[ nItemSize - 1 ] == 0 )
{
if ( nItemSize > 1 )
rString = String( ByteString( pString ), mnTextEnc );
else
rString = String();
bRetValue = sal_True;
}
}
delete[] pString;
}
catch( const std::bad_alloc& )
{
DBG_ERROR( "sd PropItem::Read bad alloc" );
}
}
if ( bAlign )
SeekRel( ( 4 - ( nItemSize & 3 ) ) & 3 ); // dword align
}
break;
case VT_LPWSTR :
{
if ( nItemSize )
{
try
{
sal_Unicode* pString = new sal_Unicode[ nItemSize ];
for ( i = 0; i < nItemSize; i++ )
*this >> pString[ i ];
if ( pString[ i - 1 ] == 0 )
{
if ( (sal_uInt16)nItemSize > 1 )
rString = String( pString, lcl_getMaxSafeStrLen(nItemSize) );
else
rString = String();
bRetValue = sal_True;
}
delete[] pString;
}
catch( const std::bad_alloc& )
{
DBG_ERROR( "sd PropItem::Read bad alloc" );
}
}
if ( bAlign && ( nItemSize & 1 ) )
SeekRel( 2 ); // dword align
}
break;
}
if ( !bRetValue )
Seek( nItemPos );
return bRetValue;
}
// -----------------------------------------------------------------------
PropItem& PropItem::operator=( PropItem& rPropItem )
{
if ( this != &rPropItem )
{
Seek( STREAM_SEEK_TO_BEGIN );
delete[] (sal_uInt8*)SwitchBuffer();
mnTextEnc = rPropItem.mnTextEnc;
sal_uInt32 nItemPos = rPropItem.Tell();
rPropItem.Seek( STREAM_SEEK_TO_END );
SvMemoryStream::Write( rPropItem.GetData(), rPropItem.Tell() );
rPropItem.Seek( nItemPos );
}
return *this;
}
// -----------------------------------------------------------------------
struct Dict
{
sal_uInt32 mnId;
String aString;
Dict( sal_uInt32 nId, String rString ) { mnId = nId; aString = rString; };
};
// -----------------------------------------------------------------------
Dictionary::~Dictionary()
{
for ( void* pPtr = First(); pPtr; pPtr = Next() )
delete (Dict*)pPtr;
}
// -----------------------------------------------------------------------
void Dictionary::AddProperty( sal_uInt32 nId, const String& rString )
{
if ( rString.Len() ) // eindeutige namen bei properties
{
// pruefen, ob es die Propertybeschreibung in der Dictionary schon gibt
for ( Dict* pDict = (Dict*)First(); pDict; pDict = (Dict*)Next() )
{
if ( pDict->mnId == nId )
{
pDict->aString = rString;
return;
}
}
Insert( new Dict( nId, rString ), LIST_APPEND );
}
}
// -----------------------------------------------------------------------
sal_uInt32 Dictionary::GetProperty( const String& rString )
{
for ( Dict* pDict = (Dict*)First(); pDict; pDict = (Dict*)Next() )
{
if ( pDict->aString == rString )
return pDict->mnId;
}
return 0;
}
// -----------------------------------------------------------------------
Dictionary& Dictionary::operator=( Dictionary& rDictionary )
{
void* pPtr;
if ( this != &rDictionary )
{
for ( pPtr = First(); pPtr; pPtr = Next() )
delete (Dict*)pPtr;
for ( pPtr = rDictionary.First(); pPtr; pPtr = rDictionary.Next() )
Insert( new Dict( ((Dict*)pPtr)->mnId, ((Dict*)pPtr)->aString ), LIST_APPEND );
}
return *this;
}
// -----------------------------------------------------------------------
Section::Section( Section& rSection )
: List()
{
mnTextEnc = rSection.mnTextEnc;
for ( int i = 0; i < 16; i++ )
aFMTID[ i ] = rSection.aFMTID[ i ];
for ( PropEntry* pProp = (PropEntry*)rSection.First(); pProp; pProp = (PropEntry*)rSection.Next() )
Insert( new PropEntry( *pProp ), LIST_APPEND );
}
// -----------------------------------------------------------------------
Section::Section( const sal_uInt8* pFMTID )
{
mnTextEnc = RTL_TEXTENCODING_MS_1252;
for ( int i = 0; i < 16; i++ )
aFMTID[ i ] = pFMTID[ i ];
}
// -----------------------------------------------------------------------
sal_Bool Section::GetProperty( sal_uInt32 nId, PropItem& rPropItem )
{
PropEntry* pProp;
if ( nId )
{
for ( pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
{
if ( pProp->mnId == nId )
break;
}
if ( pProp )
{
rPropItem.Clear();
rPropItem.SetTextEncoding( mnTextEnc );
rPropItem.Write( pProp->mpBuf, pProp->mnSize );
rPropItem.Seek( STREAM_SEEK_TO_BEGIN );
return sal_True;
}
}
return sal_False;
}
// -----------------------------------------------------------------------
void Section::AddProperty( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize )
{
// kleiner id check
if ( !nId )
return;
if ( nId == 0xffffffff )
nId = 0;
// keine doppelten PropId's zulassen, sortieren
for ( sal_uInt32 i = 0; i < Count(); i++ )
{
PropEntry* pPropEntry = (PropEntry*)GetObject( i );
if ( pPropEntry->mnId == nId )
delete (PropEntry*)Replace( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ), i );
else if ( pPropEntry->mnId > nId )
Insert( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ), i );
else
continue;
return;
}
Insert( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ), LIST_APPEND );
}
// -----------------------------------------------------------------------
sal_Bool Section::GetDictionary( Dictionary& rDict )
{
sal_Bool bRetValue = sal_False;
Dictionary aDict;
PropEntry* pProp;
for ( pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
{
if ( pProp->mnId == 0 )
break;
}
if ( pProp )
{
sal_uInt32 nDictCount, nId, nSize, nPos;
SvMemoryStream aStream( (sal_Int8*)pProp->mpBuf, pProp->mnSize, STREAM_READ );
aStream.Seek( STREAM_SEEK_TO_BEGIN );
aStream >> nDictCount;
for ( sal_uInt32 i = 0; i < nDictCount; i++ )
{
aStream >> nId >> nSize;
if ( nSize )
{
String aString;
nPos = aStream.Tell();
try
{
sal_Char* pString = new sal_Char[ nSize ];
aStream.Read( pString, nSize );
if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
{
nSize >>= 1;
aStream.Seek( nPos );
sal_Unicode* pWString = (sal_Unicode*)pString;
for ( i = 0; i < nSize; i++ )
aStream >> pWString[ i ];
aString = String( pWString, lcl_getMaxSafeStrLen(nSize) );
}
else
aString = String( ByteString( pString, lcl_getMaxSafeStrLen(nSize) ), mnTextEnc );
delete[] pString;
}
catch( const std::bad_alloc& )
{
DBG_ERROR( "sd Section::GetDictionary bad alloc" );
}
if ( !aString.Len() )
break;
aDict.AddProperty( nId, aString );
}
bRetValue = sal_True;
}
}
rDict = aDict;
return bRetValue;
}
// -----------------------------------------------------------------------
Section::~Section()
{
for ( PropEntry* pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
delete pProp;
}
// -----------------------------------------------------------------------
void Section::Read( SvStorageStream *pStrm )
{
sal_uInt32 i, nSecOfs, nSecSize, nPropCount, nPropId, nPropOfs, nPropType, nPropSize, nCurrent, nVectorCount, nTemp, nStrmSize;
nSecOfs = pStrm->Tell();
pStrm->Seek( STREAM_SEEK_TO_END );
nStrmSize = pStrm->Tell();
pStrm->Seek( nSecOfs );
mnTextEnc = RTL_TEXTENCODING_MS_1252;
*pStrm >> nSecSize >> nPropCount;
while( nPropCount-- && ( pStrm->GetError() == ERRCODE_NONE ) )
{
*pStrm >> nPropId >> nPropOfs;
nCurrent = pStrm->Tell();
pStrm->Seek( nPropOfs + nSecOfs );
if ( nPropId ) // dictionary wird nicht eingelesen
{
*pStrm >> nPropType;
nPropSize = 4;
if ( nPropType & VT_VECTOR )
{
*pStrm >> nVectorCount;
nPropType &=~VT_VECTOR;
nPropSize += 4;
}
else
nVectorCount = 1;
sal_Bool bVariant = ( nPropType == VT_VARIANT );
for ( i = 0; nPropSize && ( i < nVectorCount ); i++ )
{
if ( bVariant )
{
*pStrm >> nPropType;
nPropSize += 4;
}
switch( nPropType )
{
case VT_UI1 :
nPropSize++;
break;
case VT_I2 :
case VT_UI2 :
case VT_BOOL :
nPropSize += 2;
break;
case VT_I4 :
case VT_R4 :
case VT_UI4 :
case VT_ERROR :
nPropSize += 4;
break;
case VT_I8 :
case VT_R8 :
case VT_CY :
case VT_UI8 :
case VT_DATE :
case VT_FILETIME :
nPropSize += 8;
break;
case VT_BSTR :
*pStrm >> nTemp;
nPropSize += ( nTemp + 4 );
break;
case VT_LPSTR :
*pStrm >> nTemp;
nPropSize += ( nTemp + 4 );
break;
case VT_LPWSTR :
*pStrm >> nTemp;
nPropSize += ( nTemp << 1 ) + 4;
break;
case VT_BLOB_OBJECT :
case VT_BLOB :
case VT_CF :
*pStrm >> nTemp;
nPropSize += ( nTemp + 4 );
break;
case VT_CLSID :
case VT_STREAM :
case VT_STORAGE :
case VT_STREAMED_OBJECT :
case VT_STORED_OBJECT :
case VT_VARIANT :
case VT_VECTOR :
default :
nPropSize = 0;
}
if ( nPropSize )
{
if ( ( nVectorCount - i ) > 1 )
pStrm->Seek( nPropOfs + nSecOfs + nPropSize );
}
else
break;
}
if ( nPropSize )
{
if ( nPropSize > nStrmSize )
{
nPropCount = 0;
break;
}
pStrm->Seek( nPropOfs + nSecOfs );
sal_uInt8* pBuf = new sal_uInt8[ nPropSize ];
pStrm->Read( pBuf, nPropSize );
AddProperty( nPropId, pBuf, nPropSize );
delete[] pBuf;
}
if ( nPropId == 1 )
{
PropItem aPropItem;
if ( GetProperty( 1, aPropItem ) )
{
sal_uInt16 nCodePage;
aPropItem >> nPropType;
if ( nPropType == VT_I2 )
{
aPropItem >> nCodePage;
if ( nCodePage == 1200 )
{
mnTextEnc = RTL_TEXTENCODING_UCS2;
}
else
{
mnTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
if ( mnTextEnc == RTL_TEXTENCODING_DONTKNOW )
mnTextEnc = RTL_TEXTENCODING_MS_1252;
}
}
else
{
mnTextEnc = RTL_TEXTENCODING_MS_1252;
}
}
}
}
else
{
sal_uInt32 nDictCount, nSize;
*pStrm >> nDictCount;
for ( i = 0; i < nDictCount; i++ )
{
*pStrm >> nSize >> nSize;
pStrm->SeekRel( nSize );
}
nSize = pStrm->Tell();
pStrm->Seek( nPropOfs + nSecOfs );
nSize -= pStrm->Tell();
if ( nSize > nStrmSize )
{
nPropCount = 0;
break;
}
sal_uInt8* pBuf = new sal_uInt8[ nSize ];
pStrm->Read( pBuf, nSize );
AddProperty( 0xffffffff, pBuf, nSize );
delete[] pBuf;
}
pStrm->Seek( nCurrent );
}
pStrm->Seek( nSecOfs + nSecSize );
}
// -----------------------------------------------------------------------
Section& Section::operator=( Section& rSection )
{
PropEntry* pProp;
if ( this != &rSection )
{
memcpy( (void*)aFMTID, (void*)rSection.aFMTID, 16 );
for ( pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
delete pProp;
Clear();
for ( pProp = (PropEntry*)rSection.First(); pProp; pProp = (PropEntry*)rSection.Next() )
Insert( new PropEntry( *pProp ), LIST_APPEND );
}
return *this;
}
// -----------------------------------------------------------------------
PropRead::PropRead( SvStorage& rStorage, const String& rName ) :
mbStatus ( sal_False ),
mnByteOrder ( 0xfffe ),
mnFormat ( 0 ),
mnVersionLo ( 4 ),
mnVersionHi ( 2 )
{
if ( rStorage.IsStream( rName ) )
{
mpSvStream = rStorage.OpenSotStream( rName, STREAM_STD_READ );
if ( mpSvStream )
{
mpSvStream->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
memset( mApplicationCLSID, 0, 16 );
mbStatus = sal_True;
}
}
}
// -----------------------------------------------------------------------
void PropRead::AddSection( Section& rSection )
{
Insert( new Section( rSection ), LIST_APPEND );
}
// -----------------------------------------------------------------------
const Section* PropRead::GetSection( const sal_uInt8* pFMTID )
{
Section* pSection;
for ( pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
{
if ( memcmp( pSection->GetFMTID(), pFMTID, 16 ) == 0 )
break;
}
return pSection;
}
// -----------------------------------------------------------------------
PropRead::~PropRead()
{
for ( Section* pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
delete pSection;
}
// -----------------------------------------------------------------------
void PropRead::Read()
{
for ( Section* pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
delete pSection;
Clear();
if ( mbStatus )
{
sal_uInt32 nSections;
sal_uInt32 nSectionOfs;
sal_uInt32 nCurrent;
*mpSvStream >> mnByteOrder >> mnFormat >> mnVersionLo >> mnVersionHi;
if ( mnByteOrder == 0xfffe )
{
sal_uInt8* pSectCLSID = new sal_uInt8[ 16 ];
mpSvStream->Read( mApplicationCLSID, 16 );
*mpSvStream >> nSections;
if ( nSections > 2 ) // sj: PowerPoint documents are containing max 2 sections
{
mbStatus = sal_False;
}
else for ( sal_uInt32 i = 0; i < nSections; i++ )
{
mpSvStream->Read( pSectCLSID, 16 );
*mpSvStream >> nSectionOfs;
nCurrent = mpSvStream->Tell();
mpSvStream->Seek( nSectionOfs );
Section aSection( pSectCLSID );
aSection.Read( mpSvStream );
AddSection( aSection );
mpSvStream->Seek( nCurrent );
}
delete[] pSectCLSID;
}
}
}
// -----------------------------------------------------------------------
PropRead& PropRead::operator=( PropRead& rPropRead )
{
Section* pSection;
if ( this != &rPropRead )
{
mbStatus = rPropRead.mbStatus;
mpSvStream = rPropRead.mpSvStream;
mnByteOrder = rPropRead.mnByteOrder;
mnFormat = rPropRead.mnFormat;
mnVersionLo = rPropRead.mnVersionLo;
mnVersionHi = rPropRead.mnVersionHi;
memcpy( mApplicationCLSID, rPropRead.mApplicationCLSID, 16 );
for ( pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
delete pSection;
Clear();
for ( pSection = (Section*)rPropRead.First(); pSection; pSection = (Section*)rPropRead.Next() )
Insert( new Section( *pSection ), LIST_APPEND );
}
return *this;
}