Blame src/dec/vp8l_dec.c

Packit 9c6abc
// Copyright 2012 Google Inc. All Rights Reserved.
Packit 9c6abc
//
Packit 9c6abc
// Use of this source code is governed by a BSD-style license
Packit 9c6abc
// that can be found in the COPYING file in the root of the source
Packit 9c6abc
// tree. An additional intellectual property rights grant can be found
Packit 9c6abc
// in the file PATENTS. All contributing project authors may
Packit 9c6abc
// be found in the AUTHORS file in the root of the source tree.
Packit 9c6abc
// -----------------------------------------------------------------------------
Packit 9c6abc
//
Packit 9c6abc
// main entry for the decoder
Packit 9c6abc
//
Packit 9c6abc
// Authors: Vikas Arora (vikaas.arora@gmail.com)
Packit 9c6abc
//          Jyrki Alakuijala (jyrki@google.com)
Packit 9c6abc
Packit 9c6abc
#include <stdlib.h>
Packit 9c6abc
Packit 9c6abc
#include "src/dec/alphai_dec.h"
Packit 9c6abc
#include "src/dec/vp8li_dec.h"
Packit 9c6abc
#include "src/dsp/dsp.h"
Packit 9c6abc
#include "src/dsp/lossless.h"
Packit 9c6abc
#include "src/dsp/lossless_common.h"
Packit 9c6abc
#include "src/dsp/yuv.h"
Packit 9c6abc
#include "src/utils/endian_inl_utils.h"
Packit 9c6abc
#include "src/utils/huffman_utils.h"
Packit 9c6abc
#include "src/utils/utils.h"
Packit 9c6abc
Packit 9c6abc
#define NUM_ARGB_CACHE_ROWS          16
Packit 9c6abc
Packit 9c6abc
static const int kCodeLengthLiterals = 16;
Packit 9c6abc
static const int kCodeLengthRepeatCode = 16;
Packit 9c6abc
static const uint8_t kCodeLengthExtraBits[3] = { 2, 3, 7 };
Packit 9c6abc
static const uint8_t kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
Packit 9c6abc
Packit 9c6abc
// -----------------------------------------------------------------------------
Packit 9c6abc
//  Five Huffman codes are used at each meta code:
Packit 9c6abc
//  1. green + length prefix codes + color cache codes,
Packit 9c6abc
//  2. alpha,
Packit 9c6abc
//  3. red,
Packit 9c6abc
//  4. blue, and,
Packit 9c6abc
//  5. distance prefix codes.
Packit 9c6abc
typedef enum {
Packit 9c6abc
  GREEN = 0,
Packit 9c6abc
  RED   = 1,
Packit 9c6abc
  BLUE  = 2,
Packit 9c6abc
  ALPHA = 3,
Packit 9c6abc
  DIST  = 4
Packit 9c6abc
} HuffIndex;
Packit 9c6abc
Packit 9c6abc
static const uint16_t kAlphabetSize[HUFFMAN_CODES_PER_META_CODE] = {
Packit 9c6abc
  NUM_LITERAL_CODES + NUM_LENGTH_CODES,
Packit 9c6abc
  NUM_LITERAL_CODES, NUM_LITERAL_CODES, NUM_LITERAL_CODES,
Packit 9c6abc
  NUM_DISTANCE_CODES
Packit 9c6abc
};
Packit 9c6abc
Packit 9c6abc
static const uint8_t kLiteralMap[HUFFMAN_CODES_PER_META_CODE] = {
Packit 9c6abc
  0, 1, 1, 1, 0
Packit 9c6abc
};
Packit 9c6abc
Packit 9c6abc
#define NUM_CODE_LENGTH_CODES       19
Packit 9c6abc
static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = {
Packit 9c6abc
  17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
Packit 9c6abc
};
Packit 9c6abc
Packit 9c6abc
#define CODE_TO_PLANE_CODES        120
Packit 9c6abc
static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = {
Packit 9c6abc
  0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
Packit 9c6abc
  0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
Packit 9c6abc
  0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
Packit 9c6abc
  0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
Packit 9c6abc
  0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
Packit 9c6abc
  0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
Packit 9c6abc
  0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
Packit 9c6abc
  0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
Packit 9c6abc
  0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
Packit 9c6abc
  0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
Packit 9c6abc
  0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
Packit 9c6abc
  0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
Packit 9c6abc
};
Packit 9c6abc
Packit 9c6abc
// Memory needed for lookup tables of one Huffman tree group. Red, blue, alpha
Packit 9c6abc
// and distance alphabets are constant (256 for red, blue and alpha, 40 for
Packit 9c6abc
// distance) and lookup table sizes for them in worst case are 630 and 410
Packit 9c6abc
// respectively. Size of green alphabet depends on color cache size and is equal
Packit 9c6abc
// to 256 (green component values) + 24 (length prefix values)
Packit 9c6abc
// + color_cache_size (between 0 and 2048).
Packit 9c6abc
// All values computed for 8-bit first level lookup with Mark Adler's tool:
Packit 9c6abc
// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
Packit 9c6abc
#define FIXED_TABLE_SIZE (630 * 3 + 410)
Packit 9c6abc
static const uint16_t kTableSize[12] = {
Packit 9c6abc
  FIXED_TABLE_SIZE + 654,
Packit 9c6abc
  FIXED_TABLE_SIZE + 656,
Packit 9c6abc
  FIXED_TABLE_SIZE + 658,
Packit 9c6abc
  FIXED_TABLE_SIZE + 662,
Packit 9c6abc
  FIXED_TABLE_SIZE + 670,
Packit 9c6abc
  FIXED_TABLE_SIZE + 686,
Packit 9c6abc
  FIXED_TABLE_SIZE + 718,
Packit 9c6abc
  FIXED_TABLE_SIZE + 782,
Packit 9c6abc
  FIXED_TABLE_SIZE + 912,
Packit 9c6abc
  FIXED_TABLE_SIZE + 1168,
Packit 9c6abc
  FIXED_TABLE_SIZE + 1680,
Packit 9c6abc
  FIXED_TABLE_SIZE + 2704
Packit 9c6abc
};
Packit 9c6abc
Packit 9c6abc
static int DecodeImageStream(int xsize, int ysize,
Packit 9c6abc
                             int is_level0,
Packit 9c6abc
                             VP8LDecoder* const dec,
Packit 9c6abc
                             uint32_t** const decoded_data);
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
int VP8LCheckSignature(const uint8_t* const data, size_t size) {
Packit 9c6abc
  return (size >= VP8L_FRAME_HEADER_SIZE &&
Packit 9c6abc
          data[0] == VP8L_MAGIC_BYTE &&
Packit 9c6abc
          (data[4] >> 5) == 0);  // version
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int ReadImageInfo(VP8LBitReader* const br,
Packit 9c6abc
                         int* const width, int* const height,
Packit 9c6abc
                         int* const has_alpha) {
Packit 9c6abc
  if (VP8LReadBits(br, 8) != VP8L_MAGIC_BYTE) return 0;
Packit 9c6abc
  *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
Packit 9c6abc
  *height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
Packit 9c6abc
  *has_alpha = VP8LReadBits(br, 1);
Packit 9c6abc
  if (VP8LReadBits(br, VP8L_VERSION_BITS) != 0) return 0;
Packit 9c6abc
  return !br->eos_;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int VP8LGetInfo(const uint8_t* data, size_t data_size,
Packit 9c6abc
                int* const width, int* const height, int* const has_alpha) {
Packit 9c6abc
  if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
Packit 9c6abc
    return 0;         // not enough data
Packit 9c6abc
  } else if (!VP8LCheckSignature(data, data_size)) {
Packit 9c6abc
    return 0;         // bad signature
Packit 9c6abc
  } else {
Packit 9c6abc
    int w, h, a;
Packit 9c6abc
    VP8LBitReader br;
Packit 9c6abc
    VP8LInitBitReader(&br, data, data_size);
Packit 9c6abc
    if (!ReadImageInfo(&br, &w, &h, &a)) {
Packit 9c6abc
      return 0;
Packit 9c6abc
    }
Packit 9c6abc
    if (width != NULL) *width = w;
Packit 9c6abc
    if (height != NULL) *height = h;
Packit 9c6abc
    if (has_alpha != NULL) *has_alpha = a;
Packit 9c6abc
    return 1;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE int GetCopyDistance(int distance_symbol,
Packit 9c6abc
                                       VP8LBitReader* const br) {
Packit 9c6abc
  int extra_bits, offset;
Packit 9c6abc
  if (distance_symbol < 4) {
Packit 9c6abc
    return distance_symbol + 1;
Packit 9c6abc
  }
Packit 9c6abc
  extra_bits = (distance_symbol - 2) >> 1;
Packit 9c6abc
  offset = (2 + (distance_symbol & 1)) << extra_bits;
Packit 9c6abc
  return offset + VP8LReadBits(br, extra_bits) + 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE int GetCopyLength(int length_symbol,
Packit 9c6abc
                                     VP8LBitReader* const br) {
Packit 9c6abc
  // Length and distance prefixes are encoded the same way.
Packit 9c6abc
  return GetCopyDistance(length_symbol, br);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) {
Packit 9c6abc
  if (plane_code > CODE_TO_PLANE_CODES) {
Packit 9c6abc
    return plane_code - CODE_TO_PLANE_CODES;
Packit 9c6abc
  } else {
Packit 9c6abc
    const int dist_code = kCodeToPlane[plane_code - 1];
Packit 9c6abc
    const int yoffset = dist_code >> 4;
Packit 9c6abc
    const int xoffset = 8 - (dist_code & 0xf);
Packit 9c6abc
    const int dist = yoffset * xsize + xoffset;
Packit 9c6abc
    return (dist >= 1) ? dist : 1;  // dist<1 can happen if xsize is very small
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Decodes the next Huffman code from bit-stream.
Packit 9c6abc
// FillBitWindow(br) needs to be called at minimum every second call
Packit 9c6abc
// to ReadSymbol, in order to pre-fetch enough bits.
Packit 9c6abc
static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
Packit 9c6abc
                                  VP8LBitReader* const br) {
Packit 9c6abc
  int nbits;
Packit 9c6abc
  uint32_t val = VP8LPrefetchBits(br);
Packit 9c6abc
  table += val & HUFFMAN_TABLE_MASK;
Packit 9c6abc
  nbits = table->bits - HUFFMAN_TABLE_BITS;
Packit 9c6abc
  if (nbits > 0) {
Packit 9c6abc
    VP8LSetBitPos(br, br->bit_pos_ + HUFFMAN_TABLE_BITS);
Packit 9c6abc
    val = VP8LPrefetchBits(br);
Packit 9c6abc
    table += table->value;
Packit 9c6abc
    table += val & ((1 << nbits) - 1);
Packit 9c6abc
  }
Packit 9c6abc
  VP8LSetBitPos(br, br->bit_pos_ + table->bits);
Packit 9c6abc
  return table->value;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// Reads packed symbol depending on GREEN channel
Packit 9c6abc
#define BITS_SPECIAL_MARKER 0x100  // something large enough (and a bit-mask)
Packit 9c6abc
#define PACKED_NON_LITERAL_CODE 0  // must be < NUM_LITERAL_CODES
Packit 9c6abc
static WEBP_INLINE int ReadPackedSymbols(const HTreeGroup* group,
Packit 9c6abc
                                         VP8LBitReader* const br,
Packit 9c6abc
                                         uint32_t* const dst) {
Packit 9c6abc
  const uint32_t val = VP8LPrefetchBits(br) & (HUFFMAN_PACKED_TABLE_SIZE - 1);
Packit 9c6abc
  const HuffmanCode32 code = group->packed_table[val];
Packit 9c6abc
  assert(group->use_packed_table);
Packit 9c6abc
  if (code.bits < BITS_SPECIAL_MARKER) {
Packit 9c6abc
    VP8LSetBitPos(br, br->bit_pos_ + code.bits);
Packit 9c6abc
    *dst = code.value;
Packit 9c6abc
    return PACKED_NON_LITERAL_CODE;
Packit 9c6abc
  } else {
Packit 9c6abc
    VP8LSetBitPos(br, br->bit_pos_ + code.bits - BITS_SPECIAL_MARKER);
Packit 9c6abc
    assert(code.value >= NUM_LITERAL_CODES);
Packit 9c6abc
    return code.value;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int AccumulateHCode(HuffmanCode hcode, int shift,
Packit 9c6abc
                           HuffmanCode32* const huff) {
Packit 9c6abc
  huff->bits += hcode.bits;
Packit 9c6abc
  huff->value |= (uint32_t)hcode.value << shift;
Packit 9c6abc
  assert(huff->bits <= HUFFMAN_TABLE_BITS);
Packit 9c6abc
  return hcode.bits;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void BuildPackedTable(HTreeGroup* const htree_group) {
Packit 9c6abc
  uint32_t code;
Packit 9c6abc
  for (code = 0; code < HUFFMAN_PACKED_TABLE_SIZE; ++code) {
Packit 9c6abc
    uint32_t bits = code;
Packit 9c6abc
    HuffmanCode32* const huff = &htree_group->packed_table[bits];
Packit 9c6abc
    HuffmanCode hcode = htree_group->htrees[GREEN][bits];
Packit 9c6abc
    if (hcode.value >= NUM_LITERAL_CODES) {
Packit 9c6abc
      huff->bits = hcode.bits + BITS_SPECIAL_MARKER;
Packit 9c6abc
      huff->value = hcode.value;
Packit 9c6abc
    } else {
Packit 9c6abc
      huff->bits = 0;
Packit 9c6abc
      huff->value = 0;
Packit 9c6abc
      bits >>= AccumulateHCode(hcode, 8, huff);
Packit 9c6abc
      bits >>= AccumulateHCode(htree_group->htrees[RED][bits], 16, huff);
Packit 9c6abc
      bits >>= AccumulateHCode(htree_group->htrees[BLUE][bits], 0, huff);
Packit 9c6abc
      bits >>= AccumulateHCode(htree_group->htrees[ALPHA][bits], 24, huff);
Packit 9c6abc
      (void)bits;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int ReadHuffmanCodeLengths(
Packit 9c6abc
    VP8LDecoder* const dec, const int* const code_length_code_lengths,
Packit 9c6abc
    int num_symbols, int* const code_lengths) {
Packit 9c6abc
  int ok = 0;
Packit 9c6abc
  VP8LBitReader* const br = &dec->br_;
Packit 9c6abc
  int symbol;
Packit 9c6abc
  int max_symbol;
Packit 9c6abc
  int prev_code_len = DEFAULT_CODE_LENGTH;
Packit 9c6abc
  HuffmanCode table[1 << LENGTHS_TABLE_BITS];
Packit 9c6abc
Packit 9c6abc
  if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
Packit 9c6abc
                             code_length_code_lengths,
Packit 9c6abc
                             NUM_CODE_LENGTH_CODES)) {
Packit 9c6abc
    goto End;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  if (VP8LReadBits(br, 1)) {    // use length
Packit 9c6abc
    const int length_nbits = 2 + 2 * VP8LReadBits(br, 3);
Packit 9c6abc
    max_symbol = 2 + VP8LReadBits(br, length_nbits);
Packit 9c6abc
    if (max_symbol > num_symbols) {
Packit 9c6abc
      goto End;
Packit 9c6abc
    }
Packit 9c6abc
  } else {
Packit 9c6abc
    max_symbol = num_symbols;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  symbol = 0;
Packit 9c6abc
  while (symbol < num_symbols) {
Packit 9c6abc
    const HuffmanCode* p;
Packit 9c6abc
    int code_len;
Packit 9c6abc
    if (max_symbol-- == 0) break;
Packit 9c6abc
    VP8LFillBitWindow(br);
Packit 9c6abc
    p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
Packit 9c6abc
    VP8LSetBitPos(br, br->bit_pos_ + p->bits);
Packit 9c6abc
    code_len = p->value;
Packit 9c6abc
    if (code_len < kCodeLengthLiterals) {
Packit 9c6abc
      code_lengths[symbol++] = code_len;
Packit 9c6abc
      if (code_len != 0) prev_code_len = code_len;
Packit 9c6abc
    } else {
Packit 9c6abc
      const int use_prev = (code_len == kCodeLengthRepeatCode);
Packit 9c6abc
      const int slot = code_len - kCodeLengthLiterals;
Packit 9c6abc
      const int extra_bits = kCodeLengthExtraBits[slot];
Packit 9c6abc
      const int repeat_offset = kCodeLengthRepeatOffsets[slot];
Packit 9c6abc
      int repeat = VP8LReadBits(br, extra_bits) + repeat_offset;
Packit 9c6abc
      if (symbol + repeat > num_symbols) {
Packit 9c6abc
        goto End;
Packit 9c6abc
      } else {
Packit 9c6abc
        const int length = use_prev ? prev_code_len : 0;
Packit 9c6abc
        while (repeat-- > 0) code_lengths[symbol++] = length;
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
  ok = 1;
Packit 9c6abc
Packit 9c6abc
 End:
Packit 9c6abc
  if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
  return ok;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
Packit 9c6abc
// tree.
Packit 9c6abc
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
Packit 9c6abc
                           int* const code_lengths, HuffmanCode* const table) {
Packit 9c6abc
  int ok = 0;
Packit 9c6abc
  int size = 0;
Packit 9c6abc
  VP8LBitReader* const br = &dec->br_;
Packit 9c6abc
  const int simple_code = VP8LReadBits(br, 1);
Packit 9c6abc
Packit 9c6abc
  memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths));
Packit 9c6abc
Packit 9c6abc
  if (simple_code) {  // Read symbols, codes & code lengths directly.
Packit 9c6abc
    const int num_symbols = VP8LReadBits(br, 1) + 1;
Packit 9c6abc
    const int first_symbol_len_code = VP8LReadBits(br, 1);
Packit 9c6abc
    // The first code is either 1 bit or 8 bit code.
Packit 9c6abc
    int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
Packit 9c6abc
    code_lengths[symbol] = 1;
Packit 9c6abc
    // The second code (if present), is always 8 bit long.
Packit 9c6abc
    if (num_symbols == 2) {
Packit 9c6abc
      symbol = VP8LReadBits(br, 8);
Packit 9c6abc
      code_lengths[symbol] = 1;
Packit 9c6abc
    }
Packit 9c6abc
    ok = 1;
Packit 9c6abc
  } else {  // Decode Huffman-coded code lengths.
Packit 9c6abc
    int i;
Packit 9c6abc
    int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
Packit 9c6abc
    const int num_codes = VP8LReadBits(br, 4) + 4;
Packit 9c6abc
    if (num_codes > NUM_CODE_LENGTH_CODES) {
Packit 9c6abc
      dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
      return 0;
Packit 9c6abc
    }
Packit 9c6abc
Packit 9c6abc
    for (i = 0; i < num_codes; ++i) {
Packit 9c6abc
      code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
Packit 9c6abc
    }
Packit 9c6abc
    ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size,
Packit 9c6abc
                                code_lengths);
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  ok = ok && !br->eos_;
Packit 9c6abc
  if (ok) {
Packit 9c6abc
    size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
Packit 9c6abc
                                 code_lengths, alphabet_size);
Packit 9c6abc
  }
Packit 9c6abc
  if (!ok || size == 0) {
Packit 9c6abc
    dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
    return 0;
Packit 9c6abc
  }
Packit 9c6abc
  return size;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
Packit 9c6abc
                            int color_cache_bits, int allow_recursion) {
Packit 9c6abc
  int i, j;
Packit 9c6abc
  VP8LBitReader* const br = &dec->br_;
Packit 9c6abc
  VP8LMetadata* const hdr = &dec->hdr_;
Packit 9c6abc
  uint32_t* huffman_image = NULL;
Packit 9c6abc
  HTreeGroup* htree_groups = NULL;
Packit 9c6abc
  HuffmanCode* huffman_tables = NULL;
Packit 9c6abc
  HuffmanCode* next = NULL;
Packit 9c6abc
  int num_htree_groups = 1;
Packit 9c6abc
  int max_alphabet_size = 0;
Packit 9c6abc
  int* code_lengths = NULL;
Packit 9c6abc
  const int table_size = kTableSize[color_cache_bits];
Packit 9c6abc
Packit 9c6abc
  if (allow_recursion && VP8LReadBits(br, 1)) {
Packit 9c6abc
    // use meta Huffman codes.
Packit 9c6abc
    const int huffman_precision = VP8LReadBits(br, 3) + 2;
Packit 9c6abc
    const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
Packit 9c6abc
    const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
Packit 9c6abc
    const int huffman_pixs = huffman_xsize * huffman_ysize;
Packit 9c6abc
    if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
Packit 9c6abc
                           &huffman_image)) {
Packit 9c6abc
      goto Error;
Packit 9c6abc
    }
Packit 9c6abc
    hdr->huffman_subsample_bits_ = huffman_precision;
Packit 9c6abc
    for (i = 0; i < huffman_pixs; ++i) {
Packit 9c6abc
      // The huffman data is stored in red and green bytes.
Packit 9c6abc
      const int group = (huffman_image[i] >> 8) & 0xffff;
Packit 9c6abc
      huffman_image[i] = group;
Packit 9c6abc
      if (group >= num_htree_groups) {
Packit 9c6abc
        num_htree_groups = group + 1;
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  if (br->eos_) goto Error;
Packit 9c6abc
Packit 9c6abc
  // Find maximum alphabet size for the htree group.
Packit 9c6abc
  for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
Packit 9c6abc
    int alphabet_size = kAlphabetSize[j];
Packit 9c6abc
    if (j == 0 && color_cache_bits > 0) {
Packit 9c6abc
      alphabet_size += 1 << color_cache_bits;
Packit 9c6abc
    }
Packit 9c6abc
    if (max_alphabet_size < alphabet_size) {
Packit 9c6abc
      max_alphabet_size = alphabet_size;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
Packit 9c6abc
                                                sizeof(*huffman_tables));
Packit 9c6abc
  htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
Packit 9c6abc
  code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
Packit 9c6abc
                                      sizeof(*code_lengths));
Packit 9c6abc
Packit 9c6abc
  if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
Packit 9c6abc
    dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
Packit 9c6abc
    goto Error;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  next = huffman_tables;
Packit 9c6abc
  for (i = 0; i < num_htree_groups; ++i) {
Packit 9c6abc
    HTreeGroup* const htree_group = &htree_groups[i];
Packit 9c6abc
    HuffmanCode** const htrees = htree_group->htrees;
Packit 9c6abc
    int size;
Packit 9c6abc
    int total_size = 0;
Packit 9c6abc
    int is_trivial_literal = 1;
Packit 9c6abc
    int max_bits = 0;
Packit 9c6abc
    for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
Packit 9c6abc
      int alphabet_size = kAlphabetSize[j];
Packit 9c6abc
      htrees[j] = next;
Packit 9c6abc
      if (j == 0 && color_cache_bits > 0) {
Packit 9c6abc
        alphabet_size += 1 << color_cache_bits;
Packit 9c6abc
      }
Packit 9c6abc
      size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
Packit 9c6abc
      if (size == 0) {
Packit 9c6abc
        goto Error;
Packit 9c6abc
      }
Packit 9c6abc
      if (is_trivial_literal && kLiteralMap[j] == 1) {
Packit 9c6abc
        is_trivial_literal = (next->bits == 0);
Packit 9c6abc
      }
Packit 9c6abc
      total_size += next->bits;
Packit 9c6abc
      next += size;
Packit 9c6abc
      if (j <= ALPHA) {
Packit 9c6abc
        int local_max_bits = code_lengths[0];
Packit 9c6abc
        int k;
Packit 9c6abc
        for (k = 1; k < alphabet_size; ++k) {
Packit 9c6abc
          if (code_lengths[k] > local_max_bits) {
Packit 9c6abc
            local_max_bits = code_lengths[k];
Packit 9c6abc
          }
Packit 9c6abc
        }
Packit 9c6abc
        max_bits += local_max_bits;
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
    htree_group->is_trivial_literal = is_trivial_literal;
Packit 9c6abc
    htree_group->is_trivial_code = 0;
Packit 9c6abc
    if (is_trivial_literal) {
Packit 9c6abc
      const int red = htrees[RED][0].value;
Packit 9c6abc
      const int blue = htrees[BLUE][0].value;
Packit 9c6abc
      const int alpha = htrees[ALPHA][0].value;
Packit 9c6abc
      htree_group->literal_arb =
Packit 9c6abc
          ((uint32_t)alpha << 24) | (red << 16) | blue;
Packit 9c6abc
      if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
Packit 9c6abc
        htree_group->is_trivial_code = 1;
Packit 9c6abc
        htree_group->literal_arb |= htrees[GREEN][0].value << 8;
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
    htree_group->use_packed_table = !htree_group->is_trivial_code &&
Packit 9c6abc
                                    (max_bits < HUFFMAN_PACKED_BITS);
Packit 9c6abc
    if (htree_group->use_packed_table) BuildPackedTable(htree_group);
Packit 9c6abc
  }
Packit 9c6abc
  WebPSafeFree(code_lengths);
Packit 9c6abc
Packit 9c6abc
  // All OK. Finalize pointers and return.
Packit 9c6abc
  hdr->huffman_image_ = huffman_image;
Packit 9c6abc
  hdr->num_htree_groups_ = num_htree_groups;
Packit 9c6abc
  hdr->htree_groups_ = htree_groups;
Packit 9c6abc
  hdr->huffman_tables_ = huffman_tables;
Packit 9c6abc
  return 1;
Packit 9c6abc
Packit 9c6abc
 Error:
Packit 9c6abc
  WebPSafeFree(code_lengths);
Packit 9c6abc
  WebPSafeFree(huffman_image);
Packit 9c6abc
  WebPSafeFree(huffman_tables);
Packit 9c6abc
  VP8LHtreeGroupsFree(htree_groups);
Packit 9c6abc
  return 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Scaling.
Packit 9c6abc
Packit 9c6abc
#if !defined(WEBP_REDUCE_SIZE)
Packit 9c6abc
static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
Packit 9c6abc
  const int num_channels = 4;
Packit 9c6abc
  const int in_width = io->mb_w;
Packit 9c6abc
  const int out_width = io->scaled_width;
Packit 9c6abc
  const int in_height = io->mb_h;
Packit 9c6abc
  const int out_height = io->scaled_height;
Packit 9c6abc
  const uint64_t work_size = 2 * num_channels * (uint64_t)out_width;
Packit 9c6abc
  rescaler_t* work;        // Rescaler work area.
Packit 9c6abc
  const uint64_t scaled_data_size = (uint64_t)out_width;
Packit 9c6abc
  uint32_t* scaled_data;  // Temporary storage for scaled BGRA data.
Packit 9c6abc
  const uint64_t memory_size = sizeof(*dec->rescaler) +
Packit 9c6abc
                               work_size * sizeof(*work) +
Packit 9c6abc
                               scaled_data_size * sizeof(*scaled_data);
Packit 9c6abc
  uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
Packit 9c6abc
  if (memory == NULL) {
Packit 9c6abc
    dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
Packit 9c6abc
    return 0;
Packit 9c6abc
  }
Packit 9c6abc
  assert(dec->rescaler_memory == NULL);
Packit 9c6abc
  dec->rescaler_memory = memory;
Packit 9c6abc
Packit 9c6abc
  dec->rescaler = (WebPRescaler*)memory;
Packit 9c6abc
  memory += sizeof(*dec->rescaler);
Packit 9c6abc
  work = (rescaler_t*)memory;
Packit 9c6abc
  memory += work_size * sizeof(*work);
Packit 9c6abc
  scaled_data = (uint32_t*)memory;
Packit 9c6abc
Packit 9c6abc
  WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
Packit 9c6abc
                   out_width, out_height, 0, num_channels, work);
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
#endif   // WEBP_REDUCE_SIZE
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Export to ARGB
Packit 9c6abc
Packit 9c6abc
#if !defined(WEBP_REDUCE_SIZE)
Packit 9c6abc
Packit 9c6abc
// We have special "export" function since we need to convert from BGRA
Packit 9c6abc
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
Packit 9c6abc
                  int rgba_stride, uint8_t* const rgba) {
Packit 9c6abc
  uint32_t* const src = (uint32_t*)rescaler->dst;
Packit 9c6abc
  const int dst_width = rescaler->dst_width;
Packit 9c6abc
  int num_lines_out = 0;
Packit 9c6abc
  while (WebPRescalerHasPendingOutput(rescaler)) {
Packit 9c6abc
    uint8_t* const dst = rgba + num_lines_out * rgba_stride;
Packit 9c6abc
    WebPRescalerExportRow(rescaler);
Packit 9c6abc
    WebPMultARGBRow(src, dst_width, 1);
Packit 9c6abc
    VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
Packit 9c6abc
    ++num_lines_out;
Packit 9c6abc
  }
Packit 9c6abc
  return num_lines_out;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// Emit scaled rows.
Packit 9c6abc
static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
Packit 9c6abc
                                uint8_t* in, int in_stride, int mb_h,
Packit 9c6abc
                                uint8_t* const out, int out_stride) {
Packit 9c6abc
  const WEBP_CSP_MODE colorspace = dec->output_->colorspace;
Packit 9c6abc
  int num_lines_in = 0;
Packit 9c6abc
  int num_lines_out = 0;
Packit 9c6abc
  while (num_lines_in < mb_h) {
Packit 9c6abc
    uint8_t* const row_in = in + num_lines_in * in_stride;
Packit 9c6abc
    uint8_t* const row_out = out + num_lines_out * out_stride;
Packit 9c6abc
    const int lines_left = mb_h - num_lines_in;
Packit 9c6abc
    const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
Packit 9c6abc
    int lines_imported;
Packit 9c6abc
    assert(needed_lines > 0 && needed_lines <= lines_left);
Packit 9c6abc
    WebPMultARGBRows(row_in, in_stride,
Packit 9c6abc
                     dec->rescaler->src_width, needed_lines, 0);
Packit 9c6abc
    lines_imported =
Packit 9c6abc
        WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride);
Packit 9c6abc
    assert(lines_imported == needed_lines);
Packit 9c6abc
    num_lines_in += lines_imported;
Packit 9c6abc
    num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out);
Packit 9c6abc
  }
Packit 9c6abc
  return num_lines_out;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#endif   // WEBP_REDUCE_SIZE
Packit 9c6abc
Packit 9c6abc
// Emit rows without any scaling.
Packit 9c6abc
static int EmitRows(WEBP_CSP_MODE colorspace,
Packit 9c6abc
                    const uint8_t* row_in, int in_stride,
Packit 9c6abc
                    int mb_w, int mb_h,
Packit 9c6abc
                    uint8_t* const out, int out_stride) {
Packit 9c6abc
  int lines = mb_h;
Packit 9c6abc
  uint8_t* row_out = out;
Packit 9c6abc
  while (lines-- > 0) {
Packit 9c6abc
    VP8LConvertFromBGRA((const uint32_t*)row_in, mb_w, colorspace, row_out);
Packit 9c6abc
    row_in += in_stride;
Packit 9c6abc
    row_out += out_stride;
Packit 9c6abc
  }
Packit 9c6abc
  return mb_h;  // Num rows out == num rows in.
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Export to YUVA
Packit 9c6abc
Packit 9c6abc
static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
Packit 9c6abc
                          const WebPDecBuffer* const output) {
Packit 9c6abc
  const WebPYUVABuffer* const buf = &output->u.YUVA;
Packit 9c6abc
Packit 9c6abc
  // first, the luma plane
Packit 9c6abc
  WebPConvertARGBToY(src, buf->y + y_pos * buf->y_stride, width);
Packit 9c6abc
Packit 9c6abc
  // then U/V planes
Packit 9c6abc
  {
Packit 9c6abc
    uint8_t* const u = buf->u + (y_pos >> 1) * buf->u_stride;
Packit 9c6abc
    uint8_t* const v = buf->v + (y_pos >> 1) * buf->v_stride;
Packit 9c6abc
    // even lines: store values
Packit 9c6abc
    // odd lines: average with previous values
Packit 9c6abc
    WebPConvertARGBToUV(src, u, v, width, !(y_pos & 1));
Packit 9c6abc
  }
Packit 9c6abc
  // Lastly, store alpha if needed.
Packit 9c6abc
  if (buf->a != NULL) {
Packit 9c6abc
    uint8_t* const a = buf->a + y_pos * buf->a_stride;
Packit 9c6abc
#if defined(WORDS_BIGENDIAN)
Packit 9c6abc
    WebPExtractAlpha((uint8_t*)src + 0, 0, width, 1, a, 0);
Packit 9c6abc
#else
Packit 9c6abc
    WebPExtractAlpha((uint8_t*)src + 3, 0, width, 1, a, 0);
Packit 9c6abc
#endif
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
Packit 9c6abc
  WebPRescaler* const rescaler = dec->rescaler;
Packit 9c6abc
  uint32_t* const src = (uint32_t*)rescaler->dst;
Packit 9c6abc
  const int dst_width = rescaler->dst_width;
Packit 9c6abc
  int num_lines_out = 0;
Packit 9c6abc
  while (WebPRescalerHasPendingOutput(rescaler)) {
Packit 9c6abc
    WebPRescalerExportRow(rescaler);
Packit 9c6abc
    WebPMultARGBRow(src, dst_width, 1);
Packit 9c6abc
    ConvertToYUVA(src, dst_width, y_pos, dec->output_);
Packit 9c6abc
    ++y_pos;
Packit 9c6abc
    ++num_lines_out;
Packit 9c6abc
  }
Packit 9c6abc
  return num_lines_out;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec,
Packit 9c6abc
                                uint8_t* in, int in_stride, int mb_h) {
Packit 9c6abc
  int num_lines_in = 0;
Packit 9c6abc
  int y_pos = dec->last_out_row_;
Packit 9c6abc
  while (num_lines_in < mb_h) {
Packit 9c6abc
    const int lines_left = mb_h - num_lines_in;
Packit 9c6abc
    const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
Packit 9c6abc
    int lines_imported;
Packit 9c6abc
    WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0);
Packit 9c6abc
    lines_imported =
Packit 9c6abc
        WebPRescalerImport(dec->rescaler, lines_left, in, in_stride);
Packit 9c6abc
    assert(lines_imported == needed_lines);
Packit 9c6abc
    num_lines_in += lines_imported;
Packit 9c6abc
    in += needed_lines * in_stride;
Packit 9c6abc
    y_pos += ExportYUVA(dec, y_pos);
Packit 9c6abc
  }
Packit 9c6abc
  return y_pos;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int EmitRowsYUVA(const VP8LDecoder* const dec,
Packit 9c6abc
                        const uint8_t* in, int in_stride,
Packit 9c6abc
                        int mb_w, int num_rows) {
Packit 9c6abc
  int y_pos = dec->last_out_row_;
Packit 9c6abc
  while (num_rows-- > 0) {
Packit 9c6abc
    ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output_);
Packit 9c6abc
    in += in_stride;
Packit 9c6abc
    ++y_pos;
Packit 9c6abc
  }
Packit 9c6abc
  return y_pos;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Cropping.
Packit 9c6abc
Packit 9c6abc
// Sets io->mb_y, io->mb_h & io->mb_w according to start row, end row and
Packit 9c6abc
// crop options. Also updates the input data pointer, so that it points to the
Packit 9c6abc
// start of the cropped window. Note that pixels are in ARGB format even if
Packit 9c6abc
// 'in_data' is uint8_t*.
Packit 9c6abc
// Returns true if the crop window is not empty.
Packit 9c6abc
static int SetCropWindow(VP8Io* const io, int y_start, int y_end,
Packit 9c6abc
                         uint8_t** const in_data, int pixel_stride) {
Packit 9c6abc
  assert(y_start < y_end);
Packit 9c6abc
  assert(io->crop_left < io->crop_right);
Packit 9c6abc
  if (y_end > io->crop_bottom) {
Packit 9c6abc
    y_end = io->crop_bottom;  // make sure we don't overflow on last row.
Packit 9c6abc
  }
Packit 9c6abc
  if (y_start < io->crop_top) {
Packit 9c6abc
    const int delta = io->crop_top - y_start;
Packit 9c6abc
    y_start = io->crop_top;
Packit 9c6abc
    *in_data += delta * pixel_stride;
Packit 9c6abc
  }
Packit 9c6abc
  if (y_start >= y_end) return 0;  // Crop window is empty.
Packit 9c6abc
Packit 9c6abc
  *in_data += io->crop_left * sizeof(uint32_t);
Packit 9c6abc
Packit 9c6abc
  io->mb_y = y_start - io->crop_top;
Packit 9c6abc
  io->mb_w = io->crop_right - io->crop_left;
Packit 9c6abc
  io->mb_h = y_end - y_start;
Packit 9c6abc
  return 1;  // Non-empty crop window.
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE int GetMetaIndex(
Packit 9c6abc
    const uint32_t* const image, int xsize, int bits, int x, int y) {
Packit 9c6abc
  if (bits == 0) return 0;
Packit 9c6abc
  return image[xsize * (y >> bits) + (x >> bits)];
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr,
Packit 9c6abc
                                                   int x, int y) {
Packit 9c6abc
  const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_,
Packit 9c6abc
                                      hdr->huffman_subsample_bits_, x, y);
Packit 9c6abc
  assert(meta_index < hdr->num_htree_groups_);
Packit 9c6abc
  return hdr->htree_groups_ + meta_index;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Main loop, with custom row-processing function
Packit 9c6abc
Packit 9c6abc
typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row);
Packit 9c6abc
Packit 9c6abc
static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
Packit 9c6abc
                                   const uint32_t* const rows) {
Packit 9c6abc
  int n = dec->next_transform_;
Packit 9c6abc
  const int cache_pixs = dec->width_ * num_rows;
Packit 9c6abc
  const int start_row = dec->last_row_;
Packit 9c6abc
  const int end_row = start_row + num_rows;
Packit 9c6abc
  const uint32_t* rows_in = rows;
Packit 9c6abc
  uint32_t* const rows_out = dec->argb_cache_;
Packit 9c6abc
Packit 9c6abc
  // Inverse transforms.
Packit 9c6abc
  while (n-- > 0) {
Packit 9c6abc
    VP8LTransform* const transform = &dec->transforms_[n];
Packit 9c6abc
    VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
Packit 9c6abc
    rows_in = rows_out;
Packit 9c6abc
  }
Packit 9c6abc
  if (rows_in != rows_out) {
Packit 9c6abc
    // No transform called, hence just copy.
Packit 9c6abc
    memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// Processes (transforms, scales & color-converts) the rows decoded after the
Packit 9c6abc
// last call.
Packit 9c6abc
static void ProcessRows(VP8LDecoder* const dec, int row) {
Packit 9c6abc
  const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_;
Packit 9c6abc
  const int num_rows = row - dec->last_row_;
Packit 9c6abc
Packit 9c6abc
  assert(row <= dec->io_->crop_bottom);
Packit 9c6abc
  // We can't process more than NUM_ARGB_CACHE_ROWS at a time (that's the size
Packit 9c6abc
  // of argb_cache_), but we currently don't need more than that.
Packit 9c6abc
  assert(num_rows <= NUM_ARGB_CACHE_ROWS);
Packit 9c6abc
  if (num_rows > 0) {    // Emit output.
Packit 9c6abc
    VP8Io* const io = dec->io_;
Packit 9c6abc
    uint8_t* rows_data = (uint8_t*)dec->argb_cache_;
Packit 9c6abc
    const int in_stride = io->width * sizeof(uint32_t);  // in unit of RGBA
Packit 9c6abc
Packit 9c6abc
    ApplyInverseTransforms(dec, num_rows, rows);
Packit 9c6abc
    if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) {
Packit 9c6abc
      // Nothing to output (this time).
Packit 9c6abc
    } else {
Packit 9c6abc
      const WebPDecBuffer* const output = dec->output_;
Packit 9c6abc
      if (WebPIsRGBMode(output->colorspace)) {  // convert to RGBA
Packit 9c6abc
        const WebPRGBABuffer* const buf = &output->u.RGBA;
Packit 9c6abc
        uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
Packit 9c6abc
        const int num_rows_out =
Packit 9c6abc
#if !defined(WEBP_REDUCE_SIZE)
Packit 9c6abc
         io->use_scaling ?
Packit 9c6abc
            EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h,
Packit 9c6abc
                                 rgba, buf->stride) :
Packit 9c6abc
#endif  // WEBP_REDUCE_SIZE
Packit 9c6abc
            EmitRows(output->colorspace, rows_data, in_stride,
Packit 9c6abc
                     io->mb_w, io->mb_h, rgba, buf->stride);
Packit 9c6abc
        // Update 'last_out_row_'.
Packit 9c6abc
        dec->last_out_row_ += num_rows_out;
Packit 9c6abc
      } else {                              // convert to YUVA
Packit 9c6abc
        dec->last_out_row_ = io->use_scaling ?
Packit 9c6abc
            EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) :
Packit 9c6abc
            EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h);
Packit 9c6abc
      }
Packit 9c6abc
      assert(dec->last_out_row_ <= output->height);
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Update 'last_row_'.
Packit 9c6abc
  dec->last_row_ = row;
Packit 9c6abc
  assert(dec->last_row_ <= dec->height_);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// Row-processing for the special case when alpha data contains only one
Packit 9c6abc
// transform (color indexing), and trivial non-green literals.
Packit 9c6abc
static int Is8bOptimizable(const VP8LMetadata* const hdr) {
Packit 9c6abc
  int i;
Packit 9c6abc
  if (hdr->color_cache_size_ > 0) return 0;
Packit 9c6abc
  // When the Huffman tree contains only one symbol, we can skip the
Packit 9c6abc
  // call to ReadSymbol() for red/blue/alpha channels.
Packit 9c6abc
  for (i = 0; i < hdr->num_htree_groups_; ++i) {
Packit 9c6abc
    HuffmanCode** const htrees = hdr->htree_groups_[i].htrees;
Packit 9c6abc
    if (htrees[RED][0].bits > 0) return 0;
Packit 9c6abc
    if (htrees[BLUE][0].bits > 0) return 0;
Packit 9c6abc
    if (htrees[ALPHA][0].bits > 0) return 0;
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void AlphaApplyFilter(ALPHDecoder* const alph_dec,
Packit 9c6abc
                             int first_row, int last_row,
Packit 9c6abc
                             uint8_t* out, int stride) {
Packit 9c6abc
  if (alph_dec->filter_ != WEBP_FILTER_NONE) {
Packit 9c6abc
    int y;
Packit 9c6abc
    const uint8_t* prev_line = alph_dec->prev_line_;
Packit 9c6abc
    assert(WebPUnfilters[alph_dec->filter_] != NULL);
Packit 9c6abc
    for (y = first_row; y < last_row; ++y) {
Packit 9c6abc
      WebPUnfilters[alph_dec->filter_](prev_line, out, out, stride);
Packit 9c6abc
      prev_line = out;
Packit 9c6abc
      out += stride;
Packit 9c6abc
    }
Packit 9c6abc
    alph_dec->prev_line_ = prev_line;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int last_row) {
Packit 9c6abc
  // For vertical and gradient filtering, we need to decode the part above the
Packit 9c6abc
  // crop_top row, in order to have the correct spatial predictors.
Packit 9c6abc
  ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque;
Packit 9c6abc
  const int top_row =
Packit 9c6abc
      (alph_dec->filter_ == WEBP_FILTER_NONE ||
Packit 9c6abc
       alph_dec->filter_ == WEBP_FILTER_HORIZONTAL) ? dec->io_->crop_top
Packit 9c6abc
                                                    : dec->last_row_;
Packit 9c6abc
  const int first_row = (dec->last_row_ < top_row) ? top_row : dec->last_row_;
Packit 9c6abc
  assert(last_row <= dec->io_->crop_bottom);
Packit 9c6abc
  if (last_row > first_row) {
Packit 9c6abc
    // Special method for paletted alpha data. We only process the cropped area.
Packit 9c6abc
    const int width = dec->io_->width;
Packit 9c6abc
    uint8_t* out = alph_dec->output_ + width * first_row;
Packit 9c6abc
    const uint8_t* const in =
Packit 9c6abc
      (uint8_t*)dec->pixels_ + dec->width_ * first_row;
Packit 9c6abc
    VP8LTransform* const transform = &dec->transforms_[0];
Packit 9c6abc
    assert(dec->next_transform_ == 1);
Packit 9c6abc
    assert(transform->type_ == COLOR_INDEXING_TRANSFORM);
Packit 9c6abc
    VP8LColorIndexInverseTransformAlpha(transform, first_row, last_row,
Packit 9c6abc
                                        in, out);
Packit 9c6abc
    AlphaApplyFilter(alph_dec, first_row, last_row, out, width);
Packit 9c6abc
  }
Packit 9c6abc
  dec->last_row_ = dec->last_out_row_ = last_row;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Helper functions for fast pattern copy (8b and 32b)
Packit 9c6abc
Packit 9c6abc
// cyclic rotation of pattern word
Packit 9c6abc
static WEBP_INLINE uint32_t Rotate8b(uint32_t V) {
Packit 9c6abc
#if defined(WORDS_BIGENDIAN)
Packit 9c6abc
  return ((V & 0xff000000u) >> 24) | (V << 8);
Packit 9c6abc
#else
Packit 9c6abc
  return ((V & 0xffu) << 24) | (V >> 8);
Packit 9c6abc
#endif
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// copy 1, 2 or 4-bytes pattern
Packit 9c6abc
static WEBP_INLINE void CopySmallPattern8b(const uint8_t* src, uint8_t* dst,
Packit 9c6abc
                                           int length, uint32_t pattern) {
Packit 9c6abc
  int i;
Packit 9c6abc
  // align 'dst' to 4-bytes boundary. Adjust the pattern along the way.
Packit 9c6abc
  while ((uintptr_t)dst & 3) {
Packit 9c6abc
    *dst++ = *src++;
Packit 9c6abc
    pattern = Rotate8b(pattern);
Packit 9c6abc
    --length;
Packit 9c6abc
  }
Packit 9c6abc
  // Copy the pattern 4 bytes at a time.
Packit 9c6abc
  for (i = 0; i < (length >> 2); ++i) {
Packit 9c6abc
    ((uint32_t*)dst)[i] = pattern;
Packit 9c6abc
  }
Packit 9c6abc
  // Finish with left-overs. 'pattern' is still correctly positioned,
Packit 9c6abc
  // so no Rotate8b() call is needed.
Packit 9c6abc
  for (i <<= 2; i < length; ++i) {
Packit 9c6abc
    dst[i] = src[i];
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
Packit 9c6abc
  const uint8_t* src = dst - dist;
Packit 9c6abc
  if (length >= 8) {
Packit 9c6abc
    uint32_t pattern = 0;
Packit 9c6abc
    switch (dist) {
Packit 9c6abc
      case 1:
Packit 9c6abc
        pattern = src[0];
Packit 9c6abc
#if defined(__arm__) || defined(_M_ARM)   // arm doesn't like multiply that much
Packit 9c6abc
        pattern |= pattern << 8;
Packit 9c6abc
        pattern |= pattern << 16;
Packit 9c6abc
#elif defined(WEBP_USE_MIPS_DSP_R2)
Packit 9c6abc
        __asm__ volatile ("replv.qb %0, %0" : "+r"(pattern));
Packit 9c6abc
#else
Packit 9c6abc
        pattern = 0x01010101u * pattern;
Packit 9c6abc
#endif
Packit 9c6abc
        break;
Packit 9c6abc
      case 2:
Packit 9c6abc
        memcpy(&pattern, src, sizeof(uint16_t));
Packit 9c6abc
#if defined(__arm__) || defined(_M_ARM)
Packit 9c6abc
        pattern |= pattern << 16;
Packit 9c6abc
#elif defined(WEBP_USE_MIPS_DSP_R2)
Packit 9c6abc
        __asm__ volatile ("replv.ph %0, %0" : "+r"(pattern));
Packit 9c6abc
#else
Packit 9c6abc
        pattern = 0x00010001u * pattern;
Packit 9c6abc
#endif
Packit 9c6abc
        break;
Packit 9c6abc
      case 4:
Packit 9c6abc
        memcpy(&pattern, src, sizeof(uint32_t));
Packit 9c6abc
        break;
Packit 9c6abc
      default:
Packit 9c6abc
        goto Copy;
Packit 9c6abc
        break;
Packit 9c6abc
    }
Packit 9c6abc
    CopySmallPattern8b(src, dst, length, pattern);
Packit 9c6abc
    return;
Packit 9c6abc
  }
Packit 9c6abc
 Copy:
Packit 9c6abc
  if (dist >= length) {  // no overlap -> use memcpy()
Packit 9c6abc
    memcpy(dst, src, length * sizeof(*dst));
Packit 9c6abc
  } else {
Packit 9c6abc
    int i;
Packit 9c6abc
    for (i = 0; i < length; ++i) dst[i] = src[i];
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// copy pattern of 1 or 2 uint32_t's
Packit 9c6abc
static WEBP_INLINE void CopySmallPattern32b(const uint32_t* src,
Packit 9c6abc
                                            uint32_t* dst,
Packit 9c6abc
                                            int length, uint64_t pattern) {
Packit 9c6abc
  int i;
Packit 9c6abc
  if ((uintptr_t)dst & 4) {           // Align 'dst' to 8-bytes boundary.
Packit 9c6abc
    *dst++ = *src++;
Packit 9c6abc
    pattern = (pattern >> 32) | (pattern << 32);
Packit 9c6abc
    --length;
Packit 9c6abc
  }
Packit 9c6abc
  assert(0 == ((uintptr_t)dst & 7));
Packit 9c6abc
  for (i = 0; i < (length >> 1); ++i) {
Packit 9c6abc
    ((uint64_t*)dst)[i] = pattern;    // Copy the pattern 8 bytes at a time.
Packit 9c6abc
  }
Packit 9c6abc
  if (length & 1) {                   // Finish with left-over.
Packit 9c6abc
    dst[i << 1] = src[i << 1];
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE void CopyBlock32b(uint32_t* const dst,
Packit 9c6abc
                                     int dist, int length) {
Packit 9c6abc
  const uint32_t* const src = dst - dist;
Packit 9c6abc
  if (dist <= 2 && length >= 4 && ((uintptr_t)dst & 3) == 0) {
Packit 9c6abc
    uint64_t pattern;
Packit 9c6abc
    if (dist == 1) {
Packit 9c6abc
      pattern = (uint64_t)src[0];
Packit 9c6abc
      pattern |= pattern << 32;
Packit 9c6abc
    } else {
Packit 9c6abc
      memcpy(&pattern, src, sizeof(pattern));
Packit 9c6abc
    }
Packit 9c6abc
    CopySmallPattern32b(src, dst, length, pattern);
Packit 9c6abc
  } else if (dist >= length) {  // no overlap
Packit 9c6abc
    memcpy(dst, src, length * sizeof(*dst));
Packit 9c6abc
  } else {
Packit 9c6abc
    int i;
Packit 9c6abc
    for (i = 0; i < length; ++i) dst[i] = src[i];
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
Packit 9c6abc
                           int width, int height, int last_row) {
Packit 9c6abc
  int ok = 1;
Packit 9c6abc
  int row = dec->last_pixel_ / width;
Packit 9c6abc
  int col = dec->last_pixel_ % width;
Packit 9c6abc
  VP8LBitReader* const br = &dec->br_;
Packit 9c6abc
  VP8LMetadata* const hdr = &dec->hdr_;
Packit 9c6abc
  int pos = dec->last_pixel_;         // current position
Packit 9c6abc
  const int end = width * height;     // End of data
Packit 9c6abc
  const int last = width * last_row;  // Last pixel to decode
Packit 9c6abc
  const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
Packit 9c6abc
  const int mask = hdr->huffman_mask_;
Packit 9c6abc
  const HTreeGroup* htree_group =
Packit 9c6abc
      (pos < last) ? GetHtreeGroupForPos(hdr, col, row) : NULL;
Packit 9c6abc
  assert(pos <= end);
Packit 9c6abc
  assert(last_row <= height);
Packit 9c6abc
  assert(Is8bOptimizable(hdr));
Packit 9c6abc
Packit 9c6abc
  while (!br->eos_ && pos < last) {
Packit 9c6abc
    int code;
Packit 9c6abc
    // Only update when changing tile.
Packit 9c6abc
    if ((col & mask) == 0) {
Packit 9c6abc
      htree_group = GetHtreeGroupForPos(hdr, col, row);
Packit 9c6abc
    }
Packit 9c6abc
    assert(htree_group != NULL);
Packit 9c6abc
    VP8LFillBitWindow(br);
Packit 9c6abc
    code = ReadSymbol(htree_group->htrees[GREEN], br);
Packit 9c6abc
    if (code < NUM_LITERAL_CODES) {  // Literal
Packit 9c6abc
      data[pos] = code;
Packit 9c6abc
      ++pos;
Packit 9c6abc
      ++col;
Packit 9c6abc
      if (col >= width) {
Packit 9c6abc
        col = 0;
Packit 9c6abc
        ++row;
Packit 9c6abc
        if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
Packit 9c6abc
          ExtractPalettedAlphaRows(dec, row);
Packit 9c6abc
        }
Packit 9c6abc
      }
Packit 9c6abc
    } else if (code < len_code_limit) {  // Backward reference
Packit 9c6abc
      int dist_code, dist;
Packit 9c6abc
      const int length_sym = code - NUM_LITERAL_CODES;
Packit 9c6abc
      const int length = GetCopyLength(length_sym, br);
Packit 9c6abc
      const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br);
Packit 9c6abc
      VP8LFillBitWindow(br);
Packit 9c6abc
      dist_code = GetCopyDistance(dist_symbol, br);
Packit 9c6abc
      dist = PlaneCodeToDistance(width, dist_code);
Packit 9c6abc
      if (pos >= dist && end - pos >= length) {
Packit 9c6abc
        CopyBlock8b(data + pos, dist, length);
Packit 9c6abc
      } else {
Packit 9c6abc
        ok = 0;
Packit 9c6abc
        goto End;
Packit 9c6abc
      }
Packit 9c6abc
      pos += length;
Packit 9c6abc
      col += length;
Packit 9c6abc
      while (col >= width) {
Packit 9c6abc
        col -= width;
Packit 9c6abc
        ++row;
Packit 9c6abc
        if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
Packit 9c6abc
          ExtractPalettedAlphaRows(dec, row);
Packit 9c6abc
        }
Packit 9c6abc
      }
Packit 9c6abc
      if (pos < last && (col & mask)) {
Packit 9c6abc
        htree_group = GetHtreeGroupForPos(hdr, col, row);
Packit 9c6abc
      }
Packit 9c6abc
    } else {  // Not reached
Packit 9c6abc
      ok = 0;
Packit 9c6abc
      goto End;
Packit 9c6abc
    }
Packit 9c6abc
    br->eos_ = VP8LIsEndOfStream(br);
Packit 9c6abc
  }
Packit 9c6abc
  // Process the remaining rows corresponding to last row-block.
Packit 9c6abc
  ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row);
Packit 9c6abc
Packit 9c6abc
 End:
Packit 9c6abc
  br->eos_ = VP8LIsEndOfStream(br);
Packit 9c6abc
  if (!ok || (br->eos_ && pos < end)) {
Packit 9c6abc
    ok = 0;
Packit 9c6abc
    dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
Packit 9c6abc
                            : VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
  } else {
Packit 9c6abc
    dec->last_pixel_ = pos;
Packit 9c6abc
  }
Packit 9c6abc
  return ok;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void SaveState(VP8LDecoder* const dec, int last_pixel) {
Packit 9c6abc
  assert(dec->incremental_);
Packit 9c6abc
  dec->saved_br_ = dec->br_;
Packit 9c6abc
  dec->saved_last_pixel_ = last_pixel;
Packit 9c6abc
  if (dec->hdr_.color_cache_size_ > 0) {
Packit 9c6abc
    VP8LColorCacheCopy(&dec->hdr_.color_cache_, &dec->hdr_.saved_color_cache_);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void RestoreState(VP8LDecoder* const dec) {
Packit 9c6abc
  assert(dec->br_.eos_);
Packit 9c6abc
  dec->status_ = VP8_STATUS_SUSPENDED;
Packit 9c6abc
  dec->br_ = dec->saved_br_;
Packit 9c6abc
  dec->last_pixel_ = dec->saved_last_pixel_;
Packit 9c6abc
  if (dec->hdr_.color_cache_size_ > 0) {
Packit 9c6abc
    VP8LColorCacheCopy(&dec->hdr_.saved_color_cache_, &dec->hdr_.color_cache_);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#define SYNC_EVERY_N_ROWS 8  // minimum number of rows between check-points
Packit 9c6abc
static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
Packit 9c6abc
                           int width, int height, int last_row,
Packit 9c6abc
                           ProcessRowsFunc process_func) {
Packit 9c6abc
  int row = dec->last_pixel_ / width;
Packit 9c6abc
  int col = dec->last_pixel_ % width;
Packit 9c6abc
  VP8LBitReader* const br = &dec->br_;
Packit 9c6abc
  VP8LMetadata* const hdr = &dec->hdr_;
Packit 9c6abc
  uint32_t* src = data + dec->last_pixel_;
Packit 9c6abc
  uint32_t* last_cached = src;
Packit 9c6abc
  uint32_t* const src_end = data + width * height;     // End of data
Packit 9c6abc
  uint32_t* const src_last = data + width * last_row;  // Last pixel to decode
Packit 9c6abc
  const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
Packit 9c6abc
  const int color_cache_limit = len_code_limit + hdr->color_cache_size_;
Packit 9c6abc
  int next_sync_row = dec->incremental_ ? row : 1 << 24;
Packit 9c6abc
  VP8LColorCache* const color_cache =
Packit 9c6abc
      (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
Packit 9c6abc
  const int mask = hdr->huffman_mask_;
Packit 9c6abc
  const HTreeGroup* htree_group =
Packit 9c6abc
      (src < src_last) ? GetHtreeGroupForPos(hdr, col, row) : NULL;
Packit 9c6abc
  assert(dec->last_row_ < last_row);
Packit 9c6abc
  assert(src_last <= src_end);
Packit 9c6abc
Packit 9c6abc
  while (src < src_last) {
Packit 9c6abc
    int code;
Packit 9c6abc
    if (row >= next_sync_row) {
Packit 9c6abc
      SaveState(dec, (int)(src - data));
Packit 9c6abc
      next_sync_row = row + SYNC_EVERY_N_ROWS;
Packit 9c6abc
    }
Packit 9c6abc
    // Only update when changing tile. Note we could use this test:
Packit 9c6abc
    // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed
Packit 9c6abc
    // but that's actually slower and needs storing the previous col/row.
Packit 9c6abc
    if ((col & mask) == 0) {
Packit 9c6abc
      htree_group = GetHtreeGroupForPos(hdr, col, row);
Packit 9c6abc
    }
Packit 9c6abc
    assert(htree_group != NULL);
Packit 9c6abc
    if (htree_group->is_trivial_code) {
Packit 9c6abc
      *src = htree_group->literal_arb;
Packit 9c6abc
      goto AdvanceByOne;
Packit 9c6abc
    }
Packit 9c6abc
    VP8LFillBitWindow(br);
Packit 9c6abc
    if (htree_group->use_packed_table) {
Packit 9c6abc
      code = ReadPackedSymbols(htree_group, br, src);
Packit 9c6abc
      if (VP8LIsEndOfStream(br)) break;
Packit 9c6abc
      if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne;
Packit 9c6abc
    } else {
Packit 9c6abc
      code = ReadSymbol(htree_group->htrees[GREEN], br);
Packit 9c6abc
    }
Packit 9c6abc
    if (VP8LIsEndOfStream(br)) break;
Packit 9c6abc
    if (code < NUM_LITERAL_CODES) {  // Literal
Packit 9c6abc
      if (htree_group->is_trivial_literal) {
Packit 9c6abc
        *src = htree_group->literal_arb | (code << 8);
Packit 9c6abc
      } else {
Packit 9c6abc
        int red, blue, alpha;
Packit 9c6abc
        red = ReadSymbol(htree_group->htrees[RED], br);
Packit 9c6abc
        VP8LFillBitWindow(br);
Packit 9c6abc
        blue = ReadSymbol(htree_group->htrees[BLUE], br);
Packit 9c6abc
        alpha = ReadSymbol(htree_group->htrees[ALPHA], br);
Packit 9c6abc
        if (VP8LIsEndOfStream(br)) break;
Packit 9c6abc
        *src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue;
Packit 9c6abc
      }
Packit 9c6abc
    AdvanceByOne:
Packit 9c6abc
      ++src;
Packit 9c6abc
      ++col;
Packit 9c6abc
      if (col >= width) {
Packit 9c6abc
        col = 0;
Packit 9c6abc
        ++row;
Packit 9c6abc
        if (process_func != NULL) {
Packit 9c6abc
          if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
Packit 9c6abc
            process_func(dec, row);
Packit 9c6abc
          }
Packit 9c6abc
        }
Packit 9c6abc
        if (color_cache != NULL) {
Packit 9c6abc
          while (last_cached < src) {
Packit 9c6abc
            VP8LColorCacheInsert(color_cache, *last_cached++);
Packit 9c6abc
          }
Packit 9c6abc
        }
Packit 9c6abc
      }
Packit 9c6abc
    } else if (code < len_code_limit) {  // Backward reference
Packit 9c6abc
      int dist_code, dist;
Packit 9c6abc
      const int length_sym = code - NUM_LITERAL_CODES;
Packit 9c6abc
      const int length = GetCopyLength(length_sym, br);
Packit 9c6abc
      const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br);
Packit 9c6abc
      VP8LFillBitWindow(br);
Packit 9c6abc
      dist_code = GetCopyDistance(dist_symbol, br);
Packit 9c6abc
      dist = PlaneCodeToDistance(width, dist_code);
Packit 9c6abc
      if (VP8LIsEndOfStream(br)) break;
Packit 9c6abc
      if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) {
Packit 9c6abc
        goto Error;
Packit 9c6abc
      } else {
Packit 9c6abc
        CopyBlock32b(src, dist, length);
Packit 9c6abc
      }
Packit 9c6abc
      src += length;
Packit 9c6abc
      col += length;
Packit 9c6abc
      while (col >= width) {
Packit 9c6abc
        col -= width;
Packit 9c6abc
        ++row;
Packit 9c6abc
        if (process_func != NULL) {
Packit 9c6abc
          if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
Packit 9c6abc
            process_func(dec, row);
Packit 9c6abc
          }
Packit 9c6abc
        }
Packit 9c6abc
      }
Packit 9c6abc
      // Because of the check done above (before 'src' was incremented by
Packit 9c6abc
      // 'length'), the following holds true.
Packit 9c6abc
      assert(src <= src_end);
Packit 9c6abc
      if (col & mask) htree_group = GetHtreeGroupForPos(hdr, col, row);
Packit 9c6abc
      if (color_cache != NULL) {
Packit 9c6abc
        while (last_cached < src) {
Packit 9c6abc
          VP8LColorCacheInsert(color_cache, *last_cached++);
Packit 9c6abc
        }
Packit 9c6abc
      }
Packit 9c6abc
    } else if (code < color_cache_limit) {  // Color cache
Packit 9c6abc
      const int key = code - len_code_limit;
Packit 9c6abc
      assert(color_cache != NULL);
Packit 9c6abc
      while (last_cached < src) {
Packit 9c6abc
        VP8LColorCacheInsert(color_cache, *last_cached++);
Packit 9c6abc
      }
Packit 9c6abc
      *src = VP8LColorCacheLookup(color_cache, key);
Packit 9c6abc
      goto AdvanceByOne;
Packit 9c6abc
    } else {  // Not reached
Packit 9c6abc
      goto Error;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  br->eos_ = VP8LIsEndOfStream(br);
Packit 9c6abc
  if (dec->incremental_ && br->eos_ && src < src_end) {
Packit 9c6abc
    RestoreState(dec);
Packit 9c6abc
  } else if (!br->eos_) {
Packit 9c6abc
    // Process the remaining rows corresponding to last row-block.
Packit 9c6abc
    if (process_func != NULL) {
Packit 9c6abc
      process_func(dec, row > last_row ? last_row : row);
Packit 9c6abc
    }
Packit 9c6abc
    dec->status_ = VP8_STATUS_OK;
Packit 9c6abc
    dec->last_pixel_ = (int)(src - data);  // end-of-scan marker
Packit 9c6abc
  } else {
Packit 9c6abc
    // if not incremental, and we are past the end of buffer (eos_=1), then this
Packit 9c6abc
    // is a real bitstream error.
Packit 9c6abc
    goto Error;
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
Packit 9c6abc
 Error:
Packit 9c6abc
  dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
  return 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// -----------------------------------------------------------------------------
Packit 9c6abc
// VP8LTransform
Packit 9c6abc
Packit 9c6abc
static void ClearTransform(VP8LTransform* const transform) {
Packit 9c6abc
  WebPSafeFree(transform->data_);
Packit 9c6abc
  transform->data_ = NULL;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// For security reason, we need to remap the color map to span
Packit 9c6abc
// the total possible bundled values, and not just the num_colors.
Packit 9c6abc
static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
Packit 9c6abc
  int i;
Packit 9c6abc
  const int final_num_colors = 1 << (8 >> transform->bits_);
Packit 9c6abc
  uint32_t* const new_color_map =
Packit 9c6abc
      (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors,
Packit 9c6abc
                                sizeof(*new_color_map));
Packit 9c6abc
  if (new_color_map == NULL) {
Packit 9c6abc
    return 0;
Packit 9c6abc
  } else {
Packit 9c6abc
    uint8_t* const data = (uint8_t*)transform->data_;
Packit 9c6abc
    uint8_t* const new_data = (uint8_t*)new_color_map;
Packit 9c6abc
    new_color_map[0] = transform->data_[0];
Packit 9c6abc
    for (i = 4; i < 4 * num_colors; ++i) {
Packit 9c6abc
      // Equivalent to AddPixelEq(), on a byte-basis.
Packit 9c6abc
      new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
Packit 9c6abc
    }
Packit 9c6abc
    for (; i < 4 * final_num_colors; ++i) {
Packit 9c6abc
      new_data[i] = 0;  // black tail.
Packit 9c6abc
    }
Packit 9c6abc
    WebPSafeFree(transform->data_);
Packit 9c6abc
    transform->data_ = new_color_map;
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int ReadTransform(int* const xsize, int const* ysize,
Packit 9c6abc
                         VP8LDecoder* const dec) {
Packit 9c6abc
  int ok = 1;
Packit 9c6abc
  VP8LBitReader* const br = &dec->br_;
Packit 9c6abc
  VP8LTransform* transform = &dec->transforms_[dec->next_transform_];
Packit 9c6abc
  const VP8LImageTransformType type =
Packit 9c6abc
      (VP8LImageTransformType)VP8LReadBits(br, 2);
Packit 9c6abc
Packit 9c6abc
  // Each transform type can only be present once in the stream.
Packit 9c6abc
  if (dec->transforms_seen_ & (1U << type)) {
Packit 9c6abc
    return 0;  // Already there, let's not accept the second same transform.
Packit 9c6abc
  }
Packit 9c6abc
  dec->transforms_seen_ |= (1U << type);
Packit 9c6abc
Packit 9c6abc
  transform->type_ = type;
Packit 9c6abc
  transform->xsize_ = *xsize;
Packit 9c6abc
  transform->ysize_ = *ysize;
Packit 9c6abc
  transform->data_ = NULL;
Packit 9c6abc
  ++dec->next_transform_;
Packit 9c6abc
  assert(dec->next_transform_ <= NUM_TRANSFORMS);
Packit 9c6abc
Packit 9c6abc
  switch (type) {
Packit 9c6abc
    case PREDICTOR_TRANSFORM:
Packit 9c6abc
    case CROSS_COLOR_TRANSFORM:
Packit 9c6abc
      transform->bits_ = VP8LReadBits(br, 3) + 2;
Packit 9c6abc
      ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize_,
Packit 9c6abc
                                               transform->bits_),
Packit 9c6abc
                             VP8LSubSampleSize(transform->ysize_,
Packit 9c6abc
                                               transform->bits_),
Packit 9c6abc
                             0, dec, &transform->data_);
Packit 9c6abc
      break;
Packit 9c6abc
    case COLOR_INDEXING_TRANSFORM: {
Packit 9c6abc
       const int num_colors = VP8LReadBits(br, 8) + 1;
Packit 9c6abc
       const int bits = (num_colors > 16) ? 0
Packit 9c6abc
                      : (num_colors > 4) ? 1
Packit 9c6abc
                      : (num_colors > 2) ? 2
Packit 9c6abc
                      : 3;
Packit 9c6abc
       *xsize = VP8LSubSampleSize(transform->xsize_, bits);
Packit 9c6abc
       transform->bits_ = bits;
Packit 9c6abc
       ok = DecodeImageStream(num_colors, 1, 0, dec, &transform->data_);
Packit 9c6abc
       ok = ok && ExpandColorMap(num_colors, transform);
Packit 9c6abc
      break;
Packit 9c6abc
    }
Packit 9c6abc
    case SUBTRACT_GREEN:
Packit 9c6abc
      break;
Packit 9c6abc
    default:
Packit 9c6abc
      assert(0);    // can't happen
Packit 9c6abc
      break;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  return ok;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// -----------------------------------------------------------------------------
Packit 9c6abc
// VP8LMetadata
Packit 9c6abc
Packit 9c6abc
static void InitMetadata(VP8LMetadata* const hdr) {
Packit 9c6abc
  assert(hdr != NULL);
Packit 9c6abc
  memset(hdr, 0, sizeof(*hdr));
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void ClearMetadata(VP8LMetadata* const hdr) {
Packit 9c6abc
  assert(hdr != NULL);
Packit 9c6abc
Packit 9c6abc
  WebPSafeFree(hdr->huffman_image_);
Packit 9c6abc
  WebPSafeFree(hdr->huffman_tables_);
Packit 9c6abc
  VP8LHtreeGroupsFree(hdr->htree_groups_);
Packit 9c6abc
  VP8LColorCacheClear(&hdr->color_cache_);
Packit 9c6abc
  VP8LColorCacheClear(&hdr->saved_color_cache_);
Packit 9c6abc
  InitMetadata(hdr);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// -----------------------------------------------------------------------------
Packit 9c6abc
// VP8LDecoder
Packit 9c6abc
Packit 9c6abc
VP8LDecoder* VP8LNew(void) {
Packit 9c6abc
  VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
Packit 9c6abc
  if (dec == NULL) return NULL;
Packit 9c6abc
  dec->status_ = VP8_STATUS_OK;
Packit 9c6abc
  dec->state_ = READ_DIM;
Packit 9c6abc
Packit 9c6abc
  VP8LDspInit();  // Init critical function pointers.
Packit 9c6abc
Packit 9c6abc
  return dec;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
void VP8LClear(VP8LDecoder* const dec) {
Packit 9c6abc
  int i;
Packit 9c6abc
  if (dec == NULL) return;
Packit 9c6abc
  ClearMetadata(&dec->hdr_);
Packit 9c6abc
Packit 9c6abc
  WebPSafeFree(dec->pixels_);
Packit 9c6abc
  dec->pixels_ = NULL;
Packit 9c6abc
  for (i = 0; i < dec->next_transform_; ++i) {
Packit 9c6abc
    ClearTransform(&dec->transforms_[i]);
Packit 9c6abc
  }
Packit 9c6abc
  dec->next_transform_ = 0;
Packit 9c6abc
  dec->transforms_seen_ = 0;
Packit 9c6abc
Packit 9c6abc
  WebPSafeFree(dec->rescaler_memory);
Packit 9c6abc
  dec->rescaler_memory = NULL;
Packit 9c6abc
Packit 9c6abc
  dec->output_ = NULL;   // leave no trace behind
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
void VP8LDelete(VP8LDecoder* const dec) {
Packit 9c6abc
  if (dec != NULL) {
Packit 9c6abc
    VP8LClear(dec);
Packit 9c6abc
    WebPSafeFree(dec);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void UpdateDecoder(VP8LDecoder* const dec, int width, int height) {
Packit 9c6abc
  VP8LMetadata* const hdr = &dec->hdr_;
Packit 9c6abc
  const int num_bits = hdr->huffman_subsample_bits_;
Packit 9c6abc
  dec->width_ = width;
Packit 9c6abc
  dec->height_ = height;
Packit 9c6abc
Packit 9c6abc
  hdr->huffman_xsize_ = VP8LSubSampleSize(width, num_bits);
Packit 9c6abc
  hdr->huffman_mask_ = (num_bits == 0) ? ~0 : (1 << num_bits) - 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int DecodeImageStream(int xsize, int ysize,
Packit 9c6abc
                             int is_level0,
Packit 9c6abc
                             VP8LDecoder* const dec,
Packit 9c6abc
                             uint32_t** const decoded_data) {
Packit 9c6abc
  int ok = 1;
Packit 9c6abc
  int transform_xsize = xsize;
Packit 9c6abc
  int transform_ysize = ysize;
Packit 9c6abc
  VP8LBitReader* const br = &dec->br_;
Packit 9c6abc
  VP8LMetadata* const hdr = &dec->hdr_;
Packit 9c6abc
  uint32_t* data = NULL;
Packit 9c6abc
  int color_cache_bits = 0;
Packit 9c6abc
Packit 9c6abc
  // Read the transforms (may recurse).
Packit 9c6abc
  if (is_level0) {
Packit 9c6abc
    while (ok && VP8LReadBits(br, 1)) {
Packit 9c6abc
      ok = ReadTransform(&transform_xsize, &transform_ysize, dec);
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Color cache
Packit 9c6abc
  if (ok && VP8LReadBits(br, 1)) {
Packit 9c6abc
    color_cache_bits = VP8LReadBits(br, 4);
Packit 9c6abc
    ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS);
Packit 9c6abc
    if (!ok) {
Packit 9c6abc
      dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
      goto End;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Read the Huffman codes (may recurse).
Packit 9c6abc
  ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
Packit 9c6abc
                              color_cache_bits, is_level0);
Packit 9c6abc
  if (!ok) {
Packit 9c6abc
    dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
    goto End;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Finish setting up the color-cache
Packit 9c6abc
  if (color_cache_bits > 0) {
Packit 9c6abc
    hdr->color_cache_size_ = 1 << color_cache_bits;
Packit 9c6abc
    if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) {
Packit 9c6abc
      dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
Packit 9c6abc
      ok = 0;
Packit 9c6abc
      goto End;
Packit 9c6abc
    }
Packit 9c6abc
  } else {
Packit 9c6abc
    hdr->color_cache_size_ = 0;
Packit 9c6abc
  }
Packit 9c6abc
  UpdateDecoder(dec, transform_xsize, transform_ysize);
Packit 9c6abc
Packit 9c6abc
  if (is_level0) {   // level 0 complete
Packit 9c6abc
    dec->state_ = READ_HDR;
Packit 9c6abc
    goto End;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  {
Packit 9c6abc
    const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize;
Packit 9c6abc
    data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data));
Packit 9c6abc
    if (data == NULL) {
Packit 9c6abc
      dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
Packit 9c6abc
      ok = 0;
Packit 9c6abc
      goto End;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Use the Huffman trees to decode the LZ77 encoded data.
Packit 9c6abc
  ok = DecodeImageData(dec, data, transform_xsize, transform_ysize,
Packit 9c6abc
                       transform_ysize, NULL);
Packit 9c6abc
  ok = ok && !br->eos_;
Packit 9c6abc
Packit 9c6abc
 End:
Packit 9c6abc
  if (!ok) {
Packit 9c6abc
    WebPSafeFree(data);
Packit 9c6abc
    ClearMetadata(hdr);
Packit 9c6abc
  } else {
Packit 9c6abc
    if (decoded_data != NULL) {
Packit 9c6abc
      *decoded_data = data;
Packit 9c6abc
    } else {
Packit 9c6abc
      // We allocate image data in this function only for transforms. At level 0
Packit 9c6abc
      // (that is: not the transforms), we shouldn't have allocated anything.
Packit 9c6abc
      assert(data == NULL);
Packit 9c6abc
      assert(is_level0);
Packit 9c6abc
    }
Packit 9c6abc
    dec->last_pixel_ = 0;  // Reset for future DECODE_DATA_FUNC() calls.
Packit 9c6abc
    if (!is_level0) ClearMetadata(hdr);  // Clean up temporary data behind.
Packit 9c6abc
  }
Packit 9c6abc
  return ok;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Allocate internal buffers dec->pixels_ and dec->argb_cache_.
Packit 9c6abc
static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
Packit 9c6abc
  const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_;
Packit 9c6abc
  // Scratch buffer corresponding to top-prediction row for transforming the
Packit 9c6abc
  // first row in the row-blocks. Not needed for paletted alpha.
Packit 9c6abc
  const uint64_t cache_top_pixels = (uint16_t)final_width;
Packit 9c6abc
  // Scratch buffer for temporary BGRA storage. Not needed for paletted alpha.
Packit 9c6abc
  const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS;
Packit 9c6abc
  const uint64_t total_num_pixels =
Packit 9c6abc
      num_pixels + cache_top_pixels + cache_pixels;
Packit 9c6abc
Packit 9c6abc
  assert(dec->width_ <= final_width);
Packit 9c6abc
  dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
Packit 9c6abc
  if (dec->pixels_ == NULL) {
Packit 9c6abc
    dec->argb_cache_ = NULL;    // for sanity check
Packit 9c6abc
    dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
Packit 9c6abc
    return 0;
Packit 9c6abc
  }
Packit 9c6abc
  dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels;
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
Packit 9c6abc
  const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
Packit 9c6abc
  dec->argb_cache_ = NULL;    // for sanity check
Packit 9c6abc
  dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
Packit 9c6abc
  if (dec->pixels_ == NULL) {
Packit 9c6abc
    dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
Packit 9c6abc
    return 0;
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
// Special row-processing that only stores the alpha data.
Packit 9c6abc
static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) {
Packit 9c6abc
  int cur_row = dec->last_row_;
Packit 9c6abc
  int num_rows = last_row - cur_row;
Packit 9c6abc
  const uint32_t* in = dec->pixels_ + dec->width_ * cur_row;
Packit 9c6abc
Packit 9c6abc
  assert(last_row <= dec->io_->crop_bottom);
Packit 9c6abc
  while (num_rows > 0) {
Packit 9c6abc
    const int num_rows_to_process =
Packit 9c6abc
        (num_rows > NUM_ARGB_CACHE_ROWS) ? NUM_ARGB_CACHE_ROWS : num_rows;
Packit 9c6abc
    // Extract alpha (which is stored in the green plane).
Packit 9c6abc
    ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque;
Packit 9c6abc
    uint8_t* const output = alph_dec->output_;
Packit 9c6abc
    const int width = dec->io_->width;      // the final width (!= dec->width_)
Packit 9c6abc
    const int cache_pixs = width * num_rows_to_process;
Packit 9c6abc
    uint8_t* const dst = output + width * cur_row;
Packit 9c6abc
    const uint32_t* const src = dec->argb_cache_;
Packit 9c6abc
    ApplyInverseTransforms(dec, num_rows_to_process, in);
Packit 9c6abc
    WebPExtractGreen(src, dst, cache_pixs);
Packit 9c6abc
    AlphaApplyFilter(alph_dec,
Packit 9c6abc
                     cur_row, cur_row + num_rows_to_process, dst, width);
Packit 9c6abc
    num_rows -= num_rows_to_process;
Packit 9c6abc
    in += num_rows_to_process * dec->width_;
Packit 9c6abc
    cur_row += num_rows_to_process;
Packit 9c6abc
  }
Packit 9c6abc
  assert(cur_row == last_row);
Packit 9c6abc
  dec->last_row_ = dec->last_out_row_ = last_row;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
Packit 9c6abc
                          const uint8_t* const data, size_t data_size) {
Packit 9c6abc
  int ok = 0;
Packit 9c6abc
  VP8LDecoder* dec = VP8LNew();
Packit 9c6abc
Packit 9c6abc
  if (dec == NULL) return 0;
Packit 9c6abc
Packit 9c6abc
  assert(alph_dec != NULL);
Packit 9c6abc
  alph_dec->vp8l_dec_ = dec;
Packit 9c6abc
Packit 9c6abc
  dec->width_ = alph_dec->width_;
Packit 9c6abc
  dec->height_ = alph_dec->height_;
Packit 9c6abc
  dec->io_ = &alph_dec->io_;
Packit 9c6abc
  dec->io_->opaque = alph_dec;
Packit 9c6abc
  dec->io_->width = alph_dec->width_;
Packit 9c6abc
  dec->io_->height = alph_dec->height_;
Packit 9c6abc
Packit 9c6abc
  dec->status_ = VP8_STATUS_OK;
Packit 9c6abc
  VP8LInitBitReader(&dec->br_, data, data_size);
Packit 9c6abc
Packit 9c6abc
  if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, 1, dec, NULL)) {
Packit 9c6abc
    goto Err;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Special case: if alpha data uses only the color indexing transform and
Packit 9c6abc
  // doesn't use color cache (a frequent case), we will use DecodeAlphaData()
Packit 9c6abc
  // method that only needs allocation of 1 byte per pixel (alpha channel).
Packit 9c6abc
  if (dec->next_transform_ == 1 &&
Packit 9c6abc
      dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM &&
Packit 9c6abc
      Is8bOptimizable(&dec->hdr_)) {
Packit 9c6abc
    alph_dec->use_8b_decode_ = 1;
Packit 9c6abc
    ok = AllocateInternalBuffers8b(dec);
Packit 9c6abc
  } else {
Packit 9c6abc
    // Allocate internal buffers (note that dec->width_ may have changed here).
Packit 9c6abc
    alph_dec->use_8b_decode_ = 0;
Packit 9c6abc
    ok = AllocateInternalBuffers32b(dec, alph_dec->width_);
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  if (!ok) goto Err;
Packit 9c6abc
Packit 9c6abc
  return 1;
Packit 9c6abc
Packit 9c6abc
 Err:
Packit 9c6abc
  VP8LDelete(alph_dec->vp8l_dec_);
Packit 9c6abc
  alph_dec->vp8l_dec_ = NULL;
Packit 9c6abc
  return 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
Packit 9c6abc
  VP8LDecoder* const dec = alph_dec->vp8l_dec_;
Packit 9c6abc
  assert(dec != NULL);
Packit 9c6abc
  assert(last_row <= dec->height_);
Packit 9c6abc
Packit 9c6abc
  if (dec->last_row_ >= last_row) {
Packit 9c6abc
    return 1;  // done
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing();
Packit 9c6abc
Packit 9c6abc
  // Decode (with special row processing).
Packit 9c6abc
  return alph_dec->use_8b_decode_ ?
Packit 9c6abc
      DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
Packit 9c6abc
                      last_row) :
Packit 9c6abc
      DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
Packit 9c6abc
                      last_row, ExtractAlphaRows);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
Packit 9c6abc
  int width, height, has_alpha;
Packit 9c6abc
Packit 9c6abc
  if (dec == NULL) return 0;
Packit 9c6abc
  if (io == NULL) {
Packit 9c6abc
    dec->status_ = VP8_STATUS_INVALID_PARAM;
Packit 9c6abc
    return 0;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  dec->io_ = io;
Packit 9c6abc
  dec->status_ = VP8_STATUS_OK;
Packit 9c6abc
  VP8LInitBitReader(&dec->br_, io->data, io->data_size);
Packit 9c6abc
  if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) {
Packit 9c6abc
    dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
Packit 9c6abc
    goto Error;
Packit 9c6abc
  }
Packit 9c6abc
  dec->state_ = READ_DIM;
Packit 9c6abc
  io->width = width;
Packit 9c6abc
  io->height = height;
Packit 9c6abc
Packit 9c6abc
  if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error;
Packit 9c6abc
  return 1;
Packit 9c6abc
Packit 9c6abc
 Error:
Packit 9c6abc
  VP8LClear(dec);
Packit 9c6abc
  assert(dec->status_ != VP8_STATUS_OK);
Packit 9c6abc
  return 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int VP8LDecodeImage(VP8LDecoder* const dec) {
Packit 9c6abc
  VP8Io* io = NULL;
Packit 9c6abc
  WebPDecParams* params = NULL;
Packit 9c6abc
Packit 9c6abc
  // Sanity checks.
Packit 9c6abc
  if (dec == NULL) return 0;
Packit 9c6abc
Packit 9c6abc
  assert(dec->hdr_.huffman_tables_ != NULL);
Packit 9c6abc
  assert(dec->hdr_.htree_groups_ != NULL);
Packit 9c6abc
  assert(dec->hdr_.num_htree_groups_ > 0);
Packit 9c6abc
Packit 9c6abc
  io = dec->io_;
Packit 9c6abc
  assert(io != NULL);
Packit 9c6abc
  params = (WebPDecParams*)io->opaque;
Packit 9c6abc
  assert(params != NULL);
Packit 9c6abc
Packit 9c6abc
  // Initialization.
Packit 9c6abc
  if (dec->state_ != READ_DATA) {
Packit 9c6abc
    dec->output_ = params->output;
Packit 9c6abc
    assert(dec->output_ != NULL);
Packit 9c6abc
Packit 9c6abc
    if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
Packit 9c6abc
      dec->status_ = VP8_STATUS_INVALID_PARAM;
Packit 9c6abc
      goto Err;
Packit 9c6abc
    }
Packit 9c6abc
Packit 9c6abc
    if (!AllocateInternalBuffers32b(dec, io->width)) goto Err;
Packit 9c6abc
Packit 9c6abc
#if !defined(WEBP_REDUCE_SIZE)
Packit 9c6abc
    if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
Packit 9c6abc
#else
Packit 9c6abc
    if (io->use_scaling) {
Packit 9c6abc
      dec->status_ = VP8_STATUS_INVALID_PARAM;
Packit 9c6abc
      goto Err;
Packit 9c6abc
    }
Packit 9c6abc
#endif
Packit 9c6abc
    if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
Packit 9c6abc
      // need the alpha-multiply functions for premultiplied output or rescaling
Packit 9c6abc
      WebPInitAlphaProcessing();
Packit 9c6abc
    }
Packit 9c6abc
Packit 9c6abc
    if (!WebPIsRGBMode(dec->output_->colorspace)) {
Packit 9c6abc
      WebPInitConvertARGBToYUV();
Packit 9c6abc
      if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing();
Packit 9c6abc
    }
Packit 9c6abc
    if (dec->incremental_) {
Packit 9c6abc
      if (dec->hdr_.color_cache_size_ > 0 &&
Packit 9c6abc
          dec->hdr_.saved_color_cache_.colors_ == NULL) {
Packit 9c6abc
        if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_,
Packit 9c6abc
                                dec->hdr_.color_cache_.hash_bits_)) {
Packit 9c6abc
          dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
Packit 9c6abc
          goto Err;
Packit 9c6abc
        }
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
    dec->state_ = READ_DATA;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Decode.
Packit 9c6abc
  if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
Packit 9c6abc
                       io->crop_bottom, ProcessRows)) {
Packit 9c6abc
    goto Err;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  params->last_y = dec->last_out_row_;
Packit 9c6abc
  return 1;
Packit 9c6abc
Packit 9c6abc
 Err:
Packit 9c6abc
  VP8LClear(dec);
Packit 9c6abc
  assert(dec->status_ != VP8_STATUS_OK);
Packit 9c6abc
  return 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------