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 .
20 #include <propread.hxx>
21 #include "rtl/tencinfo.h"
22 #include "rtl/textenc.h"
23 #include <osl/diagnose.h>
25 PropEntry::PropEntry( sal_uInt32 nId
, const sal_uInt8
* pBuf
, sal_uInt32 nBufSize
, sal_uInt16 nTextEnc
) :
28 mnTextEnc ( nTextEnc
),
29 mpBuf ( new sal_uInt8
[ nBufSize
] )
31 memcpy( (void*)mpBuf
, (void*)pBuf
, nBufSize
);
34 PropEntry::PropEntry( const PropEntry
& rProp
) :
36 mnSize ( rProp
.mnSize
),
37 mnTextEnc ( rProp
.mnTextEnc
),
38 mpBuf ( new sal_uInt8
[ mnSize
] )
40 memcpy( (void*)mpBuf
, (void*)rProp
.mpBuf
, mnSize
);
43 PropEntry
& PropEntry::operator=(const PropEntry
& rPropEntry
)
45 if ( this != &rPropEntry
)
48 mnId
= rPropEntry
.mnId
;
49 mnSize
= rPropEntry
.mnSize
;
50 mnTextEnc
= rPropEntry
.mnTextEnc
;
51 mpBuf
= new sal_uInt8
[ mnSize
];
52 memcpy( (void*)mpBuf
, (void*)rPropEntry
.mpBuf
, mnSize
);
57 void PropItem::Clear()
59 Seek( STREAM_SEEK_TO_BEGIN
);
60 delete[] static_cast<sal_uInt8
*>(SwitchBuffer());
63 static sal_Int32
lcl_getMaxSafeStrLen(sal_uInt32 nSize
)
65 nSize
-= 1; //Drop NULL terminator
67 //If it won't fit in a string, clip it to the max size that does
68 if (nSize
> SAL_MAX_INT32
)
69 nSize
= SAL_MAX_INT32
;
71 return static_cast< sal_Int32
>( nSize
);
74 bool PropItem::Read( OUString
& rString
, sal_uInt32 nStringType
, bool bAlign
)
76 sal_uInt32 nType
, nItemPos
;
77 bool bRetValue
= false;
81 if ( nStringType
== VT_EMPTY
)
83 nType
= VT_NULL
; // Initialize in case stream fails.
87 nType
= nStringType
& VT_TYPEMASK
;
89 sal_uInt32
nItemSize(0); // Initialize in case stream fails.
90 ReadUInt32(nItemSize
);
98 auto nMaxSizePossible
= remainingSize();
99 if (nItemSize
> nMaxSizePossible
)
101 SAL_WARN("sd.filter", "String of Len " << nItemSize
<< " claimed, only " << nMaxSizePossible
<< " possible");
102 nItemSize
= nMaxSizePossible
;
110 sal_Char
* pString
= new sal_Char
[ nItemSize
];
111 if ( mnTextEnc
== RTL_TEXTENCODING_UCS2
)
116 sal_Unicode
* pWString
= reinterpret_cast<sal_Unicode
*>(pString
);
117 for (sal_uInt32 i
= 0; i
< nItemSize
; ++i
)
118 ReadUInt16( pWString
[ i
] );
119 rString
= OUString(pWString
, lcl_getMaxSafeStrLen(nItemSize
));
127 SvMemoryStream::Read( pString
, nItemSize
);
128 if ( pString
[ nItemSize
- 1 ] == 0 )
131 rString
= OUString(pString
, rtl_str_getLength(pString
), mnTextEnc
);
139 catch( const std::bad_alloc
& )
141 OSL_FAIL( "sd PropItem::Read bad alloc" );
145 SeekRel( ( 4 - ( nItemSize
& 3 ) ) & 3 ); // dword align
153 auto nMaxSizePossible
= remainingSize() / sizeof(sal_Unicode
);
154 if (nItemSize
> nMaxSizePossible
)
156 SAL_WARN("sd.filter", "String of Len " << nItemSize
<< " claimed, only " << nMaxSizePossible
<< " possible");
157 nItemSize
= nMaxSizePossible
;
165 sal_Unicode
* pString
= new sal_Unicode
[ nItemSize
];
166 for (sal_uInt32 i
= 0; i
< nItemSize
; ++i
)
167 ReadUInt16( pString
[ i
] );
168 if ( pString
[ nItemSize
- 1 ] == 0 )
170 if ( (sal_uInt16
)nItemSize
> 1 )
171 rString
= OUString(pString
, lcl_getMaxSafeStrLen(nItemSize
));
178 catch( const std::bad_alloc
& )
180 OSL_FAIL( "sd PropItem::Read bad alloc" );
183 if ( bAlign
&& ( nItemSize
& 1 ) )
184 SeekRel( 2 ); // dword align
193 PropItem
& PropItem::operator=( PropItem
& rPropItem
)
195 if ( this != &rPropItem
)
197 Seek( STREAM_SEEK_TO_BEGIN
);
198 delete[] static_cast<sal_uInt8
*>(SwitchBuffer());
200 mnTextEnc
= rPropItem
.mnTextEnc
;
201 sal_uInt32 nItemPos
= rPropItem
.Tell();
202 rPropItem
.Seek( STREAM_SEEK_TO_END
);
203 SvMemoryStream::Write( rPropItem
.GetData(), rPropItem
.Tell() );
204 rPropItem
.Seek( nItemPos
);
209 Section::Section( const Section
& rSection
)
210 : mnTextEnc(rSection
.mnTextEnc
),
211 maEntries(rSection
.maEntries
.clone())
213 for ( int i
= 0; i
< 16; i
++ )
214 aFMTID
[ i
] = rSection
.aFMTID
[ i
];
217 Section::Section( const sal_uInt8
* pFMTID
)
219 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
220 for ( int i
= 0; i
< 16; i
++ )
221 aFMTID
[ i
] = pFMTID
[ i
];
224 bool Section::GetProperty( sal_uInt32 nId
, PropItem
& rPropItem
)
228 boost::ptr_vector
<PropEntry
>::const_iterator iter
;
229 for (iter
= maEntries
.begin(); iter
!= maEntries
.end(); ++iter
)
231 if (iter
->mnId
== nId
)
235 if (iter
!= maEntries
.end())
238 rPropItem
.SetTextEncoding( mnTextEnc
);
239 rPropItem
.Write( iter
->mpBuf
,iter
->mnSize
);
240 rPropItem
.Seek( STREAM_SEEK_TO_BEGIN
);
247 void Section::AddProperty( sal_uInt32 nId
, const sal_uInt8
* pBuf
, sal_uInt32 nBufSize
)
249 // just a simple id check
253 if ( nId
== 0xffffffff )
256 // do not allow same PropId's, sort
257 boost::ptr_vector
<PropEntry
>::iterator iter
;
258 for ( iter
= maEntries
.begin(); iter
!= maEntries
.end(); ++iter
)
260 if ( iter
->mnId
== nId
)
261 maEntries
.replace( iter
, new PropEntry( nId
, pBuf
, nBufSize
, mnTextEnc
));
262 else if ( iter
->mnId
> nId
)
263 maEntries
.insert( iter
, new PropEntry( nId
, pBuf
, nBufSize
, mnTextEnc
));
269 maEntries
.push_back( new PropEntry( nId
, pBuf
, nBufSize
, mnTextEnc
) );
272 void Section::GetDictionary(Dictionary
& rDict
)
274 boost::ptr_vector
<PropEntry
>::iterator iter
;
275 for (iter
= maEntries
.begin(); iter
!= maEntries
.end(); ++iter
)
277 if ( iter
->mnId
== 0 )
281 if (iter
== maEntries
.end())
284 SvMemoryStream
aStream( iter
->mpBuf
, iter
->mnSize
, StreamMode::READ
);
285 aStream
.Seek( STREAM_SEEK_TO_BEGIN
);
286 sal_uInt32
nDictCount(0);
287 aStream
.ReadUInt32( nDictCount
);
288 for (sal_uInt32 i
= 0; i
< nDictCount
; ++i
)
290 sal_uInt32
nId(0), nSize(0);
291 aStream
.ReadUInt32(nId
).ReadUInt32(nSize
);
292 if (!aStream
.good() || nSize
> aStream
.remainingSize())
294 if (mnTextEnc
== RTL_TEXTENCODING_UCS2
)
301 if ( mnTextEnc
== RTL_TEXTENCODING_UCS2
)
303 sal_Unicode
* pWString
= new sal_Unicode
[nSize
];
304 for (sal_uInt32 j
= 0; j
< nSize
; ++j
)
305 aStream
.ReadUInt16(pWString
[j
]);
306 aString
= OUString(pWString
, lcl_getMaxSafeStrLen(nSize
));
311 sal_Char
* pString
= new sal_Char
[nSize
];
312 aStream
.Read(pString
, nSize
);
313 aString
= OUString(pString
, lcl_getMaxSafeStrLen(nSize
), mnTextEnc
);
317 catch( const std::bad_alloc
& )
319 OSL_FAIL( "sd Section::GetDictionary bad alloc" );
321 if (aString
.isEmpty())
323 rDict
.insert( std::make_pair(aString
,nId
) );
327 void Section::Read( SotStorageStream
*pStrm
)
329 sal_uInt32 nSecOfs
, nPropSize
, nStrmSize
;
330 nSecOfs
= pStrm
->Tell();
332 pStrm
->Seek( STREAM_SEEK_TO_END
);
333 nStrmSize
= pStrm
->Tell();
334 pStrm
->Seek( nSecOfs
);
336 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
337 sal_uInt32
nSecSize(0), nPropCount(0);
338 pStrm
->ReadUInt32( nSecSize
).ReadUInt32( nPropCount
);
341 sal_uInt32
nPropId(0), nPropOfs(0);
342 pStrm
->ReadUInt32(nPropId
).ReadUInt32(nPropOfs
);
345 auto nCurrent
= pStrm
->Tell();
346 sal_uInt64 nOffset
= nPropOfs
+ nSecOfs
;
347 if (nOffset
!= pStrm
->Seek(nOffset
))
349 if ( nPropId
) // do not read dictionary
351 sal_uInt32
nPropType(0), nVectorCount(0);
352 pStrm
->ReadUInt32(nPropType
);
356 if ( nPropType
& VT_VECTOR
)
358 pStrm
->ReadUInt32( nVectorCount
);
359 nPropType
&=~VT_VECTOR
;
365 bool bVariant
= ( nPropType
== VT_VARIANT
);
367 for (sal_uInt32 i
= 0; nPropSize
&& ( i
< nVectorCount
); ++i
)
371 pStrm
->ReadUInt32( nPropType
);
404 pStrm
->ReadUInt32( nTemp
);
405 nPropSize
+= ( nTemp
+ 4 );
409 pStrm
->ReadUInt32( nTemp
);
410 nPropSize
+= ( nTemp
+ 4 );
415 pStrm
->ReadUInt32( nTemp
);
416 // looks like these are aligned to 4 bytes
417 sal_uInt32 nLength
= nPropOfs
+ nSecOfs
+ nPropSize
+ ( nTemp
<< 1 ) + 4;
418 nPropSize
+= ( nTemp
<< 1 ) + 4 + (nLength
% 4);
422 case VT_BLOB_OBJECT
:
425 pStrm
->ReadUInt32( nTemp
);
426 nPropSize
+= ( nTemp
+ 4 );
432 case VT_STREAMED_OBJECT
:
433 case VT_STORED_OBJECT
:
441 if ( ( nVectorCount
- i
) > 1 )
443 nOffset
= nPropOfs
+ nSecOfs
+ nPropSize
;
444 if (nOffset
!= pStrm
->Seek(nOffset
))
453 if ( nPropSize
> nStrmSize
)
458 pStrm
->Seek( nPropOfs
+ nSecOfs
);
459 // make sure we don't overflow the section size
460 if( nPropSize
> nSecSize
- nSecOfs
)
461 nPropSize
= nSecSize
- nSecOfs
;
462 sal_uInt8
* pBuf
= new sal_uInt8
[ nPropSize
];
463 nPropSize
= pStrm
->Read(pBuf
, nPropSize
);
464 AddProperty( nPropId
, pBuf
, nPropSize
);
470 if ( GetProperty( 1, aPropItem
) )
472 aPropItem
.ReadUInt32( nPropType
);
473 if ( nPropType
== VT_I2
)
475 sal_uInt16
nCodePage(0);
476 aPropItem
.ReadUInt16(nCodePage
);
478 if ( nCodePage
== 1200 )
480 mnTextEnc
= RTL_TEXTENCODING_UCS2
;
484 mnTextEnc
= rtl_getTextEncodingFromWindowsCodePage( nCodePage
);
485 if ( mnTextEnc
== RTL_TEXTENCODING_DONTKNOW
)
486 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
491 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
498 sal_uInt32
nDictCount(0);
499 pStrm
->ReadUInt32(nDictCount
);
500 auto nMaxRecordsPossible
= pStrm
->remainingSize() / (sizeof(sal_uInt32
)*2);
501 if (nDictCount
> nMaxRecordsPossible
)
503 SAL_WARN("sd.filter", "Dictionary count of " << nDictCount
<< " claimed, only " << nMaxRecordsPossible
<< " possible");
504 nDictCount
= nMaxRecordsPossible
;
506 for (sal_uInt32 i
= 0; i
< nDictCount
; ++i
)
509 pStrm
->ReadUInt32( nSize
).ReadUInt32( nSize
);
512 sal_uInt64 nPos
= pStrm
->Tell() + nSize
;
513 if (nPos
!= pStrm
->Seek(nPos
))
516 sal_uInt32 nSize
= pStrm
->Tell();
517 pStrm
->Seek( nPropOfs
+ nSecOfs
);
518 nSize
-= pStrm
->Tell();
519 if ( nSize
> nStrmSize
)
524 sal_uInt8
* pBuf
= new sal_uInt8
[ nSize
];
525 nSize
= pStrm
->Read(pBuf
, nSize
);
526 AddProperty( 0xffffffff, pBuf
, nSize
);
529 pStrm
->Seek(nCurrent
);
531 pStrm
->Seek( nSecOfs
+ nSecSize
);
534 Section
& Section::operator=( const Section
& rSection
)
536 if ( this != &rSection
)
538 memcpy( (void*)aFMTID
, (void*)rSection
.aFMTID
, 16 );
540 maEntries
= rSection
.maEntries
.clone();
545 PropRead::PropRead( SotStorage
& rStorage
, const OUString
& rName
) :
547 mnByteOrder ( 0xfffe ),
552 if ( rStorage
.IsStream( rName
) )
554 mpSvStream
= rStorage
.OpenSotStream( rName
, STREAM_STD_READ
);
557 mpSvStream
->SetEndian( SvStreamEndian::LITTLE
);
558 memset( mApplicationCLSID
, 0, 16 );
564 void PropRead::AddSection( Section
& rSection
)
566 maSections
.push_back( new Section( rSection
) );
569 const Section
* PropRead::GetSection( const sal_uInt8
* pFMTID
)
571 boost::ptr_vector
<Section
>::iterator it
;
572 for ( it
= maSections
.begin(); it
!= maSections
.end(); ++it
)
574 if ( memcmp( it
->GetFMTID(), pFMTID
, 16 ) == 0 )
580 void PropRead::Read()
586 sal_uInt32 nSections
;
587 sal_uInt32 nSectionOfs
;
589 mpSvStream
->ReadUInt16( mnByteOrder
).ReadUInt16( mnFormat
).ReadUInt16( mnVersionLo
).ReadUInt16( mnVersionHi
);
590 if ( mnByteOrder
== 0xfffe )
592 sal_uInt8
* pSectCLSID
= new sal_uInt8
[ 16 ];
593 mpSvStream
->Read( mApplicationCLSID
, 16 );
594 mpSvStream
->ReadUInt32( nSections
);
595 if ( nSections
> 2 ) // sj: PowerPoint documents are containing max 2 sections
599 else for ( sal_uInt32 i
= 0; i
< nSections
; i
++ )
601 mpSvStream
->Read( pSectCLSID
, 16 );
602 mpSvStream
->ReadUInt32( nSectionOfs
);
603 nCurrent
= mpSvStream
->Tell();
604 mpSvStream
->Seek( nSectionOfs
);
605 Section
aSection( pSectCLSID
);
606 aSection
.Read( mpSvStream
);
607 AddSection( aSection
);
608 mpSvStream
->Seek( nCurrent
);
615 PropRead
& PropRead::operator=( const PropRead
& rPropRead
)
617 if ( this != &rPropRead
)
619 mbStatus
= rPropRead
.mbStatus
;
620 mpSvStream
= rPropRead
.mpSvStream
;
622 mnByteOrder
= rPropRead
.mnByteOrder
;
623 mnFormat
= rPropRead
.mnFormat
;
624 mnVersionLo
= rPropRead
.mnVersionLo
;
625 mnVersionHi
= rPropRead
.mnVersionHi
;
626 memcpy( mApplicationCLSID
, rPropRead
.mApplicationCLSID
, 16 );
628 maSections
= rPropRead
.maSections
.clone();
633 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */