xref: /AOO41X/main/sd/source/filter/ppt/propread.cxx (revision 79aad27f7f29270c03e208e3d687e8e3850af11d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26 #include <propread.hxx>
27 #include <tools/bigint.hxx>
28 #include "tools/debug.hxx"
29 #include "rtl/tencinfo.h"
30 #include "rtl/textenc.h"
31 
32 // ------------------------------------------------------------------------
33 
34 struct PropEntry
35 {
36     sal_uInt32  mnId;
37     sal_uInt32  mnSize;
38     sal_uInt16  mnTextEnc;
39     sal_uInt8*  mpBuf;
40 
41                         PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize, sal_uInt16 nTextEnc );
42                         PropEntry( const PropEntry& rProp );
~PropEntryPropEntry43                         ~PropEntry() { delete[] mpBuf; } ;
44 
45     const PropEntry&    operator=(const PropEntry& rPropEntry);
46 };
47 
PropEntry(sal_uInt32 nId,const sal_uInt8 * pBuf,sal_uInt32 nBufSize,sal_uInt16 nTextEnc)48 PropEntry::PropEntry( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize, sal_uInt16 nTextEnc ) :
49     mnId        ( nId ),
50     mnSize      ( nBufSize ),
51     mnTextEnc   ( nTextEnc ),
52     mpBuf       ( new sal_uInt8[ nBufSize ] )
53 {
54     memcpy( (void*)mpBuf, (void*)pBuf, nBufSize );
55 };
56 
PropEntry(const PropEntry & rProp)57 PropEntry::PropEntry( const PropEntry& rProp ) :
58     mnId        ( rProp.mnId ),
59     mnSize      ( rProp.mnSize ),
60     mnTextEnc   ( rProp.mnTextEnc ),
61     mpBuf       ( new sal_uInt8[ mnSize ] )
62 {
63     memcpy( (void*)mpBuf, (void*)rProp.mpBuf, mnSize );
64 };
65 
operator =(const PropEntry & rPropEntry)66 const PropEntry& PropEntry::operator=(const PropEntry& rPropEntry)
67 {
68     if ( this != &rPropEntry )
69     {
70         delete[] mpBuf;
71         mnId = rPropEntry.mnId;
72         mnSize = rPropEntry.mnSize;
73         mnTextEnc = rPropEntry.mnTextEnc;
74         mpBuf = new sal_uInt8[ mnSize ];
75         memcpy( (void*)mpBuf, (void*)rPropEntry.mpBuf, mnSize );
76     }
77     return *this;
78 }
79 
80 //  -----------------------------------------------------------------------
81 
Clear()82 void PropItem::Clear()
83 {
84     Seek( STREAM_SEEK_TO_BEGIN );
85     delete[] (sal_uInt8*)SwitchBuffer();
86 }
87 
88 //  -----------------------------------------------------------------------
89 
lcl_getMaxSafeStrLen(sal_uInt32 nSize)90 static xub_StrLen lcl_getMaxSafeStrLen(sal_uInt32 nSize)
91 {
92     nSize -= 1; //Drop NULL terminator
93 
94     //If it won't fit in a string, clip it to the max size that does
95     if (nSize > STRING_MAXLEN)
96         nSize = STRING_MAXLEN;
97 
98     return static_cast< xub_StrLen >( nSize );
99 }
100 
Read(String & rString,sal_uInt32 nStringType,sal_Bool bAlign)101 sal_Bool PropItem::Read( String& rString, sal_uInt32 nStringType, sal_Bool bAlign )
102 {
103     sal_uInt32  i, nItemSize, nType, nItemPos;
104     sal_Bool    bRetValue = sal_False;
105 
106     nItemPos = Tell();
107 
108     if ( nStringType == VT_EMPTY )
109         *this >> nType;
110     else
111         nType = nStringType & VT_TYPEMASK;
112 
113     *this >> nItemSize;
114 
115     switch( nType )
116     {
117         case VT_LPSTR :
118         {
119             if ( nItemSize )
120             {
121                 try
122                 {
123                     sal_Char* pString = new sal_Char[ nItemSize ];
124                     if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
125                     {
126                         nItemSize >>= 1;
127                         if ( nItemSize > 1 )
128                         {
129                             sal_Unicode* pWString = (sal_Unicode*)pString;
130                             for ( i = 0; i < nItemSize; i++ )
131                                 *this >> pWString[ i ];
132                             rString = String( pWString, lcl_getMaxSafeStrLen(nItemSize) );
133                         }
134                         else
135                             rString = String();
136                         bRetValue = sal_True;
137                     }
138                     else
139                     {
140                         SvMemoryStream::Read( pString, nItemSize );
141                         if ( pString[ nItemSize - 1 ] == 0 )
142                         {
143                             if ( nItemSize > 1 )
144                                 rString = String( ByteString( pString ), mnTextEnc );
145                             else
146                                 rString = String();
147                             bRetValue = sal_True;
148                         }
149                     }
150                     delete[] pString;
151                 }
152                 catch( const std::bad_alloc& )
153                 {
154                     DBG_ERROR( "sd PropItem::Read bad alloc" );
155                 }
156             }
157             if ( bAlign )
158                 SeekRel( ( 4 - ( nItemSize & 3 ) ) & 3 );       // dword align
159         }
160         break;
161 
162         case VT_LPWSTR :
163         {
164             if ( nItemSize )
165             {
166                 try
167                 {
168                     sal_Unicode* pString = new sal_Unicode[ nItemSize ];
169                     for ( i = 0; i < nItemSize; i++ )
170                         *this >> pString[ i ];
171                     if ( pString[ i - 1 ] == 0 )
172                     {
173                         if ( (sal_uInt16)nItemSize > 1 )
174                             rString = String( pString, lcl_getMaxSafeStrLen(nItemSize) );
175                         else
176                             rString = String();
177                         bRetValue = sal_True;
178                     }
179                     delete[] pString;
180                 }
181                 catch( const std::bad_alloc& )
182                 {
183                     DBG_ERROR( "sd PropItem::Read bad alloc" );
184                 }
185             }
186             if ( bAlign && ( nItemSize & 1 ) )
187                 SeekRel( 2 );                           // dword align
188         }
189         break;
190     }
191     if ( !bRetValue )
192         Seek( nItemPos );
193     return bRetValue;
194 }
195 
196 //  -----------------------------------------------------------------------
197 
operator =(PropItem & rPropItem)198 PropItem& PropItem::operator=( PropItem& rPropItem )
199 {
200     if ( this != &rPropItem )
201     {
202         Seek( STREAM_SEEK_TO_BEGIN );
203         delete[] (sal_uInt8*)SwitchBuffer();
204 
205         mnTextEnc = rPropItem.mnTextEnc;
206         sal_uInt32 nItemPos = rPropItem.Tell();
207         rPropItem.Seek( STREAM_SEEK_TO_END );
208         SvMemoryStream::Write( rPropItem.GetData(), rPropItem.Tell() );
209         rPropItem.Seek( nItemPos );
210     }
211     return *this;
212 }
213 
214 //  -----------------------------------------------------------------------
215 
216 struct Dict
217 {
218     sal_uInt32  mnId;
219     String      aString;
220 
DictDict221             Dict( sal_uInt32 nId, String rString ) { mnId = nId; aString = rString; };
222 };
223 
224 //  -----------------------------------------------------------------------
225 
~Dictionary()226 Dictionary::~Dictionary()
227 {
228     for ( void* pPtr = First(); pPtr; pPtr = Next() )
229         delete (Dict*)pPtr;
230 }
231 
232 //  -----------------------------------------------------------------------
233 
AddProperty(sal_uInt32 nId,const String & rString)234 void Dictionary::AddProperty( sal_uInt32 nId, const String& rString )
235 {
236     if ( rString.Len() )        // eindeutige namen bei properties
237     {
238         // pruefen, ob es die Propertybeschreibung in der Dictionary schon gibt
239         for ( Dict* pDict = (Dict*)First(); pDict; pDict = (Dict*)Next() )
240         {
241             if ( pDict->mnId == nId )
242             {
243                 pDict->aString = rString;
244                 return;
245             }
246         }
247         Insert( new Dict( nId, rString ), LIST_APPEND );
248     }
249 }
250 
251 //  -----------------------------------------------------------------------
252 
GetProperty(const String & rString)253 sal_uInt32 Dictionary::GetProperty( const String& rString )
254 {
255     for ( Dict* pDict = (Dict*)First(); pDict; pDict = (Dict*)Next() )
256     {
257         if ( pDict->aString == rString )
258             return pDict->mnId;
259     }
260     return 0;
261 }
262 
263 //  -----------------------------------------------------------------------
264 
operator =(Dictionary & rDictionary)265 Dictionary& Dictionary::operator=( Dictionary& rDictionary )
266 {
267     void* pPtr;
268 
269     if ( this != &rDictionary )
270     {
271         for ( pPtr = First(); pPtr; pPtr = Next() )
272             delete (Dict*)pPtr;
273 
274         for ( pPtr = rDictionary.First(); pPtr; pPtr = rDictionary.Next() )
275             Insert( new Dict( ((Dict*)pPtr)->mnId, ((Dict*)pPtr)->aString ), LIST_APPEND );
276     }
277     return *this;
278 }
279 
280 //  -----------------------------------------------------------------------
281 
Section(Section & rSection)282 Section::Section( Section& rSection )
283 : List()
284 {
285     mnTextEnc = rSection.mnTextEnc;
286     for ( int i = 0; i < 16; i++ )
287         aFMTID[ i ] = rSection.aFMTID[ i ];
288     for ( PropEntry* pProp = (PropEntry*)rSection.First(); pProp; pProp = (PropEntry*)rSection.Next() )
289         Insert( new PropEntry( *pProp ), LIST_APPEND );
290 }
291 
292 //  -----------------------------------------------------------------------
293 
Section(const sal_uInt8 * pFMTID)294 Section::Section( const sal_uInt8* pFMTID )
295 {
296     mnTextEnc = RTL_TEXTENCODING_MS_1252;
297     for ( int i = 0; i < 16; i++ )
298         aFMTID[ i ] = pFMTID[ i ];
299 }
300 
301 //  -----------------------------------------------------------------------
302 
GetProperty(sal_uInt32 nId,PropItem & rPropItem)303 sal_Bool Section::GetProperty( sal_uInt32 nId, PropItem& rPropItem )
304 {
305     PropEntry* pProp;
306     if ( nId )
307     {
308         for ( pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
309         {
310             if ( pProp->mnId == nId )
311                 break;
312         }
313         if ( pProp )
314         {
315             rPropItem.Clear();
316             rPropItem.SetTextEncoding( mnTextEnc );
317             rPropItem.Write( pProp->mpBuf, pProp->mnSize );
318             rPropItem.Seek( STREAM_SEEK_TO_BEGIN );
319             return sal_True;
320         }
321     }
322     return sal_False;
323 }
324 
325 //  -----------------------------------------------------------------------
326 
AddProperty(sal_uInt32 nId,const sal_uInt8 * pBuf,sal_uInt32 nBufSize)327 void Section::AddProperty( sal_uInt32 nId, const sal_uInt8* pBuf, sal_uInt32 nBufSize )
328 {
329     // kleiner id check
330 
331     if ( !nId )
332         return;
333     if ( nId == 0xffffffff )
334         nId = 0;
335 
336     // keine doppelten PropId's zulassen, sortieren
337     for ( sal_uInt32 i = 0; i < Count(); i++ )
338     {
339         PropEntry* pPropEntry = (PropEntry*)GetObject( i );
340         if ( pPropEntry->mnId == nId )
341             delete (PropEntry*)Replace( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ), i );
342         else if ( pPropEntry->mnId > nId )
343             Insert( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ), i );
344         else
345             continue;
346         return;
347     }
348     Insert( new PropEntry( nId, pBuf, nBufSize, mnTextEnc ), LIST_APPEND );
349 }
350 
351 //  -----------------------------------------------------------------------
352 
GetDictionary(Dictionary & rDict)353 sal_Bool Section::GetDictionary( Dictionary& rDict )
354 {
355     sal_Bool bRetValue = sal_False;
356 
357     Dictionary aDict;
358     PropEntry* pProp;
359 
360     for ( pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
361     {
362         if ( pProp->mnId == 0 )
363             break;
364     }
365     if ( pProp )
366     {
367         sal_uInt32 nDictCount, nId, nSize, nPos;
368         SvMemoryStream aStream( (sal_Int8*)pProp->mpBuf, pProp->mnSize, STREAM_READ );
369         aStream.Seek( STREAM_SEEK_TO_BEGIN );
370         aStream >> nDictCount;
371         for ( sal_uInt32 i = 0; i < nDictCount; i++ )
372         {
373             aStream >> nId >> nSize;
374             if ( nSize )
375             {
376                 String aString;
377                 nPos = aStream.Tell();
378                 try
379                 {
380                     sal_Char* pString = new sal_Char[ nSize ];
381                     aStream.Read( pString, nSize );
382                     if ( mnTextEnc == RTL_TEXTENCODING_UCS2 )
383                     {
384                         nSize >>= 1;
385                         aStream.Seek( nPos );
386                         sal_Unicode* pWString = (sal_Unicode*)pString;
387                         for ( i = 0; i < nSize; i++ )
388                             aStream >> pWString[ i ];
389                         aString = String( pWString, lcl_getMaxSafeStrLen(nSize) );
390                     }
391                     else
392                         aString = String( ByteString( pString, lcl_getMaxSafeStrLen(nSize) ), mnTextEnc );
393                     delete[] pString;
394                 }
395                 catch( const std::bad_alloc& )
396                 {
397                     DBG_ERROR( "sd Section::GetDictionary bad alloc" );
398                 }
399                 if ( !aString.Len() )
400                     break;
401                 aDict.AddProperty( nId, aString );
402             }
403             bRetValue = sal_True;
404         }
405     }
406     rDict = aDict;
407     return bRetValue;
408 }
409 
410 //  -----------------------------------------------------------------------
411 
~Section()412 Section::~Section()
413 {
414     for ( PropEntry* pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
415         delete pProp;
416 }
417 
418 //  -----------------------------------------------------------------------
419 
Read(SvStorageStream * pStrm)420 void Section::Read( SvStorageStream *pStrm )
421 {
422     sal_uInt32 i, nSecOfs, nSecSize, nPropCount, nPropId, nPropOfs, nPropType, nPropSize, nCurrent, nVectorCount, nTemp, nStrmSize;
423     nSecOfs = pStrm->Tell();
424 
425     pStrm->Seek( STREAM_SEEK_TO_END );
426     nStrmSize = pStrm->Tell();
427     pStrm->Seek( nSecOfs );
428 
429     mnTextEnc = RTL_TEXTENCODING_MS_1252;
430     *pStrm >> nSecSize >> nPropCount;
431     while( nPropCount-- && ( pStrm->GetError() == ERRCODE_NONE ) )
432     {
433         *pStrm >> nPropId >> nPropOfs;
434         nCurrent = pStrm->Tell();
435         pStrm->Seek( nPropOfs + nSecOfs );
436         if ( nPropId )                  // dictionary wird nicht eingelesen
437         {
438 
439             *pStrm >> nPropType;
440 
441             nPropSize = 4;
442 
443             if ( nPropType & VT_VECTOR )
444             {
445                 *pStrm >> nVectorCount;
446                 nPropType &=~VT_VECTOR;
447                 nPropSize += 4;
448             }
449             else
450                 nVectorCount = 1;
451 
452 
453             sal_Bool bVariant = ( nPropType == VT_VARIANT );
454 
455             for ( i = 0; nPropSize && ( i < nVectorCount ); i++ )
456             {
457                 if ( bVariant )
458                 {
459                     *pStrm >> nPropType;
460                     nPropSize += 4;
461                 }
462                 switch( nPropType )
463                 {
464                     case VT_UI1 :
465                         nPropSize++;
466                     break;
467 
468                     case VT_I2 :
469                     case VT_UI2 :
470                     case VT_BOOL :
471                         nPropSize += 2;
472                     break;
473 
474                     case VT_I4 :
475                     case VT_R4 :
476                     case VT_UI4 :
477                     case VT_ERROR :
478                         nPropSize += 4;
479                     break;
480 
481                     case VT_I8 :
482                     case VT_R8 :
483                     case VT_CY :
484                     case VT_UI8 :
485                     case VT_DATE :
486                     case VT_FILETIME :
487                         nPropSize += 8;
488                     break;
489 
490                     case VT_BSTR :
491                         *pStrm >> nTemp;
492                         nPropSize += ( nTemp + 4 );
493                     break;
494 
495                     case VT_LPSTR :
496                         *pStrm >> nTemp;
497                         nPropSize += ( nTemp + 4 );
498                     break;
499 
500                     case VT_LPWSTR :
501                         *pStrm >> nTemp;
502                         nPropSize += ( nTemp << 1 ) + 4;
503                     break;
504 
505                     case VT_BLOB_OBJECT :
506                     case VT_BLOB :
507                     case VT_CF :
508                         *pStrm >> nTemp;
509                         nPropSize += ( nTemp + 4 );
510                     break;
511 
512                     case VT_CLSID :
513                     case VT_STREAM :
514                     case VT_STORAGE :
515                     case VT_STREAMED_OBJECT :
516                     case VT_STORED_OBJECT :
517                     case VT_VARIANT :
518                     case VT_VECTOR :
519                     default :
520                         nPropSize = 0;
521                 }
522                 if ( nPropSize )
523                 {
524                     if ( ( nVectorCount - i ) > 1 )
525                         pStrm->Seek( nPropOfs + nSecOfs + nPropSize );
526                 }
527                 else
528                     break;
529             }
530             if ( nPropSize )
531             {
532                 if ( nPropSize > nStrmSize )
533                 {
534                     nPropCount = 0;
535                     break;
536                 }
537                 pStrm->Seek( nPropOfs + nSecOfs );
538                 sal_uInt8* pBuf = new sal_uInt8[ nPropSize ];
539                 pStrm->Read( pBuf, nPropSize );
540                 AddProperty( nPropId, pBuf, nPropSize );
541                 delete[] pBuf;
542             }
543             if ( nPropId == 1 )
544             {
545                 PropItem aPropItem;
546                 if ( GetProperty( 1, aPropItem ) )
547                 {
548                     sal_uInt16 nCodePage;
549                     aPropItem >> nPropType;
550                     if ( nPropType == VT_I2 )
551                     {
552                         aPropItem >> nCodePage;
553 
554                         if ( nCodePage == 1200 )
555                         {
556                             mnTextEnc = RTL_TEXTENCODING_UCS2;
557                         }
558                         else
559                         {
560                             mnTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
561                             if ( mnTextEnc == RTL_TEXTENCODING_DONTKNOW )
562                                 mnTextEnc = RTL_TEXTENCODING_MS_1252;
563                         }
564                     }
565                     else
566                     {
567                         mnTextEnc = RTL_TEXTENCODING_MS_1252;
568                     }
569                 }
570             }
571         }
572         else
573         {
574             sal_uInt32 nDictCount, nSize;
575             *pStrm >> nDictCount;
576             for ( i = 0; i < nDictCount; i++ )
577             {
578                 *pStrm >> nSize >> nSize;
579                 pStrm->SeekRel( nSize );
580             }
581             nSize = pStrm->Tell();
582             pStrm->Seek( nPropOfs + nSecOfs );
583             nSize -= pStrm->Tell();
584             if ( nSize > nStrmSize )
585             {
586                 nPropCount = 0;
587                 break;
588             }
589             sal_uInt8* pBuf = new sal_uInt8[ nSize ];
590             pStrm->Read( pBuf, nSize );
591             AddProperty( 0xffffffff, pBuf, nSize );
592             delete[] pBuf;
593         }
594         pStrm->Seek( nCurrent );
595     }
596     pStrm->Seek( nSecOfs + nSecSize );
597 }
598 
599 //  -----------------------------------------------------------------------
600 
operator =(Section & rSection)601 Section& Section::operator=( Section& rSection )
602 {
603     PropEntry* pProp;
604 
605     if ( this != &rSection )
606     {
607         memcpy( (void*)aFMTID, (void*)rSection.aFMTID, 16 );
608         for ( pProp = (PropEntry*)First(); pProp; pProp = (PropEntry*)Next() )
609             delete pProp;
610         Clear();
611         for ( pProp = (PropEntry*)rSection.First(); pProp; pProp = (PropEntry*)rSection.Next() )
612             Insert( new PropEntry( *pProp ), LIST_APPEND );
613     }
614     return *this;
615 }
616 
617 //  -----------------------------------------------------------------------
618 
PropRead(SvStorage & rStorage,const String & rName)619 PropRead::PropRead( SvStorage& rStorage, const String& rName ) :
620         mbStatus            ( sal_False ),
621         mnByteOrder         ( 0xfffe ),
622         mnFormat            ( 0 ),
623         mnVersionLo         ( 4 ),
624         mnVersionHi         ( 2 )
625 {
626     if ( rStorage.IsStream( rName ) )
627     {
628         mpSvStream = rStorage.OpenSotStream( rName, STREAM_STD_READ );
629         if ( mpSvStream )
630         {
631             mpSvStream->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
632             memset( mApplicationCLSID, 0, 16 );
633             mbStatus = sal_True;
634         }
635     }
636 }
637 
638 //  -----------------------------------------------------------------------
639 
AddSection(Section & rSection)640 void PropRead::AddSection( Section& rSection )
641 {
642     Insert( new Section( rSection ), LIST_APPEND );
643 }
644 
645 //  -----------------------------------------------------------------------
646 
GetSection(const sal_uInt8 * pFMTID)647 const Section* PropRead::GetSection( const sal_uInt8* pFMTID )
648 {
649     Section* pSection;
650 
651     for ( pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
652     {
653         if ( memcmp( pSection->GetFMTID(), pFMTID, 16 ) == 0 )
654             break;
655     }
656     return pSection;
657 }
658 
659 //  -----------------------------------------------------------------------
660 
~PropRead()661 PropRead::~PropRead()
662 {
663     for ( Section* pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
664         delete pSection;
665 }
666 
667 //  -----------------------------------------------------------------------
668 
Read()669 void PropRead::Read()
670 {
671     for ( Section* pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
672         delete pSection;
673     Clear();
674     if ( mbStatus )
675     {
676         sal_uInt32  nSections;
677         sal_uInt32  nSectionOfs;
678         sal_uInt32  nCurrent;
679         *mpSvStream >> mnByteOrder >> mnFormat >> mnVersionLo >> mnVersionHi;
680         if ( mnByteOrder == 0xfffe )
681         {
682             sal_uInt8*  pSectCLSID = new sal_uInt8[ 16 ];
683             mpSvStream->Read( mApplicationCLSID, 16 );
684             *mpSvStream >> nSections;
685             if ( nSections > 2 )                // sj: PowerPoint documents are containing max 2 sections
686             {
687                 mbStatus = sal_False;
688             }
689             else for ( sal_uInt32 i = 0; i < nSections; i++ )
690             {
691                 mpSvStream->Read( pSectCLSID, 16 );
692                 *mpSvStream >> nSectionOfs;
693                 nCurrent = mpSvStream->Tell();
694                 mpSvStream->Seek( nSectionOfs );
695                 Section aSection( pSectCLSID );
696                 aSection.Read( mpSvStream );
697                 AddSection( aSection );
698                 mpSvStream->Seek( nCurrent );
699             }
700             delete[] pSectCLSID;
701         }
702     }
703 }
704 
705 //  -----------------------------------------------------------------------
706 
operator =(PropRead & rPropRead)707 PropRead& PropRead::operator=( PropRead& rPropRead )
708 {
709     Section* pSection;
710 
711     if ( this != &rPropRead )
712     {
713         mbStatus = rPropRead.mbStatus;
714         mpSvStream = rPropRead.mpSvStream;
715 
716         mnByteOrder = rPropRead.mnByteOrder;
717         mnFormat = rPropRead.mnFormat;
718         mnVersionLo = rPropRead.mnVersionLo;
719         mnVersionHi = rPropRead.mnVersionHi;
720         memcpy( mApplicationCLSID, rPropRead.mApplicationCLSID, 16 );
721 
722         for ( pSection = (Section*)First(); pSection; pSection = (Section*)Next() )
723             delete pSection;
724         Clear();
725         for ( pSection = (Section*)rPropRead.First(); pSection; pSection = (Section*)rPropRead.Next() )
726             Insert( new Section( *pSection ), LIST_APPEND );
727     }
728     return *this;
729 }
730