mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
make the bitreader preload at least 8bits, instead of post-load them
(this makes initialization easier and will be helpful for incremental decoding). Modify ParsePartitions() to accommodate for truncated input. Change-Id: I62f52078d6b7a2314a11880a20d9eac5b4714bd0
This commit is contained in:
parent
f4888f7702
commit
13e50da6f8
@ -18,16 +18,17 @@ extern "C" {
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// VP8BitReader
|
// VP8BitReader
|
||||||
|
|
||||||
void VP8Init(VP8BitReader* const br, const uint8_t* buf, uint32_t size) {
|
void VP8InitBitReader(VP8BitReader* const br,
|
||||||
|
const uint8_t* const start, const uint8_t* const end) {
|
||||||
assert(br);
|
assert(br);
|
||||||
assert(buf);
|
assert(start);
|
||||||
br->range_ = 255 - 1;
|
assert(start <= end);
|
||||||
br->buf_ = buf;
|
br->range_ = 255 - 1;
|
||||||
br->buf_end_ = buf + size;
|
br->buf_ = start;
|
||||||
// Need two initial bytes.
|
br->buf_end_ = end;
|
||||||
br->value_ = (VP8GetByte(br) << 8) | VP8GetByte(br);
|
br->value_ = 0;
|
||||||
br->left_ = -8;
|
br->missing_ = 8;
|
||||||
br->eof_ = 0;
|
br->eof_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t kVP8Log2Range[128] = {
|
const uint8_t kVP8Log2Range[128] = {
|
||||||
|
@ -30,11 +30,12 @@ typedef struct {
|
|||||||
// boolean decoder
|
// boolean decoder
|
||||||
uint32_t range_; // current range minus 1. In [127, 254] interval.
|
uint32_t range_; // current range minus 1. In [127, 254] interval.
|
||||||
uint32_t value_; // current value
|
uint32_t value_; // current value
|
||||||
int left_; // how many unused bits (negated)
|
int missing_; // number of missing bits in value_ (8bit)
|
||||||
} VP8BitReader;
|
} VP8BitReader;
|
||||||
|
|
||||||
// Initialize the bit reader and the boolean decoder.
|
// Initialize the bit reader and the boolean decoder.
|
||||||
void VP8Init(VP8BitReader* const br, const uint8_t* buf, uint32_t size);
|
void VP8InitBitReader(VP8BitReader* const br,
|
||||||
|
const uint8_t* const start, const uint8_t* const end);
|
||||||
|
|
||||||
// return the next value made of 'num_bits' bits
|
// return the next value made of 'num_bits' bits
|
||||||
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
|
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
|
||||||
@ -55,7 +56,24 @@ static inline uint32_t VP8GetByte(VP8BitReader* const br) {
|
|||||||
return *br->buf_++;
|
return *br->buf_++;
|
||||||
}
|
}
|
||||||
br->eof_ = 1;
|
br->eof_ = 1;
|
||||||
return 0x80;
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t VP8BitUpdate(VP8BitReader* const br, uint32_t split) {
|
||||||
|
uint32_t bit;
|
||||||
|
// Make sure we have a least 8 bits in 'value_'
|
||||||
|
if (br->missing_ > 0) {
|
||||||
|
br->value_ |= VP8GetByte(br) << br->missing_;
|
||||||
|
br->missing_ -= 8;
|
||||||
|
}
|
||||||
|
bit = ((br->value_ >> 8) > split);
|
||||||
|
if (bit) {
|
||||||
|
br->range_ -= split + 1;
|
||||||
|
br->value_ -= (split + 1) << 8;
|
||||||
|
} else {
|
||||||
|
br->range_ = split;
|
||||||
|
}
|
||||||
|
return bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void VP8Shift(VP8BitReader* const br) {
|
static inline void VP8Shift(VP8BitReader* const br) {
|
||||||
@ -63,22 +81,12 @@ static inline void VP8Shift(VP8BitReader* const br) {
|
|||||||
const int shift = kVP8Log2Range[br->range_];
|
const int shift = kVP8Log2Range[br->range_];
|
||||||
br->range_ = kVP8NewRange[br->range_];
|
br->range_ = kVP8NewRange[br->range_];
|
||||||
br->value_ <<= shift;
|
br->value_ <<= shift;
|
||||||
br->left_ += shift;
|
br->missing_ += shift;
|
||||||
if (br->left_ > 0) {
|
|
||||||
br->value_ |= VP8GetByte(br) << br->left_;
|
|
||||||
br->left_ -= 8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
|
static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
|
||||||
const uint32_t split = (br->range_ * prob) >> 8;
|
const uint32_t split = (br->range_ * prob) >> 8;
|
||||||
const uint32_t bit = ((br->value_ >> 8) > split);
|
const uint32_t bit = VP8BitUpdate(br, split);
|
||||||
if (bit) {
|
|
||||||
br->range_ -= split + 1;
|
|
||||||
br->value_ -= (split + 1) << 8;
|
|
||||||
} else {
|
|
||||||
br->range_ = split;
|
|
||||||
}
|
|
||||||
if (br->range_ < 0x7f) {
|
if (br->range_ < 0x7f) {
|
||||||
VP8Shift(br);
|
VP8Shift(br);
|
||||||
}
|
}
|
||||||
@ -87,16 +95,9 @@ static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
|
|||||||
|
|
||||||
static inline int VP8GetSigned(VP8BitReader* const br, int v) {
|
static inline int VP8GetSigned(VP8BitReader* const br, int v) {
|
||||||
const uint32_t split = br->range_ >> 1;
|
const uint32_t split = br->range_ >> 1;
|
||||||
const uint32_t bit = ((br->value_ >> 8) > split);
|
const uint32_t bit = VP8BitUpdate(br, split);
|
||||||
if (bit) {
|
|
||||||
br->range_ -= split + 1;
|
|
||||||
br->value_ -= (split + 1) << 8;
|
|
||||||
v = -v;
|
|
||||||
} else {
|
|
||||||
br->range_ = split;
|
|
||||||
}
|
|
||||||
VP8Shift(br);
|
VP8Shift(br);
|
||||||
return v;
|
return bit ? -v : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -111,33 +111,41 @@ static int ParseSegmentHeader(VP8BitReader* br,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Paragraph 9.5
|
// Paragraph 9.5
|
||||||
static int ParsePartitions(VP8Decoder* const dec,
|
// This function returns VP8_STATUS_SUSPENDED if we don't have all the
|
||||||
const uint8_t* buf, uint32_t size) {
|
// necessary data in 'buf'.
|
||||||
|
// This case is not necessarily an error (for incremental decoding).
|
||||||
|
// Still, no bitreader is ever initialized to make it possible to read
|
||||||
|
// unavailable memory.
|
||||||
|
// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA
|
||||||
|
// is returned, and this is an unrecoverable error.
|
||||||
|
// If the partitions were positioned ok, VP8_STATUS_OK is returned.
|
||||||
|
static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
|
||||||
|
const uint8_t* buf, uint32_t size) {
|
||||||
VP8BitReader* const br = &dec->br_;
|
VP8BitReader* const br = &dec->br_;
|
||||||
const uint8_t* sz = buf;
|
const uint8_t* sz = buf;
|
||||||
|
const uint8_t* buf_end = buf + size;
|
||||||
|
const uint8_t* part_start;
|
||||||
int last_part;
|
int last_part;
|
||||||
uint32_t offset;
|
|
||||||
int p;
|
int p;
|
||||||
|
|
||||||
dec->num_parts_ = 1 << VP8GetValue(br, 2);
|
dec->num_parts_ = 1 << VP8GetValue(br, 2);
|
||||||
last_part = dec->num_parts_ - 1;
|
last_part = dec->num_parts_ - 1;
|
||||||
offset = last_part * 3;
|
part_start = buf + last_part * 3;
|
||||||
|
if (buf_end < part_start) {
|
||||||
if (size <= offset) {
|
// we can't even read the sizes with sz[]! That's a failure.
|
||||||
return 0;
|
return VP8_STATUS_NOT_ENOUGH_DATA;
|
||||||
}
|
}
|
||||||
for (p = 0; p < last_part; ++p) {
|
for (p = 0; p < last_part; ++p) {
|
||||||
const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
|
const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
|
||||||
if (offset + psize > size) {
|
const uint8_t* part_end = part_start + psize;
|
||||||
return 0;
|
if (part_end > buf_end) part_end = buf_end;
|
||||||
}
|
VP8InitBitReader(dec->parts_ + p, part_start, part_end);
|
||||||
VP8Init(dec->parts_ + p, buf + offset, psize);
|
part_start = part_end;
|
||||||
offset += psize;
|
|
||||||
sz += 3;
|
sz += 3;
|
||||||
}
|
}
|
||||||
size -= offset;
|
VP8InitBitReader(dec->parts_ + last_part, part_start, buf_end);
|
||||||
VP8Init(dec->parts_ + last_part, buf + offset, size);
|
return (part_start < buf_end) ? VP8_STATUS_OK :
|
||||||
return 1;
|
VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paragraph 9.4
|
// Paragraph 9.4
|
||||||
@ -284,14 +292,17 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
dec->segment_ = 0; // default for intra
|
dec->segment_ = 0; // default for intra
|
||||||
}
|
}
|
||||||
|
|
||||||
br = &dec->br_;
|
// Check if we have all the partition #0 available, and initialize dec->br_
|
||||||
VP8Init(br, buf, buf_size);
|
// to read this partition (and this partition only).
|
||||||
if (frm_hdr->partition_length_ > buf_size) {
|
if (frm_hdr->partition_length_ > buf_size) {
|
||||||
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
|
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
|
||||||
"bad partition length");
|
"bad partition length");
|
||||||
}
|
}
|
||||||
|
br = &dec->br_;
|
||||||
|
VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_);
|
||||||
buf += frm_hdr->partition_length_;
|
buf += frm_hdr->partition_length_;
|
||||||
buf_size -= frm_hdr->partition_length_;
|
buf_size -= frm_hdr->partition_length_;
|
||||||
|
|
||||||
if (frm_hdr->key_frame_) {
|
if (frm_hdr->key_frame_) {
|
||||||
pic_hdr->colorspace_ = VP8Get(br);
|
pic_hdr->colorspace_ = VP8Get(br);
|
||||||
pic_hdr->clamp_type_ = VP8Get(br);
|
pic_hdr->clamp_type_ = VP8Get(br);
|
||||||
@ -305,7 +316,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
"cannot parse filter header");
|
"cannot parse filter header");
|
||||||
}
|
}
|
||||||
if (!ParsePartitions(dec, buf, buf_size)) {
|
if (ParsePartitions(dec, buf, buf_size) != VP8_STATUS_OK) {
|
||||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
"cannot parse partitions");
|
"cannot parse partitions");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user