tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

idec_dec.c (31958B)


      1 // Copyright 2011 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Incremental decoding
     11 //
     12 // Author: somnath@google.com (Somnath Banerjee)
     13 
     14 #include <assert.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 
     18 #include "src/dec/alphai_dec.h"
     19 #include "src/dec/vp8_dec.h"
     20 #include "src/dec/vp8i_dec.h"
     21 #include "src/dec/vp8li_dec.h"
     22 #include "src/dec/webpi_dec.h"
     23 #include "src/utils/bit_reader_utils.h"
     24 #include "src/utils/thread_utils.h"
     25 #include "src/utils/utils.h"
     26 #include "src/webp/decode.h"
     27 #include "src/webp/format_constants.h"
     28 #include "src/webp/types.h"
     29 
     30 // In append mode, buffer allocations increase as multiples of this value.
     31 // Needs to be a power of 2.
     32 #define CHUNK_SIZE 4096
     33 #define MAX_MB_SIZE 4096
     34 
     35 //------------------------------------------------------------------------------
     36 // Data structures for memory and states
     37 
     38 // Decoding states. State normally flows as:
     39 // WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and
     40 // WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image.
     41 // If there is any error the decoder goes into state ERROR.
     42 typedef enum {
     43  STATE_WEBP_HEADER,  // All the data before that of the VP8/VP8L chunk.
     44  STATE_VP8_HEADER,   // The VP8 Frame header (within the VP8 chunk).
     45  STATE_VP8_PARTS0,
     46  STATE_VP8_DATA,
     47  STATE_VP8L_HEADER,
     48  STATE_VP8L_DATA,
     49  STATE_DONE,
     50  STATE_ERROR
     51 } DecState;
     52 
     53 // Operating state for the MemBuffer
     54 typedef enum {
     55  MEM_MODE_NONE = 0,
     56  MEM_MODE_APPEND,
     57  MEM_MODE_MAP
     58 } MemBufferMode;
     59 
     60 // storage for partition #0 and partial data (in a rolling fashion)
     61 typedef struct {
     62  MemBufferMode mode;  // Operation mode
     63  size_t start;        // start location of the data to be decoded
     64  size_t end;          // end location
     65  size_t buf_size;     // size of the allocated buffer
     66  uint8_t* buf;        // We don't own this buffer in case WebPIUpdate()
     67 
     68  size_t part0_size;         // size of partition #0
     69  const uint8_t* part0_buf;  // buffer to store partition #0
     70 } MemBuffer;
     71 
     72 struct WebPIDecoder {
     73  DecState state;         // current decoding state
     74  WebPDecParams params;   // Params to store output info
     75  int is_lossless;        // for down-casting 'dec'.
     76  void* dec;              // either a VP8Decoder or a VP8LDecoder instance
     77  VP8Io io;
     78 
     79  MemBuffer mem;          // input memory buffer.
     80  WebPDecBuffer output;   // output buffer (when no external one is supplied,
     81                          // or if the external one has slow-memory)
     82  WebPDecBuffer* final_output;  // Slow-memory output to copy to eventually.
     83  size_t chunk_size;      // Compressed VP8/VP8L size extracted from Header.
     84 
     85  int last_mb_y;          // last row reached for intra-mode decoding
     86 };
     87 
     88 // MB context to restore in case VP8DecodeMB() fails
     89 typedef struct {
     90  VP8MB left;
     91  VP8MB info;
     92  VP8BitReader token_br;
     93 } MBContext;
     94 
     95 //------------------------------------------------------------------------------
     96 // MemBuffer: incoming data handling
     97 
     98 static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
     99  return (mem->end - mem->start);
    100 }
    101 
    102 // Check if we need to preserve the compressed alpha data, as it may not have
    103 // been decoded yet.
    104 static int NeedCompressedAlpha(const WebPIDecoder* const idec) {
    105  if (idec->state == STATE_WEBP_HEADER) {
    106    // We haven't parsed the headers yet, so we don't know whether the image is
    107    // lossy or lossless. This also means that we haven't parsed the ALPH chunk.
    108    return 0;
    109  }
    110  if (idec->is_lossless) {
    111    return 0;  // ALPH chunk is not present for lossless images.
    112  } else {
    113    const VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    114    assert(dec != NULL);  // Must be true as idec->state != STATE_WEBP_HEADER.
    115    return (dec->alpha_data != NULL) && !dec->is_alpha_decoded;
    116  }
    117 }
    118 
    119 static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
    120  MemBuffer* const mem = &idec->mem;
    121  const uint8_t* const new_base = mem->buf + mem->start;
    122  // note: for VP8, setting up idec->io is only really needed at the beginning
    123  // of the decoding, till partition #0 is complete.
    124  idec->io.data = new_base;
    125  idec->io.data_size = MemDataSize(mem);
    126 
    127  if (idec->dec != NULL) {
    128    if (!idec->is_lossless) {
    129      VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    130      const uint32_t last_part = dec->num_parts_minus_one;
    131      if (offset != 0) {
    132        uint32_t p;
    133        for (p = 0; p <= last_part; ++p) {
    134          VP8RemapBitReader(dec->parts + p, offset);
    135        }
    136        // Remap partition #0 data pointer to new offset, but only in MAP
    137        // mode (in APPEND mode, partition #0 is copied into a fixed memory).
    138        if (mem->mode == MEM_MODE_MAP) {
    139          VP8RemapBitReader(&dec->br, offset);
    140        }
    141      }
    142      {
    143        const uint8_t* const last_start = dec->parts[last_part].buf;
    144        // 'last_start' will be NULL when 'idec->state' is < STATE_VP8_PARTS0
    145        // and through a portion of that state (when there isn't enough data to
    146        // parse the partitions). The bitreader is only used meaningfully when
    147        // there is enough data to begin parsing partition 0.
    148        if (last_start != NULL) {
    149          VP8BitReaderSetBuffer(&dec->parts[last_part], last_start,
    150                                mem->buf + mem->end - last_start);
    151        }
    152      }
    153      if (NeedCompressedAlpha(idec)) {
    154        ALPHDecoder* const alph_dec = dec->alph_dec;
    155        dec->alpha_data += offset;
    156        if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) {
    157          if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) {
    158            VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec;
    159            assert(dec->alpha_data_size >= ALPHA_HEADER_LEN);
    160            VP8LBitReaderSetBuffer(&alph_vp8l_dec->br,
    161                                   dec->alpha_data + ALPHA_HEADER_LEN,
    162                                   dec->alpha_data_size - ALPHA_HEADER_LEN);
    163          } else {  // alph_dec->method == ALPHA_NO_COMPRESSION
    164            // Nothing special to do in this case.
    165          }
    166        }
    167      }
    168    } else {    // Resize lossless bitreader
    169      VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
    170      VP8LBitReaderSetBuffer(&dec->br, new_base, MemDataSize(mem));
    171    }
    172  }
    173 }
    174 
    175 // Appends data to the end of MemBuffer->buf. It expands the allocated memory
    176 // size if required and also updates VP8BitReader's if new memory is allocated.
    177 WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec,
    178                                            const uint8_t* const data,
    179                                            size_t data_size) {
    180  VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    181  MemBuffer* const mem = &idec->mem;
    182  const int need_compressed_alpha = NeedCompressedAlpha(idec);
    183  const uint8_t* const old_start =
    184      (mem->buf == NULL) ? NULL : mem->buf + mem->start;
    185  const uint8_t* const old_base =
    186      need_compressed_alpha ? dec->alpha_data : old_start;
    187  assert(mem->buf != NULL || mem->start == 0);
    188  assert(mem->mode == MEM_MODE_APPEND);
    189  if (data_size > MAX_CHUNK_PAYLOAD) {
    190    // security safeguard: trying to allocate more than what the format
    191    // allows for a chunk should be considered a smoke smell.
    192    return 0;
    193  }
    194 
    195  if (mem->end + data_size > mem->buf_size) {  // Need some free memory
    196    const size_t new_mem_start = old_start - old_base;
    197    const size_t current_size = MemDataSize(mem) + new_mem_start;
    198    const uint64_t new_size = (uint64_t)current_size + data_size;
    199    const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
    200    uint8_t* const new_buf =
    201        (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
    202    if (new_buf == NULL) return 0;
    203    if (old_base != NULL) memcpy(new_buf, old_base, current_size);
    204    WebPSafeFree(mem->buf);
    205    mem->buf = new_buf;
    206    mem->buf_size = (size_t)extra_size;
    207    mem->start = new_mem_start;
    208    mem->end = current_size;
    209  }
    210 
    211  assert(mem->buf != NULL);
    212  memcpy(mem->buf + mem->end, data, data_size);
    213  mem->end += data_size;
    214  assert(mem->end <= mem->buf_size);
    215 
    216  DoRemap(idec, mem->buf + mem->start - old_start);
    217  return 1;
    218 }
    219 
    220 WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec,
    221                                         const uint8_t* const data,
    222                                         size_t data_size) {
    223  MemBuffer* const mem = &idec->mem;
    224  const uint8_t* const old_buf = mem->buf;
    225  const uint8_t* const old_start =
    226      (old_buf == NULL) ? NULL : old_buf + mem->start;
    227  assert(old_buf != NULL || mem->start == 0);
    228  assert(mem->mode == MEM_MODE_MAP);
    229 
    230  if (data_size < mem->buf_size) return 0;  // can't remap to a shorter buffer!
    231 
    232  mem->buf = (uint8_t*)data;
    233  mem->end = mem->buf_size = data_size;
    234 
    235  DoRemap(idec, mem->buf + mem->start - old_start);
    236  return 1;
    237 }
    238 
    239 static void InitMemBuffer(MemBuffer* const mem) {
    240  mem->mode       = MEM_MODE_NONE;
    241  mem->buf        = NULL;
    242  mem->buf_size   = 0;
    243  mem->part0_buf  = NULL;
    244  mem->part0_size = 0;
    245 }
    246 
    247 static void ClearMemBuffer(MemBuffer* const mem) {
    248  assert(mem);
    249  if (mem->mode == MEM_MODE_APPEND) {
    250    WebPSafeFree(mem->buf);
    251    WebPSafeFree((void*)mem->part0_buf);
    252  }
    253 }
    254 
    255 WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem,
    256                                             MemBufferMode expected) {
    257  if (mem->mode == MEM_MODE_NONE) {
    258    mem->mode = expected;    // switch to the expected mode
    259  } else if (mem->mode != expected) {
    260    return 0;         // we mixed the modes => error
    261  }
    262  assert(mem->mode == expected);   // mode is ok
    263  return 1;
    264 }
    265 
    266 // To be called last.
    267 WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
    268  const WebPDecoderOptions* const options = idec->params.options;
    269  WebPDecBuffer* const output = idec->params.output;
    270 
    271  idec->state = STATE_DONE;
    272  if (options != NULL && options->flip) {
    273    const VP8StatusCode status = WebPFlipBuffer(output);
    274    if (status != VP8_STATUS_OK) return status;
    275  }
    276  if (idec->final_output != NULL) {
    277    const VP8StatusCode status = WebPCopyDecBufferPixels(
    278        output, idec->final_output);  // do the slow-copy
    279    WebPFreeDecBuffer(&idec->output);
    280    if (status != VP8_STATUS_OK) return status;
    281    *output = *idec->final_output;
    282    idec->final_output = NULL;
    283  }
    284  return VP8_STATUS_OK;
    285 }
    286 
    287 //------------------------------------------------------------------------------
    288 // Macroblock-decoding contexts
    289 
    290 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
    291                        MBContext* const context) {
    292  context->left = dec->mb_info[-1];
    293  context->info = dec->mb_info[dec->mb_x];
    294  context->token_br = *token_br;
    295 }
    296 
    297 static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
    298                           VP8BitReader* const token_br) {
    299  dec->mb_info[-1] = context->left;
    300  dec->mb_info[dec->mb_x] = context->info;
    301  *token_br = context->token_br;
    302 }
    303 
    304 //------------------------------------------------------------------------------
    305 
    306 static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
    307  if (idec->state == STATE_VP8_DATA) {
    308    // Synchronize the thread, clean-up and check for errors.
    309    (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io);
    310  }
    311  idec->state = STATE_ERROR;
    312  return error;
    313 }
    314 
    315 static void ChangeState(WebPIDecoder* const idec, DecState new_state,
    316                        size_t consumed_bytes) {
    317  MemBuffer* const mem = &idec->mem;
    318  idec->state = new_state;
    319  mem->start += consumed_bytes;
    320  assert(mem->start <= mem->end);
    321  idec->io.data = mem->buf + mem->start;
    322  idec->io.data_size = MemDataSize(mem);
    323 }
    324 
    325 // Headers
    326 static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
    327  MemBuffer* const mem = &idec->mem;
    328  const uint8_t* data = mem->buf + mem->start;
    329  size_t curr_size = MemDataSize(mem);
    330  VP8StatusCode status;
    331  WebPHeaderStructure headers;
    332 
    333  headers.data = data;
    334  headers.data_size = curr_size;
    335  headers.have_all_data = 0;
    336  status = WebPParseHeaders(&headers);
    337  if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
    338    return VP8_STATUS_SUSPENDED;  // We haven't found a VP8 chunk yet.
    339  } else if (status != VP8_STATUS_OK) {
    340    return IDecError(idec, status);
    341  }
    342 
    343  idec->chunk_size = headers.compressed_size;
    344  idec->is_lossless = headers.is_lossless;
    345  if (!idec->is_lossless) {
    346    VP8Decoder* const dec = VP8New();
    347    if (dec == NULL) {
    348      return VP8_STATUS_OUT_OF_MEMORY;
    349    }
    350    dec->incremental = 1;
    351    idec->dec = dec;
    352    dec->alpha_data = headers.alpha_data;
    353    dec->alpha_data_size = headers.alpha_data_size;
    354    ChangeState(idec, STATE_VP8_HEADER, headers.offset);
    355  } else {
    356    VP8LDecoder* const dec = VP8LNew();
    357    if (dec == NULL) {
    358      return VP8_STATUS_OUT_OF_MEMORY;
    359    }
    360    idec->dec = dec;
    361    ChangeState(idec, STATE_VP8L_HEADER, headers.offset);
    362  }
    363  return VP8_STATUS_OK;
    364 }
    365 
    366 static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
    367  const uint8_t* data = idec->mem.buf + idec->mem.start;
    368  const size_t curr_size = MemDataSize(&idec->mem);
    369  int width, height;
    370  uint32_t bits;
    371 
    372  if (curr_size < VP8_FRAME_HEADER_SIZE) {
    373    // Not enough data bytes to extract VP8 Frame Header.
    374    return VP8_STATUS_SUSPENDED;
    375  }
    376  if (!VP8GetInfo(data, curr_size, idec->chunk_size, &width, &height)) {
    377    return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    378  }
    379 
    380  bits = data[0] | (data[1] << 8) | (data[2] << 16);
    381  idec->mem.part0_size = (bits >> 5) + VP8_FRAME_HEADER_SIZE;
    382 
    383  idec->io.data = data;
    384  idec->io.data_size = curr_size;
    385  idec->state = STATE_VP8_PARTS0;
    386  return VP8_STATUS_OK;
    387 }
    388 
    389 // Partition #0
    390 static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
    391  VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    392  VP8BitReader* const br = &dec->br;
    393  const size_t part_size = br->buf_end - br->buf;
    394  MemBuffer* const mem = &idec->mem;
    395  assert(!idec->is_lossless);
    396  assert(mem->part0_buf == NULL);
    397  // the following is a format limitation, no need for runtime check:
    398  assert(part_size <= mem->part0_size);
    399  if (part_size == 0) {   // can't have zero-size partition #0
    400    return VP8_STATUS_BITSTREAM_ERROR;
    401  }
    402  if (mem->mode == MEM_MODE_APPEND) {
    403    // We copy and grab ownership of the partition #0 data.
    404    uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size);
    405    if (part0_buf == NULL) {
    406      return VP8_STATUS_OUT_OF_MEMORY;
    407    }
    408    memcpy(part0_buf, br->buf, part_size);
    409    mem->part0_buf = part0_buf;
    410    VP8BitReaderSetBuffer(br, part0_buf, part_size);
    411  } else {
    412    // Else: just keep pointers to the partition #0's data in dec->br.
    413  }
    414  mem->start += part_size;
    415  return VP8_STATUS_OK;
    416 }
    417 
    418 static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
    419  VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    420  VP8Io* const io = &idec->io;
    421  const WebPDecParams* const params = &idec->params;
    422  WebPDecBuffer* const output = params->output;
    423 
    424  // Wait till we have enough data for the whole partition #0
    425  if (MemDataSize(&idec->mem) < idec->mem.part0_size) {
    426    return VP8_STATUS_SUSPENDED;
    427  }
    428 
    429  if (!VP8GetHeaders(dec, io)) {
    430    const VP8StatusCode status = dec->status;
    431    if (status == VP8_STATUS_SUSPENDED ||
    432        status == VP8_STATUS_NOT_ENOUGH_DATA) {
    433      // treating NOT_ENOUGH_DATA as SUSPENDED state
    434      return VP8_STATUS_SUSPENDED;
    435    }
    436    return IDecError(idec, status);
    437  }
    438 
    439  // Allocate/Verify output buffer now
    440  dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options,
    441                                      output);
    442  if (dec->status != VP8_STATUS_OK) {
    443    return IDecError(idec, dec->status);
    444  }
    445  // This change must be done before calling VP8InitFrame()
    446  dec->mt_method = VP8GetThreadMethod(params->options, NULL,
    447                                      io->width, io->height);
    448  VP8InitDithering(params->options, dec);
    449 
    450  dec->status = CopyParts0Data(idec);
    451  if (dec->status != VP8_STATUS_OK) {
    452    return IDecError(idec, dec->status);
    453  }
    454 
    455  // Finish setting up the decoding parameters. Will call io->setup().
    456  if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) {
    457    return IDecError(idec, dec->status);
    458  }
    459 
    460  // Note: past this point, teardown() must always be called
    461  // in case of error.
    462  idec->state = STATE_VP8_DATA;
    463  // Allocate memory and prepare everything.
    464  if (!VP8InitFrame(dec, io)) {
    465    return IDecError(idec, dec->status);
    466  }
    467  return VP8_STATUS_OK;
    468 }
    469 
    470 // Remaining partitions
    471 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
    472  VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    473  VP8Io* const io = &idec->io;
    474 
    475  // Make sure partition #0 has been read before, to set dec to ready.
    476  if (!dec->ready) {
    477    return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    478  }
    479  for (; dec->mb_y < dec->mb_h; ++dec->mb_y) {
    480    if (idec->last_mb_y != dec->mb_y) {
    481      if (!VP8ParseIntraModeRow(&dec->br, dec)) {
    482        // note: normally, error shouldn't occur since we already have the whole
    483        // partition0 available here in DecodeRemaining(). Reaching EOF while
    484        // reading intra modes really means a BITSTREAM_ERROR.
    485        return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    486      }
    487      idec->last_mb_y = dec->mb_y;
    488    }
    489    for (; dec->mb_x < dec->mb_w; ++dec->mb_x) {
    490      VP8BitReader* const token_br =
    491          &dec->parts[dec->mb_y & dec->num_parts_minus_one];
    492      MBContext context;
    493      SaveContext(dec, token_br, &context);
    494      if (!VP8DecodeMB(dec, token_br)) {
    495        // We shouldn't fail when MAX_MB data was available
    496        if (dec->num_parts_minus_one == 0 &&
    497            MemDataSize(&idec->mem) > MAX_MB_SIZE) {
    498          return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    499        }
    500        // Synchronize the threads.
    501        if (dec->mt_method > 0) {
    502          if (!WebPGetWorkerInterface()->Sync(&dec->worker)) {
    503            return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    504          }
    505        }
    506        RestoreContext(&context, dec, token_br);
    507        return VP8_STATUS_SUSPENDED;
    508      }
    509      // Release buffer only if there is only one partition
    510      if (dec->num_parts_minus_one == 0) {
    511        idec->mem.start = token_br->buf - idec->mem.buf;
    512        assert(idec->mem.start <= idec->mem.end);
    513      }
    514    }
    515    VP8InitScanline(dec);   // Prepare for next scanline
    516 
    517    // Reconstruct, filter and emit the row.
    518    if (!VP8ProcessRow(dec, io)) {
    519      return IDecError(idec, VP8_STATUS_USER_ABORT);
    520    }
    521  }
    522  // Synchronize the thread and check for errors.
    523  if (!VP8ExitCritical(dec, io)) {
    524    idec->state = STATE_ERROR;  // prevent re-entry in IDecError
    525    return IDecError(idec, VP8_STATUS_USER_ABORT);
    526  }
    527  dec->ready = 0;
    528  return FinishDecoding(idec);
    529 }
    530 
    531 static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
    532                                         VP8StatusCode status) {
    533  if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
    534    return VP8_STATUS_SUSPENDED;
    535  }
    536  return IDecError(idec, status);
    537 }
    538 
    539 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
    540  VP8Io* const io = &idec->io;
    541  VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
    542  const WebPDecParams* const params = &idec->params;
    543  WebPDecBuffer* const output = params->output;
    544  size_t curr_size = MemDataSize(&idec->mem);
    545  assert(idec->is_lossless);
    546 
    547  // Wait until there's enough data for decoding header.
    548  if (curr_size < (idec->chunk_size >> 3)) {
    549    dec->status = VP8_STATUS_SUSPENDED;
    550    return ErrorStatusLossless(idec, dec->status);
    551  }
    552 
    553  if (!VP8LDecodeHeader(dec, io)) {
    554    if (dec->status == VP8_STATUS_BITSTREAM_ERROR &&
    555        curr_size < idec->chunk_size) {
    556      dec->status = VP8_STATUS_SUSPENDED;
    557    }
    558    return ErrorStatusLossless(idec, dec->status);
    559  }
    560  // Allocate/verify output buffer now.
    561  dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options,
    562                                      output);
    563  if (dec->status != VP8_STATUS_OK) {
    564    return IDecError(idec, dec->status);
    565  }
    566 
    567  idec->state = STATE_VP8L_DATA;
    568  return VP8_STATUS_OK;
    569 }
    570 
    571 static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
    572  VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
    573  const size_t curr_size = MemDataSize(&idec->mem);
    574  assert(idec->is_lossless);
    575 
    576  // Switch to incremental decoding if we don't have all the bytes available.
    577  dec->incremental = (curr_size < idec->chunk_size);
    578 
    579  if (!VP8LDecodeImage(dec)) {
    580    return ErrorStatusLossless(idec, dec->status);
    581  }
    582  assert(dec->status == VP8_STATUS_OK || dec->status == VP8_STATUS_SUSPENDED);
    583  return (dec->status == VP8_STATUS_SUSPENDED) ? dec->status
    584                                               : FinishDecoding(idec);
    585 }
    586 
    587  // Main decoding loop
    588 static VP8StatusCode IDecode(WebPIDecoder* idec) {
    589  VP8StatusCode status = VP8_STATUS_SUSPENDED;
    590 
    591  if (idec->state == STATE_WEBP_HEADER) {
    592    status = DecodeWebPHeaders(idec);
    593  } else {
    594    if (idec->dec == NULL) {
    595      return VP8_STATUS_SUSPENDED;    // can't continue if we have no decoder.
    596    }
    597  }
    598  if (idec->state == STATE_VP8_HEADER) {
    599    status = DecodeVP8FrameHeader(idec);
    600  }
    601  if (idec->state == STATE_VP8_PARTS0) {
    602    status = DecodePartition0(idec);
    603  }
    604  if (idec->state == STATE_VP8_DATA) {
    605    const VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    606    if (dec == NULL) {
    607      return VP8_STATUS_SUSPENDED;  // can't continue if we have no decoder.
    608    }
    609    status = DecodeRemaining(idec);
    610  }
    611  if (idec->state == STATE_VP8L_HEADER) {
    612    status = DecodeVP8LHeader(idec);
    613  }
    614  if (idec->state == STATE_VP8L_DATA) {
    615    status = DecodeVP8LData(idec);
    616  }
    617  return status;
    618 }
    619 
    620 //------------------------------------------------------------------------------
    621 // Internal constructor
    622 
    623 WEBP_NODISCARD static WebPIDecoder* NewDecoder(
    624    WebPDecBuffer* const output_buffer,
    625    const WebPBitstreamFeatures* const features) {
    626  WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
    627  if (idec == NULL) {
    628    return NULL;
    629  }
    630 
    631  idec->state = STATE_WEBP_HEADER;
    632  idec->chunk_size = 0;
    633 
    634  idec->last_mb_y = -1;
    635 
    636  InitMemBuffer(&idec->mem);
    637  if (!WebPInitDecBuffer(&idec->output) || !VP8InitIo(&idec->io)) {
    638    WebPSafeFree(idec);
    639    return NULL;
    640  }
    641 
    642  WebPResetDecParams(&idec->params);
    643  if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) {
    644    idec->params.output = &idec->output;
    645    idec->final_output = output_buffer;
    646    if (output_buffer != NULL) {
    647      idec->params.output->colorspace = output_buffer->colorspace;
    648    }
    649  } else {
    650    idec->params.output = output_buffer;
    651    idec->final_output = NULL;
    652  }
    653  WebPInitCustomIo(&idec->params, &idec->io);  // Plug the I/O functions.
    654 
    655  return idec;
    656 }
    657 
    658 //------------------------------------------------------------------------------
    659 // Public functions
    660 
    661 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
    662  return NewDecoder(output_buffer, NULL);
    663 }
    664 
    665 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
    666                          WebPDecoderConfig* config) {
    667  WebPIDecoder* idec;
    668  WebPBitstreamFeatures tmp_features;
    669  WebPBitstreamFeatures* const features =
    670      (config == NULL) ? &tmp_features : &config->input;
    671  memset(&tmp_features, 0, sizeof(tmp_features));
    672 
    673  // Parse the bitstream's features, if requested:
    674  if (data != NULL && data_size > 0) {
    675    if (WebPGetFeatures(data, data_size, features) != VP8_STATUS_OK) {
    676      return NULL;
    677    }
    678  }
    679 
    680  // Create an instance of the incremental decoder
    681  idec = (config != NULL) ? NewDecoder(&config->output, features)
    682                          : NewDecoder(NULL, features);
    683  if (idec == NULL) {
    684    return NULL;
    685  }
    686  // Finish initialization
    687  if (config != NULL) {
    688    idec->params.options = &config->options;
    689  }
    690  return idec;
    691 }
    692 
    693 void WebPIDelete(WebPIDecoder* idec) {
    694  if (idec == NULL) return;
    695  if (idec->dec != NULL) {
    696    if (!idec->is_lossless) {
    697      if (idec->state == STATE_VP8_DATA) {
    698        // Synchronize the thread, clean-up and check for errors.
    699        // TODO(vrabaud) do we care about the return result?
    700        (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io);
    701      }
    702      VP8Delete((VP8Decoder*)idec->dec);
    703    } else {
    704      VP8LDelete((VP8LDecoder*)idec->dec);
    705    }
    706  }
    707  ClearMemBuffer(&idec->mem);
    708  WebPFreeDecBuffer(&idec->output);
    709  WebPSafeFree(idec);
    710 }
    711 
    712 //------------------------------------------------------------------------------
    713 // Wrapper toward WebPINewDecoder
    714 
    715 WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
    716                          size_t output_buffer_size, int output_stride) {
    717  const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
    718  WebPIDecoder* idec;
    719 
    720  if (csp >= MODE_YUV) return NULL;
    721  if (is_external_memory == 0) {    // Overwrite parameters to sane values.
    722    output_buffer_size = 0;
    723    output_stride = 0;
    724  } else {  // A buffer was passed. Validate the other params.
    725    if (output_stride == 0 || output_buffer_size == 0) {
    726      return NULL;   // invalid parameter.
    727    }
    728  }
    729  idec = WebPINewDecoder(NULL);
    730  if (idec == NULL) return NULL;
    731  idec->output.colorspace = csp;
    732  idec->output.is_external_memory = is_external_memory;
    733  idec->output.u.RGBA.rgba = output_buffer;
    734  idec->output.u.RGBA.stride = output_stride;
    735  idec->output.u.RGBA.size = output_buffer_size;
    736  return idec;
    737 }
    738 
    739 WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
    740                           uint8_t* u, size_t u_size, int u_stride,
    741                           uint8_t* v, size_t v_size, int v_stride,
    742                           uint8_t* a, size_t a_size, int a_stride) {
    743  const int is_external_memory = (luma != NULL) ? 1 : 0;
    744  WebPIDecoder* idec;
    745  WEBP_CSP_MODE colorspace;
    746 
    747  if (is_external_memory == 0) {    // Overwrite parameters to sane values.
    748    luma_size = u_size = v_size = a_size = 0;
    749    luma_stride = u_stride = v_stride = a_stride = 0;
    750    u = v = a = NULL;
    751    colorspace = MODE_YUVA;
    752  } else {  // A luma buffer was passed. Validate the other parameters.
    753    if (u == NULL || v == NULL) return NULL;
    754    if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL;
    755    if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL;
    756    if (a != NULL) {
    757      if (a_size == 0 || a_stride == 0) return NULL;
    758    }
    759    colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
    760  }
    761 
    762  idec = WebPINewDecoder(NULL);
    763  if (idec == NULL) return NULL;
    764 
    765  idec->output.colorspace = colorspace;
    766  idec->output.is_external_memory = is_external_memory;
    767  idec->output.u.YUVA.y = luma;
    768  idec->output.u.YUVA.y_stride = luma_stride;
    769  idec->output.u.YUVA.y_size = luma_size;
    770  idec->output.u.YUVA.u = u;
    771  idec->output.u.YUVA.u_stride = u_stride;
    772  idec->output.u.YUVA.u_size = u_size;
    773  idec->output.u.YUVA.v = v;
    774  idec->output.u.YUVA.v_stride = v_stride;
    775  idec->output.u.YUVA.v_size = v_size;
    776  idec->output.u.YUVA.a = a;
    777  idec->output.u.YUVA.a_stride = a_stride;
    778  idec->output.u.YUVA.a_size = a_size;
    779  return idec;
    780 }
    781 
    782 WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
    783                          uint8_t* u, size_t u_size, int u_stride,
    784                          uint8_t* v, size_t v_size, int v_stride) {
    785  return WebPINewYUVA(luma, luma_size, luma_stride,
    786                      u, u_size, u_stride,
    787                      v, v_size, v_stride,
    788                      NULL, 0, 0);
    789 }
    790 
    791 //------------------------------------------------------------------------------
    792 
    793 static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
    794  assert(idec);
    795  if (idec->state == STATE_ERROR) {
    796    return VP8_STATUS_BITSTREAM_ERROR;
    797  }
    798  if (idec->state == STATE_DONE) {
    799    return VP8_STATUS_OK;
    800  }
    801  return VP8_STATUS_SUSPENDED;
    802 }
    803 
    804 VP8StatusCode WebPIAppend(WebPIDecoder* idec,
    805                          const uint8_t* data, size_t data_size) {
    806  VP8StatusCode status;
    807  if (idec == NULL || data == NULL) {
    808    return VP8_STATUS_INVALID_PARAM;
    809  }
    810  status = IDecCheckStatus(idec);
    811  if (status != VP8_STATUS_SUSPENDED) {
    812    return status;
    813  }
    814  // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
    815  if (!CheckMemBufferMode(&idec->mem, MEM_MODE_APPEND)) {
    816    return VP8_STATUS_INVALID_PARAM;
    817  }
    818  // Append data to memory buffer
    819  if (!AppendToMemBuffer(idec, data, data_size)) {
    820    return VP8_STATUS_OUT_OF_MEMORY;
    821  }
    822  return IDecode(idec);
    823 }
    824 
    825 VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
    826                          const uint8_t* data, size_t data_size) {
    827  VP8StatusCode status;
    828  if (idec == NULL || data == NULL) {
    829    return VP8_STATUS_INVALID_PARAM;
    830  }
    831  status = IDecCheckStatus(idec);
    832  if (status != VP8_STATUS_SUSPENDED) {
    833    return status;
    834  }
    835  // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
    836  if (!CheckMemBufferMode(&idec->mem, MEM_MODE_MAP)) {
    837    return VP8_STATUS_INVALID_PARAM;
    838  }
    839  // Make the memory buffer point to the new buffer
    840  if (!RemapMemBuffer(idec, data, data_size)) {
    841    return VP8_STATUS_INVALID_PARAM;
    842  }
    843  return IDecode(idec);
    844 }
    845 
    846 //------------------------------------------------------------------------------
    847 
    848 static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
    849  if (idec == NULL || idec->dec == NULL) {
    850    return NULL;
    851  }
    852  if (idec->state <= STATE_VP8_PARTS0) {
    853    return NULL;
    854  }
    855  if (idec->final_output != NULL) {
    856    return NULL;   // not yet slow-copied
    857  }
    858  return idec->params.output;
    859 }
    860 
    861 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
    862                                      int* left, int* top,
    863                                      int* width, int* height) {
    864  const WebPDecBuffer* const src = GetOutputBuffer(idec);
    865  if (left != NULL) *left = 0;
    866  if (top != NULL) *top = 0;
    867  if (src != NULL) {
    868    if (width != NULL) *width = src->width;
    869    if (height != NULL) *height = idec->params.last_y;
    870  } else {
    871    if (width != NULL) *width = 0;
    872    if (height != NULL) *height = 0;
    873  }
    874  return src;
    875 }
    876 
    877 WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
    878                                       int* width, int* height, int* stride) {
    879  const WebPDecBuffer* const src = GetOutputBuffer(idec);
    880  if (src == NULL) return NULL;
    881  if (src->colorspace >= MODE_YUV) {
    882    return NULL;
    883  }
    884 
    885  if (last_y != NULL) *last_y = idec->params.last_y;
    886  if (width != NULL) *width = src->width;
    887  if (height != NULL) *height = src->height;
    888  if (stride != NULL) *stride = src->u.RGBA.stride;
    889 
    890  return src->u.RGBA.rgba;
    891 }
    892 
    893 WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
    894                                        uint8_t** u, uint8_t** v, uint8_t** a,
    895                                        int* width, int* height, int* stride,
    896                                        int* uv_stride, int* a_stride) {
    897  const WebPDecBuffer* const src = GetOutputBuffer(idec);
    898  if (src == NULL) return NULL;
    899  if (src->colorspace < MODE_YUV) {
    900    return NULL;
    901  }
    902 
    903  if (last_y != NULL) *last_y = idec->params.last_y;
    904  if (u != NULL) *u = src->u.YUVA.u;
    905  if (v != NULL) *v = src->u.YUVA.v;
    906  if (a != NULL) *a = src->u.YUVA.a;
    907  if (width != NULL) *width = src->width;
    908  if (height != NULL) *height = src->height;
    909  if (stride != NULL) *stride = src->u.YUVA.y_stride;
    910  if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride;
    911  if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride;
    912 
    913  return src->u.YUVA.y;
    914 }
    915 
    916 int WebPISetIOHooks(WebPIDecoder* const idec,
    917                    VP8IoPutHook put,
    918                    VP8IoSetupHook setup,
    919                    VP8IoTeardownHook teardown,
    920                    void* user_data) {
    921  if (idec == NULL || idec->state > STATE_WEBP_HEADER) {
    922    return 0;
    923  }
    924 
    925  idec->io.put = put;
    926  idec->io.setup = setup;
    927  idec->io.teardown = teardown;
    928  idec->io.opaque = user_data;
    929 
    930  return 1;
    931 }