Example #1
0
static int
read_logical_screen_descriptor(Gif_Stream *gfs, Gif_Reader *grr)
     /* returns 0 on memory error */
{
  uint8_t packed;

  /* we don't care about logical screen width or height */
  gfs->screen_width = gifgetunsigned(grr);
  gfs->screen_height = gifgetunsigned(grr);

  packed = gifgetbyte(grr);
  gfs->background = gifgetbyte(grr);

  /* don't care about pixel aspect ratio */
  gifgetbyte(grr);

  if (packed & 0x80) { /* have a global color table */
    int ncol = 1 << ((packed & 0x07) + 1);
    gfs->global = read_color_table(ncol, grr);
    if (!gfs->global) return 0;
    gfs->global->refcount = 1;
  }

  return 1;
}
Example #2
0
static inline uint16_t
gifgetunsigned(Gif_Reader *grr)
{
  uint8_t one = gifgetbyte(grr);
  uint8_t two = gifgetbyte(grr);
  return one | (two << 8);
}
Example #3
0
static int
read_image(Gif_Reader *grr, Gif_Context *gfc, Gif_Image *gfi, int read_flags)
/* returns 0 on memory error */
{
    uint8_t packed;

    gfi->left = gifgetunsigned(grr);
    gfi->top = gifgetunsigned(grr);
    gfi->width = gifgetunsigned(grr);
    gfi->height = gifgetunsigned(grr);
    packed = gifgetbyte(grr);
    GIF_DEBUG(("<%ux%u>", gfi->width, gfi->height));

    if (packed & 0x80) { /* have a local color table */
        int ncol = 1 << ((packed & 0x07) + 1);
        gfi->local = read_color_table(ncol, grr);
        if (!gfi->local) return 0;
        gfi->local->refcount = 1;
    }

    gfi->interlace = (packed & 0x40) != 0;

    /* Keep the compressed data if asked */
    if (read_flags & GIF_READ_COMPRESSED) {
        if (!read_compressed_image(gfi, grr, read_flags))
            return 0;
        if (read_flags & GIF_READ_UNCOMPRESSED) {
            Gif_Reader new_grr;
            make_data_reader(&new_grr, gfi->compressed, gfi->compressed_len);
            if (!uncompress_image(gfc, gfi, &new_grr))
                return 0;
        }

    } else if (read_flags & GIF_READ_UNCOMPRESSED) {
        if (!uncompress_image(gfc, gfi, grr))
            return 0;

    } else {
        /* skip over the image */
        uint8_t buffer[GIF_MAX_BLOCK];
        int i = gifgetbyte(grr);
        while (i > 0) {
            gifgetblock(buffer, i, grr);
            i = gifgetbyte(grr);
        }
    }

    return 1;
}
Example #4
0
static int
read_image_block(Gif_Reader *grr, uint8_t *buffer, int *bit_pos_store,
		 int *bit_len_store, int bits_needed)
{
  int bit_position = *bit_pos_store;
  int bit_length = *bit_len_store;
  uint8_t block_len;

  while (bit_position + bits_needed > bit_length) {
    /* Read in the next data block. */
    if (bit_position >= 8) {
      /* Need to shift down the upper, unused part of 'buffer' */
      int i = bit_position / 8;
      buffer[0] = buffer[i];
      buffer[1] = buffer[i+1];
      bit_position -= i * 8;
      bit_length -= i * 8;
    }
    block_len = gifgetbyte(grr);
    GIF_DEBUG(("\nimage_block(%d)", block_len));
    if (block_len == 0) return 0;
    gifgetblock(buffer + bit_length / 8, block_len, grr);
    bit_length += block_len * 8;
  }

  *bit_pos_store = bit_position;
  *bit_len_store = bit_length;
  return 1;
}
Example #5
0
static Gif_Colormap *
read_color_table(int size, Gif_Reader *grr)
{
  Gif_Colormap *gfcm = Gif_NewFullColormap(size, size);
  Gif_Color *c;
  if (!gfcm) return 0;

  GIF_DEBUG(("colormap(%d)", size));
  for (c = gfcm->col; size; size--, c++) {
    c->gfc_red = gifgetbyte(grr);
    c->gfc_green = gifgetbyte(grr);
    c->gfc_blue = gifgetbyte(grr);
    c->haspixel = 0;
  }

  return gfcm;
}
Example #6
0
static void
read_graphic_control_extension(Gif_Context *gfc, Gif_Image *gfi,
			       Gif_Reader *grr)
{
  uint8_t len;
  uint8_t crap[GIF_MAX_BLOCK];

  len = gifgetbyte(grr);

  if (len == 4) {
    uint8_t packed = gifgetbyte(grr);
    gfi->disposal = (packed >> 2) & 0x07;
    gfi->delay = gifgetunsigned(grr);
    gfi->transparent = gifgetbyte(grr);
    if (!(packed & 0x01)) /* transparent color doesn't exist */
      gfi->transparent = -1;
    len -= 4;
  }
Example #7
0
static int
read_image(Gif_Reader *grr, Gif_Context *gfc, Gif_Image *gfi, int read_flags)
     /* returns 0 on memory error */
{
  uint8_t packed;

  gfi->left = gifgetunsigned(grr);
  gfi->top = gifgetunsigned(grr);
  gfi->width = gifgetunsigned(grr);
  gfi->height = gifgetunsigned(grr);
  /* Mainline GIF processors (Firefox, etc.) process missing width (height)
     as screen_width (screen_height). */
  if (gfi->width == 0)
      gfi->width = gfc->stream->screen_width;
  if (gfi->height == 0)
      gfi->height = gfc->stream->screen_height;
  /* If still zero, error. */
  if (gfi->width == 0 || gfi->height == 0) {
      gif_read_error(gfc, 1, "image has zero width and/or height");
      Gif_MakeImageEmpty(gfi);
      read_flags = 0;
  }
  /* If position out of range, error. */
  if ((unsigned) gfi->left + (unsigned) gfi->width > 0xFFFF
      || (unsigned) gfi->top + (unsigned) gfi->height > 0xFFFF) {
      gif_read_error(gfc, 1, "image position and/or dimensions out of range");
      Gif_MakeImageEmpty(gfi);
      read_flags = 0;
  }
  GIF_DEBUG(("<%ux%u>", gfi->width, gfi->height));

  packed = gifgetbyte(grr);
  if (packed & 0x80) { /* have a local color table */
    int ncol = 1 << ((packed & 0x07) + 1);
    gfi->local = read_color_table(ncol, grr);
    if (!gfi->local) return 0;
    gfi->local->refcount = 1;
  }

  gfi->interlace = (packed & 0x40) != 0;

  /* Keep the compressed data if asked */
  if (read_flags & GIF_READ_COMPRESSED) {
    if (!read_compressed_image(gfi, grr, read_flags))
      return 0;
    if (read_flags & GIF_READ_UNCOMPRESSED) {
      Gif_Reader new_grr;
      make_data_reader(&new_grr, gfi->compressed, gfi->compressed_len);
      if (!uncompress_image(gfc, gfi, &new_grr))
	return 0;
    }

  } else if (read_flags & GIF_READ_UNCOMPRESSED) {
    if (!uncompress_image(gfc, gfi, grr))
      return 0;

  } else {
    /* skip over the image */
    uint8_t buffer[GIF_MAX_BLOCK];
    int i = gifgetbyte(grr);
    while (i > 0) {
      gifgetblock(buffer, i, grr);
      i = gifgetbyte(grr);
    }
  }

  return 1;
}
Example #8
0
static int
read_compressed_image(Gif_Image *gfi, Gif_Reader *grr, int read_flags)
{
  if (grr->is_record) {
    const uint8_t *first = grr->v;
    uint32_t pos;

    /* scan over image */
    pos = 1;			/* skip min code size */
    while (pos < grr->w) {
      int amt = grr->v[pos];
      pos += amt + 1;
      if (amt == 0) break;
    }
    if (pos > grr->w) pos = grr->w;

    gfi->compressed_len = pos;
    if (read_flags & GIF_READ_CONST_RECORD) {
      gfi->compressed = (uint8_t *)first;
      gfi->free_compressed = 0;
    } else {
      gfi->compressed = Gif_NewArray(uint8_t, gfi->compressed_len);
      gfi->free_compressed = Gif_Free;
      if (!gfi->compressed) return 0;
      memcpy(gfi->compressed, first, gfi->compressed_len);
    }

    /* move reader over that image */
    grr->v += pos;
    grr->w -= pos;

  } else {
    /* non-record; have to read it block by block. */
    uint32_t comp_cap = 1024;
    uint32_t comp_len;
    uint8_t *comp = Gif_NewArray(uint8_t, comp_cap);
    int i;
    if (!comp) return 0;

    /* min code size */
    i = gifgetbyte(grr);
    comp[0] = i;
    comp_len = 1;

    i = gifgetbyte(grr);
    while (i > 0) {
      /* add 2 before check so we don't have to check after loop when appending
	 0 block */
      if (comp_len + i + 2 > comp_cap) {
	comp_cap *= 2;
	Gif_ReArray(comp, uint8_t, comp_cap);
	if (!comp) return 0;
      }
      comp[comp_len] = i;
      gifgetblock(comp + comp_len + 1, i, grr);
      comp_len += i + 1;
      i = gifgetbyte(grr);
    }
    comp[comp_len++] = 0;

    gfi->compressed = comp;
    gfi->compressed_len = comp_len;
    gfi->free_compressed = Gif_Free;
  }

  return 1;
}
Example #9
0
static void
read_image_data(Gif_Context *gfc, Gif_Reader *grr)
{
  /* we need a bit more than GIF_MAX_BLOCK in case a single code is split
     across blocks */
  uint8_t buffer[GIF_MAX_BLOCK + 5];
  int i;
  uint32_t accum;

  int bit_position;
  int bit_length;

  Gif_Code code;
  Gif_Code old_code;
  Gif_Code clear_code;
  Gif_Code eoi_code;
  Gif_Code next_code;
#define CUR_BUMP_CODE (1 << bits_needed)
#define CUR_CODE_MASK ((1 << bits_needed) - 1)

  int min_code_size;
  int bits_needed;

  gfc->decodepos = 0;

  min_code_size = gifgetbyte(grr);
  GIF_DEBUG(("\n\nmin_code_size(%d)", min_code_size));
  if (min_code_size >= GIF_MAX_CODE_BITS) {
    gif_read_error(gfc, 1, "image corrupted, min_code_size too big");
    min_code_size = GIF_MAX_CODE_BITS - 1;
  } else if (min_code_size < 2) {
    gif_read_error(gfc, 1, "image corrupted, min_code_size too small");
    min_code_size = 2;
  }
  clear_code = 1 << min_code_size;
  for (code = 0; code < clear_code; code++) {
    gfc->prefix[code] = 49428;
    gfc->suffix[code] = (uint8_t)code;
    gfc->length[code] = 1;
  }
  eoi_code = clear_code + 1;

  next_code = eoi_code;
  bits_needed = min_code_size + 1;

  code = clear_code;

  bit_length = bit_position = 0;
  /* Thus the 'Read in the next data block.' code below will be invoked on the
     first time through: exactly right! */

  while (1) {

    old_code = code;

    /* GET A CODE INTO THE 'code' VARIABLE.
     *
     * 9.Dec.1998 - Rather than maintain a byte pointer and a bit offset into
     * the current byte (and the processing associated with that), we maintain
     * one number: the offset, in bits, from the beginning of 'buffer'. This
     * much cleaner choice was inspired by Patrick J. Naughton
     * <*****@*****.**>'s GIF-reading code, which does the same thing.
     * His code distributed as part of XV in xvgif.c. */

    if (bit_position + bits_needed > bit_length)
      /* Read in the next data block. */
      if (!read_image_block(grr, buffer, &bit_position, &bit_length,
			    bits_needed))
	goto zero_length_block;

    i = bit_position / 8;
    accum = buffer[i] + (buffer[i+1] << 8);
    if (bits_needed >= 8)
      accum |= (buffer[i+2]) << 16;
    code = (Gif_Code)((accum >> (bit_position % 8)) & CUR_CODE_MASK);
    bit_position += bits_needed;

    GIF_DEBUG(("%d", code));

    /* CHECK FOR SPECIAL OR BAD CODES: clear_code, eoi_code, or a code that is
     * too large. */
    if (code == clear_code) {
      GIF_DEBUG(("clear"));
      bits_needed = min_code_size + 1;
      next_code = eoi_code;
      continue;

    } else if (code == eoi_code)
      break;

    else if (code > next_code && next_code && next_code != clear_code) {
      /* code > next_code: a (hopefully recoverable) error.

	 Bug fix, 5/27: Do this even if old_code == clear_code, and set code
	 to 0 to prevent errors later. (If we didn't zero code, we'd later set
	 old_code = code; then we had old_code >= next_code; so the prefixes
	 array got all screwed up!)

	 Bug fix, 4/12/2010: It is not an error if next_code == clear_code.
	 This happens at the end of a large GIF: see the next comment ("If no
	 meaningful next code should be defined...."). */
      if (gfc->errors[1] < 20)
          gif_read_error(gfc, 1, "image corrupted, code out of range");
      else if (gfc->errors[1] == 20)
          gif_read_error(gfc, 1, "(not reporting more errors)");
      code = 0;
    }

    /* PROCESS THE CURRENT CODE and define the next code. If no meaningful
     * next code should be defined, then we have set next_code to either
     * 'eoi_code' or 'clear_code' -- so we'll store useless prefix/suffix data
     * in a useless place. */

    /* *First,* set up the prefix and length for the next code
       (in case code == next_code). */
    gfc->prefix[next_code] = old_code;
    gfc->length[next_code] = gfc->length[old_code] + 1;

    /* Use one_code to process code. It's nice that it returns the first
       pixel in code: that's what we need. */
    gfc->suffix[next_code] = one_code(gfc, code);

    /* Special processing if code == next_code: we didn't know code's final
       suffix when we called one_code, but we do now. */
    /* 7.Mar.2014 -- Avoid error if image has zero width/height. */
    if (code == next_code && gfc->image + gfc->decodepos <= gfc->maximage)
      gfc->image[gfc->decodepos - 1] = gfc->suffix[next_code];

    /* Increment next_code except for the 'clear_code' special case (that's
       when we're reading at the end of a GIF) */
    if (next_code != clear_code) {
      next_code++;
      if (next_code == CUR_BUMP_CODE) {
	if (bits_needed < GIF_MAX_CODE_BITS)
	  bits_needed++;
	else
	  next_code = clear_code;
      }
    }

  }

  /* read blocks until zero-length reached. */
  i = gifgetbyte(grr);
  GIF_DEBUG(("\nafter_image(%d)\n", i));
  while (i > 0) {
    gifgetblock(buffer, i, grr);
    i = gifgetbyte(grr);
    GIF_DEBUG(("\nafter_image(%d)\n", i));
  }

  /* zero-length block reached. */
 zero_length_block: {
      long delta = (long) (gfc->maximage - gfc->image) - (long) gfc->decodepos;
      char buf[BUFSIZ];
      if (delta > 0) {
          sprintf(buf, "missing %ld pixels of image data", delta);
          gif_read_error(gfc, 1, buf);
      } else if (delta < -1) {
          /* One pixel of superfluous data is OK; that could be the
             code == next_code case. */
          sprintf(buf, "%ld superfluous pixels of image data", -delta);
          gif_read_error(gfc, 0, buf);
      }
  }
}