tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sd / source / filter / ppt / propread.cxx
blob436c80cc4d0e9fc382ead13e5ee61220d46a8de9
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 <sal/log.hxx>
24 #include <o3tl/sorted_vector.hxx>
25 #include <osl/diagnose.h>
26 #include <memory>
28 PropEntry::PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize ) :
29 mnId ( nId ),
30 mnSize ( nBufSize ),
31 mpBuf ( new sal_uInt8[ nBufSize ] )
33 memcpy( mpBuf.get(), pBuf, nBufSize );
36 PropEntry::PropEntry( const PropEntry& rProp ) :
37 mnId ( rProp.mnId ),
38 mnSize ( rProp.mnSize ),
39 mpBuf ( new sal_uInt8[ mnSize ] )
41 memcpy( mpBuf.get(), rProp.mpBuf.get(), mnSize );
44 PropEntry& PropEntry::operator=(const PropEntry& rPropEntry)
46 if ( this != &rPropEntry )
48 mnId = rPropEntry.mnId;
49 mnSize = rPropEntry.mnSize;
50 mpBuf.reset( new sal_uInt8[ mnSize ] );
51 memcpy( mpBuf.get(), rPropEntry.mpBuf.get(), mnSize );
53 return *this;
56 void PropItem::Clear()
58 Seek( STREAM_SEEK_TO_BEGIN );
59 delete[] static_cast<sal_uInt8*>(SwitchBuffer());
62 static sal_Int32 lcl_getMaxSafeStrLen(sal_uInt32 nSize)
64 nSize -= 1; //Drop NULL terminator
66 //If it won't fit in a string, clip it to the max size that does
67 if (nSize > SAL_MAX_INT32)
68 nSize = SAL_MAX_INT32;
70 return static_cast< sal_Int32 >( nSize );
73 bool PropItem::Read( OUString& rString, sal_uInt32 nStringType, bool bAlign )
75 sal_uInt32 nType, nItemPos;
76 bool bRetValue = false;
78 nItemPos = Tell();
80 if ( nStringType == VT_EMPTY )
82 nType = VT_NULL; // Initialize in case stream fails.
83 ReadUInt32( nType );
85 else
86 nType = nStringType & VT_TYPEMASK;
88 sal_uInt32 nItemSize(0); // Initialize in case stream fails.
89 ReadUInt32(nItemSize);
91 switch( nType )
93 case VT_LPSTR :
95 if (nItemSize > 0)
97 auto nMaxSizePossible = remainingSize();
98 if (nItemSize > nMaxSizePossible)
100 SAL_WARN("sd.filter", "String of Len " << nItemSize << " claimed, only " << nMaxSizePossible << " possible");
101 nItemSize = nMaxSizePossible;
105 if (nItemSize > 0)
109 std::unique_ptr<char[]> pString( new char[ nItemSize ] );
110 if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
112 nItemSize >>= 1;
113 if ( nItemSize > 1 )
115 sal_Unicode* pWString = reinterpret_cast<sal_Unicode*>(pString.get());
116 for (sal_uInt32 i = 0; i < nItemSize; ++i)
117 ReadUtf16( pWString[ i ] );
118 rString = OUString(pWString, lcl_getMaxSafeStrLen(nItemSize));
120 else
121 rString.clear();
122 bRetValue = true;
124 else
126 SvMemoryStream::ReadBytes(pString.get(), nItemSize);
127 if ( pString[ nItemSize - 1 ] == 0 )
129 if ( nItemSize > 1 )
130 rString = OUString(pString.get(), rtl_str_getLength(pString.get()), mnTextEnc);
131 else
132 rString.clear();
133 bRetValue = true;
137 catch( const std::bad_alloc& )
139 OSL_FAIL( "sd PropItem::Read bad alloc" );
142 if ( bAlign )
143 SeekRel( ( 4 - ( nItemSize & 3 ) ) & 3 ); // dword align
145 break;
147 case VT_LPWSTR :
149 if (nItemSize)
151 auto nMaxSizePossible = remainingSize() / sizeof(sal_Unicode);
152 if (nItemSize > nMaxSizePossible)
154 SAL_WARN("sd.filter", "String of Len " << nItemSize << " claimed, only " << nMaxSizePossible << " possible");
155 nItemSize = nMaxSizePossible;
159 if (nItemSize)
163 std::unique_ptr<sal_Unicode[]> pString( new sal_Unicode[ nItemSize ] );
164 for (sal_uInt32 i = 0; i < nItemSize; ++i)
165 ReadUtf16( pString[ i ] );
166 if ( pString[ nItemSize - 1 ] == 0 )
168 if ( static_cast<sal_uInt16>(nItemSize) > 1 )
169 rString = OUString(pString.get(), lcl_getMaxSafeStrLen(nItemSize));
170 else
171 rString.clear();
172 bRetValue = true;
175 catch( const std::bad_alloc& )
177 OSL_FAIL( "sd PropItem::Read bad alloc" );
180 if ( bAlign && ( nItemSize & 1 ) )
181 SeekRel( 2 ); // dword align
183 break;
185 if ( !bRetValue )
186 Seek( nItemPos );
187 return bRetValue;
190 PropItem& PropItem::operator=( PropItem& rPropItem )
192 if ( this != &rPropItem )
194 Seek( STREAM_SEEK_TO_BEGIN );
195 delete[] static_cast<sal_uInt8*>(SwitchBuffer());
197 mnTextEnc = rPropItem.mnTextEnc;
198 SvMemoryStream::WriteBytes(rPropItem.GetData(), rPropItem.TellEnd());
200 return *this;
203 Section::Section( const Section& rSection )
204 : mnTextEnc(rSection.mnTextEnc)
206 for ( int i = 0; i < 16; i++ )
207 aFMTID[ i ] = rSection.aFMTID[ i ];
208 for(const std::unique_ptr<PropEntry>& rEntry : rSection.maEntries)
209 maEntries.push_back(std::make_unique<PropEntry>(*rEntry));
212 Section::Section( const sal_uInt8* pFMTID ) : 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(PropDictionary& 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<char[]> pString( new 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_uInt64 nSecOfs = pStrm->Tell();
314 sal_uInt64 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 > 0)
327 --nPropCount;
328 sal_uInt32 nPropId(0), nPropOfs(0);
329 pStrm->ReadUInt32(nPropId).ReadUInt32(nPropOfs);
330 if (!pStrm->good())
331 break;
332 auto nCurrent = pStrm->Tell();
333 sal_uInt64 nOffset = nPropOfs + nSecOfs;
334 if (!checkSeek(*pStrm, nOffset))
335 break;
336 if ( nPropId ) // do not read dictionary
338 sal_uInt32 nPropType(0), nVectorCount(0);
339 pStrm->ReadUInt32(nPropType);
341 sal_uInt32 nPropSize = 4;
342 if ( nPropType & VT_VECTOR )
344 pStrm->ReadUInt32( nVectorCount );
345 nPropType &=~VT_VECTOR;
346 nPropSize += 4;
348 else
349 nVectorCount = 1;
351 bool bVariant = ( nPropType == VT_VARIANT );
353 o3tl::sorted_vector<sal_uInt64> aVisitedOffsets;
355 for (sal_uInt32 i = 0; nPropSize && i < nVectorCount && pStrm->good(); ++i)
357 if ( bVariant )
359 pStrm->ReadUInt32( nPropType );
360 nPropSize += 4;
362 sal_uInt32 nTemp(0);
363 switch( nPropType )
365 case VT_UI1 :
366 nPropSize++;
367 break;
369 case VT_I2 :
370 case VT_UI2 :
371 case VT_BOOL :
372 nPropSize += 2;
373 break;
375 case VT_I4 :
376 case VT_R4 :
377 case VT_UI4 :
378 case VT_ERROR :
379 nPropSize += 4;
380 break;
382 case VT_I8 :
383 case VT_R8 :
384 case VT_CY :
385 case VT_UI8 :
386 case VT_DATE :
387 case VT_FILETIME :
388 nPropSize += 8;
389 break;
391 case VT_BSTR :
392 pStrm->ReadUInt32( nTemp );
393 nPropSize += ( nTemp + 4 );
394 break;
396 case VT_LPSTR :
397 pStrm->ReadUInt32( nTemp );
398 nPropSize += ( nTemp + 4 );
399 break;
401 case VT_LPWSTR :
403 pStrm->ReadUInt32( nTemp );
404 // looks like these are aligned to 4 bytes
405 sal_uInt64 nLength = nPropOfs + nSecOfs + nPropSize + ( nTemp << 1 ) + 4;
406 nPropSize += ( nTemp << 1 ) + 4 + (nLength % 4);
408 break;
410 case VT_BLOB_OBJECT :
411 case VT_BLOB :
412 case VT_CF :
413 pStrm->ReadUInt32( nTemp );
414 nPropSize += ( nTemp + 4 );
415 break;
417 case VT_CLSID :
418 case VT_STREAM :
419 case VT_STORAGE :
420 case VT_STREAMED_OBJECT :
421 case VT_STORED_OBJECT :
422 case VT_VARIANT :
423 case VT_VECTOR :
424 default :
425 nPropSize = 0;
427 if ( nPropSize )
429 if ( ( nVectorCount - i ) > 1 )
431 nOffset = nPropOfs + nSecOfs + nPropSize;
432 if (!checkSeek(*pStrm, nOffset))
433 break;
434 // inserts returns false if an equivalent element already existed
435 if (!aVisitedOffsets.insert(nOffset).second)
437 SAL_WARN("sd.filter", "loop in Section::Read property list");
438 break;
442 else
443 break;
445 if ( nPropSize )
447 if ( nPropSize > nStrmSize )
449 break;
451 pStrm->Seek( nPropOfs + nSecOfs );
452 // make sure we don't overflow the section size
453 if( nPropSize > nSecSize - nSecOfs )
454 nPropSize = nSecSize - nSecOfs;
455 std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nPropSize ] );
456 nPropSize = pStrm->ReadBytes(pBuf.get(), nPropSize);
457 AddProperty( nPropId, pBuf.get(), nPropSize );
459 if ( nPropId == 1 )
461 PropItem aPropItem;
462 if ( GetProperty( 1, aPropItem ) )
464 aPropItem.ReadUInt32( nPropType );
465 if ( nPropType == VT_I2 )
467 sal_uInt16 nCodePage(0);
468 aPropItem.ReadUInt16(nCodePage);
470 if ( nCodePage == 1200 )
472 mnTextEnc = RTL_TEXTENCODING_UCS2;
474 else
476 mnTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
477 if ( mnTextEnc == RTL_TEXTENCODING_DONTKNOW )
478 mnTextEnc = RTL_TEXTENCODING_MS_1252;
481 else
483 mnTextEnc = RTL_TEXTENCODING_MS_1252;
488 else
490 sal_uInt32 nDictCount(0);
491 pStrm->ReadUInt32(nDictCount);
492 auto nMaxRecordsPossible = pStrm->remainingSize() / (sizeof(sal_uInt32)*2);
493 if (nDictCount > nMaxRecordsPossible)
495 SAL_WARN("sd.filter", "Dictionary count of " << nDictCount << " claimed, only " << nMaxRecordsPossible << " possible");
496 nDictCount = nMaxRecordsPossible;
498 for (sal_uInt32 i = 0; i < nDictCount; ++i)
500 sal_uInt32 nSize(0);
501 pStrm->ReadUInt32( nSize ).ReadUInt32( nSize );
502 if (!pStrm->good())
503 break;
504 sal_uInt64 nPos = pStrm->Tell() + nSize;
505 if (!checkSeek(*pStrm, nPos))
506 break;
508 sal_uInt64 nSize = pStrm->Tell();
509 pStrm->Seek( nPropOfs + nSecOfs );
510 nSize -= pStrm->Tell();
511 if ( nSize > nStrmSize )
513 break;
515 std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nSize ] );
516 nSize = pStrm->ReadBytes(pBuf.get(), nSize);
517 AddProperty( 0xffffffff, pBuf.get(), nSize );
519 pStrm->Seek(nCurrent);
521 pStrm->Seek(nSecOfs + nSecSize);
524 Section& Section::operator=( const Section& rSection )
526 if ( this != &rSection )
528 memcpy( static_cast<void*>(aFMTID), static_cast<void const *>(rSection.aFMTID), 16 );
530 for(const std::unique_ptr<PropEntry>& rEntry : rSection.maEntries)
531 maEntries.push_back(std::make_unique<PropEntry>(*rEntry));
533 return *this;
536 PropRead::PropRead( SotStorage& rStorage, const OUString& rName ) :
537 mbStatus ( false ),
538 mnByteOrder ( 0xfffe )
540 if ( rStorage.IsStream( rName ) )
542 mpSvStream = rStorage.OpenSotStream( rName, StreamMode::STD_READ );
543 if ( mpSvStream.is() )
545 mpSvStream->SetEndian( SvStreamEndian::LITTLE );
546 memset( mApplicationCLSID, 0, 16 );
547 mbStatus = true;
552 const Section* PropRead::GetSection( const sal_uInt8* pFMTID )
554 auto it = std::find_if(maSections.begin(), maSections.end(),
555 [&pFMTID](const std::unique_ptr<Section>& rxSection) { return memcmp( rxSection->GetFMTID(), pFMTID, 16 ) == 0; });
556 if (it != maSections.end())
557 return it->get();
558 return nullptr;
561 void PropRead::Read()
563 maSections.clear();
565 if ( !mbStatus )
566 return;
568 sal_uInt16 mnVersionLo;
569 sal_uInt16 mnVersionHi;
570 sal_uInt16 mnFormat;
571 mpSvStream->ReadUInt16( mnByteOrder ).ReadUInt16( mnFormat ).ReadUInt16( mnVersionLo ).ReadUInt16( mnVersionHi );
572 if ( mnByteOrder != 0xfffe )
573 return;
575 std::vector<sal_uInt8> aSectCLSID(16);
576 mpSvStream->ReadBytes(mApplicationCLSID, 16);
577 sal_uInt32 nSections(0);
578 mpSvStream->ReadUInt32(nSections);
579 if ( nSections > 2 ) // sj: PowerPoint documents are containing max 2 sections
581 mbStatus = false;
583 else
584 for ( sal_uInt32 i = 0; i < nSections; i++ )
586 mpSvStream->ReadBytes(aSectCLSID.data(), aSectCLSID.size());
587 sal_uInt32 nSectionOfs(0);
588 mpSvStream->ReadUInt32( nSectionOfs );
589 sal_uInt64 nCurrent = mpSvStream->Tell();
590 if (checkSeek(*mpSvStream, nSectionOfs))
592 Section aSection(aSectCLSID.data());
593 aSection.Read(mpSvStream.get());
594 maSections.push_back(std::make_unique<Section>(aSection));
596 mpSvStream->Seek( nCurrent );
600 PropRead& PropRead::operator=( const PropRead& rPropRead )
602 if ( this != &rPropRead )
604 mbStatus = rPropRead.mbStatus;
605 mpSvStream = rPropRead.mpSvStream;
607 mnByteOrder = rPropRead.mnByteOrder;
608 memcpy( mApplicationCLSID, rPropRead.mApplicationCLSID, 16 );
610 for(const std::unique_ptr<Section>& rSection : rPropRead.maSections)
611 maSections.push_back(std::make_unique<Section>(*rSection));
613 return *this;
616 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */