Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <propread.hxx>
21 : #include "rtl/tencinfo.h"
22 : #include "rtl/textenc.h"
23 : #include <osl/diagnose.h>
24 :
25 98 : 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 98 : mpBuf ( new sal_uInt8[ nBufSize ] )
30 : {
31 98 : memcpy( static_cast<void*>(mpBuf), static_cast<void const *>(pBuf), nBufSize );
32 98 : };
33 :
34 98 : PropEntry::PropEntry( const PropEntry& rProp ) :
35 : mnId ( rProp.mnId ),
36 : mnSize ( rProp.mnSize ),
37 : mnTextEnc ( rProp.mnTextEnc ),
38 98 : mpBuf ( new sal_uInt8[ mnSize ] )
39 : {
40 98 : memcpy( static_cast<void*>(mpBuf), static_cast<void const *>(rProp.mpBuf), mnSize );
41 98 : };
42 :
43 0 : PropEntry& PropEntry::operator=(const PropEntry& rPropEntry)
44 : {
45 0 : if ( this != &rPropEntry )
46 : {
47 0 : delete[] mpBuf;
48 0 : mnId = rPropEntry.mnId;
49 0 : mnSize = rPropEntry.mnSize;
50 0 : mnTextEnc = rPropEntry.mnTextEnc;
51 0 : mpBuf = new sal_uInt8[ mnSize ];
52 0 : memcpy( static_cast<void*>(mpBuf), static_cast<void const *>(rPropEntry.mpBuf), mnSize );
53 : }
54 0 : return *this;
55 : }
56 :
57 32 : void PropItem::Clear()
58 : {
59 32 : Seek( STREAM_SEEK_TO_BEGIN );
60 32 : delete[] static_cast<sal_uInt8*>(SwitchBuffer());
61 32 : }
62 :
63 13 : static sal_Int32 lcl_getMaxSafeStrLen(sal_uInt32 nSize)
64 : {
65 13 : nSize -= 1; //Drop NULL terminator
66 :
67 : //If it won't fit in a string, clip it to the max size that does
68 13 : if (nSize > SAL_MAX_INT32)
69 0 : nSize = SAL_MAX_INT32;
70 :
71 13 : return static_cast< sal_Int32 >( nSize );
72 : }
73 :
74 15 : bool PropItem::Read( OUString& rString, sal_uInt32 nStringType, bool bAlign )
75 : {
76 : sal_uInt32 i, nItemSize, nType, nItemPos;
77 15 : bool bRetValue = false;
78 :
79 15 : nItemPos = Tell();
80 :
81 15 : if ( nStringType == VT_EMPTY )
82 : {
83 12 : nType = VT_NULL; // Initialize in case stream fails.
84 12 : ReadUInt32( nType );
85 : }
86 : else
87 3 : nType = nStringType & VT_TYPEMASK;
88 :
89 15 : nItemSize = 0; // Initialize in case stream fails.
90 15 : ReadUInt32( nItemSize );
91 :
92 15 : switch( nType )
93 : {
94 : case VT_LPSTR :
95 : {
96 15 : if ( nItemSize )
97 : {
98 : try
99 : {
100 15 : sal_Char* pString = new sal_Char[ nItemSize ];
101 15 : if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
102 : {
103 0 : nItemSize >>= 1;
104 0 : if ( nItemSize > 1 )
105 : {
106 0 : sal_Unicode* pWString = reinterpret_cast<sal_Unicode*>(pString);
107 0 : for ( i = 0; i < nItemSize; i++ )
108 0 : ReadUInt16( pWString[ i ] );
109 0 : rString = OUString(pWString, lcl_getMaxSafeStrLen(nItemSize));
110 : }
111 : else
112 0 : rString.clear();
113 0 : bRetValue = true;
114 : }
115 : else
116 : {
117 15 : SvMemoryStream::Read( pString, nItemSize );
118 15 : if ( pString[ nItemSize - 1 ] == 0 )
119 : {
120 15 : if ( nItemSize > 1 )
121 15 : rString = OUString(pString, rtl_str_getLength(pString), mnTextEnc);
122 : else
123 0 : rString.clear();
124 15 : bRetValue = true;
125 : }
126 : }
127 15 : delete[] pString;
128 : }
129 0 : catch( const std::bad_alloc& )
130 : {
131 : OSL_FAIL( "sd PropItem::Read bad alloc" );
132 : }
133 : }
134 15 : if ( bAlign )
135 0 : SeekRel( ( 4 - ( nItemSize & 3 ) ) & 3 ); // dword align
136 : }
137 15 : break;
138 :
139 : case VT_LPWSTR :
140 : {
141 0 : if ( nItemSize )
142 : {
143 : try
144 : {
145 0 : sal_Unicode* pString = new sal_Unicode[ nItemSize ];
146 0 : for ( i = 0; i < nItemSize; i++ )
147 0 : ReadUInt16( pString[ i ] );
148 0 : if ( pString[ i - 1 ] == 0 )
149 : {
150 0 : if ( (sal_uInt16)nItemSize > 1 )
151 0 : rString = OUString(pString, lcl_getMaxSafeStrLen(nItemSize));
152 : else
153 0 : rString.clear();
154 0 : bRetValue = true;
155 : }
156 0 : delete[] pString;
157 : }
158 0 : catch( const std::bad_alloc& )
159 : {
160 : OSL_FAIL( "sd PropItem::Read bad alloc" );
161 : }
162 : }
163 0 : if ( bAlign && ( nItemSize & 1 ) )
164 0 : SeekRel( 2 ); // dword align
165 : }
166 0 : break;
167 : }
168 15 : if ( !bRetValue )
169 0 : Seek( nItemPos );
170 15 : return bRetValue;
171 : }
172 :
173 0 : PropItem& PropItem::operator=( PropItem& rPropItem )
174 : {
175 0 : if ( this != &rPropItem )
176 : {
177 0 : Seek( STREAM_SEEK_TO_BEGIN );
178 0 : delete[] static_cast<sal_uInt8*>(SwitchBuffer());
179 :
180 0 : mnTextEnc = rPropItem.mnTextEnc;
181 0 : sal_uInt32 nItemPos = rPropItem.Tell();
182 0 : rPropItem.Seek( STREAM_SEEK_TO_END );
183 0 : SvMemoryStream::Write( rPropItem.GetData(), rPropItem.Tell() );
184 0 : rPropItem.Seek( nItemPos );
185 : }
186 0 : return *this;
187 : }
188 :
189 20 : Section::Section( const Section& rSection )
190 : : mnTextEnc(rSection.mnTextEnc),
191 20 : maEntries(rSection.maEntries.clone())
192 : {
193 340 : for ( int i = 0; i < 16; i++ )
194 320 : aFMTID[ i ] = rSection.aFMTID[ i ];
195 20 : }
196 :
197 20 : Section::Section( const sal_uInt8* pFMTID )
198 : {
199 20 : mnTextEnc = RTL_TEXTENCODING_MS_1252;
200 340 : for ( int i = 0; i < 16; i++ )
201 320 : aFMTID[ i ] = pFMTID[ i ];
202 20 : }
203 :
204 40 : bool Section::GetProperty( sal_uInt32 nId, PropItem& rPropItem )
205 : {
206 40 : if ( nId )
207 : {
208 40 : boost::ptr_vector<PropEntry>::const_iterator iter;
209 140 : for (iter = maEntries.begin(); iter != maEntries.end(); ++iter)
210 : {
211 132 : if (iter->mnId == nId)
212 32 : break;
213 : }
214 :
215 40 : if (iter != maEntries.end())
216 : {
217 32 : rPropItem.Clear();
218 32 : rPropItem.SetTextEncoding( mnTextEnc );
219 32 : rPropItem.Write( iter->mpBuf,iter->mnSize );
220 32 : rPropItem.Seek( STREAM_SEEK_TO_BEGIN );
221 32 : return true;
222 : }
223 : }
224 8 : return false;
225 : }
226 :
227 98 : void Section::AddProperty( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize )
228 : {
229 : // just a simple id check
230 :
231 98 : if ( !nId )
232 48 : return;
233 98 : if ( nId == 0xffffffff )
234 8 : nId = 0;
235 :
236 : // do not allow same PropId's, sort
237 98 : boost::ptr_vector<PropEntry>::iterator iter;
238 529 : for ( iter = maEntries.begin(); iter != maEntries.end(); ++iter )
239 : {
240 479 : if ( iter->mnId == nId )
241 0 : maEntries.replace( iter, new PropEntry( nId, pBuf, nBufSize, mnTextEnc ));
242 479 : else if ( iter->mnId > nId )
243 48 : maEntries.insert( iter, new PropEntry( nId, pBuf, nBufSize, mnTextEnc ));
244 : else
245 431 : continue;
246 48 : return;
247 : }
248 :
249 50 : maEntries.push_back( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ) );
250 : }
251 :
252 8 : bool Section::GetDictionary( Dictionary& rDict )
253 : {
254 8 : bool bRetValue = false;
255 :
256 8 : boost::ptr_vector<PropEntry>::iterator iter;
257 8 : for (iter = maEntries.begin(); iter != maEntries.end(); ++iter)
258 : {
259 8 : if ( iter->mnId == 0 )
260 8 : break;
261 : }
262 :
263 8 : if ( iter != maEntries.end() )
264 : {
265 : sal_uInt32 nDictCount, nId, nSize, nPos;
266 8 : SvMemoryStream aStream( iter->mpBuf, iter->mnSize, StreamMode::READ );
267 8 : aStream.Seek( STREAM_SEEK_TO_BEGIN );
268 8 : aStream.ReadUInt32( nDictCount );
269 21 : for ( sal_uInt32 i = 0; i < nDictCount; i++ )
270 : {
271 13 : aStream.ReadUInt32( nId ).ReadUInt32( nSize );
272 13 : if ( nSize )
273 : {
274 13 : OUString aString;
275 13 : nPos = aStream.Tell();
276 : try
277 : {
278 13 : sal_Char* pString = new sal_Char[ nSize ];
279 13 : aStream.Read( pString, nSize );
280 13 : if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
281 : {
282 0 : nSize >>= 1;
283 0 : aStream.Seek( nPos );
284 0 : sal_Unicode* pWString = reinterpret_cast<sal_Unicode*>(pString);
285 0 : for ( i = 0; i < nSize; i++ )
286 0 : aStream.ReadUInt16( pWString[ i ] );
287 0 : aString = OUString(pWString, lcl_getMaxSafeStrLen(nSize));
288 : }
289 : else
290 13 : aString = OUString(pString, lcl_getMaxSafeStrLen(nSize), mnTextEnc);
291 13 : delete[] pString;
292 : }
293 0 : catch( const std::bad_alloc& )
294 : {
295 : OSL_FAIL( "sd Section::GetDictionary bad alloc" );
296 : }
297 13 : if ( aString.isEmpty() )
298 0 : break;
299 13 : rDict.insert( std::make_pair(aString,nId) );
300 : }
301 13 : bRetValue = true;
302 8 : }
303 : }
304 8 : return bRetValue;
305 : }
306 :
307 20 : void Section::Read( SotStorageStream *pStrm )
308 : {
309 : sal_uInt32 i, nSecOfs, nSecSize, nPropCount, nPropId, nPropOfs, nPropType, nPropSize, nCurrent, nVectorCount, nTemp, nStrmSize;
310 20 : nSecOfs = pStrm->Tell();
311 :
312 20 : pStrm->Seek( STREAM_SEEK_TO_END );
313 20 : nStrmSize = pStrm->Tell();
314 20 : pStrm->Seek( nSecOfs );
315 :
316 20 : mnTextEnc = RTL_TEXTENCODING_MS_1252;
317 20 : pStrm->ReadUInt32( nSecSize ).ReadUInt32( nPropCount );
318 138 : while( nPropCount-- && ( pStrm->GetError() == ERRCODE_NONE ) )
319 : {
320 98 : pStrm->ReadUInt32( nPropId ).ReadUInt32( nPropOfs );
321 98 : nCurrent = pStrm->Tell();
322 98 : pStrm->Seek( nPropOfs + nSecOfs );
323 98 : if ( nPropId ) // do not read dictionary
324 : {
325 :
326 90 : pStrm->ReadUInt32( nPropType );
327 :
328 90 : nPropSize = 4;
329 :
330 90 : if ( nPropType & VT_VECTOR )
331 : {
332 8 : pStrm->ReadUInt32( nVectorCount );
333 8 : nPropType &=~VT_VECTOR;
334 8 : nPropSize += 4;
335 : }
336 : else
337 82 : nVectorCount = 1;
338 :
339 90 : bool bVariant = ( nPropType == VT_VARIANT );
340 :
341 248 : for ( i = 0; nPropSize && ( i < nVectorCount ); i++ )
342 : {
343 158 : if ( bVariant )
344 : {
345 24 : pStrm->ReadUInt32( nPropType );
346 24 : nPropSize += 4;
347 : }
348 158 : switch( nPropType )
349 : {
350 : case VT_UI1 :
351 0 : nPropSize++;
352 0 : break;
353 :
354 : case VT_I2 :
355 : case VT_UI2 :
356 : case VT_BOOL :
357 33 : nPropSize += 2;
358 33 : break;
359 :
360 : case VT_I4 :
361 : case VT_R4 :
362 : case VT_UI4 :
363 : case VT_ERROR :
364 40 : nPropSize += 4;
365 40 : break;
366 :
367 : case VT_I8 :
368 : case VT_R8 :
369 : case VT_CY :
370 : case VT_UI8 :
371 : case VT_DATE :
372 : case VT_FILETIME :
373 0 : nPropSize += 8;
374 0 : break;
375 :
376 : case VT_BSTR :
377 0 : pStrm->ReadUInt32( nTemp );
378 0 : nPropSize += ( nTemp + 4 );
379 0 : break;
380 :
381 : case VT_LPSTR :
382 72 : pStrm->ReadUInt32( nTemp );
383 72 : nPropSize += ( nTemp + 4 );
384 72 : break;
385 :
386 : case VT_LPWSTR :
387 : {
388 0 : pStrm->ReadUInt32( nTemp );
389 : // looks like these are aligned to 4 bytes
390 0 : sal_uInt32 nLength = nPropOfs + nSecOfs + nPropSize + ( nTemp << 1 ) + 4;
391 0 : nPropSize += ( nTemp << 1 ) + 4 + (nLength % 4);
392 : }
393 0 : break;
394 :
395 : case VT_BLOB_OBJECT :
396 : case VT_BLOB :
397 : case VT_CF :
398 13 : pStrm->ReadUInt32( nTemp );
399 13 : nPropSize += ( nTemp + 4 );
400 13 : break;
401 :
402 : case VT_CLSID :
403 : case VT_STREAM :
404 : case VT_STORAGE :
405 : case VT_STREAMED_OBJECT :
406 : case VT_STORED_OBJECT :
407 : case VT_VARIANT :
408 : case VT_VECTOR :
409 : default :
410 0 : nPropSize = 0;
411 : }
412 158 : if ( nPropSize )
413 : {
414 158 : if ( ( nVectorCount - i ) > 1 )
415 68 : pStrm->Seek( nPropOfs + nSecOfs + nPropSize );
416 : }
417 : else
418 0 : break;
419 : }
420 90 : if ( nPropSize )
421 : {
422 90 : if ( nPropSize > nStrmSize )
423 : {
424 0 : nPropCount = 0;
425 0 : break;
426 : }
427 90 : pStrm->Seek( nPropOfs + nSecOfs );
428 : // make sure we don't overflow the section size
429 90 : if( nPropSize > nSecSize - nSecOfs )
430 3 : nPropSize = nSecSize - nSecOfs;
431 90 : sal_uInt8* pBuf = new sal_uInt8[ nPropSize ];
432 90 : pStrm->Read( pBuf, nPropSize );
433 90 : AddProperty( nPropId, pBuf, nPropSize );
434 90 : delete[] pBuf;
435 : }
436 90 : if ( nPropId == 1 )
437 : {
438 17 : PropItem aPropItem;
439 17 : if ( GetProperty( 1, aPropItem ) )
440 : {
441 : sal_uInt16 nCodePage;
442 17 : aPropItem.ReadUInt32( nPropType );
443 17 : if ( nPropType == VT_I2 )
444 : {
445 17 : aPropItem.ReadUInt16( nCodePage );
446 :
447 17 : if ( nCodePage == 1200 )
448 : {
449 0 : mnTextEnc = RTL_TEXTENCODING_UCS2;
450 : }
451 : else
452 : {
453 17 : mnTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
454 17 : if ( mnTextEnc == RTL_TEXTENCODING_DONTKNOW )
455 0 : mnTextEnc = RTL_TEXTENCODING_MS_1252;
456 : }
457 : }
458 : else
459 : {
460 0 : mnTextEnc = RTL_TEXTENCODING_MS_1252;
461 : }
462 17 : }
463 : }
464 : }
465 : else
466 : {
467 : sal_uInt32 nDictCount, nSize;
468 8 : pStrm->ReadUInt32( nDictCount );
469 21 : for ( i = 0; i < nDictCount; i++ )
470 : {
471 13 : pStrm->ReadUInt32( nSize ).ReadUInt32( nSize );
472 13 : pStrm->SeekRel( nSize );
473 : }
474 8 : nSize = pStrm->Tell();
475 8 : pStrm->Seek( nPropOfs + nSecOfs );
476 8 : nSize -= pStrm->Tell();
477 8 : if ( nSize > nStrmSize )
478 : {
479 0 : nPropCount = 0;
480 0 : break;
481 : }
482 8 : sal_uInt8* pBuf = new sal_uInt8[ nSize ];
483 8 : pStrm->Read( pBuf, nSize );
484 8 : AddProperty( 0xffffffff, pBuf, nSize );
485 8 : delete[] pBuf;
486 : }
487 98 : pStrm->Seek( nCurrent );
488 : }
489 20 : pStrm->Seek( nSecOfs + nSecSize );
490 20 : }
491 :
492 0 : Section& Section::operator=( const Section& rSection )
493 : {
494 0 : if ( this != &rSection )
495 : {
496 0 : memcpy( static_cast<void*>(aFMTID), static_cast<void const *>(rSection.aFMTID), 16 );
497 :
498 0 : maEntries = rSection.maEntries.clone();
499 : }
500 0 : return *this;
501 : }
502 :
503 12 : PropRead::PropRead( SotStorage& rStorage, const OUString& rName ) :
504 : mbStatus ( false ),
505 : mnByteOrder ( 0xfffe ),
506 : mnFormat ( 0 ),
507 : mnVersionLo ( 4 ),
508 12 : mnVersionHi ( 2 )
509 : {
510 12 : if ( rStorage.IsStream( rName ) )
511 : {
512 12 : mpSvStream = rStorage.OpenSotStream( rName, STREAM_STD_READ );
513 12 : if ( mpSvStream )
514 : {
515 12 : mpSvStream->SetEndian( SvStreamEndian::LITTLE );
516 12 : memset( mApplicationCLSID, 0, 16 );
517 12 : mbStatus = true;
518 : }
519 : }
520 12 : }
521 :
522 20 : void PropRead::AddSection( Section& rSection )
523 : {
524 20 : maSections.push_back( new Section( rSection ) );
525 20 : }
526 :
527 24 : const Section* PropRead::GetSection( const sal_uInt8* pFMTID )
528 : {
529 24 : boost::ptr_vector<Section>::iterator it;
530 36 : for ( it = maSections.begin(); it != maSections.end(); ++it)
531 : {
532 32 : if ( memcmp( it->GetFMTID(), pFMTID, 16 ) == 0 )
533 20 : return &(*it);
534 : }
535 4 : return NULL;
536 : }
537 :
538 12 : void PropRead::Read()
539 : {
540 12 : maSections.clear();
541 :
542 12 : if ( mbStatus )
543 : {
544 : sal_uInt32 nSections;
545 : sal_uInt32 nSectionOfs;
546 : sal_uInt32 nCurrent;
547 12 : mpSvStream->ReadUInt16( mnByteOrder ).ReadUInt16( mnFormat ).ReadUInt16( mnVersionLo ).ReadUInt16( mnVersionHi );
548 12 : if ( mnByteOrder == 0xfffe )
549 : {
550 12 : sal_uInt8* pSectCLSID = new sal_uInt8[ 16 ];
551 12 : mpSvStream->Read( mApplicationCLSID, 16 );
552 12 : mpSvStream->ReadUInt32( nSections );
553 12 : if ( nSections > 2 ) // sj: PowerPoint documents are containing max 2 sections
554 : {
555 0 : mbStatus = false;
556 : }
557 32 : else for ( sal_uInt32 i = 0; i < nSections; i++ )
558 : {
559 20 : mpSvStream->Read( pSectCLSID, 16 );
560 20 : mpSvStream->ReadUInt32( nSectionOfs );
561 20 : nCurrent = mpSvStream->Tell();
562 20 : mpSvStream->Seek( nSectionOfs );
563 20 : Section aSection( pSectCLSID );
564 20 : aSection.Read( mpSvStream );
565 20 : AddSection( aSection );
566 20 : mpSvStream->Seek( nCurrent );
567 20 : }
568 12 : delete[] pSectCLSID;
569 : }
570 : }
571 12 : }
572 :
573 0 : PropRead& PropRead::operator=( const PropRead& rPropRead )
574 : {
575 0 : if ( this != &rPropRead )
576 : {
577 0 : mbStatus = rPropRead.mbStatus;
578 0 : mpSvStream = rPropRead.mpSvStream;
579 :
580 0 : mnByteOrder = rPropRead.mnByteOrder;
581 0 : mnFormat = rPropRead.mnFormat;
582 0 : mnVersionLo = rPropRead.mnVersionLo;
583 0 : mnVersionHi = rPropRead.mnVersionHi;
584 0 : memcpy( mApplicationCLSID, rPropRead.mApplicationCLSID, 16 );
585 :
586 0 : maSections = rPropRead.maSections.clone();
587 : }
588 0 : return *this;
589 : }
590 :
591 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|