func: static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role,
  
                                        int w, int h)
  
  {
  
      ImageContext *img;
  
      HuffReader *hg;
  
      int i, j, ret, x, y, width;
  
  
  
      img       = &s->image[role];
  
      img->role = role;
  
  
  
      if (!img->frame) {
  
          img->frame = av_frame_alloc();
  
          if (!img->frame)
  
              return AVERROR(ENOMEM);
  
      }
  
  
  
      img->frame->format = AV_PIX_FMT_ARGB;
  
      img->frame->width  = w;
  
      img->frame->height = h;
  
  
  
      if (role == IMAGE_ROLE_ARGB && !img->is_alpha_primary) {
  
          ThreadFrame pt = { .f = img->frame };
  
          ret = ff_thread_get_buffer(s->avctx, &pt, 0);
  
      } else
  
          ret = av_frame_get_buffer(img->frame, 1);
  
      if (ret < 0)
  
          return ret;
  
  
  
      if (get_bits1(&s->gb)) {
  
          img->color_cache_bits = get_bits(&s->gb, 4);
  
          if (img->color_cache_bits < 1 || img->color_cache_bits > 11) {
  
              av_log(s->avctx, AV_LOG_ERROR, "invalid color cache bits: %d\n",
  
                     img->color_cache_bits);
  
              return AVERROR_INVALIDDATA;
  
          }
  
          img->color_cache = av_mallocz_array(1 << img->color_cache_bits,
  
                                              sizeof(*img->color_cache));
  
          if (!img->color_cache)
  
              return AVERROR(ENOMEM);
  
      } else {
  
          img->color_cache_bits = 0;
  
      }
  
  
  
      img->nb_huffman_groups = 1;
  
      if (role == IMAGE_ROLE_ARGB && get_bits1(&s->gb)) {
  
          ret = decode_entropy_image(s);
  
          if (ret < 0)
  
              return ret;
  
          img->nb_huffman_groups = s->nb_huffman_groups;
  
      }
  
      img->huffman_groups = av_mallocz_array(img->nb_huffman_groups *
  
                                             HUFFMAN_CODES_PER_META_CODE,
  
                                             sizeof(*img->huffman_groups));
  
      if (!img->huffman_groups)
  
          return AVERROR(ENOMEM);
  
  
  
      for (i = 0; i < img->nb_huffman_groups; i++) {
  
          hg = &img->huffman_groups[i * HUFFMAN_CODES_PER_META_CODE];
  
          for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; j++) {
  
              int alphabet_size = alphabet_sizes[j];
  
              if (!j && img->color_cache_bits > 0)
  
                  alphabet_size += 1 << img->color_cache_bits;
  
  
  
              if (get_bits1(&s->gb)) {
  
                  read_huffman_code_simple(s, &hg[j]);
  
              } else {
  
                  ret = read_huffman_code_normal(s, &hg[j], alphabet_size);
  
                  if (ret < 0)
  
                      return ret;
  
              }
  
          }
  
      }
  
  
  
      width = img->frame->width;
  
      if (role == IMAGE_ROLE_ARGB && s->reduced_width > 0)
  
          width = s->reduced_width;
  
  
  
      x = 0; y = 0;
  
      while (y < img->frame->height) {
  
          int v;
  
  
  
          hg = get_huffman_group(s, img, x, y);
  
          v = huff_reader_get_symbol(&hg[HUFF_IDX_GREEN], &s->gb);
  
          if (v < NUM_LITERAL_CODES) {
  
              /* literal pixel values */
  
              uint8_t *p = GET_PIXEL(img->frame, x, y);
  
              p[2] = v;
  
              p[1] = huff_reader_get_symbol(&hg[HUFF_IDX_RED],   &s->gb);
  
              p[3] = huff_reader_get_symbol(&hg[HUFF_IDX_BLUE],  &s->gb);
  
              p[0] = huff_reader_get_symbol(&hg[HUFF_IDX_ALPHA], &s->gb);
  
              if (img->color_cache_bits)
  
                  color_cache_put(img, AV_RB32(p));
  
              x++;
  
              if (x == width) {
  
                  x = 0;
  
                  y++;
  
              }
  
          } else if (v < NUM_LITERAL_CODES + NUM_LENGTH_CODES) {
  
              /* LZ77 backwards mapping */
  
              int prefix_code, length, distance, ref_x, ref_y;
  
  
  
              /* parse length and distance */
  
              prefix_code = v - NUM_LITERAL_CODES;
  
              if (prefix_code < 4) {
  
                  length = prefix_code + 1;
  
              } else {
  
                  int extra_bits = (prefix_code - 2) >> 1;
  
                  int offset     = 2 + (prefix_code & 1) << extra_bits;
  
                  length = offset + get_bits(&s->gb, extra_bits) + 1;
  
              }
  
              prefix_code = huff_reader_get_symbol(&hg[HUFF_IDX_DIST], &s->gb);
  
              if (prefix_code > 39) {
  
                  av_log(s->avctx, AV_LOG_ERROR,
  
                         "distance prefix code too large: %d\n", prefix_code);
  
                  return AVERROR_INVALIDDATA;
  
              }
  
              if (prefix_code < 4) {
  
                  distance = prefix_code + 1;
  
              } else {
  
                  int extra_bits = prefix_code - 2 >> 1;
  
                  int offset     = 2 + (prefix_code & 1) << extra_bits;
  
                  distance = offset + get_bits(&s->gb, extra_bits) + 1;
  
              }
  
  
  
              /* find reference location */
  
              if (distance <= NUM_SHORT_DISTANCES) {
  
                  int xi = lz77_distance_offsets[distance - 1][0];
  
                  int yi = lz77_distance_offsets[distance - 1][1];
  
                  distance = FFMAX(1, xi + yi * width);
  
              } else {
  
                  distance -= NUM_SHORT_DISTANCES;
  
              }
  
              ref_x = x;
  
              ref_y = y;
  
              if (distance <= x) {
  
                  ref_x -= distance;
  
                  distance = 0;
  
              } else {
  
                  ref_x = 0;
  
                  distance -= x;
  
              }
  
              while (distance >= width) {
  
                  ref_y--;
  
                  distance -= width;
  
              }
  
              if (distance > 0) {
  
                  ref_x = width - distance;
  
                  ref_y--;
  
              }
  
              ref_x = FFMAX(0, ref_x);
  
              ref_y = FFMAX(0, ref_y);
  
  
  
              /* copy pixels
  
               * source and dest regions can overlap and wrap lines, so just
  
               * copy per-pixel */
  
              for (i = 0; i < length; i++) {
  
                  uint8_t *p_ref = GET_PIXEL(img->frame, ref_x, ref_y);
  
                  uint8_t *p     = GET_PIXEL(img->frame,     x,     y);
  
  
  
                  AV_COPY32(p, p_ref);
  
                  if (img->color_cache_bits)
  
                      color_cache_put(img, AV_RB32(p));
  
                  x++;
  
                  ref_x++;
  
                  if (x == width) {
  
                      x = 0;
  
                      y++;
  
                  }
  
                  if (ref_x == width) {
  
                      ref_x = 0;
  
                      ref_y++;
  
                  }
  
                  if (y == img->frame->height || ref_y == img->frame->height)
  
                      break;
  
              }
  
          } else {
  
              /* read from color cache */
  
              uint8_t *p = GET_PIXEL(img->frame, x, y);
  
              int cache_idx = v - (NUM_LITERAL_CODES + NUM_LENGTH_CODES);
  
  
  
              if (!img->color_cache_bits) {
  
                  av_log(s->avctx, AV_LOG_ERROR, "color cache not found\n");
  
                  return AVERROR_INVALIDDATA;
  
              }
  
              if (cache_idx >= 1 << img->color_cache_bits) {
  
                  av_log(s->avctx, AV_LOG_ERROR,
  
                         "color cache index out-of-bounds\n");
  
                  return AVERROR_INVALIDDATA;
  
              }
  
              AV_WB32(p, img->color_cache[cache_idx]);
  
              x++;
  
              if (x == width) {
  
                  x = 0;
  
                  y++;
  
              }
  
          }
  
      }
  
  
  
      return 0;
  
  }
  