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