Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / vcl / source / filter / igif / gifread.cxx
blob733fd9572bc2f0b7764136ce737069d3ee317edb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #define _GIFPRIVATE
23 #include "decode.hxx"
24 #include "gifread.hxx"
26 // -----------
27 // - Defines -
28 // -----------
30 #define NO_PENDING( rStm ) ( ( rStm ).GetError() != ERRCODE_IO_PENDING )
32 // -------------
33 // - GIFReader -
34 // -------------
36 GIFReader::GIFReader( SvStream& rStm ) :
37 aGPalette ( 256 ),
38 aLPalette ( 256 ),
39 rIStm ( rStm ),
40 pAcc8 ( NULL ),
41 pAcc1 ( NULL ),
42 nLastPos ( rStm.Tell() ),
43 nLogWidth100 ( 0UL ),
44 nLogHeight100 ( 0UL ),
45 nGlobalWidth ( 0 ),
46 nGlobalHeight ( 0 ),
47 nImageWidth ( 0 ),
48 nImageHeight ( 0 ),
49 nLoops ( 1 ),
50 eActAction ( GLOBAL_HEADER_READING ),
51 bGCTransparent ( sal_False ),
52 bImGraphicReady ( sal_False )
54 maUpperName = rtl::OUString("SVIGIF");
55 pSrcBuf = new sal_uInt8[ 256 ];
56 ClearImageExtensions();
59 // ------------------------------------------------------------------------
61 GIFReader::~GIFReader()
63 aImGraphic.SetContext( NULL );
65 if( pAcc1 )
66 aBmp1.ReleaseAccess( pAcc1 );
68 if( pAcc8 )
69 aBmp8.ReleaseAccess( pAcc8 );
71 delete[] pSrcBuf;
74 // ------------------------------------------------------------------------
76 void GIFReader::ClearImageExtensions()
78 nGCDisposalMethod = 0;
79 bGCTransparent = sal_False;
80 nTimer = 0;
83 // ------------------------------------------------------------------------
85 sal_Bool GIFReader::CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal,
86 sal_Bool bWatchForBackgroundColor )
88 const Size aSize( nWidth, nHeight );
90 #ifdef __LP64__
91 // Don't bother allocating a bitmap of a size that would fail on a
92 // 32-bit system. We have at least one unit tests that is expected
93 // to fail (loading a 65535*65535 size GIF
94 // svtools/qa/cppunit/data/gif/fail/CVE-2008-5937-1.gif), but
95 // which doesn't fail on 64-bit Mac OS X at least. Why the loading
96 // fails on 64-bit Linux, no idea.
97 if (nWidth >= 64000 && nHeight >= 64000)
99 bStatus = sal_False;
100 return bStatus;
102 #endif
104 if( bGCTransparent )
106 const Color aWhite( COL_WHITE );
108 aBmp1 = Bitmap( aSize, 1 );
110 if( !aAnimation.Count() )
111 aBmp1.Erase( aWhite );
113 pAcc1 = aBmp1.AcquireWriteAccess();
115 if( pAcc1 )
117 cTransIndex1 = (sal_uInt8) pAcc1->GetBestPaletteIndex( aWhite );
118 cNonTransIndex1 = cTransIndex1 ? 0 : 1;
120 else
121 bStatus = sal_False;
124 if( bStatus )
126 aBmp8 = Bitmap( aSize, 8, pPal );
128 if( !!aBmp8 && bWatchForBackgroundColor && aAnimation.Count() )
129 aBmp8.Erase( (*pPal)[ nBackgroundColor ] );
130 else
131 aBmp8.Erase( Color( COL_WHITE ) );
133 pAcc8 = aBmp8.AcquireWriteAccess();
134 bStatus = ( pAcc8 != NULL );
137 return bStatus;
140 // ------------------------------------------------------------------------
142 sal_Bool GIFReader::ReadGlobalHeader()
144 char pBuf[ 7 ];
145 sal_uInt8 nRF;
146 sal_uInt8 nAspect;
147 sal_Bool bRet = sal_False;
149 rIStm.Read( pBuf, 6 );
150 if( NO_PENDING( rIStm ) )
152 pBuf[ 6 ] = 0;
153 if( !strcmp( pBuf, "GIF87a" ) || !strcmp( pBuf, "GIF89a" ) )
155 rIStm.Read( pBuf, 7 );
156 if( NO_PENDING( rIStm ) )
158 SvMemoryStream aMemStm;
160 aMemStm.SetBuffer( pBuf, 7, sal_False, 7 );
161 aMemStm >> nGlobalWidth;
162 aMemStm >> nGlobalHeight;
163 aMemStm >> nRF;
164 aMemStm >> nBackgroundColor;
165 aMemStm >> nAspect;
167 bGlobalPalette = (sal_Bool) ( nRF & 0x80 );
169 if( bGlobalPalette )
170 ReadPaletteEntries( &aGPalette, 1 << ( ( nRF & 7 ) + 1 ) );
171 else
172 nBackgroundColor = 0;
174 if( NO_PENDING( rIStm ) )
175 bRet = sal_True;
178 else
179 bStatus = sal_False;
182 return bRet;
185 // ------------------------------------------------------------------------
187 void GIFReader::ReadPaletteEntries( BitmapPalette* pPal, sal_uLong nCount )
189 const sal_uLong nLen = 3UL * nCount;
190 sal_uInt8* pBuf = new sal_uInt8[ nLen ];
192 rIStm.Read( pBuf, nLen );
193 if( NO_PENDING( rIStm ) )
195 sal_uInt8* pTmp = pBuf;
197 for( sal_uLong i = 0UL; i < nCount; )
199 BitmapColor& rColor = (*pPal)[ (sal_uInt16) i++ ];
201 rColor.SetRed( *pTmp++ );
202 rColor.SetGreen( *pTmp++ );
203 rColor.SetBlue( *pTmp++ );
206 // nach Moeglichkeit noch einige Standardfarben unterbringen
207 if( nCount < 256UL )
209 (*pPal)[ 255UL ] = Color( COL_WHITE );
211 if( nCount < 255UL )
212 (*pPal)[ 254UL ] = Color( COL_BLACK );
216 delete[] pBuf;
219 // ------------------------------------------------------------------------
221 sal_Bool GIFReader::ReadExtension()
223 sal_uInt8 cFunction;
224 sal_uInt8 cSize;
225 sal_uInt8 cByte;
226 sal_Bool bRet = sal_False;
227 sal_Bool bOverreadDataBlocks = sal_False;
229 // Extension-Label
230 rIStm >> cFunction;
231 if( NO_PENDING( rIStm ) )
233 // Block-Laenge
234 rIStm >> cSize;
236 switch( cFunction )
238 // 'Graphic Control Extension'
239 case( 0xf9 ) :
241 sal_uInt8 cFlags;
243 rIStm >> cFlags;
244 rIStm >> nTimer;
245 rIStm >> nGCTransparentIndex;
246 rIStm >> cByte;
248 if ( NO_PENDING( rIStm ) )
250 nGCDisposalMethod = ( cFlags >> 2) & 7;
251 bGCTransparent = ( cFlags & 1 ) ? sal_True : sal_False;
252 bStatus = ( cSize == 4 ) && ( cByte == 0 );
253 bRet = sal_True;
256 break;
258 // Application-Extension
259 case ( 0xff ) :
261 if ( NO_PENDING( rIStm ) )
263 // default diese Extension ueberlesen
264 bOverreadDataBlocks = sal_True;
266 // Appl.-Extension hat Laenge 11
267 if ( cSize == 0x0b )
269 rtl::OString aAppId = read_uInt8s_ToOString(rIStm, 8);
270 rtl::OString aAppCode = read_uInt8s_ToOString(rIStm, 3);
271 rIStm >> cSize;
273 // NetScape-Extension
274 if( aAppId.equalsL(RTL_CONSTASCII_STRINGPARAM("NETSCAPE")) && aAppCode.equalsL(RTL_CONSTASCII_STRINGPARAM("2.0")) && cSize == 3 )
276 rIStm >> cByte;
278 // Loop-Extension
279 if ( cByte == 0x01 )
281 rIStm >> cByte;
282 nLoops = cByte;
283 rIStm >> cByte;
284 nLoops |= ( (sal_uInt16) cByte << 8 );
285 rIStm >> cByte;
287 bStatus = ( cByte == 0 );
288 bRet = NO_PENDING( rIStm );
289 bOverreadDataBlocks = sal_False;
291 // Netscape interpretiert den LoopCount
292 // als reine Anzahl der _Wiederholungen_;
293 // bei uns ist es die Gesamtanzahl der
294 // Durchlaeufe
295 if( nLoops )
296 nLoops++;
298 else
299 rIStm.SeekRel( -1 );
301 else if ( aAppId.equalsL(RTL_CONSTASCII_STRINGPARAM("STARDIV ")) && aAppCode.equalsL(RTL_CONSTASCII_STRINGPARAM("5.0")) && cSize == 9 )
303 rIStm >> cByte;
305 // Loop-Extension
306 if ( cByte == 0x01 )
308 rIStm >> nLogWidth100 >> nLogHeight100;
309 rIStm >> cByte;
310 bStatus = ( cByte == 0 );
311 bRet = NO_PENDING( rIStm );
312 bOverreadDataBlocks = sal_False;
314 else
315 rIStm.SeekRel( -1 );
321 break;
323 // alles andere ueberlesen
324 default:
325 bOverreadDataBlocks = sal_True;
326 break;
329 // Sub-Blocks ueberlesen
330 if ( bOverreadDataBlocks )
332 bRet = sal_True;
333 while( cSize && bStatus && !rIStm.IsEof() )
335 sal_uInt16 nCount = (sal_uInt16) cSize + 1;
336 char* pBuffer = new char[ nCount ];
338 bRet = sal_False;
339 rIStm.Read( pBuffer, nCount );
340 if( NO_PENDING( rIStm ) )
342 cSize = (sal_uInt8) pBuffer[ cSize ];
343 bRet = sal_True;
345 else
346 cSize = 0;
348 delete[] pBuffer;
353 return bRet;
356 // ------------------------------------------------------------------------
358 sal_Bool GIFReader::ReadLocalHeader()
360 sal_uInt8 pBuf[ 9 ];
361 sal_Bool bRet = sal_False;
363 rIStm.Read( pBuf, 9 );
364 if( NO_PENDING( rIStm ) )
366 SvMemoryStream aMemStm;
367 BitmapPalette* pPal;
368 sal_uInt8 nFlags;
370 aMemStm.SetBuffer( (char*) pBuf, 9, sal_False, 9 );
371 aMemStm >> nImagePosX;
372 aMemStm >> nImagePosY;
373 aMemStm >> nImageWidth;
374 aMemStm >> nImageHeight;
375 aMemStm >> nFlags;
377 // Falls Interlaced, ersten Startwert vorgeben
378 bInterlaced = ( ( nFlags & 0x40 ) == 0x40 );
379 nLastInterCount = 7;
380 nLastImageY = 0;
382 if( nFlags & 0x80 )
384 pPal = &aLPalette;
385 ReadPaletteEntries( pPal, 1 << ( (nFlags & 7 ) + 1 ) );
387 else
388 pPal = &aGPalette;
390 // Falls alles soweit eingelesen werden konnte, kann
391 // nun das lokale Bild angelegt werden;
392 // es wird uebergeben, ob der BackgroundColorIndex evtl.
393 // beruecksichtigt werden soll ( wenn Globale Farbtab. und
394 // diese auch fuer dieses Bild gilt )
395 if( NO_PENDING( rIStm ) )
397 CreateBitmaps( nImageWidth, nImageHeight, pPal, bGlobalPalette && ( pPal == &aGPalette ) );
398 bRet = sal_True;
402 return bRet;
405 // ------------------------------------------------------------------------
407 sal_uLong GIFReader::ReadNextBlock()
409 sal_uLong nRet = 0UL;
410 sal_uLong nRead;
411 sal_uInt8 cBlockSize;
413 rIStm >> cBlockSize;
415 if ( rIStm.IsEof() )
416 nRet = 4UL;
417 else if ( NO_PENDING( rIStm ) )
419 if ( cBlockSize == 0 )
420 nRet = 2UL;
421 else
423 rIStm.Read( pSrcBuf, cBlockSize );
425 if( NO_PENDING( rIStm ) )
427 if( bOverreadBlock )
428 nRet = 3UL;
429 else
431 sal_Bool bEOI;
432 HPBYTE pTarget = pDecomp->DecompressBlock( pSrcBuf, cBlockSize, nRead, bEOI );
434 nRet = ( bEOI ? 3 : 1 );
436 if( nRead && !bOverreadBlock )
437 FillImages( pTarget, nRead );
439 rtl_freeMemory( pTarget );
445 return nRet;
448 // ------------------------------------------------------------------------
450 void GIFReader::FillImages( HPBYTE pBytes, sal_uLong nCount )
452 for( sal_uLong i = 0UL; i < nCount; i++ )
454 if( nImageX >= nImageWidth )
456 if( bInterlaced )
458 long nT1, nT2;
460 // falls Interlaced, werden die Zeilen kopiert
461 if( nLastInterCount )
463 long nMinY = Min( (long) nLastImageY + 1, (long) nImageHeight - 1 );
464 long nMaxY = Min( (long) nLastImageY + nLastInterCount, (long) nImageHeight - 1 );
466 // letzte gelesene Zeile kopieren, wenn Zeilen
467 // nicht zusanmmenfallen ( kommt vorm wenn wir am Ende des Bildes sind )
468 if( ( nMinY > nLastImageY ) && ( nLastImageY < ( nImageHeight - 1 ) ) )
470 HPBYTE pScanline8 = pAcc8->GetScanline( nYAcc );
471 sal_uLong nSize8 = pAcc8->GetScanlineSize();
472 HPBYTE pScanline1 = 0;
473 sal_uLong nSize1 = 0;
475 if( bGCTransparent )
477 pScanline1 = pAcc1->GetScanline( nYAcc );
478 nSize1 = pAcc1->GetScanlineSize();
481 for( long j = nMinY; j <= nMaxY; j++ )
483 memcpy( pAcc8->GetScanline( j ), pScanline8, nSize8 );
485 if( bGCTransparent )
486 memcpy( pAcc1->GetScanline( j ), pScanline1, nSize1 );
491 nT1 = ( ++nImageY ) << 3;
492 nLastInterCount = 7;
494 if( nT1 >= nImageHeight )
496 nT2 = nImageY - ( ( nImageHeight + 7 ) >> 3 );
497 nT1 = ( nT2 << 3 ) + 4;
498 nLastInterCount = 3;
500 if( nT1 >= nImageHeight )
502 nT2 -= ( nImageHeight + 3 ) >> 3;
503 nT1 = ( nT2 << 2 ) + 2;
504 nLastInterCount = 1;
506 if( nT1 >= nImageHeight )
508 nT2 -= ( nImageHeight + 1 ) >> 2;
509 nT1 = ( nT2 << 1 ) + 1;
510 nLastInterCount = 0;
515 nLastImageY = (sal_uInt16) nT1;
516 nYAcc = nT1;
518 else
520 nLastImageY = ++nImageY;
521 nYAcc = nImageY;
524 // Zeile faengt von vorne an
525 nImageX = 0;
528 if( nImageY < nImageHeight )
530 const sal_uInt8 cTmp = pBytes[ i ];
532 if( bGCTransparent )
534 if( cTmp == nGCTransparentIndex )
535 pAcc1->SetPixel( nYAcc, nImageX++, cTransIndex1 );
536 else
538 pAcc8->SetPixel( nYAcc, nImageX, cTmp );
539 pAcc1->SetPixel( nYAcc, nImageX++, cNonTransIndex1 );
542 else
543 pAcc8->SetPixel( nYAcc, nImageX++, cTmp );
545 else
547 bOverreadBlock = sal_True;
548 break;
553 // ------------------------------------------------------------------------
555 void GIFReader::CreateNewBitmaps()
557 AnimationBitmap aAnimBmp;
559 aBmp8.ReleaseAccess( pAcc8 );
560 pAcc8 = NULL;
562 if( bGCTransparent )
564 aBmp1.ReleaseAccess( pAcc1 );
565 pAcc1 = NULL;
566 aAnimBmp.aBmpEx = BitmapEx( aBmp8, aBmp1 );
568 else
569 aAnimBmp.aBmpEx = BitmapEx( aBmp8 );
571 aAnimBmp.aPosPix = Point( nImagePosX, nImagePosY );
572 aAnimBmp.aSizePix = Size( nImageWidth, nImageHeight );
573 aAnimBmp.nWait = ( nTimer != 65535 ) ? nTimer : ANIMATION_TIMEOUT_ON_CLICK;
574 aAnimBmp.bUserInput = sal_False;
576 if( nGCDisposalMethod == 2 )
577 aAnimBmp.eDisposal = DISPOSE_BACK;
578 else if( nGCDisposalMethod == 3 )
579 aAnimBmp.eDisposal = DISPOSE_PREVIOUS;
580 else
581 aAnimBmp.eDisposal = DISPOSE_NOT;
583 aAnimation.Insert( aAnimBmp );
585 if( aAnimation.Count() == 1 )
587 aAnimation.SetDisplaySizePixel( Size( nGlobalWidth, nGlobalHeight ) );
588 aAnimation.SetLoopCount( nLoops );
592 // ------------------------------------------------------------------------
594 const Graphic& GIFReader::GetIntermediateGraphic()
596 // Intermediate-Graphic nur erzeugen, wenn schon
597 // Daten vorliegen, aber die Graphic noch nicht
598 // vollstaendig eingelesen wurde
599 if ( bImGraphicReady && !aAnimation.Count() )
601 Bitmap aBmp;
603 aBmp8.ReleaseAccess( pAcc8 );
605 if ( bGCTransparent )
607 aBmp1.ReleaseAccess( pAcc1 );
608 aImGraphic = BitmapEx( aBmp8, aBmp1 );
610 pAcc1 = aBmp1.AcquireWriteAccess();
611 bStatus = bStatus && ( pAcc1 != NULL );
613 else
614 aImGraphic = aBmp8;
616 pAcc8 = aBmp8.AcquireWriteAccess();
617 bStatus = bStatus && ( pAcc8 != NULL );
620 return aImGraphic;
623 // ------------------------------------------------------------------------
625 sal_Bool GIFReader::ProcessGIF()
627 sal_Bool bRead = sal_False;
628 sal_Bool bEnd = sal_False;
630 if ( !bStatus )
631 eActAction = ABORT_READING;
633 // Stream an die richtige Stelle bringen
634 rIStm.Seek( nLastPos );
636 switch( eActAction )
638 // naechsten Marker lesen
639 case( MARKER_READING ):
641 sal_uInt8 cByte;
643 rIStm >> cByte;
645 if( rIStm.IsEof() )
646 eActAction = END_READING;
647 else if( NO_PENDING( rIStm ) )
649 bRead = sal_True;
651 if( cByte == '!' )
652 eActAction = EXTENSION_READING;
653 else if( cByte == ',' )
654 eActAction = LOCAL_HEADER_READING;
655 else if( cByte == ';' )
656 eActAction = END_READING;
657 else
658 eActAction = ABORT_READING;
661 break;
663 // ScreenDescriptor lesen
664 case( GLOBAL_HEADER_READING ):
666 if( ( bRead = ReadGlobalHeader() ) == sal_True )
668 ClearImageExtensions();
669 eActAction = MARKER_READING;
672 break;
675 // Extension lesen
676 case( EXTENSION_READING ):
678 if( ( bRead = ReadExtension() ) == sal_True )
679 eActAction = MARKER_READING;
681 break;
684 // Image-Descriptor lesen
685 case( LOCAL_HEADER_READING ):
687 if( ( bRead = ReadLocalHeader() ) == sal_True )
689 nYAcc = nImageX = nImageY = 0;
690 eActAction = FIRST_BLOCK_READING;
693 break;
696 // ersten Datenblock lesen
697 case( FIRST_BLOCK_READING ):
699 sal_uInt8 cDataSize;
701 rIStm >> cDataSize;
703 if( rIStm.IsEof() )
704 eActAction = ABORT_READING;
705 else if( cDataSize > 12 )
706 bStatus = sal_False;
707 else if( NO_PENDING( rIStm ) )
709 bRead = sal_True;
710 pDecomp = new GIFLZWDecompressor( cDataSize );
711 eActAction = NEXT_BLOCK_READING;
712 bOverreadBlock = sal_False;
714 else
715 eActAction = FIRST_BLOCK_READING;
717 break;
719 // naechsten Datenblock lesen
720 case( NEXT_BLOCK_READING ):
722 sal_uInt16 nLastX = nImageX;
723 sal_uInt16 nLastY = nImageY;
724 sal_uLong nRet = ReadNextBlock();
726 // Return: 0:Pending / 1:OK; / 2:OK und letzter Block: / 3:EOI / 4:HardAbort
727 if( nRet )
729 bRead = sal_True;
731 if ( nRet == 1UL )
733 bImGraphicReady = sal_True;
734 eActAction = NEXT_BLOCK_READING;
735 bOverreadBlock = sal_False;
737 else
739 if( nRet == 2UL )
741 delete pDecomp;
742 CreateNewBitmaps();
743 eActAction = MARKER_READING;
744 ClearImageExtensions();
746 else if( nRet == 3UL )
748 eActAction = NEXT_BLOCK_READING;
749 bOverreadBlock = sal_True;
751 else
753 delete pDecomp;
754 CreateNewBitmaps();
755 eActAction = ABORT_READING;
756 ClearImageExtensions();
760 else
762 nImageX = nLastX;
763 nImageY = nLastY;
766 break;
768 // ein Fehler trat auf
769 case( ABORT_READING ):
771 bEnd = sal_True;
772 eActAction = END_READING;
774 break;
776 default:
777 break;
780 // Stream an die richtige Stelle bringen,
781 // falls Daten gelesen werden konnten
782 // entweder alte Position oder aktuelle Position
783 if( bRead || bEnd )
784 nLastPos = rIStm.Tell();
786 return bRead;
789 // ------------------------------------------------------------------------
791 ReadState GIFReader::ReadGIF( Graphic& rGraphic )
793 ReadState eReadState;
795 bStatus = sal_True;
797 while( ProcessGIF() && ( eActAction != END_READING ) ) {}
799 if( !bStatus )
800 eReadState = GIFREAD_ERROR;
801 else if( eActAction == END_READING )
802 eReadState = GIFREAD_OK;
803 else
805 if ( rIStm.GetError() == ERRCODE_IO_PENDING )
806 rIStm.ResetError();
808 eReadState = GIFREAD_NEED_MORE;
811 if( aAnimation.Count() == 1 )
813 rGraphic = aAnimation.Get( 0 ).aBmpEx;
815 if( nLogWidth100 && nLogHeight100 )
817 rGraphic.SetPrefSize( Size( nLogWidth100, nLogHeight100 ) );
818 rGraphic.SetPrefMapMode( MAP_100TH_MM );
821 else
822 rGraphic = aAnimation;
824 return eReadState;
828 // -------------
829 // - ImportGIF -
830 // -------------
832 sal_Bool ImportGIF( SvStream & rStm, Graphic& rGraphic )
834 GIFReader* pGIFReader = (GIFReader*) rGraphic.GetContext();
835 sal_uInt16 nOldFormat = rStm.GetNumberFormatInt();
836 ReadState eReadState;
837 sal_Bool bRet = sal_True;
839 rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
841 if( !pGIFReader )
842 pGIFReader = new GIFReader( rStm );
844 rGraphic.SetContext( NULL );
845 eReadState = pGIFReader->ReadGIF( rGraphic );
847 if( eReadState == GIFREAD_ERROR )
849 bRet = sal_False;
850 delete pGIFReader;
852 else if( eReadState == GIFREAD_OK )
853 delete pGIFReader;
854 else
856 rGraphic = pGIFReader->GetIntermediateGraphic();
857 rGraphic.SetContext( pGIFReader );
860 rStm.SetNumberFormatInt( nOldFormat );
862 return bRet;
865 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */