bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / filter / ppt / propread.cxx
blob2f5fc73fb2ec30e0196329110039fdd9b93c2a39
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 ) :
26 mnId ( nId ),
27 mnSize ( nBufSize ),
28 mnTextEnc ( nTextEnc ),
29 mpBuf ( new sal_uInt8[ nBufSize ] )
31 memcpy( (void*)mpBuf, (void*)pBuf, nBufSize );
34 PropEntry::PropEntry( const PropEntry& rProp ) :
35 mnId ( rProp.mnId ),
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 )
47 delete[] mpBuf;
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 );
54 return *this;
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;
79 nItemPos = Tell();
81 if ( nStringType == VT_EMPTY )
83 nType = VT_NULL; // Initialize in case stream fails.
84 ReadUInt32( nType );
86 else
87 nType = nStringType & VT_TYPEMASK;
89 sal_uInt32 nItemSize(0); // Initialize in case stream fails.
90 ReadUInt32(nItemSize);
92 switch( nType )
94 case VT_LPSTR :
96 if (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;
106 if (nItemSize)
110 sal_Char* pString = new sal_Char[ nItemSize ];
111 if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
113 nItemSize >>= 1;
114 if ( nItemSize > 1 )
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));
121 else
122 rString.clear();
123 bRetValue = true;
125 else
127 SvMemoryStream::Read( pString, nItemSize );
128 if ( pString[ nItemSize - 1 ] == 0 )
130 if ( nItemSize > 1 )
131 rString = OUString(pString, rtl_str_getLength(pString), mnTextEnc);
132 else
133 rString.clear();
134 bRetValue = true;
137 delete[] pString;
139 catch( const std::bad_alloc& )
141 OSL_FAIL( "sd PropItem::Read bad alloc" );
144 if ( bAlign )
145 SeekRel( ( 4 - ( nItemSize & 3 ) ) & 3 ); // dword align
147 break;
149 case VT_LPWSTR :
151 if (nItemSize)
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;
161 if (nItemSize)
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));
172 else
173 rString.clear();
174 bRetValue = true;
176 delete[] pString;
178 catch( const std::bad_alloc& )
180 OSL_FAIL( "sd PropItem::Read bad alloc" );
183 if ( bAlign && ( nItemSize & 1 ) )
184 SeekRel( 2 ); // dword align
186 break;
188 if ( !bRetValue )
189 Seek( nItemPos );
190 return bRetValue;
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 );
206 return *this;
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 )
226 if ( nId )
228 boost::ptr_vector<PropEntry>::const_iterator iter;
229 for (iter = maEntries.begin(); iter != maEntries.end(); ++iter)
231 if (iter->mnId == nId)
232 break;
235 if (iter != maEntries.end())
237 rPropItem.Clear();
238 rPropItem.SetTextEncoding( mnTextEnc );
239 rPropItem.Write( iter->mpBuf,iter->mnSize );
240 rPropItem.Seek( STREAM_SEEK_TO_BEGIN );
241 return true;
244 return false;
247 void Section::AddProperty( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize )
249 // just a simple id check
251 if ( !nId )
252 return;
253 if ( nId == 0xffffffff )
254 nId = 0;
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 ));
264 else
265 continue;
266 return;
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 )
278 break;
281 if (iter == maEntries.end())
282 return;
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())
293 break;
294 if (mnTextEnc == RTL_TEXTENCODING_UCS2)
295 nSize >>= 1;
296 if (!nSize)
297 continue;
298 OUString aString;
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));
307 delete[] pWString;
309 else
311 sal_Char* pString = new sal_Char[nSize];
312 aStream.Read(pString, nSize);
313 aString = OUString(pString, lcl_getMaxSafeStrLen(nSize), mnTextEnc);
314 delete[] pString;
317 catch( const std::bad_alloc& )
319 OSL_FAIL( "sd Section::GetDictionary bad alloc" );
321 if (aString.isEmpty())
322 break;
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 );
339 while (nPropCount--)
341 sal_uInt32 nPropId(0), nPropOfs(0);
342 pStrm->ReadUInt32(nPropId).ReadUInt32(nPropOfs);
343 if (!pStrm->good())
344 break;
345 auto nCurrent = pStrm->Tell();
346 sal_uInt64 nOffset = nPropOfs + nSecOfs;
347 if (nOffset != pStrm->Seek(nOffset))
348 break;
349 if ( nPropId ) // do not read dictionary
351 sal_uInt32 nPropType(0), nVectorCount(0);
352 pStrm->ReadUInt32(nPropType);
354 nPropSize = 4;
356 if ( nPropType & VT_VECTOR )
358 pStrm->ReadUInt32( nVectorCount );
359 nPropType &=~VT_VECTOR;
360 nPropSize += 4;
362 else
363 nVectorCount = 1;
365 bool bVariant = ( nPropType == VT_VARIANT );
367 for (sal_uInt32 i = 0; nPropSize && ( i < nVectorCount ); ++i)
369 if ( bVariant )
371 pStrm->ReadUInt32( nPropType );
372 nPropSize += 4;
374 sal_uInt32 nTemp(0);
375 switch( nPropType )
377 case VT_UI1 :
378 nPropSize++;
379 break;
381 case VT_I2 :
382 case VT_UI2 :
383 case VT_BOOL :
384 nPropSize += 2;
385 break;
387 case VT_I4 :
388 case VT_R4 :
389 case VT_UI4 :
390 case VT_ERROR :
391 nPropSize += 4;
392 break;
394 case VT_I8 :
395 case VT_R8 :
396 case VT_CY :
397 case VT_UI8 :
398 case VT_DATE :
399 case VT_FILETIME :
400 nPropSize += 8;
401 break;
403 case VT_BSTR :
404 pStrm->ReadUInt32( nTemp );
405 nPropSize += ( nTemp + 4 );
406 break;
408 case VT_LPSTR :
409 pStrm->ReadUInt32( nTemp );
410 nPropSize += ( nTemp + 4 );
411 break;
413 case VT_LPWSTR :
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);
420 break;
422 case VT_BLOB_OBJECT :
423 case VT_BLOB :
424 case VT_CF :
425 pStrm->ReadUInt32( nTemp );
426 nPropSize += ( nTemp + 4 );
427 break;
429 case VT_CLSID :
430 case VT_STREAM :
431 case VT_STORAGE :
432 case VT_STREAMED_OBJECT :
433 case VT_STORED_OBJECT :
434 case VT_VARIANT :
435 case VT_VECTOR :
436 default :
437 nPropSize = 0;
439 if ( nPropSize )
441 if ( ( nVectorCount - i ) > 1 )
443 nOffset = nPropOfs + nSecOfs + nPropSize;
444 if (nOffset != pStrm->Seek(nOffset))
445 break;
448 else
449 break;
451 if ( nPropSize )
453 if ( nPropSize > nStrmSize )
455 nPropCount = 0;
456 break;
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 );
465 delete[] pBuf;
467 if ( nPropId == 1 )
469 PropItem aPropItem;
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;
482 else
484 mnTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
485 if ( mnTextEnc == RTL_TEXTENCODING_DONTKNOW )
486 mnTextEnc = RTL_TEXTENCODING_MS_1252;
489 else
491 mnTextEnc = RTL_TEXTENCODING_MS_1252;
496 else
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)
508 sal_uInt32 nSize(0);
509 pStrm->ReadUInt32( nSize ).ReadUInt32( nSize );
510 if (!pStrm->good())
511 break;
512 sal_uInt64 nPos = pStrm->Tell() + nSize;
513 if (nPos != pStrm->Seek(nPos))
514 break;
516 sal_uInt32 nSize = pStrm->Tell();
517 pStrm->Seek( nPropOfs + nSecOfs );
518 nSize -= pStrm->Tell();
519 if ( nSize > nStrmSize )
521 nPropCount = 0;
522 break;
524 sal_uInt8* pBuf = new sal_uInt8[ nSize ];
525 nSize = pStrm->Read(pBuf, nSize);
526 AddProperty( 0xffffffff, pBuf, nSize );
527 delete[] pBuf;
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();
542 return *this;
545 PropRead::PropRead( SotStorage& rStorage, const OUString& rName ) :
546 mbStatus ( false ),
547 mnByteOrder ( 0xfffe ),
548 mnFormat ( 0 ),
549 mnVersionLo ( 4 ),
550 mnVersionHi ( 2 )
552 if ( rStorage.IsStream( rName ) )
554 mpSvStream = rStorage.OpenSotStream( rName, STREAM_STD_READ );
555 if ( mpSvStream )
557 mpSvStream->SetEndian( SvStreamEndian::LITTLE );
558 memset( mApplicationCLSID, 0, 16 );
559 mbStatus = true;
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 )
575 return &(*it);
577 return NULL;
580 void PropRead::Read()
582 maSections.clear();
584 if ( mbStatus )
586 sal_uInt32 nSections;
587 sal_uInt32 nSectionOfs;
588 sal_uInt32 nCurrent;
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
597 mbStatus = false;
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 );
610 delete[] pSectCLSID;
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();
630 return *this;
633 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */