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