diff options
Diffstat (limited to 'src/3rdparty/libwebp/src/dec/idec.c')
-rw-r--r-- | src/3rdparty/libwebp/src/dec/idec.c | 123 |
1 files changed, 68 insertions, 55 deletions
diff --git a/src/3rdparty/libwebp/src/dec/idec.c b/src/3rdparty/libwebp/src/dec/idec.c index 40d5ff6..e003851 100644 --- a/src/3rdparty/libwebp/src/dec/idec.c +++ b/src/3rdparty/libwebp/src/dec/idec.c @@ -72,28 +72,20 @@ struct WebPIDecoder { MemBuffer mem_; // input memory buffer. WebPDecBuffer output_; // output buffer (when no external one is supplied) size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header. + + int last_mb_y_; // last row reached for intra-mode decoding }; // MB context to restore in case VP8DecodeMB() fails typedef struct { VP8MB left_; VP8MB info_; - uint8_t intra_t_[4]; - uint8_t intra_l_[4]; - VP8BitReader br_; VP8BitReader token_br_; } MBContext; //------------------------------------------------------------------------------ // MemBuffer: incoming data handling -static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) { - if (br->buf_ != NULL) { - br->buf_ += offset; - br->buf_end_ += offset; - } -} - static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { return (mem->end_ - mem->start_); } @@ -130,12 +122,12 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { if (offset != 0) { int p; for (p = 0; p <= last_part; ++p) { - RemapBitReader(dec->parts_ + p, offset); + VP8RemapBitReader(dec->parts_ + p, offset); } // Remap partition #0 data pointer to new offset, but only in MAP // mode (in APPEND mode, partition #0 is copied into a fixed memory). if (mem->mode_ == MEM_MODE_MAP) { - RemapBitReader(&dec->br_, offset); + VP8RemapBitReader(&dec->br_, offset); } } assert(last_part >= 0); @@ -189,7 +181,7 @@ static int AppendToMemBuffer(WebPIDecoder* const idec, (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); if (new_buf == NULL) return 0; memcpy(new_buf, old_base, current_size); - free(mem->buf_); + WebPSafeFree(mem->buf_); mem->buf_ = new_buf; mem->buf_size_ = (size_t)extra_size; mem->start_ = new_mem_start; @@ -231,8 +223,8 @@ static void InitMemBuffer(MemBuffer* const mem) { static void ClearMemBuffer(MemBuffer* const mem) { assert(mem); if (mem->mode_ == MEM_MODE_APPEND) { - free(mem->buf_); - free((void*)mem->part0_buf_); + WebPSafeFree(mem->buf_); + WebPSafeFree((void*)mem->part0_buf_); } } @@ -246,35 +238,36 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) { return 1; } +// To be called last. +static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { +#if WEBP_DECODER_ABI_VERSION > 0x0203 + const WebPDecoderOptions* const options = idec->params_.options; + WebPDecBuffer* const output = idec->params_.output; + + idec->state_ = STATE_DONE; + if (options != NULL && options->flip) { + return WebPFlipBuffer(output); + } +#endif + idec->state_ = STATE_DONE; + return VP8_STATUS_OK; +} + //------------------------------------------------------------------------------ // Macroblock-decoding contexts static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, MBContext* const context) { - const VP8BitReader* const br = &dec->br_; - const VP8MB* const left = dec->mb_info_ - 1; - const VP8MB* const info = dec->mb_info_ + dec->mb_x_; - - context->left_ = *left; - context->info_ = *info; - context->br_ = *br; + context->left_ = dec->mb_info_[-1]; + context->info_ = dec->mb_info_[dec->mb_x_]; context->token_br_ = *token_br; - memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4); - memcpy(context->intra_l_, dec->intra_l_, 4); } static void RestoreContext(const MBContext* context, VP8Decoder* const dec, VP8BitReader* const token_br) { - VP8BitReader* const br = &dec->br_; - VP8MB* const left = dec->mb_info_ - 1; - VP8MB* const info = dec->mb_info_ + dec->mb_x_; - - *left = context->left_; - *info = context->info_; - *br = context->br_; + dec->mb_info_[-1] = context->left_; + dec->mb_info_[dec->mb_x_] = context->info_; *token_br = context->token_br_; - memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4); - memcpy(dec->intra_l_, context->intra_l_, 4); } //------------------------------------------------------------------------------ @@ -310,6 +303,7 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) { headers.data = data; headers.data_size = curr_size; + headers.have_all_data = 0; status = WebPParseHeaders(&headers); if (status == VP8_STATUS_NOT_ENOUGH_DATA) { return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet. @@ -363,30 +357,33 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { } // Partition #0 -static int CopyParts0Data(WebPIDecoder* const idec) { +static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) { VP8Decoder* const dec = (VP8Decoder*)idec->dec_; VP8BitReader* const br = &dec->br_; - const size_t psize = br->buf_end_ - br->buf_; + const size_t part_size = br->buf_end_ - br->buf_; MemBuffer* const mem = &idec->mem_; assert(!idec->is_lossless_); assert(mem->part0_buf_ == NULL); - assert(psize > 0); - assert(psize <= mem->part0_size_); // Format limit: no need for runtime check + // the following is a format limitation, no need for runtime check: + assert(part_size <= mem->part0_size_); + if (part_size == 0) { // can't have zero-size partition #0 + return VP8_STATUS_BITSTREAM_ERROR; + } if (mem->mode_ == MEM_MODE_APPEND) { // We copy and grab ownership of the partition #0 data. - uint8_t* const part0_buf = (uint8_t*)malloc(psize); + uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size); if (part0_buf == NULL) { - return 0; + return VP8_STATUS_OUT_OF_MEMORY; } - memcpy(part0_buf, br->buf_, psize); + memcpy(part0_buf, br->buf_, part_size); mem->part0_buf_ = part0_buf; br->buf_ = part0_buf; - br->buf_end_ = part0_buf + psize; + br->buf_end_ = part0_buf + part_size; } else { // Else: just keep pointers to the partition #0's data in dec_->br_. } - mem->start_ += psize; - return 1; + mem->start_ += part_size; + return VP8_STATUS_OK; } static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { @@ -420,8 +417,10 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { dec->mt_method_ = VP8GetThreadMethod(params->options, NULL, io->width, io->height); VP8InitDithering(params->options, dec); - if (!CopyParts0Data(idec)) { - return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY); + + dec->status_ = CopyParts0Data(idec); + if (dec->status_ != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); } // Finish setting up the decoding parameters. Will call io->setup(). @@ -446,16 +445,26 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { assert(dec->ready_); for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { - VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; + if (idec->last_mb_y_ != dec->mb_y_) { + if (!VP8ParseIntraModeRow(&dec->br_, dec)) { + // note: normally, error shouldn't occur since we already have the whole + // partition0 available here in DecodeRemaining(). Reaching EOF while + // reading intra modes really means a BITSTREAM_ERROR. + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + idec->last_mb_y_ = dec->mb_y_; + } for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + VP8BitReader* const token_br = + &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; MBContext context; SaveContext(dec, token_br, &context); if (!VP8DecodeMB(dec, token_br)) { - RestoreContext(&context, dec, token_br); // We shouldn't fail when MAX_MB data was available if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } + RestoreContext(&context, dec, token_br); return VP8_STATUS_SUSPENDED; } // Release buffer only if there is only one partition @@ -476,9 +485,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { return IDecError(idec, VP8_STATUS_USER_ABORT); } dec->ready_ = 0; - idec->state_ = STATE_DONE; - - return VP8_STATUS_OK; + return FinishDecoding(idec); } static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec, @@ -527,12 +534,16 @@ static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) { } if (!VP8LDecodeImage(dec)) { + // The decoding is called after all the data-bytes are aggregated. Change + // the error to VP8_BITSTREAM_ERROR in case lossless decoder fails to decode + // all the pixels (VP8_STATUS_SUSPENDED). + if (dec->status_ == VP8_STATUS_SUSPENDED) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + } return ErrorStatusLossless(idec, dec->status_); } - idec->state_ = STATE_DONE; - - return VP8_STATUS_OK; + return FinishDecoding(idec); } // Main decoding loop @@ -568,7 +579,7 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) { // Public functions WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { - WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec)); + WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec)); if (idec == NULL) { return NULL; } @@ -576,6 +587,8 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { idec->state_ = STATE_WEBP_HEADER; idec->chunk_size_ = 0; + idec->last_mb_y_ = -1; + InitMemBuffer(&idec->mem_); WebPInitDecBuffer(&idec->output_); VP8InitIo(&idec->io_); @@ -625,7 +638,7 @@ void WebPIDelete(WebPIDecoder* idec) { } ClearMemBuffer(&idec->mem_); WebPFreeDecBuffer(&idec->output_); - free(idec); + WebPSafeFree(idec); } //------------------------------------------------------------------------------ |