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