202int QGIFFormat::decode(QImage *image,
const uchar *buffer,
int length,
203 int *nextFrameDelay,
int *loopCount)
211 stack =
new short[(1 << max_lzw_bits) * 4];
212 table[0] = &stack[(1 << max_lzw_bits) * 2];
213 table[1] = &stack[(1 << max_lzw_bits) * 3];
217 qsizetype bpl = image->bytesPerLine();
218 unsigned char *bits = image->bits();
220#define LM(l, m) (((m)<<8
)|l)
222 const int initial = length;
223 while (!digress && length) {
225 unsigned char ch=*buffer++;
231 gif89=(hold[3]!=
'8' || hold[4]!=
'7');
232 state=LogicalScreenDescriptor;
236 case LogicalScreenDescriptor:
240 swidth=
LM(hold[0], hold[1]);
241 sheight=
LM(hold[2], hold[3]);
242 gcmap=!!(hold[4]&0x80);
245 gncols=2<<(hold[4]&0x7);
246 bgcol=(gcmap) ? hold[5] : -1;
254 state=GlobalColorMap;
255 globalcmap =
new QRgb[gncols+1];
262 case GlobalColorMap:
case LocalColorMap:
265 QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
266 if (state == LocalColorMap) {
268 localcmap[ccount] = rgb;
270 globalcmap[ccount] = rgb;
272 if (++ccount >= ncols) {
273 if (state == LocalColorMap)
274 state=TableImageLZWSize;
285 state=ImageDescriptor;
288 state=ExtensionLabel;
300 case ImageDescriptor:
303 int newleft=
LM(hold[1], hold[2]);
304 int newtop=
LM(hold[3], hold[4]);
305 int newwidth=
LM(hold[5], hold[6]);
306 int newheight=
LM(hold[7], hold[8]);
310 if (swidth/10 > qMax(newwidth,16384))
312 if (sheight/10 > qMax(newheight,16384))
316 swidth = newleft + newwidth;
318 sheight = newtop + newheight;
320 QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
321 if (image->isNull()) {
322 if (!withinSizeLimit(swidth, sheight)) {
326 if (!QImageIOHandler::allocateImage(QSize(swidth, sheight), format, image)) {
330 bpl = image->bytesPerLine();
331 bits = image->bits();
333 memset(bits, 0, image->sizeInBytes());
338 if (image->isNull()) {
343 disposePrevious(image);
351 right=qMax(0, qMin(left+width, swidth)-1);
352 bottom=qMax(0, qMin(top+height, sheight)-1);
353 lcmap=!!(hold[9]&0x80);
354 interlace=!!(hold[9]&0x40);
356 lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
360 localcmap =
new QRgb[lncols+1];
368 if (left || top || width<swidth || height<sheight) {
370 if (trans_index >= 0) {
371 fillRect(image, 0, 0, swidth, sheight, color(trans_index));
373 }
else if (bgcol>=0) {
374 fillRect(image, 0, 0, swidth, sheight, color(bgcol));
380 if (disposal == RestoreImage) {
381 int l = qMin(swidth-1,left);
382 int r = qMin(swidth-1,right);
383 int t = qMin(sheight-1,top);
384 int b = qMin(sheight-1,bottom);
388 if (backingstore.width() < w
389 || backingstore.height() < h) {
391 if (!withinSizeLimit(w, h)) {
396 QSize bsSize(qMax(backingstore.width(), w), qMax(backingstore.height(), h));
397 if (!QImageIOHandler::allocateImage(bsSize, QImage::Format_RGB32,
402 memset(backingstore.bits(), 0, backingstore.sizeInBytes());
404 const qsizetype dest_bpl = backingstore.bytesPerLine();
405 unsigned char *dest_data = backingstore.bits();
406 for (
int ln=0; ln<h; ln++) {
408 FAST_SCAN_LINE(bits, bpl, t+ln) + l*
sizeof(QRgb), w*
sizeof(QRgb));
417 state=TableImageLZWSize;
424 firstcode = oldcode = 0;
426 out_of_bounds = left>=swidth || y>=sheight;
429 case TableImageLZWSize: {
431 if (lzwsize > max_lzw_bits) {
435 clear_code=1<<lzwsize;
436 end_code=clear_code+1;
437 max_code_size=2*clear_code;
438 max_code=clear_code+2;
440 for (i=0; i<clear_code; i++) {
444 state=ImageDataBlockSize;
448 }
case ImageDataBlockSize:
451 state=ImageDataBlock;
460 if (bitcount != -32768) {
461 if (bitcount < 0 || bitcount > 31) {
465 accum |= (ch << bitcount);
468 while (bitcount>=code_size && state==ImageDataBlock) {
469 int code=accum&((1<<code_size)-1);
473 if (code==clear_code) {
476 max_code_size=2*clear_code;
477 max_code=clear_code+2;
480 }
else if (code==end_code) {
485 firstcode=oldcode=code;
486 if (!out_of_bounds && image->height() > y && ((frame == 0) || (firstcode != trans_index)))
489 if (x>=swidth) out_of_bounds =
true;
493 out_of_bounds = left>=swidth || y>=sheight;
498 if (code>=max_code) {
502 while (code>=clear_code+2) {
503 if (code >= max_code) {
507 *sp++=table[1][code];
508 if (code==table[0][code]) {
512 if (sp-stack>=(1<<(max_lzw_bits))*2) {
523 *sp++=firstcode=table[1][code];
525 if (code<(1<<max_lzw_bits)) {
526 table[0][code]=oldcode;
527 table[1][code]=firstcode;
529 if ((max_code>=max_code_size)
530 && (max_code_size<(1<<max_lzw_bits)))
537 const int h = image->height();
538 QRgb *line =
nullptr;
539 if (!out_of_bounds && h > y)
542 const uchar index = *(--sp);
543 if (!out_of_bounds && h > y && ((frame == 0) || (index != trans_index))) {
544 line[x] = color(index);
547 if (x>=swidth) out_of_bounds =
true;
550 out_of_bounds = left>=swidth || y>=sheight;
552 if (!out_of_bounds && h > y)
559 partialNewFrame =
true;
560 if (count==expectcount) {
562 state=ImageDataBlockSize;
568 state=GraphicControlExtension;
571 state=ApplicationExtension;
575 state=CommentExtension;
584 memset(hold, 0,
sizeof(hold));
586 case ApplicationExtension:
587 if (count<11) hold[count]=ch;
589 if (count==hold[0]+1) {
590 if (qstrncmp((
char*)(hold+1),
"NETSCAPE", 8)==0) {
592 state=NetscapeExtensionBlockSize;
599 case NetscapeExtensionBlockSize:
602 memset(hold, 0,
sizeof(hold));
603 if (expectcount) state=NetscapeExtensionBlock;
604 else state=Introducer;
606 case NetscapeExtensionBlock:
607 if (count<3) hold[count]=ch;
609 if (count==expectcount) {
610 *loopCount = hold[1]+hold[2]*256;
614 case GraphicControlExtension:
615 if (count<5) hold[count]=ch;
617 if (count==hold[0]+1) {
618 disposePrevious(image);
619 uint dBits = (hold[1] >> 2) & 0x7;
620 disposal = (dBits <= RestoreImage) ? Disposal(dBits) : NoDisposal;
622 int delay=count>3 ?
LM(hold[2], hold[3]) : 1;
625 *nextFrameDelay = (delay < 2 ? 10 : delay) * 10;
627 bool havetrans=hold[1]&0x1;
628 trans_index = havetrans ? hold[4] : -1;
637 if (expectcount) state=SkipBlock;
638 else state=Introducer;
642 if (count==expectcount) state=SkipBlockSize;
647
648
649
655 return initial-length;
664void QGIFFormat::
scan(QIODevice *device, QSize *imageSize,
int *imageCount,
int *loopCount)
666 *imageSize = QSize();
671 qint64 oldPos = device->pos();
672 if (device->isSequential() || !device->seek(0))
676 int localColorCount = 0;
677 int globalColorCount = 0;
678 int colorReadCount = 0;
679 bool localColormap =
false;
680 bool globalColormap =
false;
686 uchar hold[16] = { };
687 State state = Header;
689 const int readBufferSize = 40960;
690 QByteArray readBuffer(device->read(readBufferSize));
692 if (readBuffer.isEmpty()) {
693 device->seek(oldPos);
702 while (!readBuffer.isEmpty()) {
703 int length = readBuffer.size();
704 const uchar *buffer = (
const uchar *) readBuffer.constData();
705 while (!done && length) {
707 uchar ch = *buffer++;
712 state = LogicalScreenDescriptor;
716 case LogicalScreenDescriptor:
719 imageWidth =
LM(hold[0], hold[1]);
720 imageHeight =
LM(hold[2], hold[3]);
721 globalColormap = !!(hold[4] & 0x80);
722 globalColorCount = 2 << (hold[4] & 0x7);
724 colorCount = globalColorCount;
725 if (globalColormap) {
726 int colorTableSize = 3 * globalColorCount;
727 if (length >= colorTableSize) {
729 length -= colorTableSize;
730 buffer += colorTableSize;
734 state = GlobalColorMap;
745 if (++colorReadCount >= colorCount) {
746 if (state == LocalColorMap)
747 state = TableImageLZWSize;
758 state = ImageDescriptor;
761 state = ExtensionLabel;
771 case ImageDescriptor:
774 int newLeft =
LM(hold[1], hold[2]);
775 int newTop =
LM(hold[3], hold[4]);
776 int newWidth =
LM(hold[5], hold[6]);
777 int newHeight =
LM(hold[7], hold[8]);
780 if (*imageCount == 0) {
781 if (imageWidth / 10 > qMax(newWidth, 16384))
783 if (imageHeight / 10 > qMax(newHeight, 16384))
787 imageWidth = newLeft + newWidth;
788 if (imageHeight <= 0)
789 imageHeight = newTop + newHeight;
791 if (!withinSizeLimit(imageWidth, imageHeight)) {
796 *imageSize = QSize(imageWidth, imageHeight);
798 if (*imageCount <
std::numeric_limits<
int>::max())
801 localColormap = !!(hold[9] & 0x80);
802 localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0;
804 colorCount = localColorCount;
806 colorCount = globalColorCount;
810 int colorTableSize = 3 * localColorCount;
811 if (length >= colorTableSize) {
813 length -= colorTableSize;
814 buffer += colorTableSize;
815 state = TableImageLZWSize;
818 state = LocalColorMap;
821 state = TableImageLZWSize;
825 case TableImageLZWSize:
826 if (ch > max_lzw_bits)
829 state = ImageDataBlockSize;
832 case ImageDataBlockSize:
835 if (length >= blockSize) {
841 state = ImageDataBlock;
849 if (count == blockSize) {
851 state = ImageDataBlockSize;
857 state = GraphicControlExtension;
860 state = ApplicationExtension;
863 state = SkipBlockSize;
866 memset(hold, 0,
sizeof(hold));
868 case ApplicationExtension:
872 if (count == hold[0] + 1) {
873 if (qstrncmp((
char*)(hold+1),
"NETSCAPE", 8) == 0)
874 state=NetscapeExtensionBlockSize;
880 case GraphicControlExtension:
884 if (count == hold[0] + 1) {
886 state = SkipBlockSize;
889 case NetscapeExtensionBlockSize:
892 memset(hold, 0,
sizeof(hold));
894 state = NetscapeExtensionBlock;
898 case NetscapeExtensionBlock:
902 if (count == blockSize) {
903 *loopCount =
LM(hold[1], hold[2]);
904 state = SkipBlockSize;
911 if (length >= blockSize) {
924 if (count == blockSize)
925 state = SkipBlockSize;
931 device->seek(oldPos);
935 readBuffer = device->read(readBufferSize);
937 device->seek(oldPos);