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