xref: /AOO41X/main/svtools/source/filter/igif/gifread.cxx (revision 87bc88d3ed834c36654f277ed18005c290f77bdd)
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_svtools.hxx"
26 
27 #define _GIFPRIVATE
28 
29 #include "decode.hxx"
30 #include "gifread.hxx"
31 
32 // -----------
33 // - Defines -
34 // -----------
35 
36 #define NO_PENDING( rStm ) ( ( rStm ).GetError() != ERRCODE_IO_PENDING )
37 
38 // -------------
39 // - GIFReader -
40 // -------------
41 
GIFReader(SvStream & rStm)42 GIFReader::GIFReader( SvStream& rStm ) :
43             aGPalette       ( 256 ),
44             aLPalette       ( 256 ),
45             rIStm           ( rStm ),
46             pAcc8           ( NULL ),
47             pAcc1           ( NULL ),
48             nLastPos        ( rStm.Tell() ),
49             nLogWidth100    ( 0UL ),
50             nLogHeight100   ( 0UL ),
51             nLoops          ( 1 ),
52             eActAction      ( GLOBAL_HEADER_READING ),
53             bGCTransparent  ( sal_False ),
54             bImGraphicReady ( sal_False )
55 {
56     maUpperName = UniString::CreateFromAscii( "SVIGIF", 6 );
57     pSrcBuf = new sal_uInt8[ 256 ];
58     ClearImageExtensions();
59 }
60 
61 // ------------------------------------------------------------------------
62 
~GIFReader()63 GIFReader::~GIFReader()
64 {
65     aImGraphic.SetContext( NULL );
66 
67     if( pAcc1 )
68         aBmp1.ReleaseAccess( pAcc1 );
69 
70     if( pAcc8 )
71         aBmp8.ReleaseAccess( pAcc8 );
72 
73     delete[] pSrcBuf;
74 }
75 
76 // ------------------------------------------------------------------------
77 
ClearImageExtensions()78 void GIFReader::ClearImageExtensions()
79 {
80     nGCDisposalMethod = 0;
81     bGCTransparent = sal_False;
82     nTimer = 0;
83 }
84 
85 // ------------------------------------------------------------------------
86 
CreateBitmaps(long nWidth,long nHeight,BitmapPalette * pPal,sal_Bool bWatchForBackgroundColor)87 sal_Bool GIFReader::CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal,
88                                sal_Bool bWatchForBackgroundColor )
89 {
90     const Size aSize( nWidth, nHeight );
91 
92     if( bGCTransparent )
93     {
94         const Color aWhite( COL_WHITE );
95 
96         aBmp1 = Bitmap( aSize, 1 );
97 
98         if( !aAnimation.Count() )
99             aBmp1.Erase( aWhite );
100 
101         pAcc1 = aBmp1.AcquireWriteAccess();
102 
103         if( pAcc1 )
104         {
105             cTransIndex1 = (sal_uInt8) pAcc1->GetBestPaletteIndex( aWhite );
106             cNonTransIndex1 = cTransIndex1 ? 0 : 1;
107         }
108         else
109             bStatus = sal_False;
110     }
111 
112     if( bStatus )
113     {
114         aBmp8 = Bitmap( aSize, 8, pPal );
115 
116         if( !!aBmp8 && bWatchForBackgroundColor && aAnimation.Count() )
117             aBmp8.Erase( (*pPal)[ nBackgroundColor ] );
118         else
119           aBmp8.Erase( Color( COL_WHITE ) );
120 
121         pAcc8 = aBmp8.AcquireWriteAccess();
122         bStatus = ( pAcc8 != NULL );
123     }
124 
125     return bStatus;
126 }
127 
128 // ------------------------------------------------------------------------
129 
ReadGlobalHeader()130 sal_Bool GIFReader::ReadGlobalHeader()
131 {
132     char    pBuf[ 7 ];
133     sal_uInt8   nRF;
134     sal_uInt8   nAspect;
135     sal_Bool    bRet = sal_False;
136 
137     rIStm.Read( pBuf, 6 );
138     if( NO_PENDING( rIStm ) )
139     {
140         pBuf[ 6 ] = 0;
141         if( !strcmp( pBuf, "GIF87a" ) || !strcmp( pBuf, "GIF89a" ) )
142         {
143             rIStm.Read( pBuf, 7 );
144             if( NO_PENDING( rIStm ) )
145             {
146                 SvMemoryStream aMemStm;
147 
148                 aMemStm.SetBuffer( pBuf, 7, sal_False, 7 );
149                 aMemStm >> nGlobalWidth;
150                 aMemStm >> nGlobalHeight;
151                 aMemStm >> nRF;
152                 aMemStm >> nBackgroundColor;
153                 aMemStm >> nAspect;
154 
155                 bGlobalPalette = (sal_Bool) ( nRF & 0x80 );
156 
157                 if( bGlobalPalette )
158                     ReadPaletteEntries( &aGPalette, 1 << ( ( nRF & 7 ) + 1 ) );
159                 else
160                     nBackgroundColor = 0;
161 
162                 if( NO_PENDING( rIStm ) )
163                     bRet = sal_True;
164             }
165         }
166         else
167             bStatus = sal_False;
168     }
169 
170     return bRet;
171 }
172 
173 // ------------------------------------------------------------------------
174 
ReadPaletteEntries(BitmapPalette * pPal,sal_uLong nCount)175 void GIFReader::ReadPaletteEntries( BitmapPalette* pPal, sal_uLong nCount )
176 {
177     const sal_uLong nLen = 3UL * nCount;
178     sal_uInt8*      pBuf = new sal_uInt8[ nLen ];
179 
180     rIStm.Read( pBuf, nLen );
181     if( NO_PENDING( rIStm ) )
182     {
183         sal_uInt8* pTmp = pBuf;
184 
185         for( sal_uLong i = 0UL; i < nCount; )
186         {
187             BitmapColor& rColor = (*pPal)[ (sal_uInt16) i++ ];
188 
189             rColor.SetRed( *pTmp++ );
190             rColor.SetGreen( *pTmp++ );
191             rColor.SetBlue( *pTmp++ );
192         }
193 
194         // nach Moeglichkeit noch einige Standardfarben unterbringen
195         if( nCount < 256UL )
196         {
197             (*pPal)[ 255UL ] = Color( COL_WHITE );
198 
199             if( nCount < 255UL )
200                 (*pPal)[ 254UL ] = Color( COL_BLACK );
201         }
202     }
203 
204     delete[] pBuf;
205 }
206 
207 // ------------------------------------------------------------------------
208 
ReadExtension()209 sal_Bool GIFReader::ReadExtension()
210 {
211     sal_uInt8   cFunction;
212     sal_uInt8   cSize;
213     sal_uInt8   cByte;
214     sal_Bool    bRet = sal_False;
215     sal_Bool    bOverreadDataBlocks = sal_False;
216 
217     // Extension-Label
218     rIStm >> cFunction;
219     if( NO_PENDING( rIStm ) )
220     {
221         // Block-Laenge
222         rIStm >> cSize;
223 
224         switch( cFunction )
225         {
226             // 'Graphic Control Extension'
227             case( 0xf9 ) :
228             {
229                 sal_uInt8 cFlags;
230 
231                 rIStm >> cFlags;
232                 rIStm >> nTimer;
233                 rIStm >> nGCTransparentIndex;
234                 rIStm >> cByte;
235 
236                 if ( NO_PENDING( rIStm ) )
237                 {
238                     nGCDisposalMethod = ( cFlags >> 2) & 7;
239                     bGCTransparent = ( cFlags & 1 ) ? sal_True : sal_False;
240                     bStatus = ( cSize == 4 ) && ( cByte == 0 );
241                     bRet = sal_True;
242                 }
243             }
244             break;
245 
246             // Application-Extension
247             case ( 0xff ) :
248             {
249                 if ( NO_PENDING( rIStm ) )
250                 {
251                     // default diese Extension ueberlesen
252                     bOverreadDataBlocks = sal_True;
253 
254                     // Appl.-Extension hat Laenge 11
255                     if ( cSize == 0x0b )
256                     {
257                         ByteString  aAppId;
258                         ByteString  aAppCode;
259 
260                         rIStm.Read( aAppId.AllocBuffer( 8 ), 8 );
261                         rIStm.Read( aAppCode.AllocBuffer( 3 ), 3 );
262                         rIStm >> cSize;
263 
264                         // NetScape-Extension
265                         if( aAppId == "NETSCAPE" && aAppCode == "2.0" && cSize == 3 )
266                         {
267                             rIStm >> cByte;
268 
269                             // Loop-Extension
270                             if ( cByte == 0x01 )
271                             {
272                                 rIStm >> cByte;
273                                 nLoops = cByte;
274                                 rIStm >> cByte;
275                                 nLoops |= ( (sal_uInt16) cByte << 8 );
276                                 rIStm >> cByte;
277 
278                                 bStatus = ( cByte == 0 );
279                                 bRet = NO_PENDING( rIStm );
280                                 bOverreadDataBlocks = sal_False;
281 
282                                 // Netscape interpretiert den LoopCount
283                                 // als reine Anzahl der _Wiederholungen_;
284                                 // bei uns ist es die Gesamtanzahl der
285                                 // Durchlaeufe
286                                 if( nLoops )
287                                     nLoops++;
288                             }
289                             else
290                                 rIStm.SeekRel( -1 );
291                         }
292                         else if ( aAppId == "STARDIV " && aAppCode == "5.0" && cSize == 9 )
293                         {
294                             rIStm >> cByte;
295 
296                             // Loop-Extension
297                             if ( cByte == 0x01 )
298                             {
299                                 rIStm >> nLogWidth100 >> nLogHeight100;
300                                 rIStm >> cByte;
301                                 bStatus = ( cByte == 0 );
302                                 bRet = NO_PENDING( rIStm );
303                                 bOverreadDataBlocks = sal_False;
304                             }
305                             else
306                                 rIStm.SeekRel( -1 );
307                         }
308 
309                     }
310                 }
311             }
312             break;
313 
314             // alles andere ueberlesen
315             default:
316                 bOverreadDataBlocks = sal_True;
317             break;
318         }
319 
320         // Sub-Blocks ueberlesen
321         if ( bOverreadDataBlocks )
322         {
323             bRet = sal_True;
324             while( cSize && bStatus && !rIStm.IsEof() )
325             {
326                 sal_uInt16  nCount = (sal_uInt16) cSize + 1;
327                 char*   pBuffer = new char[ nCount ];
328 
329                 bRet = sal_False;
330                 rIStm.Read( pBuffer, nCount );
331                 if( NO_PENDING( rIStm ) )
332                 {
333                     cSize = (sal_uInt8) pBuffer[ cSize ];
334                     bRet = sal_True;
335                 }
336                 else
337                     cSize = 0;
338 
339                 delete[] pBuffer;
340             }
341         }
342     }
343 
344     return bRet;
345 }
346 
347 // ------------------------------------------------------------------------
348 
ReadLocalHeader()349 sal_Bool GIFReader::ReadLocalHeader()
350 {
351     sal_uInt8   pBuf[ 9 ];
352     sal_Bool    bRet = sal_False;
353 
354     rIStm.Read( pBuf, 9 );
355     if( NO_PENDING( rIStm ) )
356     {
357         SvMemoryStream  aMemStm;
358         BitmapPalette*  pPal;
359         sal_uInt8           nFlags;
360 
361         aMemStm.SetBuffer( (char*) pBuf, 9, sal_False, 9 );
362         aMemStm >> nImagePosX;
363         aMemStm >> nImagePosY;
364         aMemStm >> nImageWidth;
365         aMemStm >> nImageHeight;
366         aMemStm >> nFlags;
367 
368         // Falls Interlaced, ersten Startwert vorgeben
369         bInterlaced = ( ( nFlags & 0x40 ) == 0x40 );
370         nLastInterCount = 7;
371         nLastImageY = 0;
372 
373         if( nFlags & 0x80 )
374         {
375             pPal = &aLPalette;
376             ReadPaletteEntries( pPal, 1 << ( (nFlags & 7 ) + 1 ) );
377         }
378         else
379             pPal = &aGPalette;
380 
381         // Falls alles soweit eingelesen werden konnte, kann
382         // nun das lokale Bild angelegt werden;
383         // es wird uebergeben, ob der BackgroundColorIndex evtl.
384         // beruecksichtigt werden soll ( wenn Globale Farbtab. und
385         // diese auch fuer dieses Bild gilt )
386         if( NO_PENDING( rIStm ) )
387         {
388             CreateBitmaps( nImageWidth, nImageHeight, pPal, bGlobalPalette && ( pPal == &aGPalette ) );
389             bRet = sal_True;
390         }
391     }
392 
393     return bRet;
394 }
395 
396 // ------------------------------------------------------------------------
397 
ReadNextBlock()398 sal_uLong GIFReader::ReadNextBlock()
399 {
400     sal_uLong   nRet = 0UL;
401     sal_uLong   nRead;
402     sal_uInt8   cBlockSize;
403 
404     rIStm >> cBlockSize;
405 
406     if ( rIStm.IsEof() )
407         nRet = 4UL;
408     else if ( NO_PENDING( rIStm ) )
409     {
410         if ( cBlockSize == 0 )
411             nRet = 2UL;
412         else
413         {
414             rIStm.Read( pSrcBuf, cBlockSize );
415 
416             if( NO_PENDING( rIStm ) )
417             {
418                 if( bOverreadBlock )
419                     nRet = 3UL;
420                 else
421                 {
422                     sal_Bool    bEOI;
423                     HPBYTE  pTarget = pDecomp->DecompressBlock( pSrcBuf, cBlockSize, nRead, bEOI );
424 
425                     nRet = ( bEOI ? 3 : 1 );
426 
427                     if( nRead && !bOverreadBlock )
428                         FillImages( pTarget, nRead );
429 
430                     rtl_freeMemory( pTarget );
431                 }
432             }
433         }
434     }
435 
436     return nRet;
437 }
438 
439 // ------------------------------------------------------------------------
440 
FillImages(HPBYTE pBytes,sal_uLong nCount)441 void GIFReader::FillImages( HPBYTE pBytes, sal_uLong nCount )
442 {
443     for( sal_uLong i = 0UL; i < nCount; i++ )
444     {
445         if( nImageX >= nImageWidth )
446         {
447             if( bInterlaced )
448             {
449                 long nT1, nT2;
450 
451                 // falls Interlaced, werden die Zeilen kopiert
452                 if( nLastInterCount )
453                 {
454                     long nMinY = Min( (long) nLastImageY + 1, (long) nImageHeight - 1 );
455                     long nMaxY = Min( (long) nLastImageY + nLastInterCount, (long) nImageHeight - 1 );
456 
457                     // letzte gelesene Zeile kopieren, wenn Zeilen
458                     // nicht zusanmmenfallen ( kommt vorm wenn wir am Ende des Bildes sind )
459                     if( ( nMinY > nLastImageY ) && ( nLastImageY < ( nImageHeight - 1 ) ) )
460                     {
461                         HPBYTE  pScanline8 = pAcc8->GetScanline( nYAcc );
462                         sal_uLong   nSize8 = pAcc8->GetScanlineSize();
463                         HPBYTE  pScanline1 = 0;
464                         sal_uLong   nSize1 = 0;
465 
466                         if( bGCTransparent )
467                         {
468                             pScanline1 = pAcc1->GetScanline( nYAcc );
469                             nSize1 = pAcc1->GetScanlineSize();
470                         }
471 
472                         for( long j = nMinY; j <= nMaxY; j++ )
473                         {
474                             memcpy( pAcc8->GetScanline( j ), pScanline8, nSize8 );
475 
476                             if( bGCTransparent )
477                                 memcpy( pAcc1->GetScanline( j ), pScanline1, nSize1 );
478                         }
479                     }
480                 }
481 
482                 nT1 = ( ++nImageY ) << 3;
483                 nLastInterCount = 7;
484 
485                 if( nT1 >= nImageHeight )
486                 {
487                     nT2 = nImageY - ( ( nImageHeight + 7 ) >> 3 );
488                     nT1 = ( nT2 << 3 ) + 4;
489                     nLastInterCount = 3;
490 
491                     if( nT1 >= nImageHeight )
492                     {
493                         nT2 -= ( nImageHeight + 3 ) >> 3;
494                         nT1 = ( nT2 << 2 ) + 2;
495                         nLastInterCount = 1;
496 
497                         if( nT1 >= nImageHeight )
498                         {
499                             nT2 -= ( nImageHeight + 1 ) >> 2;
500                             nT1 = ( nT2 << 1 ) + 1;
501                             nLastInterCount = 0;
502                         }
503                     }
504                 }
505 
506                 nLastImageY = (sal_uInt16) nT1;
507                 nYAcc = nT1;
508             }
509             else
510             {
511                 nLastImageY = ++nImageY;
512                 nYAcc = nImageY;
513             }
514 
515             // Zeile faengt von vorne an
516             nImageX = 0;
517         }
518 
519         if( nImageY < nImageHeight )
520         {
521             const sal_uInt8 cTmp = pBytes[ i ];
522 
523             if( bGCTransparent )
524             {
525                 if( cTmp == nGCTransparentIndex )
526                     pAcc1->SetPixelIndex( nYAcc, nImageX++, cTransIndex1 );
527                 else
528                 {
529                     pAcc8->SetPixelIndex( nYAcc, nImageX, cTmp );
530                     pAcc1->SetPixelIndex( nYAcc, nImageX++, cNonTransIndex1 );
531                 }
532             }
533             else
534                 pAcc8->SetPixelIndex( nYAcc, nImageX++, cTmp );
535         }
536         else
537         {
538             bOverreadBlock = sal_True;
539             break;
540         }
541     }
542 }
543 
544 // ------------------------------------------------------------------------
545 
CreateNewBitmaps()546 void GIFReader::CreateNewBitmaps()
547 {
548     AnimationBitmap aAnimBmp;
549 
550     aBmp8.ReleaseAccess( pAcc8 );
551     pAcc8 = NULL;
552 
553     if( bGCTransparent )
554     {
555         aBmp1.ReleaseAccess( pAcc1 );
556         pAcc1 = NULL;
557         aAnimBmp.aBmpEx = BitmapEx( aBmp8, aBmp1 );
558     }
559     else
560         aAnimBmp.aBmpEx = BitmapEx( aBmp8 );
561 
562     aAnimBmp.aPosPix = Point( nImagePosX, nImagePosY );
563     aAnimBmp.aSizePix = Size( nImageWidth, nImageHeight );
564     aAnimBmp.nWait = ( nTimer != 65535 ) ? nTimer : ANIMATION_TIMEOUT_ON_CLICK;
565     aAnimBmp.bUserInput = sal_False;
566 
567     if( nGCDisposalMethod == 2 )
568         aAnimBmp.eDisposal = DISPOSE_BACK;
569     else if( nGCDisposalMethod == 3 )
570         aAnimBmp.eDisposal = DISPOSE_PREVIOUS;
571     else
572         aAnimBmp.eDisposal = DISPOSE_NOT;
573 
574     aAnimation.Insert( aAnimBmp );
575 
576     if( aAnimation.Count() == 1 )
577     {
578         aAnimation.SetDisplaySizePixel( Size( nGlobalWidth, nGlobalHeight ) );
579         aAnimation.SetLoopCount( nLoops );
580     }
581 }
582 
583 // ------------------------------------------------------------------------
584 
GetIntermediateGraphic()585 const Graphic& GIFReader::GetIntermediateGraphic()
586 {
587     // Intermediate-Graphic nur erzeugen, wenn schon
588     // Daten vorliegen, aber die Graphic noch nicht
589     // vollstaendig eingelesen wurde
590     if ( bImGraphicReady && !aAnimation.Count() )
591     {
592         Bitmap  aBmp;
593 
594         aBmp8.ReleaseAccess( pAcc8 );
595 
596         if ( bGCTransparent )
597         {
598             aBmp1.ReleaseAccess( pAcc1 );
599             aImGraphic = BitmapEx( aBmp8, aBmp1 );
600 
601             pAcc1 = aBmp1.AcquireWriteAccess();
602             bStatus = bStatus && ( pAcc1 != NULL );
603         }
604         else
605             aImGraphic = aBmp8;
606 
607         pAcc8 = aBmp8.AcquireWriteAccess();
608         bStatus = bStatus && ( pAcc8 != NULL );
609     }
610 
611     return aImGraphic;
612 }
613 
614 // ------------------------------------------------------------------------
615 
ProcessGIF()616 sal_Bool GIFReader::ProcessGIF()
617 {
618     sal_Bool bRead = sal_False;
619     sal_Bool bEnd = sal_False;
620 
621     if ( !bStatus )
622         eActAction = ABORT_READING;
623 
624     // Stream an die richtige Stelle bringen
625     rIStm.Seek( nLastPos );
626 
627     switch( eActAction )
628     {
629         // naechsten Marker lesen
630         case( MARKER_READING ):
631         {
632             sal_uInt8 cByte;
633 
634             rIStm >> cByte;
635 
636             if( rIStm.IsEof() )
637                 eActAction = END_READING;
638             else if( NO_PENDING( rIStm ) )
639             {
640                 bRead = sal_True;
641 
642                 if( cByte == '!' )
643                     eActAction = EXTENSION_READING;
644                 else if( cByte == ',' )
645                     eActAction = LOCAL_HEADER_READING;
646                 else if( cByte == ';' )
647                     eActAction = END_READING;
648                 else
649                     eActAction = ABORT_READING;
650             }
651         }
652         break;
653 
654         // ScreenDescriptor lesen
655         case( GLOBAL_HEADER_READING ):
656         {
657             if( ( bRead = ReadGlobalHeader() ) == sal_True )
658             {
659                 ClearImageExtensions();
660                 eActAction = MARKER_READING;
661             }
662         }
663         break;
664 
665 
666         // Extension lesen
667         case( EXTENSION_READING ):
668         {
669             if( ( bRead = ReadExtension() ) == sal_True )
670                 eActAction = MARKER_READING;
671         }
672         break;
673 
674 
675         // Image-Descriptor lesen
676         case( LOCAL_HEADER_READING ):
677         {
678             if( ( bRead = ReadLocalHeader() ) == sal_True )
679             {
680                 nYAcc = nImageX = nImageY = 0;
681                 eActAction = FIRST_BLOCK_READING;
682             }
683         }
684         break;
685 
686 
687         // ersten Datenblock lesen
688         case( FIRST_BLOCK_READING ):
689         {
690             sal_uInt8 cDataSize;
691 
692             rIStm >> cDataSize;
693 
694             if( rIStm.IsEof() )
695                 eActAction = ABORT_READING;
696             else if( cDataSize > 12 )
697                 bStatus = sal_False;
698             else if( NO_PENDING( rIStm ) )
699             {
700                 bRead = sal_True;
701                 pDecomp = new GIFLZWDecompressor( cDataSize );
702                 eActAction = NEXT_BLOCK_READING;
703                 bOverreadBlock = sal_False;
704             }
705             else
706                 eActAction = FIRST_BLOCK_READING;
707         }
708         break;
709 
710         // naechsten Datenblock lesen
711         case( NEXT_BLOCK_READING ):
712         {
713             sal_uInt16  nLastX = nImageX;
714             sal_uInt16  nLastY = nImageY;
715             sal_uLong   nRet = ReadNextBlock();
716 
717             // Return: 0:Pending / 1:OK; / 2:OK und letzter Block: / 3:EOI / 4:HardAbort
718             if( nRet )
719             {
720                 bRead = sal_True;
721 
722                 if ( nRet == 1UL )
723                 {
724                     bImGraphicReady = sal_True;
725                     eActAction = NEXT_BLOCK_READING;
726                     bOverreadBlock = sal_False;
727                 }
728                 else
729                 {
730                     if( nRet == 2UL )
731                     {
732                         delete pDecomp;
733                         CreateNewBitmaps();
734                         eActAction = MARKER_READING;
735                         ClearImageExtensions();
736                     }
737                     else if( nRet == 3UL )
738                     {
739                         eActAction = NEXT_BLOCK_READING;
740                         bOverreadBlock = sal_True;
741                     }
742                     else
743                     {
744                         delete pDecomp;
745                         CreateNewBitmaps();
746                         eActAction = ABORT_READING;
747                         ClearImageExtensions();
748                     }
749                 }
750             }
751             else
752             {
753                 nImageX = nLastX;
754                 nImageY = nLastY;
755             }
756         }
757         break;
758 
759         // ein Fehler trat auf
760         case( ABORT_READING ):
761         {
762             bEnd = sal_True;
763             eActAction = END_READING;
764         }
765         break;
766 
767         default:
768         break;
769     }
770 
771     // Stream an die richtige Stelle bringen,
772     // falls Daten gelesen werden konnten
773     // entweder alte Position oder aktuelle Position
774     if( bRead || bEnd )
775         nLastPos = rIStm.Tell();
776 
777     return bRead;
778 }
779 
780 // ------------------------------------------------------------------------
781 
ReadGIF(Graphic & rGraphic)782 ReadState GIFReader::ReadGIF( Graphic& rGraphic )
783 {
784     ReadState eReadState;
785 
786     bStatus = sal_True;
787 
788     while( ProcessGIF() && ( eActAction != END_READING ) ) {}
789 
790     if( !bStatus )
791         eReadState = GIFREAD_ERROR;
792     else if( eActAction == END_READING )
793         eReadState = GIFREAD_OK;
794     else
795     {
796         if ( rIStm.GetError() == ERRCODE_IO_PENDING )
797             rIStm.ResetError();
798 
799         eReadState = GIFREAD_NEED_MORE;
800     }
801 
802     if( aAnimation.Count() == 1 )
803     {
804         rGraphic = aAnimation.Get( 0 ).aBmpEx;
805 
806         if( nLogWidth100 && nLogHeight100 )
807         {
808             rGraphic.SetPrefSize( Size( nLogWidth100, nLogHeight100 ) );
809             rGraphic.SetPrefMapMode( MAP_100TH_MM );
810         }
811     }
812     else
813         rGraphic = aAnimation;
814 
815     return eReadState;
816 }
817 
818 
819 // -------------
820 // - ImportGIF -
821 // -------------
822 
ImportGIF(SvStream & rStm,Graphic & rGraphic)823 sal_Bool ImportGIF( SvStream & rStm, Graphic& rGraphic )
824 {
825     GIFReader*  pGIFReader = (GIFReader*) rGraphic.GetContext();
826     sal_uInt16      nOldFormat = rStm.GetNumberFormatInt();
827     ReadState   eReadState;
828     sal_Bool        bRet = sal_True;
829 
830     rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
831 
832     if( !pGIFReader )
833         pGIFReader = new GIFReader( rStm );
834 
835     rGraphic.SetContext( NULL );
836     eReadState = pGIFReader->ReadGIF( rGraphic );
837 
838     if( eReadState == GIFREAD_ERROR )
839     {
840         bRet = sal_False;
841         delete pGIFReader;
842     }
843     else if( eReadState == GIFREAD_OK )
844         delete pGIFReader;
845     else
846     {
847         rGraphic = pGIFReader->GetIntermediateGraphic();
848         rGraphic.SetContext( pGIFReader );
849     }
850 
851     rStm.SetNumberFormatInt( nOldFormat );
852 
853     return bRet;
854 }
855