/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sd.hxx" #include #include #include "tools/debug.hxx" #include "rtl/tencinfo.h" #include "rtl/textenc.h" 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& ) { OSL_FAIL( "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& ) { OSL_FAIL( "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; } // ----------------------------------------------------------------------- Section::Section( const Section& rSection ) : mnTextEnc(rSection.mnTextEnc), maEntries(rSection.maEntries.clone()) { for ( int i = 0; i < 16; i++ ) aFMTID[ i ] = rSection.aFMTID[ i ]; } // ----------------------------------------------------------------------- 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 ) { if ( nId ) { boost::ptr_vector::const_iterator iter; for (iter = maEntries.begin(); iter != maEntries.end(); ++iter) { if (iter->mnId == nId) break; } if (iter != maEntries.end()) { rPropItem.Clear(); rPropItem.SetTextEncoding( mnTextEnc ); rPropItem.Write( iter->mpBuf,iter->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 boost::ptr_vector::iterator iter; for ( iter = maEntries.begin(); iter != maEntries.end(); ++iter ) { if ( iter->mnId == nId ) maEntries.replace( iter, new PropEntry( nId, pBuf, nBufSize, mnTextEnc )); else if ( iter->mnId > nId ) maEntries.insert( iter, new PropEntry( nId, pBuf, nBufSize, mnTextEnc )); else continue; return; } maEntries.push_back( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ) ); } // ----------------------------------------------------------------------- sal_Bool Section::GetDictionary( Dictionary& rDict ) { sal_Bool bRetValue = sal_False; boost::ptr_vector::iterator iter; for (iter = maEntries.begin(); iter != maEntries.end(); ++iter) { if ( iter->mnId == 0 ) break; } if ( iter != maEntries.end() ) { sal_uInt32 nDictCount, nId, nSize, nPos; SvMemoryStream aStream( (sal_Int8*)iter->mpBuf, iter->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& ) { OSL_FAIL( "sd Section::GetDictionary bad alloc" ); } if ( !aString.Len() ) break; rDict.insert( std::make_pair(aString,nId) ); } bRetValue = sal_True; } } return bRetValue; } // ----------------------------------------------------------------------- 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; // looks like these are aligned to 4 bytes sal_uInt32 nLength = nPropOfs + nSecOfs + nPropSize + ( nTemp << 1 ) + 4; nPropSize += ( nTemp << 1 ) + 4 + (nLength % 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 ); // make sure we don't overflow the section size if( nPropSize > nSecSize - nSecOfs ) nPropSize = nSecSize - 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=( const Section& rSection ) { if ( this != &rSection ) { memcpy( (void*)aFMTID, (void*)rSection.aFMTID, 16 ); maEntries = rSection.maEntries.clone(); } 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 ) { maSections.push_back( new Section( rSection ) ); } // ----------------------------------------------------------------------- const Section* PropRead::GetSection( const sal_uInt8* pFMTID ) { boost::ptr_vector
::iterator it; for ( it = maSections.begin(); it != maSections.end(); ++it) { if ( memcmp( it->GetFMTID(), pFMTID, 16 ) == 0 ) return &(*it); } return NULL; } // ----------------------------------------------------------------------- void PropRead::Read() { maSections.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=( const PropRead& rPropRead ) { 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 ); maSections = rPropRead.maSections.clone(); } return *this; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */