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