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 .
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
) :
30 mpBuf ( new sal_uInt8
[ nBufSize
] )
32 memcpy( mpBuf
.get(), pBuf
, nBufSize
);
35 PropEntry::PropEntry( const PropEntry
& rProp
) :
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
);
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;
79 if ( nStringType
== VT_EMPTY
)
81 nType
= VT_NULL
; // Initialize in case stream fails.
85 nType
= nStringType
& VT_TYPEMASK
;
87 sal_uInt32
nItemSize(0); // Initialize in case stream fails.
88 ReadUInt32(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
;
108 std::unique_ptr
<sal_Char
[]> pString( new sal_Char
[ nItemSize
] );
109 if ( mnTextEnc
== RTL_TEXTENCODING_UCS2
)
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
));
125 SvMemoryStream::ReadBytes(pString
.get(), nItemSize
);
126 if ( pString
[ nItemSize
- 1 ] == 0 )
129 rString
= OUString(pString
.get(), rtl_str_getLength(pString
.get()), mnTextEnc
);
136 catch( const std::bad_alloc
& )
138 OSL_FAIL( "sd PropItem::Read bad alloc" );
142 SeekRel( ( 4 - ( nItemSize
& 3 ) ) & 3 ); // dword align
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
;
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
));
174 catch( const std::bad_alloc
& )
176 OSL_FAIL( "sd PropItem::Read bad alloc" );
179 if ( bAlign
&& ( nItemSize
& 1 ) )
180 SeekRel( 2 ); // dword align
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());
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
)
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())
228 rPropItem
.SetTextEncoding( mnTextEnc
);
229 rPropItem
.WriteBytes( (*iter
)->mpBuf
.get(), (*iter
)->mnSize
);
230 rPropItem
.Seek( STREAM_SEEK_TO_BEGIN
);
237 void Section::AddProperty( sal_uInt32 nId
, const sal_uInt8
* pBuf
, sal_uInt32 nBufSize
)
239 // just a simple id check
243 if ( nId
== 0xffffffff )
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
));
254 maEntries
.insert( iter
, std::make_unique
<PropEntry
>( nId
, pBuf
, nBufSize
));
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())
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())
280 if (mnTextEnc
== RTL_TEXTENCODING_UCS2
)
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
));
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())
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
;
327 sal_uInt32
nPropId(0), nPropOfs(0);
328 pStrm
->ReadUInt32(nPropId
).ReadUInt32(nPropOfs
);
331 auto nCurrent
= pStrm
->Tell();
332 sal_uInt64 nOffset
= nPropOfs
+ nSecOfs
;
333 if (!checkSeek(*pStrm
, nOffset
))
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
;
350 bool bVariant
= ( nPropType
== VT_VARIANT
);
352 for (sal_uInt32 i
= 0; nPropSize
&& ( i
< nVectorCount
); ++i
)
356 pStrm
->ReadUInt32( nPropType
);
389 pStrm
->ReadUInt32( nTemp
);
390 nPropSize
+= ( nTemp
+ 4 );
394 pStrm
->ReadUInt32( nTemp
);
395 nPropSize
+= ( nTemp
+ 4 );
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);
407 case VT_BLOB_OBJECT
:
410 pStrm
->ReadUInt32( nTemp
);
411 nPropSize
+= ( nTemp
+ 4 );
417 case VT_STREAMED_OBJECT
:
418 case VT_STORED_OBJECT
:
426 if ( ( nVectorCount
- i
) > 1 )
428 nOffset
= nPropOfs
+ nSecOfs
+ nPropSize
;
429 if (!checkSeek(*pStrm
, nOffset
))
438 if ( nPropSize
> nStrmSize
)
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
);
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
;
467 mnTextEnc
= rtl_getTextEncodingFromWindowsCodePage( nCodePage
);
468 if ( mnTextEnc
== RTL_TEXTENCODING_DONTKNOW
)
469 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
474 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
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
)
492 pStrm
->ReadUInt32( nSize
).ReadUInt32( nSize
);
495 sal_uInt64 nPos
= pStrm
->Tell() + nSize
;
496 if (!checkSeek(*pStrm
, nPos
))
499 sal_uInt32 nSize
= pStrm
->Tell();
500 pStrm
->Seek( nPropOfs
+ nSecOfs
);
501 nSize
-= pStrm
->Tell();
502 if ( nSize
> nStrmSize
)
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
));
527 PropRead::PropRead( SotStorage
& rStorage
, const OUString
& rName
) :
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 );
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())
552 void PropRead::Read()
559 sal_uInt16 mnVersionLo
;
560 sal_uInt16 mnVersionHi
;
562 mpSvStream
->ReadUInt16( mnByteOrder
).ReadUInt16( mnFormat
).ReadUInt16( mnVersionLo
).ReadUInt16( mnVersionHi
);
563 if ( mnByteOrder
!= 0xfffe )
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
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
));
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */