1 /*
2 (c) Copyright 2001-2010 The world wide DirectFB Open Source Community (directfb.org)
3 (c) Copyright 2000-2004 Convergence (integrated media) GmbH
4
5 All rights reserved.
6
7 Written by Denis Oliver Kropp <dok@directfb.org>,
8 Andreas Hundt <andi@fischlustig.de>,
9 Sven Neumann <neo@directfb.org>,
10 Ville Syrjälä <syrjala@sci.fi> and
11 Claudio Ciccani <klan@users.sf.net>.
12
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2 of the License, or (at your option) any later version.
17
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the
25 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 Boston, MA 02111-1307, USA.
27 */
28
29 #include <config.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <stdarg.h>
37
38 #include <directfb.h>
39
40 #include <display/idirectfbsurface.h>
41
42 #include <media/idirectfbimageprovider.h>
43
44 #include <core/layers.h>
45
46 #include <core/CoreSurface.h>
47
48 #include <misc/gfx_util.h>
49 #include <direct/interface.h>
50 #include <direct/mem.h>
51 #include <direct/memcpy.h>
52 #include <misc/util.h>
53
54 static DFBResult
55 Probe( IDirectFBImageProvider_ProbeContext *ctx );
56
57 static DFBResult
58 Construct( IDirectFBImageProvider *thiz,
59 ... );
60
61 #include <direct/interface_implementation.h>
62
63 DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBImageProvider, GIF )
64
65
66 #ifndef NODEBUG
67 #define GIFERRORMSG(...) { fprintf( stderr, "(GIFLOADER) " __VA_ARGS__ ); \
68 fprintf( stderr, "\n" ); }
69 #else
70 #define GIFERRORMSG(...)
71 #endif
72
73 #define MAXCOLORMAPSIZE 256
74
75 #define CM_RED 0
76 #define CM_GREEN 1
77 #define CM_BLUE 2
78
79 #define MAX_LWZ_BITS 12
80
81 #define INTERLACE 0x40
82 #define LOCALCOLORMAP 0x80
83
84 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
85
86 #define LM_to_uint(a,b) (((b)<<8)|(a))
87
88 /*
89 * private data struct of IDirectFBImageProvider_GIF
90 */
91 typedef struct {
92 IDirectFBImageProvider_data base;
93
94 u32 *image;
95 int image_width;
96 int image_height;
97 bool image_transparency;
98 u32 image_colorkey;
99
100 unsigned int Width;
101 unsigned int Height;
102 u8 ColorMap[3][MAXCOLORMAPSIZE];
103 unsigned int BitPixel;
104 unsigned int ColorResolution;
105 u32 Background;
106 unsigned int AspectRatio;
107
108
109 int GrayScale;
110 int transparent;
111 int delayTime;
112 int inputFlag;
113 int disposal;
114
115
116 u8 buf[280];
117 int curbit, lastbit, done, last_byte;
118
119
120 int fresh;
121 int code_size, set_code_size;
122 int max_code, max_code_size;
123 int firstcode, oldcode;
124 int clear_code, end_code;
125 int table[2][(1<< MAX_LWZ_BITS)];
126 int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
127 } IDirectFBImageProvider_GIF_data;
128
129 static bool verbose = false;
130 static bool showComment = false;
131 static bool ZeroDataBlock = false;
132
133 static u32* ReadGIF( IDirectFBImageProvider_GIF_data *data, int imageNumber,
134 int *width, int *height, bool *transparency,
135 u32 *key_rgb, bool alpha, bool headeronly);
136
137 static bool ReadOK( IDirectFBDataBuffer *buffer, void *data, unsigned int len );
138
139
140 static DFBResult
141 IDirectFBImageProvider_GIF_RenderTo( IDirectFBImageProvider *thiz,
142 IDirectFBSurface *destination,
143 const DFBRectangle *destination_rect );
144
145 static DFBResult
146 IDirectFBImageProvider_GIF_GetSurfaceDescription( IDirectFBImageProvider *thiz,
147 DFBSurfaceDescription *dsc );
148
149 static DFBResult
150 IDirectFBImageProvider_GIF_GetImageDescription( IDirectFBImageProvider *thiz,
151 DFBImageDescription *dsc );
152
153
154 static void
IDirectFBImageProvider_GIF_Destruct(IDirectFBImageProvider * thiz)155 IDirectFBImageProvider_GIF_Destruct( IDirectFBImageProvider *thiz )
156 {
157 IDirectFBImageProvider_GIF_data *data =
158 (IDirectFBImageProvider_GIF_data*)thiz->priv;
159
160 if (data->image)
161 D_FREE( data->image );
162 }
163
164 static DFBResult
Probe(IDirectFBImageProvider_ProbeContext * ctx)165 Probe( IDirectFBImageProvider_ProbeContext *ctx )
166 {
167 if (strncmp ((char*) ctx->header, "GIF8", 4) == 0)
168 return DFB_OK;
169
170 return DFB_UNSUPPORTED;
171 }
172
173 static DFBResult
Construct(IDirectFBImageProvider * thiz,...)174 Construct( IDirectFBImageProvider *thiz,
175 ... )
176 {
177 IDirectFBDataBuffer *buffer;
178 CoreDFB *core;
179 va_list tag;
180
181 DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IDirectFBImageProvider_GIF)
182
183 va_start( tag, thiz );
184 buffer = va_arg( tag, IDirectFBDataBuffer * );
185 core = va_arg( tag, CoreDFB * );
186 va_end( tag );
187
188 data->base.ref = 1;
189
190 data->base.buffer = buffer;
191 data->base.core = core;
192
193 buffer->AddRef( buffer );
194
195 data->GrayScale = -1;
196 data->transparent = -1;
197 data->delayTime = -1;
198
199 data->image = ReadGIF( data, 1, &data->image_width, &data->image_height,
200 &data->image_transparency, &data->image_colorkey,
201 true, false );
202
203 buffer->Release( buffer );
204 data->base.buffer = NULL;
205
206 if (!data->image ||
207 (data->image_height == 0) ||
208 (data->image_width == 0) ) {
209 DIRECT_DEALLOCATE_INTERFACE( thiz );
210 return DFB_FAILURE;
211 }
212
213 data->base.Destruct = IDirectFBImageProvider_GIF_Destruct;
214
215 thiz->RenderTo = IDirectFBImageProvider_GIF_RenderTo;
216 thiz->GetImageDescription = IDirectFBImageProvider_GIF_GetImageDescription;
217 thiz->GetSurfaceDescription =
218 IDirectFBImageProvider_GIF_GetSurfaceDescription;
219
220 return DFB_OK;
221 }
222
223 static DFBResult
IDirectFBImageProvider_GIF_RenderTo(IDirectFBImageProvider * thiz,IDirectFBSurface * destination,const DFBRectangle * dest_rect)224 IDirectFBImageProvider_GIF_RenderTo( IDirectFBImageProvider *thiz,
225 IDirectFBSurface *destination,
226 const DFBRectangle *dest_rect )
227 {
228 DFBResult ret;
229 DFBRegion clip;
230 DFBRectangle rect;
231 DFBSurfacePixelFormat format;
232 IDirectFBSurface_data *dst_data;
233 CoreSurface *dst_surface;
234
235 DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF)
236
237 dst_data = (IDirectFBSurface_data*) destination->priv;
238 if (!dst_data)
239 return DFB_DEAD;
240
241 dst_surface = dst_data->surface;
242 if (!dst_surface)
243 return DFB_DESTROYED;
244
245 dfb_region_from_rectangle( &clip, &dst_data->area.current );
246
247 if (dest_rect) {
248 if (dest_rect->w < 1 || dest_rect->h < 1)
249 return DFB_INVARG;
250 rect = *dest_rect;
251 rect.x += dst_data->area.wanted.x;
252 rect.y += dst_data->area.wanted.y;
253 }
254 else {
255 rect = dst_data->area.wanted;
256 }
257
258 ret = destination->GetPixelFormat( destination, &format );
259 if (ret)
260 return ret;
261
262 /* actual loading and rendering */
263 if (dfb_rectangle_region_intersects( &rect, &clip )) {
264 CoreSurfaceBufferLock lock;
265
266 ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
267 if (ret)
268 return ret;
269
270 dfb_scale_linear_32( data->image, data->image_width, data->image_height,
271 lock.addr, lock.pitch, &rect, dst_surface, &clip );
272
273 dfb_surface_unlock_buffer( dst_surface, &lock );
274
275 if (data->base.render_callback) {
276 DIRenderCallbackResult r;
277
278 rect.x = 0;
279 rect.y = 0;
280 rect.w = data->image_width;
281 rect.h = data->image_height;
282
283 r = data->base.render_callback( &rect,
284 data->base.render_callback_context );
285
286 if (r != DIRCR_OK)
287 return DFB_INTERRUPTED;
288 }
289 }
290
291 return DFB_OK;
292 }
293
294 static DFBResult
IDirectFBImageProvider_GIF_GetSurfaceDescription(IDirectFBImageProvider * thiz,DFBSurfaceDescription * dsc)295 IDirectFBImageProvider_GIF_GetSurfaceDescription( IDirectFBImageProvider *thiz,
296 DFBSurfaceDescription *dsc )
297 {
298 DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF)
299
300 dsc->flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
301 dsc->width = data->image_width;
302 dsc->height = data->image_height;
303 dsc->pixelformat = dfb_primary_layer_pixelformat();
304
305 return DFB_OK;
306 }
307
308 static DFBResult
IDirectFBImageProvider_GIF_GetImageDescription(IDirectFBImageProvider * thiz,DFBImageDescription * dsc)309 IDirectFBImageProvider_GIF_GetImageDescription( IDirectFBImageProvider *thiz,
310 DFBImageDescription *dsc )
311 {
312 DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF)
313
314 if (data->image_transparency) {
315 dsc->caps = DICAPS_COLORKEY;
316
317 dsc->colorkey_r = (data->image_colorkey & 0xff0000) >> 16;
318 dsc->colorkey_g = (data->image_colorkey & 0x00ff00) >> 8;
319 dsc->colorkey_b = (data->image_colorkey & 0x0000ff);
320 }
321 else
322 dsc->caps = DICAPS_NONE;
323
324 return DFB_OK;
325 }
326
327
328 /**********************************
329 GIF Loader Code
330 **********************************/
331
ReadColorMap(IDirectFBDataBuffer * buffer,int number,u8 buf[3][MAXCOLORMAPSIZE])332 static int ReadColorMap( IDirectFBDataBuffer *buffer, int number,
333 u8 buf[3][MAXCOLORMAPSIZE] )
334 {
335 int i;
336 u8 rgb[3];
337
338 for (i = 0; i < number; ++i) {
339 if (! ReadOK( buffer, rgb, sizeof(rgb) )) {
340 GIFERRORMSG("bad colormap" );
341 return true;
342 }
343
344 buf[CM_RED][i] = rgb[0] ;
345 buf[CM_GREEN][i] = rgb[1] ;
346 buf[CM_BLUE][i] = rgb[2] ;
347 }
348 return false;
349 }
350
GetDataBlock(IDirectFBDataBuffer * buffer,u8 * buf)351 static int GetDataBlock(IDirectFBDataBuffer *buffer, u8 *buf)
352 {
353 unsigned char count;
354
355 if (! ReadOK( buffer, &count, 1 )) {
356 GIFERRORMSG("error in getting DataBlock size" );
357 return -1;
358 }
359 ZeroDataBlock = count == 0;
360
361 if ((count != 0) && (! ReadOK( buffer, buf, count ))) {
362 GIFERRORMSG("error in reading DataBlock" );
363 return -1;
364 }
365
366 return count;
367 }
368
GetCode(IDirectFBImageProvider_GIF_data * data,int code_size,int flag)369 static int GetCode(IDirectFBImageProvider_GIF_data *data, int code_size, int flag)
370 {
371 int i, j, ret;
372 unsigned char count;
373
374 if (flag) {
375 data->curbit = 0;
376 data->lastbit = 0;
377 data->done = false;
378 return 0;
379 }
380
381 if ( (data->curbit+code_size) >= data->lastbit) {
382 if (data->done) {
383 if (data->curbit >= data->lastbit) {
384 GIFERRORMSG("ran off the end of my bits" );
385 }
386 return -1;
387 }
388 data->buf[0] = data->buf[data->last_byte-2];
389 data->buf[1] = data->buf[data->last_byte-1];
390
391 if ((count = GetDataBlock( data->base.buffer, &data->buf[2] )) == 0) {
392 data->done = true;
393 }
394
395 data->last_byte = 2 + count;
396 data->curbit = (data->curbit - data->lastbit) + 16;
397 data->lastbit = (2+count) * 8;
398 }
399
400 ret = 0;
401 for (i = data->curbit, j = 0; j < code_size; ++i, ++j) {
402 ret |= ((data->buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
403 }
404 data->curbit += code_size;
405
406 return ret;
407 }
408
DoExtension(IDirectFBImageProvider_GIF_data * data,int label)409 static int DoExtension( IDirectFBImageProvider_GIF_data *data, int label )
410 {
411 unsigned char buf[256] = { 0 };
412 char *str;
413
414 switch (label) {
415 case 0x01: /* Plain Text Extension */
416 str = "Plain Text Extension";
417 break;
418 case 0xff: /* Application Extension */
419 str = "Application Extension";
420 break;
421 case 0xfe: /* Comment Extension */
422 str = "Comment Extension";
423 while (GetDataBlock( data->base.buffer, (u8*) buf ) != 0) {
424 if (showComment)
425 GIFERRORMSG("gif comment: %s", buf );
426 }
427 return false;
428 case 0xf9: /* Graphic Control Extension */
429 str = "Graphic Control Extension";
430 (void) GetDataBlock( data->base.buffer, (u8*) buf );
431 data->disposal = (buf[0] >> 2) & 0x7;
432 data->inputFlag = (buf[0] >> 1) & 0x1;
433 data->delayTime = LM_to_uint( buf[1], buf[2] );
434 if ((buf[0] & 0x1) != 0) {
435 data->transparent = buf[3];
436 }
437 while (GetDataBlock( data->base.buffer, (u8*) buf ) != 0)
438 ;
439 return false;
440 default:
441 str = (char*) buf;
442 snprintf(str, 256, "UNKNOWN (0x%02x)", label);
443 break;
444 }
445
446 if (verbose)
447 GIFERRORMSG("got a '%s' extension", str );
448
449 while (GetDataBlock( data->base.buffer, (u8*) buf ) != 0)
450 ;
451
452 return false;
453 }
454
LWZReadByte(IDirectFBImageProvider_GIF_data * data,int flag,int input_code_size)455 static int LWZReadByte( IDirectFBImageProvider_GIF_data *data, int flag, int input_code_size )
456 {
457 int code, incode;
458 int i;
459
460 if (flag) {
461 data->set_code_size = input_code_size;
462 data->code_size = data->set_code_size+1;
463 data->clear_code = 1 << data->set_code_size ;
464 data->end_code = data->clear_code + 1;
465 data->max_code_size = 2*data->clear_code;
466 data->max_code = data->clear_code+2;
467
468 GetCode(data, 0, true);
469
470 data->fresh = true;
471
472 for (i = 0; i < data->clear_code; ++i) {
473 data->table[0][i] = 0;
474 data->table[1][i] = i;
475 }
476 for (; i < (1<<MAX_LWZ_BITS); ++i) {
477 data->table[0][i] = data->table[1][0] = 0;
478 }
479 data->sp = data->stack;
480
481 return 0;
482 }
483 else if (data->fresh) {
484 data->fresh = false;
485 do {
486 data->firstcode = data->oldcode = GetCode( data, data->code_size, false );
487 } while (data->firstcode == data->clear_code);
488
489 return data->firstcode;
490 }
491
492 if (data->sp > data->stack) {
493 return *--data->sp;
494 }
495
496 while ((code = GetCode( data, data->code_size, false )) >= 0) {
497 if (code == data->clear_code) {
498 for (i = 0; i < data->clear_code; ++i) {
499 data->table[0][i] = 0;
500 data->table[1][i] = i;
501 }
502 for (; i < (1<<MAX_LWZ_BITS); ++i) {
503 data->table[0][i] = data->table[1][i] = 0;
504 }
505 data->code_size = data->set_code_size+1;
506 data->max_code_size = 2*data->clear_code;
507 data->max_code = data->clear_code+2;
508 data->sp = data->stack;
509 data->firstcode = data->oldcode = GetCode( data, data->code_size, false );
510
511 return data->firstcode;
512 }
513 else if (code == data->end_code) {
514 int count;
515 u8 buf[260];
516
517 if (ZeroDataBlock) {
518 return -2;
519 }
520
521 while ((count = GetDataBlock( data->base.buffer, buf )) > 0)
522 ;
523
524 if (count != 0)
525 GIFERRORMSG("missing EOD in data stream "
526 "(common occurence)");
527
528 return -2;
529 }
530
531 incode = code;
532
533 if (code >= data->max_code) {
534 *data->sp++ = data->firstcode;
535 code = data->oldcode;
536 }
537
538 while (code >= data->clear_code) {
539 *data->sp++ = data->table[1][code];
540 if (code == data->table[0][code]) {
541 GIFERRORMSG("circular table entry BIG ERROR");
542 }
543 code = data->table[0][code];
544 }
545
546 *data->sp++ = data->firstcode = data->table[1][code];
547
548 if ((code = data->max_code) <(1<<MAX_LWZ_BITS)) {
549 data->table[0][code] = data->oldcode;
550 data->table[1][code] = data->firstcode;
551 ++data->max_code;
552 if ((data->max_code >= data->max_code_size)
553 && (data->max_code_size < (1<<MAX_LWZ_BITS)))
554 {
555 data->max_code_size *= 2;
556 ++data->code_size;
557 }
558 }
559
560 data->oldcode = incode;
561
562 if (data->sp > data->stack) {
563 return *--data->sp;
564 }
565 }
566 return code;
567 }
568
SortColors(const void * a,const void * b)569 static int SortColors (const void *a, const void *b)
570 {
571 return (*((const u8 *) a) - *((const u8 *) b));
572 }
573
574 /* looks for a color that is not in the colormap and ideally not
575 even close to the colors used in the colormap */
FindColorKey(int n_colors,u8 cmap[3][MAXCOLORMAPSIZE])576 static u32 FindColorKey( int n_colors, u8 cmap[3][MAXCOLORMAPSIZE] )
577 {
578 u32 color = 0xFF000000;
579 u8 csort[MAXCOLORMAPSIZE];
580 int i, j, index, d;
581
582 if (n_colors < 1)
583 return color;
584
585 D_ASSERT( n_colors <= MAXCOLORMAPSIZE );
586
587 for (i = 0; i < 3; i++) {
588 direct_memcpy( csort, cmap[i], n_colors );
589 qsort( csort, n_colors, 1, SortColors );
590
591 for (j = 1, index = 0, d = 0; j < n_colors; j++) {
592 if (csort[j] - csort[j-1] > d) {
593 d = csort[j] - csort[j-1];
594 index = j;
595 }
596 }
597 if ((csort[0] - 0x0) > d) {
598 d = csort[0] - 0x0;
599 index = n_colors;
600 }
601 if (0xFF - (csort[n_colors - 1]) > d) {
602 index = n_colors + 1;
603 }
604
605 if (index < n_colors)
606 csort[0] = csort[index] - (d/2);
607 else if (index == n_colors)
608 csort[0] = 0x0;
609 else
610 csort[0] = 0xFF;
611
612 color |= (csort[0] << (8 * (2 - i)));
613 }
614
615 return color;
616 }
617
ReadImage(IDirectFBImageProvider_GIF_data * data,int width,int height,u8 cmap[3][MAXCOLORMAPSIZE],u32 key_rgb,bool interlace,bool ignore)618 static u32* ReadImage( IDirectFBImageProvider_GIF_data *data, int width, int height,
619 u8 cmap[3][MAXCOLORMAPSIZE], u32 key_rgb,
620 bool interlace, bool ignore )
621 {
622 u8 c;
623 int v;
624 int xpos = 0, ypos = 0, pass = 0;
625 u32 *image;
626
627 /*
628 ** Initialize the decompression routines
629 */
630 if (! ReadOK( data->base.buffer, &c, 1 ))
631 GIFERRORMSG("EOF / read error on image data" );
632
633 if (LWZReadByte( data, true, c ) < 0)
634 GIFERRORMSG("error reading image" );
635
636 /*
637 ** If this is an "uninteresting picture" ignore it.
638 */
639 if (ignore) {
640 if (verbose)
641 GIFERRORMSG("skipping image..." );
642
643 while (LWZReadByte( data, false, c ) >= 0)
644 ;
645 return NULL;
646 }
647
648 // FIXME: allocates four additional bytes because the scaling functions
649 // in src/misc/gfx_util.c have an off-by-one bug which causes
650 // segfaults on darwin/osx (not on linux)
651 if ((image = D_MALLOC(width * height * 4 + 4)) == NULL) {
652 GIFERRORMSG("couldn't alloc space for image" );
653 }
654
655 if (verbose) {
656 GIFERRORMSG("reading %d by %d%s GIF image", width, height,
657 interlace ? " interlaced" : "" );
658 }
659
660 while ((v = LWZReadByte( data, false, c )) >= 0 ) {
661 u32 *dst = image + (ypos * width + xpos);
662
663 if (v == data->transparent) {
664 *dst++ = key_rgb;
665 }
666 else {
667 *dst++ = (0xFF000000 |
668 cmap[CM_RED][v] << 16 |
669 cmap[CM_GREEN][v] << 8 |
670 cmap[CM_BLUE][v]);
671 }
672
673 ++xpos;
674 if (xpos == width) {
675 xpos = 0;
676 if (interlace) {
677 switch (pass) {
678 case 0:
679 case 1:
680 ypos += 8;
681 break;
682 case 2:
683 ypos += 4;
684 break;
685 case 3:
686 ypos += 2;
687 break;
688 }
689
690 if (ypos >= height) {
691 ++pass;
692 switch (pass) {
693 case 1:
694 ypos = 4;
695 break;
696 case 2:
697 ypos = 2;
698 break;
699 case 3:
700 ypos = 1;
701 break;
702 default:
703 goto fini;
704 }
705 }
706 }
707 else {
708 ++ypos;
709 }
710 }
711 if (ypos >= height) {
712 break;
713 }
714 }
715
716 fini:
717
718 if (LWZReadByte( data, false, c ) >= 0) {
719 GIFERRORMSG("too much input data, ignoring extra...");
720 }
721 return image;
722 }
723
724
ReadGIF(IDirectFBImageProvider_GIF_data * data,int imageNumber,int * width,int * height,bool * transparency,u32 * key_rgb,bool alpha,bool headeronly)725 static u32* ReadGIF( IDirectFBImageProvider_GIF_data *data, int imageNumber,
726 int *width, int *height, bool *transparency,
727 u32 *key_rgb, bool alpha, bool headeronly)
728 {
729 u8 buf[16];
730 u8 c;
731 u8 localColorMap[3][MAXCOLORMAPSIZE];
732 u32 colorKey = 0;
733 bool useGlobalColormap;
734 int bitPixel;
735 int imageCount = 0;
736 char version[4];
737
738 if (! ReadOK( data->base.buffer, buf, 6 )) {
739 GIFERRORMSG("error reading magic number" );
740 }
741
742 if (strncmp( (char *)buf, "GIF", 3 ) != 0) {
743 GIFERRORMSG("not a GIF file" );
744 }
745
746 direct_snputs( version, (char *)buf + 3, 4 );
747
748 if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
749 GIFERRORMSG("bad version number, not '87a' or '89a'" );
750 }
751
752 if (! ReadOK(data->base.buffer,buf,7)) {
753 GIFERRORMSG("failed to read screen descriptor" );
754 }
755
756 data->Width = LM_to_uint( buf[0], buf[1] );
757 data->Height = LM_to_uint( buf[2], buf[3] );
758 data->BitPixel = 2 << (buf[4] & 0x07);
759 data->ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
760 data->Background = buf[5];
761 data->AspectRatio = buf[6];
762
763 if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
764 if (ReadColorMap( data->base.buffer, data->BitPixel, data->ColorMap )) {
765 GIFERRORMSG("error reading global colormap" );
766 }
767 }
768
769 if (data->AspectRatio != 0 && data->AspectRatio != 49) {
770 /* float r = ( (float) data->AspectRatio + 15.0 ) / 64.0; */
771 GIFERRORMSG("warning - non-square pixels");
772 }
773
774 data->transparent = -1;
775 data->delayTime = -1;
776 data->inputFlag = -1;
777 data->disposal = 0;
778
779 for (;;) {
780 if (! ReadOK( data->base.buffer, &c, 1)) {
781 GIFERRORMSG("EOF / read error on image data" );
782 }
783
784 if (c == ';') { /* GIF terminator */
785 if (imageCount < imageNumber) {
786 GIFERRORMSG("only %d image%s found in file",
787 imageCount, imageCount>1?"s":"" );
788 }
789 return NULL;
790 }
791
792 if (c == '!') { /* Extension */
793 if (! ReadOK( data->base.buffer, &c, 1)) {
794 GIFERRORMSG("OF / read error on extention function code");
795 }
796 DoExtension( data, c );
797 continue;
798 }
799
800 if (c != ',') { /* Not a valid start character */
801 GIFERRORMSG("bogus character 0x%02x, ignoring", (int) c );
802 continue;
803 }
804
805 ++imageCount;
806
807 if (! ReadOK( data->base.buffer, buf, 9 )) {
808 GIFERRORMSG("couldn't read left/top/width/height");
809 }
810
811 *width = LM_to_uint( buf[4], buf[5] );
812 *height = LM_to_uint( buf[6], buf[7] );
813 *transparency = (data->transparent != -1);
814
815 if (headeronly && !(*transparency && key_rgb))
816 return NULL;
817
818 useGlobalColormap = ! BitSet( buf[8], LOCALCOLORMAP );
819
820 if (useGlobalColormap) {
821 if (*transparency && (key_rgb || !headeronly))
822 colorKey = FindColorKey( data->BitPixel,
823 data->ColorMap );
824 }
825 else {
826 bitPixel = 2 << (buf[8] & 0x07);
827 if (ReadColorMap( data->base.buffer, bitPixel, localColorMap ))
828 GIFERRORMSG("error reading local colormap" );
829
830 if (*transparency && (key_rgb || !headeronly))
831 colorKey = FindColorKey( bitPixel, localColorMap );
832 }
833
834 if (key_rgb)
835 *key_rgb = colorKey;
836
837 if (headeronly)
838 return NULL;
839
840 if (alpha)
841 colorKey &= 0x00FFFFFF;
842
843 return ReadImage( data, *width, *height,
844 (useGlobalColormap ?
845 data->ColorMap : localColorMap), colorKey,
846 BitSet( buf[8], INTERLACE ),
847 imageCount != imageNumber);
848 }
849 }
850
851 static bool
ReadOK(IDirectFBDataBuffer * buffer,void * data,unsigned int len)852 ReadOK( IDirectFBDataBuffer *buffer, void *data, unsigned int len )
853 {
854 DFBResult ret;
855
856 ret = buffer->WaitForData( buffer, len );
857 if (ret) {
858 DirectFBError( "(DirectFB/ImageProvider_GIF) WaitForData failed", ret );
859 return false;
860 }
861
862 ret = buffer->GetData( buffer, len, data, NULL );
863 if (ret) {
864 DirectFBError( "(DirectFB/ImageProvider_GIF) GetData failed", ret );
865 return false;
866 }
867
868 return true;
869 }
870
871