build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / filter / igif / gifread.cxx
blob857523f15402bc4d9243bf7a4d2875a891b82a3c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "decode.hxx"
21 #include "gifread.hxx"
22 #include <memory>
23 #include <o3tl/make_unique.hxx>
25 #define NO_PENDING( rStm ) ( ( rStm ).GetError() != ERRCODE_IO_PENDING )
27 enum GIFAction
29 GLOBAL_HEADER_READING,
30 MARKER_READING,
31 EXTENSION_READING,
32 LOCAL_HEADER_READING,
33 FIRST_BLOCK_READING,
34 NEXT_BLOCK_READING,
35 ABORT_READING,
36 END_READING
39 enum ReadState
41 GIFREAD_OK,
42 GIFREAD_ERROR,
43 GIFREAD_NEED_MORE
46 class GIFLZWDecompressor;
48 class SvStream;
50 class GIFReader : public GraphicReader
52 Graphic aImGraphic;
53 Animation aAnimation;
54 Bitmap aBmp8;
55 Bitmap aBmp1;
56 BitmapPalette aGPalette;
57 BitmapPalette aLPalette;
58 SvStream& rIStm;
59 std::vector<sal_uInt8> aSrcBuf;
60 std::unique_ptr<GIFLZWDecompressor> pDecomp;
61 Bitmap::ScopedWriteAccess pAcc8;
62 Bitmap::ScopedWriteAccess pAcc1;
63 long nYAcc;
64 long nLastPos;
65 sal_uInt32 nLogWidth100;
66 sal_uInt32 nLogHeight100;
67 sal_uInt16 nTimer;
68 sal_uInt16 nGlobalWidth; // maximum imagewidth from header
69 sal_uInt16 nGlobalHeight; // maximum imageheight from header
70 sal_uInt16 nImageWidth; // maximum screenwidth from header
71 sal_uInt16 nImageHeight; // maximum screenheight from header
72 sal_uInt16 nImagePosX;
73 sal_uInt16 nImagePosY;
74 sal_uInt16 nImageX; // maximum screenwidth from header
75 sal_uInt16 nImageY; // maximum screenheight from header
76 sal_uInt16 nLastImageY;
77 sal_uInt16 nLastInterCount;
78 sal_uInt16 nLoops;
79 GIFAction eActAction;
80 bool bStatus;
81 bool bGCTransparent; // is the image transparent, if yes:
82 bool bInterlaced;
83 bool bOverreadBlock;
84 bool bImGraphicReady;
85 bool bGlobalPalette;
86 sal_uInt8 nBackgroundColor; // backgroundcolour
87 sal_uInt8 nGCTransparentIndex; // pixels of this index are transparant
88 sal_uInt8 nGCDisposalMethod; // 'Disposal Method' (see GIF docs)
89 sal_uInt8 cTransIndex1;
90 sal_uInt8 cNonTransIndex1;
92 void ReadPaletteEntries( BitmapPalette* pPal, sal_uLong nCount );
93 void ClearImageExtensions();
94 void CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal, bool bWatchForBackgroundColor );
95 bool ReadGlobalHeader();
96 bool ReadExtension();
97 bool ReadLocalHeader();
98 sal_uLong ReadNextBlock();
99 void FillImages( sal_uInt8* pBytes, sal_uLong nCount );
100 void CreateNewBitmaps();
101 bool ProcessGIF();
103 public:
105 ReadState ReadGIF( Graphic& rGraphic );
106 const Graphic& GetIntermediateGraphic();
108 explicit GIFReader( SvStream& rStm );
109 virtual ~GIFReader() override;
112 GIFReader::GIFReader( SvStream& rStm )
113 : aGPalette ( 256 )
114 , aLPalette ( 256 )
115 , rIStm ( rStm )
116 , nYAcc ( 0 )
117 , nLastPos ( rStm.Tell() )
118 , nLogWidth100 ( 0UL )
119 , nLogHeight100 ( 0UL )
120 , nGlobalWidth ( 0 )
121 , nGlobalHeight ( 0 )
122 , nImageWidth ( 0 )
123 , nImageHeight ( 0 )
124 , nImagePosX ( 0 )
125 , nImagePosY ( 0 )
126 , nImageX ( 0 )
127 , nImageY ( 0 )
128 , nLastImageY ( 0 )
129 , nLastInterCount ( 0 )
130 , nLoops ( 1 )
131 , eActAction ( GLOBAL_HEADER_READING )
132 , bStatus ( false )
133 , bGCTransparent ( false )
134 , bInterlaced ( false)
135 , bOverreadBlock ( false )
136 , bImGraphicReady ( false )
137 , bGlobalPalette ( false )
138 , nBackgroundColor ( 0 )
139 , nGCTransparentIndex ( 0 )
140 , cTransIndex1 ( 0 )
141 , cNonTransIndex1 ( 0 )
143 maUpperName = "SVIGIF";
144 aSrcBuf.resize(256); // Memory buffer for ReadNextBlock
145 ClearImageExtensions();
148 GIFReader::~GIFReader()
150 aImGraphic.SetContext( nullptr );
153 void GIFReader::ClearImageExtensions()
155 nGCDisposalMethod = 0;
156 bGCTransparent = false;
157 nTimer = 0;
160 void GIFReader::CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal,
161 bool bWatchForBackgroundColor )
163 const Size aSize( nWidth, nHeight );
165 #if SAL_TYPES_SIZEOFPOINTER == 8
166 // Don't bother allocating a bitmap of a size that would fail on a
167 // 32-bit system. We have at least one unit tests that is expected
168 // to fail (loading a 65535*65535 size GIF
169 // svtools/qa/cppunit/data/gif/fail/CVE-2008-5937-1.gif), but
170 // which doesn't fail on 64-bit Mac OS X at least. Why the loading
171 // fails on 64-bit Linux, no idea.
172 if (nWidth >= 64000 && nHeight >= 64000)
174 bStatus = false;
175 return;
177 #endif
179 if( bGCTransparent )
181 const Color aWhite( COL_WHITE );
183 aBmp1 = Bitmap( aSize, 1 );
185 if( !aAnimation.Count() )
186 aBmp1.Erase( aWhite );
188 pAcc1 = Bitmap::ScopedWriteAccess(aBmp1);
190 if( pAcc1 )
192 cTransIndex1 = (sal_uInt8) pAcc1->GetBestPaletteIndex( aWhite );
193 cNonTransIndex1 = cTransIndex1 ? 0 : 1;
195 else
196 bStatus = false;
199 if( bStatus )
201 aBmp8 = Bitmap( aSize, 8, pPal );
203 if( !!aBmp8 && bWatchForBackgroundColor && aAnimation.Count() )
204 aBmp8.Erase( (*pPal)[ nBackgroundColor ] );
205 else
206 aBmp8.Erase( Color( COL_WHITE ) );
208 pAcc8 = Bitmap::ScopedWriteAccess(aBmp8);
209 bStatus = ( pAcc8 != nullptr );
213 bool GIFReader::ReadGlobalHeader()
215 char pBuf[ 7 ];
216 sal_uInt8 nRF;
217 sal_uInt8 nAspect;
218 bool bRet = false;
220 rIStm.ReadBytes( pBuf, 6 );
221 if( NO_PENDING( rIStm ) )
223 pBuf[ 6 ] = 0;
224 if( !strcmp( pBuf, "GIF87a" ) || !strcmp( pBuf, "GIF89a" ) )
226 rIStm.ReadBytes( pBuf, 7 );
227 if( NO_PENDING( rIStm ) )
229 SvMemoryStream aMemStm;
231 aMemStm.SetBuffer( pBuf, 7, 7 );
232 aMemStm.ReadUInt16( nGlobalWidth );
233 aMemStm.ReadUInt16( nGlobalHeight );
234 aMemStm.ReadUChar( nRF );
235 aMemStm.ReadUChar( nBackgroundColor );
236 aMemStm.ReadUChar( nAspect );
238 bGlobalPalette = ( nRF & 0x80 );
240 if( bGlobalPalette )
241 ReadPaletteEntries( &aGPalette, sal_uLong(1) << ( ( nRF & 7 ) + 1 ) );
242 else
243 nBackgroundColor = 0;
245 if( NO_PENDING( rIStm ) )
246 bRet = true;
249 else
250 bStatus = false;
253 return bRet;
256 void GIFReader::ReadPaletteEntries( BitmapPalette* pPal, sal_uLong nCount )
258 sal_uLong nLen = 3 * nCount;
259 const sal_uInt64 nMaxPossible = rIStm.remainingSize();
260 if (nLen > nMaxPossible)
261 nLen = nMaxPossible;
262 std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ nLen ]);
263 std::size_t nRead = rIStm.ReadBytes(pBuf.get(), nLen);
264 nCount = nRead/3UL;
265 if( NO_PENDING( rIStm ) )
267 sal_uInt8* pTmp = pBuf.get();
269 for (sal_uLong i = 0; i < nCount; ++i)
271 BitmapColor& rColor = (*pPal)[i];
273 rColor.SetRed( *pTmp++ );
274 rColor.SetGreen( *pTmp++ );
275 rColor.SetBlue( *pTmp++ );
278 // if possible accommodate some standard colours
279 if( nCount < 256 )
281 (*pPal)[ 255UL ] = Color( COL_WHITE );
283 if( nCount < 255 )
284 (*pPal)[ 254UL ] = Color( COL_BLACK );
289 bool GIFReader::ReadExtension()
291 bool bRet = false;
293 // Extension-Label
294 sal_uInt8 cFunction(0);
295 rIStm.ReadUChar( cFunction );
296 if( NO_PENDING( rIStm ) )
298 bool bOverreadDataBlocks = false;
299 sal_uInt8 cSize(0);
300 // Block length
301 rIStm.ReadUChar( cSize );
302 switch( cFunction )
304 // 'Graphic Control Extension'
305 case 0xf9 :
307 sal_uInt8 cFlags(0);
308 rIStm.ReadUChar(cFlags);
309 rIStm.ReadUInt16(nTimer);
310 rIStm.ReadUChar(nGCTransparentIndex);
311 sal_uInt8 cByte(0);
312 rIStm.ReadUChar(cByte);
314 if ( NO_PENDING( rIStm ) )
316 nGCDisposalMethod = ( cFlags >> 2) & 7;
317 bGCTransparent = ( cFlags & 1 );
318 bStatus = ( cSize == 4 ) && ( cByte == 0 );
319 bRet = true;
322 break;
324 // Application extension
325 case 0xff :
327 if ( NO_PENDING( rIStm ) )
329 // by default overread this extension
330 bOverreadDataBlocks = true;
332 // Appl. extension has length 11
333 if ( cSize == 0x0b )
335 OString aAppId = read_uInt8s_ToOString(rIStm, 8);
336 OString aAppCode = read_uInt8s_ToOString(rIStm, 3);
337 rIStm.ReadUChar( cSize );
339 // NetScape-Extension
340 if( aAppId == "NETSCAPE" && aAppCode == "2.0" && cSize == 3 )
342 sal_uInt8 cByte(0);
343 rIStm.ReadUChar( cByte );
345 // Loop-Extension
346 if ( cByte == 0x01 )
348 rIStm.ReadUChar( cByte );
349 nLoops = cByte;
350 rIStm.ReadUChar( cByte );
351 nLoops |= ( (sal_uInt16) cByte << 8 );
352 rIStm.ReadUChar( cByte );
354 bStatus = ( cByte == 0 );
355 bRet = NO_PENDING( rIStm );
356 bOverreadDataBlocks = false;
358 // Netscape interpretes the loop count
359 // as pure number of _repeats_;
360 // here it is the total number of loops
361 if( nLoops )
362 nLoops++;
364 else
365 rIStm.SeekRel( -1 );
367 else if ( aAppId == "STARDIV " && aAppCode == "5.0" && cSize == 9 )
369 sal_uInt8 cByte(0);
370 rIStm.ReadUChar( cByte );
372 // Loop extension
373 if ( cByte == 0x01 )
375 rIStm.ReadUInt32( nLogWidth100 ).ReadUInt32( nLogHeight100 );
376 rIStm.ReadUChar( cByte );
377 bStatus = ( cByte == 0 );
378 bRet = NO_PENDING( rIStm );
379 bOverreadDataBlocks = false;
381 else
382 rIStm.SeekRel( -1 );
388 break;
390 // overread everything else
391 default:
392 bOverreadDataBlocks = true;
393 break;
396 // overread sub-blocks
397 if ( bOverreadDataBlocks )
399 bRet = true;
400 while( cSize && bStatus && !rIStm.IsEof() )
402 sal_uInt16 nCount = (sal_uInt16) cSize + 1;
403 const sal_uInt64 nMaxPossible = rIStm.remainingSize();
404 if (nCount > nMaxPossible)
405 nCount = nMaxPossible;
407 if (nCount)
408 rIStm.SeekRel( nCount - 1 ); // Skip subblock data
410 bRet = false;
411 std::size_t nRead = rIStm.ReadBytes(&cSize, 1);
412 if (NO_PENDING(rIStm) && nRead == 1)
414 bRet = true;
416 else
417 cSize = 0;
422 return bRet;
425 bool GIFReader::ReadLocalHeader()
427 sal_uInt8 pBuf[ 9 ];
428 bool bRet = false;
430 std::size_t nRead = rIStm.ReadBytes(pBuf, 9);
431 if (NO_PENDING(rIStm) && nRead == 9)
433 SvMemoryStream aMemStm;
434 BitmapPalette* pPal;
436 aMemStm.SetBuffer( pBuf, 9, 9 );
437 aMemStm.ReadUInt16( nImagePosX );
438 aMemStm.ReadUInt16( nImagePosY );
439 aMemStm.ReadUInt16( nImageWidth );
440 aMemStm.ReadUInt16( nImageHeight );
441 sal_uInt8 nFlags(0);
442 aMemStm.ReadUChar(nFlags);
444 // if interlaced, first define startvalue
445 bInterlaced = ( ( nFlags & 0x40 ) == 0x40 );
446 nLastInterCount = 7;
447 nLastImageY = 0;
449 if( nFlags & 0x80 )
451 pPal = &aLPalette;
452 ReadPaletteEntries( pPal, sal_uLong(1) << ( (nFlags & 7 ) + 1 ) );
454 else
455 pPal = &aGPalette;
457 // if we could read everything, we will create the local image;
458 // if the global colour table is valid for the image, we will
459 // consider the BackGroudColorIndex.
460 if( NO_PENDING( rIStm ) )
462 CreateBitmaps( nImageWidth, nImageHeight, pPal, bGlobalPalette && ( pPal == &aGPalette ) );
463 bRet = true;
467 return bRet;
470 sal_uLong GIFReader::ReadNextBlock()
472 sal_uLong nRet = 0;
473 sal_uLong nRead;
474 sal_uInt8 cBlockSize;
476 rIStm.ReadUChar( cBlockSize );
478 if ( rIStm.IsEof() )
479 nRet = 4;
480 else if ( NO_PENDING( rIStm ) )
482 if ( cBlockSize == 0 )
483 nRet = 2;
484 else
486 rIStm.ReadBytes( aSrcBuf.data(), cBlockSize );
488 if( NO_PENDING( rIStm ) )
490 if( bOverreadBlock )
491 nRet = 3;
492 else
494 bool bEOI;
495 sal_uInt8* pTarget = pDecomp->DecompressBlock( aSrcBuf.data(), cBlockSize, nRead, bEOI );
497 nRet = ( bEOI ? 3 : 1 );
499 if( nRead && !bOverreadBlock )
500 FillImages( pTarget, nRead );
502 rtl_freeMemory( pTarget );
508 return nRet;
511 void GIFReader::FillImages( sal_uInt8* pBytes, sal_uLong nCount )
513 for( sal_uLong i = 0; i < nCount; i++ )
515 if( nImageX >= nImageWidth )
517 if( bInterlaced )
519 long nT1;
521 // lines will be copied if interlaced
522 if( nLastInterCount )
524 long nMinY = std::min( (long) nLastImageY + 1, (long) nImageHeight - 1 );
525 long nMaxY = std::min( (long) nLastImageY + nLastInterCount, (long) nImageHeight - 1 );
527 // copy last line read, if lines do not coincide
528 // ( happens at the end of the image )
529 if( ( nMinY > nLastImageY ) && ( nLastImageY < ( nImageHeight - 1 ) ) )
531 sal_uInt8* pScanline8 = pAcc8->GetScanline( nYAcc );
532 sal_uLong nSize8 = pAcc8->GetScanlineSize();
533 sal_uInt8* pScanline1 = nullptr;
534 sal_uLong nSize1 = 0;
536 if( bGCTransparent )
538 pScanline1 = pAcc1->GetScanline( nYAcc );
539 nSize1 = pAcc1->GetScanlineSize();
542 for( long j = nMinY; j <= nMaxY; j++ )
544 memcpy( pAcc8->GetScanline( j ), pScanline8, nSize8 );
546 if( bGCTransparent )
547 memcpy( pAcc1->GetScanline( j ), pScanline1, nSize1 );
552 nT1 = ( ++nImageY ) << 3;
553 nLastInterCount = 7;
555 if( nT1 >= nImageHeight )
557 long nT2 = nImageY - ( ( nImageHeight + 7 ) >> 3 );
558 nT1 = ( nT2 << 3 ) + 4;
559 nLastInterCount = 3;
561 if( nT1 >= nImageHeight )
563 nT2 -= ( nImageHeight + 3 ) >> 3;
564 nT1 = ( nT2 << 2 ) + 2;
565 nLastInterCount = 1;
567 if( nT1 >= nImageHeight )
569 nT2 -= ( nImageHeight + 1 ) >> 2;
570 nT1 = ( nT2 << 1 ) + 1;
571 nLastInterCount = 0;
576 nLastImageY = (sal_uInt16) nT1;
577 nYAcc = nT1;
579 else
581 nLastImageY = ++nImageY;
582 nYAcc = nImageY;
585 // line starts from the beginning
586 nImageX = 0;
589 if( nImageY < nImageHeight )
591 const sal_uInt8 cTmp = pBytes[ i ];
593 if( bGCTransparent )
595 if( cTmp == nGCTransparentIndex )
596 pAcc1->SetPixelIndex( nYAcc, nImageX++, cTransIndex1 );
597 else
599 pAcc8->SetPixelIndex( nYAcc, nImageX, cTmp );
600 pAcc1->SetPixelIndex( nYAcc, nImageX++, cNonTransIndex1 );
603 else
604 pAcc8->SetPixelIndex( nYAcc, nImageX++, cTmp );
606 else
608 bOverreadBlock = true;
609 break;
614 void GIFReader::CreateNewBitmaps()
616 AnimationBitmap aAnimBmp;
618 pAcc8.reset();
620 if( bGCTransparent )
622 pAcc1.reset();
623 aAnimBmp.aBmpEx = BitmapEx( aBmp8, aBmp1 );
625 else
626 aAnimBmp.aBmpEx = BitmapEx( aBmp8 );
628 aAnimBmp.aPosPix = Point( nImagePosX, nImagePosY );
629 aAnimBmp.aSizePix = Size( nImageWidth, nImageHeight );
630 aAnimBmp.nWait = ( nTimer != 65535 ) ? nTimer : ANIMATION_TIMEOUT_ON_CLICK;
631 aAnimBmp.bUserInput = false;
633 if( nGCDisposalMethod == 2 )
634 aAnimBmp.eDisposal = Disposal::Back;
635 else if( nGCDisposalMethod == 3 )
636 aAnimBmp.eDisposal = Disposal::Previous;
637 else
638 aAnimBmp.eDisposal = Disposal::Not;
640 aAnimation.Insert( aAnimBmp );
642 if( aAnimation.Count() == 1 )
644 aAnimation.SetDisplaySizePixel( Size( nGlobalWidth, nGlobalHeight ) );
645 aAnimation.SetLoopCount( nLoops );
649 const Graphic& GIFReader::GetIntermediateGraphic()
651 // only create intermediate graphic, if data is available
652 // but graphic still not completely read
653 if ( bImGraphicReady && !aAnimation.Count() )
655 Bitmap aBmp;
657 pAcc8.reset();
659 if ( bGCTransparent )
661 pAcc1.reset();
662 aImGraphic = BitmapEx( aBmp8, aBmp1 );
664 pAcc1 = Bitmap::ScopedWriteAccess(aBmp1);
665 bStatus = bStatus && ( pAcc1 != nullptr );
667 else
668 aImGraphic = aBmp8;
670 pAcc8 = Bitmap::ScopedWriteAccess(aBmp8);
671 bStatus = bStatus && ( pAcc8 != nullptr );
674 return aImGraphic;
677 bool GIFReader::ProcessGIF()
679 bool bRead = false;
680 bool bEnd = false;
682 if ( !bStatus )
683 eActAction = ABORT_READING;
685 // set stream to right position
686 rIStm.Seek( nLastPos );
688 switch( eActAction )
690 // read next marker
691 case MARKER_READING:
693 sal_uInt8 cByte;
695 rIStm.ReadUChar( cByte );
697 if( rIStm.IsEof() )
698 eActAction = END_READING;
699 else if( NO_PENDING( rIStm ) )
701 bRead = true;
703 if( cByte == '!' )
704 eActAction = EXTENSION_READING;
705 else if( cByte == ',' )
706 eActAction = LOCAL_HEADER_READING;
707 else if( cByte == ';' )
708 eActAction = END_READING;
709 else
710 eActAction = ABORT_READING;
713 break;
715 // read ScreenDescriptor
716 case GLOBAL_HEADER_READING:
718 if( ( bRead = ReadGlobalHeader() ) )
720 ClearImageExtensions();
721 eActAction = MARKER_READING;
724 break;
726 // read extension
727 case EXTENSION_READING:
729 if( ( bRead = ReadExtension() ) )
730 eActAction = MARKER_READING;
732 break;
734 // read Image-Descriptor
735 case LOCAL_HEADER_READING:
737 if( ( bRead = ReadLocalHeader() ) )
739 nYAcc = nImageX = nImageY = 0;
740 eActAction = FIRST_BLOCK_READING;
743 break;
745 // read first data block
746 case FIRST_BLOCK_READING:
748 sal_uInt8 cDataSize;
750 rIStm.ReadUChar( cDataSize );
752 if( rIStm.IsEof() )
753 eActAction = ABORT_READING;
754 else if( cDataSize > 12 )
755 bStatus = false;
756 else if( NO_PENDING( rIStm ) )
758 bRead = true;
759 pDecomp = o3tl::make_unique<GIFLZWDecompressor>( cDataSize );
760 eActAction = NEXT_BLOCK_READING;
761 bOverreadBlock = false;
763 else
764 eActAction = FIRST_BLOCK_READING;
766 break;
768 // read next data block
769 case NEXT_BLOCK_READING:
771 sal_uInt16 nLastX = nImageX;
772 sal_uInt16 nLastY = nImageY;
773 sal_uLong nRet = ReadNextBlock();
775 // Return: 0:Pending / 1:OK; / 2:OK and last block: / 3:EOI / 4:HardAbort
776 if( nRet )
778 bRead = true;
780 if ( nRet == 1 )
782 bImGraphicReady = true;
783 eActAction = NEXT_BLOCK_READING;
784 bOverreadBlock = false;
786 else
788 if( nRet == 2 )
790 pDecomp.reset();
791 CreateNewBitmaps();
792 eActAction = MARKER_READING;
793 ClearImageExtensions();
795 else if( nRet == 3 )
797 eActAction = NEXT_BLOCK_READING;
798 bOverreadBlock = true;
800 else
802 pDecomp.reset();
803 CreateNewBitmaps();
804 eActAction = ABORT_READING;
805 ClearImageExtensions();
809 else
811 nImageX = nLastX;
812 nImageY = nLastY;
815 break;
817 // an error occurred
818 case ABORT_READING:
820 bEnd = true;
821 eActAction = END_READING;
823 break;
825 default:
826 break;
829 // set stream to right position,
830 // if data could be read put it a the old
831 // position otherwise at the actual one
832 if( bRead || bEnd )
833 nLastPos = rIStm.Tell();
835 return bRead;
838 ReadState GIFReader::ReadGIF( Graphic& rGraphic )
840 ReadState eReadState;
842 bStatus = true;
844 while( ProcessGIF() && ( eActAction != END_READING ) ) {}
846 if( !bStatus )
847 eReadState = GIFREAD_ERROR;
848 else if( eActAction == END_READING )
849 eReadState = GIFREAD_OK;
850 else
852 if ( rIStm.GetError() == ERRCODE_IO_PENDING )
853 rIStm.ResetError();
855 eReadState = GIFREAD_NEED_MORE;
858 if( aAnimation.Count() == 1 )
860 rGraphic = aAnimation.Get( 0 ).aBmpEx;
862 if( nLogWidth100 && nLogHeight100 )
864 rGraphic.SetPrefSize( Size( nLogWidth100, nLogHeight100 ) );
865 rGraphic.SetPrefMapMode( MapUnit::Map100thMM );
868 else
869 rGraphic = aAnimation;
871 return eReadState;
874 VCL_DLLPUBLIC bool ImportGIF( SvStream & rStm, Graphic& rGraphic )
876 std::shared_ptr<GraphicReader> pContext = rGraphic.GetContext();
877 rGraphic.SetContext(nullptr);
878 GIFReader* pGIFReader = dynamic_cast<GIFReader*>( pContext.get() );
879 if (!pGIFReader)
881 pContext = std::make_shared<GIFReader>( rStm );
882 pGIFReader = static_cast<GIFReader*>( pContext.get() );
885 SvStreamEndian nOldFormat = rStm.GetEndian();
886 rStm.SetEndian( SvStreamEndian::LITTLE );
888 bool bRet = true;
890 ReadState eReadState = pGIFReader->ReadGIF(rGraphic);
892 if (eReadState == GIFREAD_ERROR)
894 bRet = false;
896 else if (eReadState == GIFREAD_NEED_MORE)
898 rGraphic = pGIFReader->GetIntermediateGraphic();
899 rGraphic.SetContext(pContext);
902 rStm.SetEndian(nOldFormat);
904 return bRet;
907 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */