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