bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / filter / ppt / propread.cxx
blob71472b2f9515676e0ad6c27465281f1f1a4f92c9
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 <memory>
21 #include "propread.hxx"
22 #include <rtl/tencinfo.h>
23 #include <rtl/textenc.h>
24 #include <sal/log.hxx>
25 #include <osl/diagnose.h>
27 PropEntry::PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize ) :
28 mnId ( nId ),
29 mnSize ( nBufSize ),
30 mpBuf ( new sal_uInt8[ nBufSize ] )
32 memcpy( mpBuf.get(), pBuf, nBufSize );
35 PropEntry::PropEntry( const PropEntry& rProp ) :
36 mnId ( rProp.mnId ),
37 mnSize ( rProp.mnSize ),
38 mpBuf ( new sal_uInt8[ mnSize ] )
40 memcpy( mpBuf.get(), rProp.mpBuf.get(), mnSize );
43 PropEntry& PropEntry::operator=(const PropEntry& rPropEntry)
45 if ( this != &rPropEntry )
47 mnId = rPropEntry.mnId;
48 mnSize = rPropEntry.mnSize;
49 mpBuf.reset( new sal_uInt8[ mnSize ] );
50 memcpy( mpBuf.get(), rPropEntry.mpBuf.get(), mnSize );
52 return *this;
55 void PropItem::Clear()
57 Seek( STREAM_SEEK_TO_BEGIN );
58 delete[] static_cast<sal_uInt8*>(SwitchBuffer());
61 static sal_Int32 lcl_getMaxSafeStrLen(sal_uInt32 nSize)
63 nSize -= 1; //Drop NULL terminator
65 //If it won't fit in a string, clip it to the max size that does
66 if (nSize > SAL_MAX_INT32)
67 nSize = SAL_MAX_INT32;
69 return static_cast< sal_Int32 >( nSize );
72 bool PropItem::Read( OUString& rString, sal_uInt32 nStringType, bool bAlign )
74 sal_uInt32 nType, nItemPos;
75 bool bRetValue = false;
77 nItemPos = Tell();
79 if ( nStringType == VT_EMPTY )
81 nType = VT_NULL; // Initialize in case stream fails.
82 ReadUInt32( nType );
84 else
85 nType = nStringType & VT_TYPEMASK;
87 sal_uInt32 nItemSize(0); // Initialize in case stream fails.
88 ReadUInt32(nItemSize);
90 switch( nType )
92 case VT_LPSTR :
94 if (nItemSize)
96 auto nMaxSizePossible = remainingSize();
97 if (nItemSize > nMaxSizePossible)
99 SAL_WARN("sd.filter", "String of Len " << nItemSize << " claimed, only " << nMaxSizePossible << " possible");
100 nItemSize = nMaxSizePossible;
104 if (nItemSize)
108 std::unique_ptr<sal_Char[]> pString( new sal_Char[ nItemSize ] );
109 if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
111 nItemSize >>= 1;
112 if ( nItemSize > 1 )
114 sal_Unicode* pWString = reinterpret_cast<sal_Unicode*>(pString.get());
115 for (sal_uInt32 i = 0; i < nItemSize; ++i)
116 ReadUtf16( pWString[ i ] );
117 rString = OUString(pWString, lcl_getMaxSafeStrLen(nItemSize));
119 else
120 rString.clear();
121 bRetValue = true;
123 else
125 SvMemoryStream::ReadBytes(pString.get(), nItemSize);
126 if ( pString[ nItemSize - 1 ] == 0 )
128 if ( nItemSize > 1 )
129 rString = OUString(pString.get(), rtl_str_getLength(pString.get()), mnTextEnc);
130 else
131 rString.clear();
132 bRetValue = true;
136 catch( const std::bad_alloc& )
138 OSL_FAIL( "sd PropItem::Read bad alloc" );
141 if ( bAlign )
142 SeekRel( ( 4 - ( nItemSize & 3 ) ) & 3 ); // dword align
144 break;
146 case VT_LPWSTR :
148 if (nItemSize)
150 auto nMaxSizePossible = remainingSize() / sizeof(sal_Unicode);
151 if (nItemSize > nMaxSizePossible)
153 SAL_WARN("sd.filter", "String of Len " << nItemSize << " claimed, only " << nMaxSizePossible << " possible");
154 nItemSize = nMaxSizePossible;
158 if (nItemSize)
162 std::unique_ptr<sal_Unicode[]> pString( new sal_Unicode[ nItemSize ] );
163 for (sal_uInt32 i = 0; i < nItemSize; ++i)
164 ReadUtf16( pString[ i ] );
165 if ( pString[ nItemSize - 1 ] == 0 )
167 if ( static_cast<sal_uInt16>(nItemSize) > 1 )
168 rString = OUString(pString.get(), lcl_getMaxSafeStrLen(nItemSize));
169 else
170 rString.clear();
171 bRetValue = true;
174 catch( const std::bad_alloc& )
176 OSL_FAIL( "sd PropItem::Read bad alloc" );
179 if ( bAlign && ( nItemSize & 1 ) )
180 SeekRel( 2 ); // dword align
182 break;
184 if ( !bRetValue )
185 Seek( nItemPos );
186 return bRetValue;
189 PropItem& PropItem::operator=( PropItem& rPropItem )
191 if ( this != &rPropItem )
193 Seek( STREAM_SEEK_TO_BEGIN );
194 delete[] static_cast<sal_uInt8*>(SwitchBuffer());
196 mnTextEnc = rPropItem.mnTextEnc;
197 SvMemoryStream::WriteBytes(rPropItem.GetData(), rPropItem.TellEnd());
199 return *this;
202 Section::Section( const Section& rSection )
203 : mnTextEnc(rSection.mnTextEnc)
205 for ( int i = 0; i < 16; i++ )
206 aFMTID[ i ] = rSection.aFMTID[ i ];
207 for(const std::unique_ptr<PropEntry>& rEntry : rSection.maEntries)
208 maEntries.push_back(std::make_unique<PropEntry>(*rEntry));
211 Section::Section( const sal_uInt8* pFMTID )
213 mnTextEnc = RTL_TEXTENCODING_MS_1252;
214 for ( int i = 0; i < 16; i++ )
215 aFMTID[ i ] = pFMTID[ i ];
218 bool Section::GetProperty( sal_uInt32 nId, PropItem& rPropItem )
220 if ( nId )
222 auto iter = std::find_if(maEntries.begin(), maEntries.end(),
223 [nId](const std::unique_ptr<PropEntry>& rxEntry) { return rxEntry->mnId == nId; });
225 if (iter != maEntries.end())
227 rPropItem.Clear();
228 rPropItem.SetTextEncoding( mnTextEnc );
229 rPropItem.WriteBytes( (*iter)->mpBuf.get(), (*iter)->mnSize );
230 rPropItem.Seek( STREAM_SEEK_TO_BEGIN );
231 return true;
234 return false;
237 void Section::AddProperty( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize )
239 // just a simple id check
241 if ( !nId )
242 return;
243 if ( nId == 0xffffffff )
244 nId = 0;
246 // do not allow same PropId's, sort
247 auto iter = std::find_if(maEntries.begin(), maEntries.end(),
248 [nId](const std::unique_ptr<PropEntry>& rxEntry) { return rxEntry->mnId >= nId; });
249 if (iter != maEntries.end())
251 if ( (*iter)->mnId == nId )
252 (*iter).reset(new PropEntry( nId, pBuf, nBufSize ));
253 else
254 maEntries.insert( iter, std::make_unique<PropEntry>( nId, pBuf, nBufSize ));
256 else
258 maEntries.push_back( std::make_unique<PropEntry>( nId, pBuf, nBufSize ) );
262 void Section::GetDictionary(Dictionary& rDict)
264 auto iter = std::find_if(maEntries.begin(), maEntries.end(),
265 [](const std::unique_ptr<PropEntry>& rxEntry) { return rxEntry->mnId == 0; });
267 if (iter == maEntries.end())
268 return;
270 SvMemoryStream aStream( (*iter)->mpBuf.get(), (*iter)->mnSize, StreamMode::READ );
271 aStream.Seek( STREAM_SEEK_TO_BEGIN );
272 sal_uInt32 nDictCount(0);
273 aStream.ReadUInt32( nDictCount );
274 for (sal_uInt32 i = 0; i < nDictCount; ++i)
276 sal_uInt32 nId(0), nSize(0);
277 aStream.ReadUInt32(nId).ReadUInt32(nSize);
278 if (!aStream.good() || nSize > aStream.remainingSize())
279 break;
280 if (mnTextEnc == RTL_TEXTENCODING_UCS2)
281 nSize >>= 1;
282 if (!nSize)
283 continue;
284 OUString aString;
287 if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
289 std::unique_ptr<sal_Unicode[]> pWString( new sal_Unicode[nSize] );
290 for (sal_uInt32 j = 0; j < nSize; ++j)
291 aStream.ReadUtf16(pWString[j]);
292 aString = OUString(pWString.get(), lcl_getMaxSafeStrLen(nSize));
294 else
296 std::unique_ptr<sal_Char[]> pString( new sal_Char[nSize] );
297 aStream.ReadBytes(pString.get(), nSize);
298 aString = OUString(pString.get(), lcl_getMaxSafeStrLen(nSize), mnTextEnc);
301 catch( const std::bad_alloc& )
303 OSL_FAIL( "sd Section::GetDictionary bad alloc" );
305 if (aString.isEmpty())
306 break;
307 rDict.insert( std::make_pair(aString,nId) );
311 void Section::Read( SotStorageStream *pStrm )
313 sal_uInt32 nSecOfs = pStrm->Tell();
314 sal_uInt32 nStrmSize = pStrm->remainingSize();
316 mnTextEnc = RTL_TEXTENCODING_MS_1252;
317 sal_uInt32 nSecSize(0), nPropCount(0);
318 pStrm->ReadUInt32(nSecSize).ReadUInt32(nPropCount);
319 if (nSecSize > nStrmSize)
321 SAL_WARN("sd.filter", "Section Len " << nSecSize << " claimed, only " << nStrmSize << " possible");
322 nSecSize = nStrmSize;
325 while (nPropCount--)
327 sal_uInt32 nPropId(0), nPropOfs(0);
328 pStrm->ReadUInt32(nPropId).ReadUInt32(nPropOfs);
329 if (!pStrm->good())
330 break;
331 auto nCurrent = pStrm->Tell();
332 sal_uInt64 nOffset = nPropOfs + nSecOfs;
333 if (!checkSeek(*pStrm, nOffset))
334 break;
335 if ( nPropId ) // do not read dictionary
337 sal_uInt32 nPropType(0), nVectorCount(0);
338 pStrm->ReadUInt32(nPropType);
340 sal_uInt32 nPropSize = 4;
341 if ( nPropType & VT_VECTOR )
343 pStrm->ReadUInt32( nVectorCount );
344 nPropType &=~VT_VECTOR;
345 nPropSize += 4;
347 else
348 nVectorCount = 1;
350 bool bVariant = ( nPropType == VT_VARIANT );
352 for (sal_uInt32 i = 0; nPropSize && ( i < nVectorCount ); ++i)
354 if ( bVariant )
356 pStrm->ReadUInt32( nPropType );
357 nPropSize += 4;
359 sal_uInt32 nTemp(0);
360 switch( nPropType )
362 case VT_UI1 :
363 nPropSize++;
364 break;
366 case VT_I2 :
367 case VT_UI2 :
368 case VT_BOOL :
369 nPropSize += 2;
370 break;
372 case VT_I4 :
373 case VT_R4 :
374 case VT_UI4 :
375 case VT_ERROR :
376 nPropSize += 4;
377 break;
379 case VT_I8 :
380 case VT_R8 :
381 case VT_CY :
382 case VT_UI8 :
383 case VT_DATE :
384 case VT_FILETIME :
385 nPropSize += 8;
386 break;
388 case VT_BSTR :
389 pStrm->ReadUInt32( nTemp );
390 nPropSize += ( nTemp + 4 );
391 break;
393 case VT_LPSTR :
394 pStrm->ReadUInt32( nTemp );
395 nPropSize += ( nTemp + 4 );
396 break;
398 case VT_LPWSTR :
400 pStrm->ReadUInt32( nTemp );
401 // looks like these are aligned to 4 bytes
402 sal_uInt32 nLength = nPropOfs + nSecOfs + nPropSize + ( nTemp << 1 ) + 4;
403 nPropSize += ( nTemp << 1 ) + 4 + (nLength % 4);
405 break;
407 case VT_BLOB_OBJECT :
408 case VT_BLOB :
409 case VT_CF :
410 pStrm->ReadUInt32( nTemp );
411 nPropSize += ( nTemp + 4 );
412 break;
414 case VT_CLSID :
415 case VT_STREAM :
416 case VT_STORAGE :
417 case VT_STREAMED_OBJECT :
418 case VT_STORED_OBJECT :
419 case VT_VARIANT :
420 case VT_VECTOR :
421 default :
422 nPropSize = 0;
424 if ( nPropSize )
426 if ( ( nVectorCount - i ) > 1 )
428 nOffset = nPropOfs + nSecOfs + nPropSize;
429 if (!checkSeek(*pStrm, nOffset))
430 break;
433 else
434 break;
436 if ( nPropSize )
438 if ( nPropSize > nStrmSize )
440 break;
442 pStrm->Seek( nPropOfs + nSecOfs );
443 // make sure we don't overflow the section size
444 if( nPropSize > nSecSize - nSecOfs )
445 nPropSize = nSecSize - nSecOfs;
446 std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nPropSize ] );
447 nPropSize = pStrm->ReadBytes(pBuf.get(), nPropSize);
448 AddProperty( nPropId, pBuf.get(), nPropSize );
450 if ( nPropId == 1 )
452 PropItem aPropItem;
453 if ( GetProperty( 1, aPropItem ) )
455 aPropItem.ReadUInt32( nPropType );
456 if ( nPropType == VT_I2 )
458 sal_uInt16 nCodePage(0);
459 aPropItem.ReadUInt16(nCodePage);
461 if ( nCodePage == 1200 )
463 mnTextEnc = RTL_TEXTENCODING_UCS2;
465 else
467 mnTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
468 if ( mnTextEnc == RTL_TEXTENCODING_DONTKNOW )
469 mnTextEnc = RTL_TEXTENCODING_MS_1252;
472 else
474 mnTextEnc = RTL_TEXTENCODING_MS_1252;
479 else
481 sal_uInt32 nDictCount(0);
482 pStrm->ReadUInt32(nDictCount);
483 auto nMaxRecordsPossible = pStrm->remainingSize() / (sizeof(sal_uInt32)*2);
484 if (nDictCount > nMaxRecordsPossible)
486 SAL_WARN("sd.filter", "Dictionary count of " << nDictCount << " claimed, only " << nMaxRecordsPossible << " possible");
487 nDictCount = nMaxRecordsPossible;
489 for (sal_uInt32 i = 0; i < nDictCount; ++i)
491 sal_uInt32 nSize(0);
492 pStrm->ReadUInt32( nSize ).ReadUInt32( nSize );
493 if (!pStrm->good())
494 break;
495 sal_uInt64 nPos = pStrm->Tell() + nSize;
496 if (!checkSeek(*pStrm, nPos))
497 break;
499 sal_uInt32 nSize = pStrm->Tell();
500 pStrm->Seek( nPropOfs + nSecOfs );
501 nSize -= pStrm->Tell();
502 if ( nSize > nStrmSize )
504 break;
506 std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nSize ] );
507 nSize = pStrm->ReadBytes(pBuf.get(), nSize);
508 AddProperty( 0xffffffff, pBuf.get(), nSize );
510 pStrm->Seek(nCurrent);
512 pStrm->Seek(nSecOfs + nSecSize);
515 Section& Section::operator=( const Section& rSection )
517 if ( this != &rSection )
519 memcpy( static_cast<void*>(aFMTID), static_cast<void const *>(rSection.aFMTID), 16 );
521 for(const std::unique_ptr<PropEntry>& rEntry : rSection.maEntries)
522 maEntries.push_back(std::make_unique<PropEntry>(*rEntry));
524 return *this;
527 PropRead::PropRead( SotStorage& rStorage, const OUString& rName ) :
528 mbStatus ( false ),
529 mnByteOrder ( 0xfffe )
531 if ( rStorage.IsStream( rName ) )
533 mpSvStream = rStorage.OpenSotStream( rName, StreamMode::STD_READ );
534 if ( mpSvStream.is() )
536 mpSvStream->SetEndian( SvStreamEndian::LITTLE );
537 memset( mApplicationCLSID, 0, 16 );
538 mbStatus = true;
543 const Section* PropRead::GetSection( const sal_uInt8* pFMTID )
545 auto it = std::find_if(maSections.begin(), maSections.end(),
546 [&pFMTID](const std::unique_ptr<Section>& rxSection) { return memcmp( rxSection->GetFMTID(), pFMTID, 16 ) == 0; });
547 if (it != maSections.end())
548 return it->get();
549 return nullptr;
552 void PropRead::Read()
554 maSections.clear();
556 if ( !mbStatus )
557 return;
559 sal_uInt16 mnVersionLo;
560 sal_uInt16 mnVersionHi;
561 sal_uInt16 mnFormat;
562 mpSvStream->ReadUInt16( mnByteOrder ).ReadUInt16( mnFormat ).ReadUInt16( mnVersionLo ).ReadUInt16( mnVersionHi );
563 if ( mnByteOrder != 0xfffe )
564 return;
566 std::vector<sal_uInt8> aSectCLSID(16);
567 mpSvStream->ReadBytes(mApplicationCLSID, 16);
568 sal_uInt32 nSections(0);
569 mpSvStream->ReadUInt32(nSections);
570 if ( nSections > 2 ) // sj: PowerPoint documents are containing max 2 sections
572 mbStatus = false;
574 else for ( sal_uInt32 i = 0; i < nSections; i++ )
576 mpSvStream->ReadBytes(aSectCLSID.data(), aSectCLSID.size());
577 sal_uInt32 nSectionOfs(0);
578 mpSvStream->ReadUInt32( nSectionOfs );
579 sal_uInt32 nCurrent = mpSvStream->Tell();
580 if (checkSeek(*mpSvStream, nSectionOfs))
582 Section aSection(aSectCLSID.data());
583 aSection.Read(mpSvStream.get());
584 maSections.push_back(std::make_unique<Section>(aSection));
586 mpSvStream->Seek( nCurrent );
590 PropRead& PropRead::operator=( const PropRead& rPropRead )
592 if ( this != &rPropRead )
594 mbStatus = rPropRead.mbStatus;
595 mpSvStream = rPropRead.mpSvStream;
597 mnByteOrder = rPropRead.mnByteOrder;
598 memcpy( mApplicationCLSID, rPropRead.mApplicationCLSID, 16 );
600 for(const std::unique_ptr<Section>& rSection : rPropRead.maSections)
601 maSections.push_back(std::make_unique<Section>(*rSection));
603 return *this;
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */