root/ext/gd/libgd/gd_gif_in.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_verbose
  2. gdImageCreateFromGifSource
  3. gdImageCreateFromGif
  4. gdImageCreateFromGifCtx
  5. ReadColorMap
  6. DoExtension
  7. GetDataBlock_
  8. GetDataBlock
  9. GetCode_
  10. GetCode
  11. LWZReadByte_
  12. LWZReadByte
  13. ReadImage

   1 #include <stdio.h>
   2 #include <math.h>
   3 #include <string.h>
   4 #include <stdlib.h>
   5 #include "gd.h"
   6 
   7 #include "php.h"
   8 
   9 /* Used only when debugging GIF compression code */
  10 /* #define DEBUGGING_ENVARS */
  11 
  12 #ifdef DEBUGGING_ENVARS
  13 
  14 static int verbose_set = 0;
  15 static int verbose;
  16 #define VERBOSE (verbose_set?verbose:set_verbose())
  17 
  18 static int set_verbose(void)
  19 {
  20         verbose = !!getenv("GIF_VERBOSE");
  21         verbose_set = 1;
  22         return(verbose);
  23 }
  24 
  25 #else
  26 
  27 #define VERBOSE 0
  28 
  29 #endif
  30 
  31 
  32 #define        MAXCOLORMAPSIZE         256
  33 
  34 #define        TRUE    1
  35 #define        FALSE   0
  36 
  37 #define CM_RED         0
  38 #define CM_GREEN       1
  39 #define CM_BLUE                2
  40 
  41 #define        MAX_LWZ_BITS            12
  42 
  43 #define INTERLACE              0x40
  44 #define LOCALCOLORMAP  0x80
  45 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
  46 
  47 #define        ReadOK(file,buffer,len) (gdGetBuf(buffer, len, file) > 0)
  48 
  49 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
  50 
  51 /* We may eventually want to use this information, but def it out for now */
  52 #if 0
  53 static struct {
  54         unsigned int    Width;
  55         unsigned int    Height;
  56         unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
  57         unsigned int    BitPixel;
  58         unsigned int    ColorResolution;
  59         unsigned int    Background;
  60         unsigned int    AspectRatio;
  61 } GifScreen;
  62 #endif
  63 
  64 #if 0
  65 static struct {
  66         int     transparent;
  67         int     delayTime;
  68         int     inputFlag;
  69         int     disposal;
  70 } Gif89 = { -1, -1, -1, 0 };
  71 #endif
  72 
  73 #define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2)
  74 
  75 #define CSD_BUF_SIZE 280
  76 
  77 typedef struct {
  78         unsigned char    buf[CSD_BUF_SIZE];
  79         int              curbit, lastbit, done, last_byte;
  80 } CODE_STATIC_DATA;
  81 
  82 typedef struct {
  83         int fresh;
  84         int code_size, set_code_size;
  85         int max_code, max_code_size;
  86         int firstcode, oldcode;
  87         int clear_code, end_code;
  88         int table[2][(1<< MAX_LWZ_BITS)];
  89         int stack[STACK_SIZE], *sp;
  90         CODE_STATIC_DATA scd;
  91 } LZW_STATIC_DATA;
  92 
  93 static int ReadColorMap (gdIOCtx *fd, int number, unsigned char (*buffer)[256]);
  94 static int DoExtension (gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP);
  95 static int GetDataBlock (gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP);
  96 static int GetCode (gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP);
  97 static int LWZReadByte (gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP);
  98 
  99 static void ReadImage (gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP); /*1.4//, int ignore); */
 100 
 101 gdImagePtr gdImageCreateFromGifSource(gdSourcePtr inSource) /* {{{ */
 102 {
 103         gdIOCtx         *in = gdNewSSCtx(inSource, NULL);
 104         gdImagePtr      im;
 105 
 106         im = gdImageCreateFromGifCtx(in);
 107 
 108         in->gd_free(in);
 109 
 110         return im;
 111 }
 112 /* }}} */
 113 
 114 gdImagePtr gdImageCreateFromGif(FILE *fdFile) /* {{{ */
 115 {
 116         gdIOCtx         *fd = gdNewFileCtx(fdFile);
 117         gdImagePtr      im = 0;
 118 
 119         im = gdImageCreateFromGifCtx(fd);
 120 
 121         fd->gd_free(fd);
 122 
 123         return im;
 124 }
 125 /* }}} */
 126 
 127 gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr fd) /* {{{ */
 128 {
 129         int BitPixel;
 130 #if 0
 131         int ColorResolution;
 132         int Background;
 133         int AspectRatio;
 134 #endif
 135         int Transparent = (-1);
 136         unsigned char   buf[16];
 137         unsigned char   c;
 138         unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
 139         unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
 140         int             imw, imh, screen_width, screen_height;
 141         int             gif87a, useGlobalColormap;
 142         int             bitPixel;
 143         int            i;
 144         /*1.4//int             imageCount = 0; */
 145 
 146         int ZeroDataBlock = FALSE;
 147         int haveGlobalColormap;
 148         gdImagePtr im = 0;
 149 
 150         /*1.4//imageNumber = 1; */
 151         if (! ReadOK(fd,buf,6)) {
 152                 return 0;
 153         }
 154         if (strncmp((char *)buf,"GIF",3) != 0) {
 155                 return 0;
 156         }
 157 
 158         if (memcmp((char *)buf+3, "87a", 3) == 0) {
 159                 gif87a = 1;
 160         } else if (memcmp((char *)buf+3, "89a", 3) == 0) {
 161                 gif87a = 0;
 162         } else {
 163                 return 0;
 164         }
 165 
 166         if (! ReadOK(fd,buf,7)) {
 167                 return 0;
 168         }
 169 
 170         BitPixel        = 2<<(buf[4]&0x07);
 171 #if 0
 172         ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
 173         Background      = buf[5];
 174         AspectRatio     = buf[6];
 175 #endif
 176         screen_width = imw = LM_to_uint(buf[0],buf[1]);
 177         screen_height = imh = LM_to_uint(buf[2],buf[3]);
 178 
 179         haveGlobalColormap = BitSet(buf[4], LOCALCOLORMAP);    /* Global Colormap */
 180         if (haveGlobalColormap) {
 181                 if (ReadColorMap(fd, BitPixel, ColorMap)) {
 182                         return 0;
 183                 }
 184         }
 185 
 186         for (;;) {
 187                 int top, left;
 188                 int width, height;
 189 
 190                 if (! ReadOK(fd,&c,1)) {
 191                         return 0;
 192                 }
 193                 if (c == ';') {         /* GIF terminator */
 194                         goto terminated;
 195                 }
 196 
 197                 if (c == '!') {         /* Extension */
 198                         if (! ReadOK(fd,&c,1)) {
 199                                 return 0;
 200                         }
 201                         DoExtension(fd, c, &Transparent, &ZeroDataBlock);
 202                         continue;
 203                 }
 204 
 205                 if (c != ',') {         /* Not a valid start character */
 206                         continue;
 207                 }
 208 
 209                 /*1.4//++imageCount; */
 210 
 211                 if (! ReadOK(fd,buf,9)) {
 212                         return 0;
 213                 }
 214 
 215                 useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
 216 
 217                 bitPixel = 1<<((buf[8]&0x07)+1);
 218                 left = LM_to_uint(buf[0], buf[1]);
 219                 top = LM_to_uint(buf[2], buf[3]);
 220                 width = LM_to_uint(buf[4], buf[5]);
 221                 height = LM_to_uint(buf[6], buf[7]);
 222 
 223                 if (left + width > screen_width || top + height > screen_height) {
 224                         if (VERBOSE) {
 225                                 printf("Frame is not confined to screen dimension.\n");
 226                         }
 227                         return 0;
 228                 }
 229 
 230                 if (!(im = gdImageCreate(width, height))) {
 231                         return 0;
 232                 }
 233                 im->interlace = BitSet(buf[8], INTERLACE);
 234                 if (!useGlobalColormap) {
 235                         if (ReadColorMap(fd, bitPixel, localColorMap)) {
 236                                 gdImageDestroy(im);
 237                                 return 0;
 238                         }
 239                         ReadImage(im, fd, width, height, localColorMap,
 240                                         BitSet(buf[8], INTERLACE), &ZeroDataBlock);
 241                 } else {
 242                         if (!haveGlobalColormap) {
 243                                 gdImageDestroy(im);
 244                                 return 0;
 245                         }
 246                         ReadImage(im, fd, width, height,
 247                                                 ColorMap,
 248                                                 BitSet(buf[8], INTERLACE), &ZeroDataBlock);
 249                 }
 250                 if (Transparent != (-1)) {
 251                         gdImageColorTransparent(im, Transparent);
 252                 }
 253                 goto terminated;
 254         }
 255 
 256 terminated:
 257         /* Terminator before any image was declared! */
 258         if (!im) {
 259                 return 0;
 260         }
 261         if (!im->colorsTotal) {
 262                 gdImageDestroy(im);
 263                 return 0;
 264         }
 265         /* Check for open colors at the end, so
 266            we can reduce colorsTotal and ultimately
 267            BitsPerPixel */
 268         for (i=((im->colorsTotal-1)); (i>=0); i--) {
 269                 if (im->open[i]) {
 270                         im->colorsTotal--;
 271                 } else {
 272                         break;
 273                 }
 274         }
 275         return im;
 276 }
 277 /* }}} */
 278 
 279 static int ReadColorMap(gdIOCtx *fd, int number, unsigned char (*buffer)[256]) /* {{{ */
 280 {
 281         int             i;
 282         unsigned char   rgb[3];
 283 
 284 
 285         for (i = 0; i < number; ++i) {
 286                 if (! ReadOK(fd, rgb, sizeof(rgb))) {
 287                         return TRUE;
 288                 }
 289                 buffer[CM_RED][i] = rgb[0] ;
 290                 buffer[CM_GREEN][i] = rgb[1] ;
 291                 buffer[CM_BLUE][i] = rgb[2] ;
 292         }
 293 
 294 
 295         return FALSE;
 296 }
 297 /* }}} */
 298 
 299 static int
 300 DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP)
 301 {
 302         unsigned char buf[256];
 303 
 304         switch (label) {
 305                 case 0xf9:              /* Graphic Control Extension */
 306                         memset(buf, 0, 4); /* initialize a few bytes in the case the next function fails */
 307                (void) GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP);
 308 #if 0
 309                         Gif89.disposal    = (buf[0] >> 2) & 0x7;
 310                         Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
 311                         Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
 312 #endif
 313                         if ((buf[0] & 0x1) != 0)
 314                                 *Transparent = buf[3];
 315 
 316                         while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0);
 317                         return FALSE;
 318                 default:
 319                         break;
 320         }
 321        while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0)
 322                 ;
 323 
 324         return FALSE;
 325 }
 326 /* }}} */
 327 
 328 static int
 329 GetDataBlock_(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
 330 {
 331         unsigned char   count;
 332 
 333         if (! ReadOK(fd,&count,1)) {
 334                 return -1;
 335         }
 336 
 337         *ZeroDataBlockP = count == 0;
 338 
 339         if ((count != 0) && (! ReadOK(fd, buf, count))) {
 340                 return -1;
 341         }
 342 
 343         return count;
 344 }
 345 /* }}} */
 346 
 347 static int
 348 GetDataBlock(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
 349 {
 350         int rv;
 351         int i;
 352 
 353         rv = GetDataBlock_(fd,buf, ZeroDataBlockP);
 354         if (VERBOSE) {
 355                 char *tmp = NULL;
 356                 if (rv > 0) {
 357                         tmp = safe_emalloc(3 * rv, sizeof(char), 1);
 358                         for (i=0;i<rv;i++) {
 359                                 sprintf(&tmp[3*sizeof(char)*i], " %02x", buf[i]);
 360                         }
 361                 } else {
 362                         tmp = estrdup("");
 363                 }
 364                 php_gd_error_ex(E_NOTICE, "[GetDataBlock returning %d: %s]", rv, tmp);
 365                 efree(tmp);
 366         }
 367         return(rv);
 368 }
 369 /* }}} */
 370 
 371 static int
 372 GetCode_(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
 373 {
 374         int           i, j, ret;
 375         unsigned char count;
 376 
 377         if (flag) {
 378                 scd->curbit = 0;
 379                 scd->lastbit = 0;
 380                 scd->last_byte = 0;
 381                 scd->done = FALSE;
 382                 return 0;
 383         }
 384 
 385         if ( (scd->curbit + code_size) >= scd->lastbit) {
 386                 if (scd->done) {
 387                         if (scd->curbit >= scd->lastbit) {
 388                                 /* Oh well */
 389                         }
 390                         return -1;
 391                 }
 392                 scd->buf[0] = scd->buf[scd->last_byte-2];
 393                 scd->buf[1] = scd->buf[scd->last_byte-1];
 394 
 395                if ((count = GetDataBlock(fd, &scd->buf[2], ZeroDataBlockP)) <= 0)
 396                         scd->done = TRUE;
 397 
 398                 scd->last_byte = 2 + count;
 399                 scd->curbit = (scd->curbit - scd->lastbit) + 16;
 400                 scd->lastbit = (2+count)*8 ;
 401         }
 402 
 403         if ((scd->curbit + code_size - 1) >= (CSD_BUF_SIZE * 8)) {
 404                 ret = -1;
 405         } else {
 406                 ret = 0;
 407                 for (i = scd->curbit, j = 0; j < code_size; ++i, ++j) {
 408                         ret |= ((scd->buf[i / 8] & (1 << (i % 8))) != 0) << j;
 409                 }
 410         }
 411 
 412         scd->curbit += code_size;
 413         return ret;
 414 }
 415 
 416 static int
 417 GetCode(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
 418 {
 419         int rv;
 420 
 421  rv = GetCode_(fd, scd, code_size,flag, ZeroDataBlockP);
 422  if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
 423         return(rv);
 424 }
 425 /* }}} */
 426 
 427 static int
 428 LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
 429 {
 430         int code, incode, i;
 431 
 432         if (flag) {
 433                 sd->set_code_size = input_code_size;
 434                 sd->code_size = sd->set_code_size+1;
 435                 sd->clear_code = 1 << sd->set_code_size ;
 436                 sd->end_code = sd->clear_code + 1;
 437                 sd->max_code_size = 2*sd->clear_code;
 438                 sd->max_code = sd->clear_code+2;
 439 
 440                 GetCode(fd, &sd->scd, 0, TRUE, ZeroDataBlockP);
 441 
 442                 sd->fresh = TRUE;
 443 
 444                 for (i = 0; i < sd->clear_code; ++i) {
 445                         sd->table[0][i] = 0;
 446                         sd->table[1][i] = i;
 447                 }
 448                 for (; i < (1<<MAX_LWZ_BITS); ++i)
 449                         sd->table[0][i] = sd->table[1][0] = 0;
 450 
 451                 sd->sp = sd->stack;
 452 
 453                 return 0;
 454         } else if (sd->fresh) {
 455                 sd->fresh = FALSE;
 456                 do {
 457                         sd->firstcode = sd->oldcode =
 458                         GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
 459                 } while (sd->firstcode == sd->clear_code);
 460                 return sd->firstcode;
 461         }
 462 
 463         if (sd->sp > sd->stack)
 464                 return *--sd->sp;
 465 
 466                 while ((code = GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP)) >= 0) {
 467                 if (code == sd->clear_code) {
 468                         for (i = 0; i < sd->clear_code; ++i) {
 469                                 sd->table[0][i] = 0;
 470                                 sd->table[1][i] = i;
 471                         }
 472                         for (; i < (1<<MAX_LWZ_BITS); ++i)
 473                                 sd->table[0][i] = sd->table[1][i] = 0;
 474                         sd->code_size = sd->set_code_size+1;
 475                         sd->max_code_size = 2*sd->clear_code;
 476                         sd->max_code = sd->clear_code+2;
 477                         sd->sp = sd->stack;
 478                         sd->firstcode = sd->oldcode =
 479                                                                 GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
 480                         return sd->firstcode;
 481                 } else if (code == sd->end_code) {
 482                         int             count;
 483                         unsigned char   buf[260];
 484 
 485                         if (*ZeroDataBlockP)
 486                                 return -2;
 487 
 488                         while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0)
 489                                 ;
 490 
 491                         if (count != 0)
 492                                 return -2;
 493                 }
 494 
 495                 incode = code;
 496 
 497                 if (sd->sp == (sd->stack + STACK_SIZE)) {
 498                         /* Bad compressed data stream */
 499                         return -1;
 500                 }
 501 
 502                 if (code >= sd->max_code) {
 503                         *sd->sp++ = sd->firstcode;
 504                         code = sd->oldcode;
 505                 }
 506 
 507                 while (code >= sd->clear_code) {
 508                         if (sd->sp == (sd->stack + STACK_SIZE)) {
 509                                 /* Bad compressed data stream */
 510                                 return -1;
 511                         }
 512                         *sd->sp++ = sd->table[1][code];
 513                         if (code == sd->table[0][code]) {
 514                                 /* Oh well */
 515                         }
 516                         code = sd->table[0][code];
 517                 }
 518 
 519                 *sd->sp++ = sd->firstcode = sd->table[1][code];
 520 
 521                 if ((code = sd->max_code) <(1<<MAX_LWZ_BITS)) {
 522                         sd->table[0][code] = sd->oldcode;
 523                         sd->table[1][code] = sd->firstcode;
 524                         ++sd->max_code;
 525                         if ((sd->max_code >= sd->max_code_size) &&
 526                                         (sd->max_code_size < (1<<MAX_LWZ_BITS))) {
 527                                 sd->max_code_size *= 2;
 528                                 ++sd->code_size;
 529                         }
 530                 }
 531 
 532                 sd->oldcode = incode;
 533 
 534                 if (sd->sp > sd->stack)
 535                         return *--sd->sp;
 536         }
 537         return code;
 538 }
 539 /* }}} */
 540 
 541 static int
 542 LWZReadByte(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
 543 {
 544         int rv;
 545 
 546  rv = LWZReadByte_(fd, sd, flag, input_code_size, ZeroDataBlockP);
 547  if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
 548         return(rv);
 549 }
 550 /* }}} */
 551 
 552 static void
 553 ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP) /*1.4//, int ignore) */
 554 {
 555         unsigned char   c;
 556         int             v;
 557         int             xpos = 0, ypos = 0, pass = 0;
 558         int i;
 559         LZW_STATIC_DATA sd;
 560 
 561 
 562         /*
 563          **  Initialize the Compression routines
 564          */
 565         if (! ReadOK(fd,&c,1)) {
 566                 return;
 567         }
 568 
 569         if (c > MAX_LWZ_BITS) {
 570                 return;
 571         }
 572 
 573         /* Stash the color map into the image */
 574         for (i=0; (i<gdMaxColors); i++) {
 575                 im->red[i] = cmap[CM_RED][i];
 576                 im->green[i] = cmap[CM_GREEN][i];
 577                 im->blue[i] = cmap[CM_BLUE][i];
 578                 im->open[i] = 1;
 579         }
 580         /* Many (perhaps most) of these colors will remain marked open. */
 581         im->colorsTotal = gdMaxColors;
 582         if (LWZReadByte(fd, &sd, TRUE, c, ZeroDataBlockP) < 0) {
 583                 return;
 584         }
 585 
 586         /*
 587          **  If this is an "uninteresting picture" ignore it.
 588          **  REMOVED For 1.4
 589          */
 590         /*if (ignore) { */
 591         /*        while (LWZReadByte(fd, &sd, FALSE, c) >= 0) */
 592         /*                ; */
 593         /*        return; */
 594         /*} */
 595 
 596         while ((v = LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP)) >= 0) {
 597                 if (v >= gdMaxColors) {
 598                         v = 0;
 599                 }
 600                 /* This how we recognize which colors are actually used. */
 601                 if (im->open[v]) {
 602                         im->open[v] = 0;
 603                 }
 604                 gdImageSetPixel(im, xpos, ypos, v);
 605                 ++xpos;
 606                 if (xpos == len) {
 607                         xpos = 0;
 608                         if (interlace) {
 609                                 switch (pass) {
 610                                         case 0:
 611                                         case 1:
 612                                                 ypos += 8; break;
 613                                         case 2:
 614                                                 ypos += 4; break;
 615                                         case 3:
 616                                                 ypos += 2; break;
 617                                 }
 618 
 619                                 if (ypos >= height) {
 620                                         ++pass;
 621                                         switch (pass) {
 622                                                 case 1:
 623                                                         ypos = 4; break;
 624                                                 case 2:
 625                                                         ypos = 2; break;
 626                                                 case 3:
 627                                                         ypos = 1; break;
 628                                                 default:
 629                                                         goto fini;
 630                                         }
 631                                 }
 632                         } else {
 633                                 ++ypos;
 634                         }
 635                 }
 636                 if (ypos >= height)
 637                         break;
 638         }
 639 
 640 fini:
 641         if (LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP) >=0) {
 642                 /* Ignore extra */
 643         }
 644 }
 645 /* }}} */

/* [<][>][^][v][top][bottom][index][help] */