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