summaryrefslogtreecommitdiffstats
path: root/media/libwebp/src/dec/vp8l_dec.c
diff options
context:
space:
mode:
Diffstat (limited to 'media/libwebp/src/dec/vp8l_dec.c')
-rw-r--r--media/libwebp/src/dec/vp8l_dec.c153
1 files changed, 87 insertions, 66 deletions
diff --git a/media/libwebp/src/dec/vp8l_dec.c b/media/libwebp/src/dec/vp8l_dec.c
index 1a6c0a8980..11c00ea964 100644
--- a/media/libwebp/src/dec/vp8l_dec.c
+++ b/media/libwebp/src/dec/vp8l_dec.c
@@ -12,6 +12,7 @@
// Authors: Vikas Arora (vikaas.arora@gmail.com)
// Jyrki Alakuijala (jyrki@google.com)
+#include <assert.h>
#include <stdlib.h>
#include "src/dec/alphai_dec.h"
@@ -101,6 +102,14 @@ static const uint16_t kTableSize[12] = {
FIXED_TABLE_SIZE + 2704
};
+static int VP8LSetError(VP8LDecoder* const dec, VP8StatusCode error) {
+ // The oldest error reported takes precedence over the new one.
+ if (dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED) {
+ dec->status_ = error;
+ }
+ return 0;
+}
+
static int DecodeImageStream(int xsize, int ysize,
int is_level0,
VP8LDecoder* const dec,
@@ -301,7 +310,7 @@ static int ReadHuffmanCodeLengths(
End:
VP8LHuffmanTablesDeallocate(&tables);
- if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ if (!ok) return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
return ok;
}
@@ -333,10 +342,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
int i;
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
const int num_codes = VP8LReadBits(br, 4) + 4;
- if (num_codes > NUM_CODE_LENGTH_CODES) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
- }
+ assert(num_codes <= NUM_CODE_LENGTH_CODES);
for (i = 0; i < num_codes; ++i) {
code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
@@ -351,15 +357,14 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
code_lengths, alphabet_size);
}
if (!ok || size == 0) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
}
return size;
}
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int color_cache_bits, int allow_recursion) {
- int i, j;
+ int i;
VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
@@ -367,9 +372,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
HuffmanTables* huffman_tables = &hdr->huffman_tables_;
int num_htree_groups = 1;
int num_htree_groups_max = 1;
- int max_alphabet_size = 0;
- int* code_lengths = NULL;
- const int table_size = kTableSize[color_cache_bits];
int* mapping = NULL;
int ok = 0;
@@ -383,7 +385,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
const int huffman_pixs = huffman_xsize * huffman_ysize;
- if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
+ if (!DecodeImageStream(huffman_xsize, huffman_ysize, /*is_level0=*/0, dec,
&huffman_image)) {
goto Error;
}
@@ -407,7 +409,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
// values [0, num_htree_groups)
mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
if (mapping == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Error;
}
// -1 means a value is unmapped, and therefore unused in the Huffman
@@ -426,25 +428,52 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
if (br->eos_) goto Error;
- // Find maximum alphabet size for the htree group.
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- int alphabet_size = kAlphabetSize[j];
- if (j == 0 && color_cache_bits > 0) {
- alphabet_size += 1 << color_cache_bits;
- }
- if (max_alphabet_size < alphabet_size) {
- max_alphabet_size = alphabet_size;
- }
+ if (!ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups,
+ num_htree_groups_max, mapping, dec,
+ huffman_tables, &htree_groups)) {
+ goto Error;
}
+ ok = 1;
- code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
- sizeof(*code_lengths));
- htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+ // All OK. Finalize pointers.
+ hdr->huffman_image_ = huffman_image;
+ hdr->num_htree_groups_ = num_htree_groups;
+ hdr->htree_groups_ = htree_groups;
- if (htree_groups == NULL || code_lengths == NULL ||
+ Error:
+ WebPSafeFree(mapping);
+ if (!ok) {
+ WebPSafeFree(huffman_image);
+ VP8LHuffmanTablesDeallocate(huffman_tables);
+ VP8LHtreeGroupsFree(htree_groups);
+ }
+ return ok;
+}
+
+int ReadHuffmanCodesHelper(int color_cache_bits, int num_htree_groups,
+ int num_htree_groups_max, const int* const mapping,
+ VP8LDecoder* const dec,
+ HuffmanTables* const huffman_tables,
+ HTreeGroup** const htree_groups) {
+ int i, j, ok = 0;
+ const int max_alphabet_size =
+ kAlphabetSize[0] + ((color_cache_bits > 0) ? 1 << color_cache_bits : 0);
+ const int table_size = kTableSize[color_cache_bits];
+ int* code_lengths = NULL;
+
+ if ((mapping == NULL && num_htree_groups != num_htree_groups_max) ||
+ num_htree_groups > num_htree_groups_max) {
+ goto Error;
+ }
+
+ code_lengths =
+ (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, sizeof(*code_lengths));
+ *htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+
+ if (*htree_groups == NULL || code_lengths == NULL ||
!VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
huffman_tables)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Error;
}
@@ -464,7 +493,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
} else {
HTreeGroup* const htree_group =
- &htree_groups[(mapping == NULL) ? i : mapping[i]];
+ &(*htree_groups)[(mapping == NULL) ? i : mapping[i]];
HuffmanCode** const htrees = htree_group->htrees;
int size;
int total_size = 0;
@@ -516,18 +545,12 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
ok = 1;
- // All OK. Finalize pointers.
- hdr->huffman_image_ = huffman_image;
- hdr->num_htree_groups_ = num_htree_groups;
- hdr->htree_groups_ = htree_groups;
-
Error:
WebPSafeFree(code_lengths);
- WebPSafeFree(mapping);
if (!ok) {
- WebPSafeFree(huffman_image);
VP8LHuffmanTablesDeallocate(huffman_tables);
- VP8LHtreeGroupsFree(htree_groups);
+ VP8LHtreeGroupsFree(*htree_groups);
+ *htree_groups = NULL;
}
return ok;
}
@@ -551,8 +574,7 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
scaled_data_size * sizeof(*scaled_data);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
if (memory == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
assert(dec->rescaler_memory == NULL);
dec->rescaler_memory = memory;
@@ -1086,12 +1108,10 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
End:
br->eos_ = VP8LIsEndOfStream(br);
if (!ok || (br->eos_ && pos < end)) {
- ok = 0;
- dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
- : VP8_STATUS_BITSTREAM_ERROR;
- } else {
- dec->last_pixel_ = pos;
+ return VP8LSetError(
+ dec, br->eos_ ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR);
}
+ dec->last_pixel_ = pos;
return ok;
}
@@ -1269,8 +1289,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
return 1;
Error:
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
}
// -----------------------------------------------------------------------------
@@ -1337,7 +1356,7 @@ static int ReadTransform(int* const xsize, int const* ysize,
transform->bits_),
VP8LSubSampleSize(transform->ysize_,
transform->bits_),
- 0, dec, &transform->data_);
+ /*is_level0=*/0, dec, &transform->data_);
break;
case COLOR_INDEXING_TRANSFORM: {
const int num_colors = VP8LReadBits(br, 8) + 1;
@@ -1347,8 +1366,11 @@ static int ReadTransform(int* const xsize, int const* ysize,
: 3;
*xsize = VP8LSubSampleSize(transform->xsize_, bits);
transform->bits_ = bits;
- ok = DecodeImageStream(num_colors, 1, 0, dec, &transform->data_);
- ok = ok && ExpandColorMap(num_colors, transform);
+ ok = DecodeImageStream(num_colors, /*ysize=*/1, /*is_level0=*/0, dec,
+ &transform->data_);
+ if (ok && !ExpandColorMap(num_colors, transform)) {
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
+ }
break;
}
case SUBTRACT_GREEN_TRANSFORM:
@@ -1454,7 +1476,7 @@ static int DecodeImageStream(int xsize, int ysize,
color_cache_bits = VP8LReadBits(br, 4);
ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS);
if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto End;
}
}
@@ -1463,7 +1485,7 @@ static int DecodeImageStream(int xsize, int ysize,
ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
color_cache_bits, is_level0);
if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto End;
}
@@ -1471,8 +1493,7 @@ static int DecodeImageStream(int xsize, int ysize,
if (color_cache_bits > 0) {
hdr->color_cache_size_ = 1 << color_cache_bits;
if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
+ ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto End;
}
} else {
@@ -1489,8 +1510,7 @@ static int DecodeImageStream(int xsize, int ysize,
const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize;
data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data));
if (data == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
+ ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto End;
}
}
@@ -1535,8 +1555,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
if (dec->pixels_ == NULL) {
dec->argb_cache_ = NULL; // for soundness
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels;
return 1;
@@ -1547,8 +1566,7 @@ static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
dec->argb_cache_ = NULL; // for soundness
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
if (dec->pixels_ == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
return 1;
}
@@ -1603,7 +1621,8 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
dec->status_ = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br_, data, data_size);
- if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, 1, dec, NULL)) {
+ if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, /*is_level0=*/1,
+ dec, /*decoded_data=*/NULL)) {
goto Err;
}
@@ -1658,22 +1677,24 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
if (dec == NULL) return 0;
if (io == NULL) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
}
dec->io_ = io;
dec->status_ = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br_, io->data, io->data_size);
if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto Error;
}
dec->state_ = READ_DIM;
io->width = width;
io->height = height;
- if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error;
+ if (!DecodeImageStream(width, height, /*is_level0=*/1, dec,
+ /*decoded_data=*/NULL)) {
+ goto Error;
+ }
return 1;
Error:
@@ -1703,7 +1724,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
assert(dec->output_ != NULL);
if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
+ VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
goto Err;
}
@@ -1713,7 +1734,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
#else
if (io->use_scaling) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
+ VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
goto Err;
}
#endif
@@ -1731,7 +1752,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
dec->hdr_.saved_color_cache_.colors_ == NULL) {
if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_,
dec->hdr_.color_cache_.hash_bits_)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Err;
}
}