diff --git a/src/dec/webp.c b/src/dec/webp.c index a42ce3f7..6c90c6e8 100644 --- a/src/dec/webp.c +++ b/src/dec/webp.c @@ -38,15 +38,19 @@ extern "C" { // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. // 16..19 size of the VP8X chunk starting at offset 20. // 20..23 VP8X flags bit-map corresponding to the chunk-types present. -// 24..27 Width of the Canvas Image. -// 28..31 Height of the Canvas Image. +// 24..26 Width of the Canvas Image. +// 27..29 Height of the Canvas Image. // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, // META ...) -// All 32-bits sizes are in little-endian order. -// Note: chunk data must be padded to multiple of 2 in size +// All sizes are in little-endian order. +// Note: chunk data size must be padded to multiple of 2 when written. + +static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) { + return data[0] | (data[1] << 8) | (data[2] << 16); +} static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) { - return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + return (uint32_t)get_le24(data) | (data[3] << 24); } // Validates the RIFF container (if detected) and skips over it. @@ -115,10 +119,10 @@ static VP8StatusCode ParseVP8X(const uint8_t** data, size_t* data_size, *flags = get_le32(*data + 8); } if (width != NULL) { - *width = get_le32(*data + 12); + *width = 1 + get_le24(*data + 12); } if (height != NULL) { - *height = get_le32(*data + 16); + *height = 1 + get_le24(*data + 15); } // Skip over VP8X header bytes. *data += vp8x_size; diff --git a/src/enc/syntax.c b/src/enc/syntax.c index 7773c9a7..7c8c7b1a 100644 --- a/src/enc/syntax.c +++ b/src/enc/syntax.c @@ -22,10 +22,14 @@ extern "C" { // Helper functions // TODO(later): Move to webp/format_constants.h? -static void PutLE32(uint8_t* const data, uint32_t val) { +static void PutLE24(uint8_t* const data, uint32_t val) { data[0] = (val >> 0) & 0xff; data[1] = (val >> 8) & 0xff; data[2] = (val >> 16) & 0xff; +} + +static void PutLE32(uint8_t* const data, uint32_t val) { + PutLE24(data, val); data[3] = (val >> 24) & 0xff; } @@ -65,6 +69,8 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) { uint32_t flags = 0; assert(IsVP8XNeeded(enc)); + assert(pic->width >= 1 && pic->height >= 1); + assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE); if (enc->has_alpha_) { flags |= ALPHA_FLAG_BIT; @@ -72,8 +78,8 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) { PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE); PutLE32(vp8x + CHUNK_HEADER_SIZE, flags); - PutLE32(vp8x + CHUNK_HEADER_SIZE + 4, pic->width); - PutLE32(vp8x + CHUNK_HEADER_SIZE + 8, pic->height); + PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1); + PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1); if(!pic->writer(vp8x, sizeof(vp8x), pic)) { return VP8_ENC_ERROR_BAD_WRITE; } @@ -274,12 +280,6 @@ static int EmitPartitionsSize(const VP8Encoder* const enc, #define KTRAILER_SIZE 8 -static void PutLE24(uint8_t* buf, size_t value) { - buf[0] = (value >> 0) & 0xff; - buf[1] = (value >> 8) & 0xff; - buf[2] = (value >> 16) & 0xff; -} - static int WriteExtensions(VP8Encoder* const enc) { uint8_t buffer[KTRAILER_SIZE]; VP8BitWriter* const bw = &enc->bw_; diff --git a/src/mux/demux.c b/src/mux/demux.c index e7f33875..cd858586 100644 --- a/src/mux/demux.c +++ b/src/mux/demux.c @@ -133,9 +133,19 @@ static WEBP_INLINE uint8_t GetByte(MemBuffer* const mem) { return byte; } +static WEBP_INLINE int ReadLE24s(const uint8_t* const data) { + return (int)(data[0] << 0) | (data[1] << 8) | (data[2] << 16); +} + static WEBP_INLINE uint32_t ReadLE32(const uint8_t* const data) { - return (uint32_t)(data[0] << 0 | (data[1] << 8) | - (data[2] << 16) | (data[3] << 24)); + return (uint32_t)ReadLE24s(data) | (data[3] << 24); +} + +static WEBP_INLINE int GetLE24s(MemBuffer* const mem) { + const uint8_t* const data = mem->buf_ + mem->start_; + const uint32_t val = ReadLE24s(data); + Skip(mem, 3); + return val; } static WEBP_INLINE uint32_t GetLE32(MemBuffer* const mem) { @@ -432,8 +442,8 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { dmux->feature_flags_ = GetByte(mem); Skip(mem, 3); // Reserved. - dmux->canvas_width_ = GetLE32s(mem); - dmux->canvas_height_ = GetLE32s(mem); + dmux->canvas_width_ = 1 + GetLE24s(mem); + dmux->canvas_height_ = 1 + GetLE24s(mem); Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. dmux->state_ = WEBP_DEMUX_PARSED_HEADER; diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index 16d5746c..00ca9ac6 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -569,10 +569,10 @@ static WebPMuxError GetImageCanvasWidthHeight( } // VP8X format: -// Total Size : 12, +// Total Size : 10, // Flags : 4 bytes, -// Width : 4 bytes, -// Height : 4 bytes. +// Width : 3 bytes, +// Height : 3 bytes. static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { WebPMuxError err = WEBP_MUX_OK; uint32_t flags = 0; @@ -635,8 +635,8 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { } PutLE32(data + 0, flags); // VP8X chunk flags. - PutLE32(data + 4, width); // canvas width. - PutLE32(data + 8, height); // canvas height. + PutLE24(data + 4, width - 1); // canvas width. + PutLE24(data + 7, height - 1); // canvas height. err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, NULL, 1); return err; diff --git a/src/mux/muxi.h b/src/mux/muxi.h index b4882d1e..cf8b9692 100644 --- a/src/mux/muxi.h +++ b/src/mux/muxi.h @@ -108,11 +108,16 @@ static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) { return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); } -static WEBP_INLINE void PutLE16(uint8_t* const data, uint16_t val) { +static WEBP_INLINE void PutLE16(uint8_t* const data, uint32_t val) { data[0] = (val >> 0) & 0xff; data[1] = (val >> 8) & 0xff; } +static WEBP_INLINE void PutLE24(uint8_t* const data, uint32_t val) { + PutLE16(data, val); + data[2] = (val >> 16); +} + static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) { PutLE16(data, val); PutLE16(data + 2, val >> 16); diff --git a/src/mux/muxread.c b/src/mux/muxread.c index e64be69c..2fd6d07b 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -215,11 +215,13 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* const mux, uint32_t* flags) { static uint8_t* EmitVP8XChunk(uint8_t* const dst, uint32_t width, uint32_t height, uint32_t flags) { const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; + assert(width >= 1 && height >= 1); + assert(width <= MAX_CANVAS_SIZE && height <= MAX_CANVAS_SIZE); PutLE32(dst, mktag('V', 'P', '8', 'X')); PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE); PutLE32(dst + CHUNK_HEADER_SIZE, flags); - PutLE32(dst + CHUNK_HEADER_SIZE + 4, width); - PutLE32(dst + CHUNK_HEADER_SIZE + 8, height); + PutLE24(dst + CHUNK_HEADER_SIZE + 4, width - 1); + PutLE24(dst + CHUNK_HEADER_SIZE + 7, height - 1); return dst + vp8x_size; } diff --git a/src/webp/format_constants.h b/src/webp/format_constants.h index 63a3c0c6..4ddc5b43 100644 --- a/src/webp/format_constants.h +++ b/src/webp/format_constants.h @@ -64,9 +64,17 @@ typedef enum { #define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP"). #define FRAME_CHUNK_SIZE 20 // Size of a FRM chunk. #define LOOP_CHUNK_SIZE 4 // Size of a LOOP chunk. -#define TILE_CHUNK_SIZE 8 // Size of a LOOP chunk. -#define VP8X_CHUNK_SIZE 12 // Size of a VP8X chunk. +#define TILE_CHUNK_SIZE 8 // Size of a TILE chunk. +#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. + +#define TILING_FLAG_BIT 0x01 // Set if tiles are possibly used. +#define ANIMATION_FLAG_BIT 0x02 // Set if some animation is expected +#define ICC_FLAG_BIT 0x04 // Whether ICC is present or not. +#define METADATA_FLAG_BIT 0x08 // Set if some META chunk is possibly present. #define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h +#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry + +#define MAX_CANVAS_SIZE (1 << 24) // 24 bit max for VP8X width/height. // Maximum chunk payload is such that adding the header and padding won't // overflow a uint32_t.