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