diff --git a/src/demux/demux.c b/src/demux/demux.c index 08a7c8ed..b6639700 100644 --- a/src/demux/demux.c +++ b/src/demux/demux.c @@ -75,6 +75,7 @@ struct WebPDemuxer { Frame* frames_; Frame** frames_tail_; Chunk* chunks_; // non-image chunks + Chunk** chunks_tail_; }; typedef enum { @@ -179,10 +180,9 @@ static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) { // Secondary chunk parsing static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) { - Chunk** c = &dmux->chunks_; - while (*c != NULL) c = &(*c)->next_; - *c = chunk; + *dmux->chunks_tail_ = chunk; chunk->next_ = NULL; + dmux->chunks_tail_ = &chunk->next_; } // Add a frame to the end of the list, ensuring the last frame is complete. @@ -466,36 +466,12 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { return status; } -static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { +static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { + const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); MemBuffer* const mem = &dmux->mem_; int anim_chunks = 0; - uint32_t vp8x_size; ParseStatus status = PARSE_OK; - if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; - - dmux->is_ext_format_ = 1; - Skip(mem, TAG_SIZE); // VP8X - vp8x_size = ReadLE32(mem); - if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; - if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR; - vp8x_size += vp8x_size & 1; - if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; - if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; - - dmux->feature_flags_ = ReadByte(mem); - Skip(mem, 3); // Reserved. - dmux->canvas_width_ = 1 + ReadLE24s(mem); - dmux->canvas_height_ = 1 + ReadLE24s(mem); - if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { - return PARSE_ERROR; // image final dimension is too large - } - Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. - dmux->state_ = WEBP_DEMUX_PARSED_HEADER; - - if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; - if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; - do { int store_chunk = 1; const size_t chunk_start_offset = mem->start_; @@ -513,7 +489,6 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { case MKFOURCC('A', 'L', 'P', 'H'): case MKFOURCC('V', 'P', '8', ' '): case MKFOURCC('V', 'P', '8', 'L'): { - const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); // check that this isn't an animation (all frames should be in an ANMF). if (anim_chunks > 0 || is_animation) return PARSE_ERROR; @@ -552,14 +527,14 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); goto Skip; } - case MKFOURCC('X', 'M', 'P', ' '): { - store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); - goto Skip; - } case MKFOURCC('E', 'X', 'I', 'F'): { store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); goto Skip; } + case MKFOURCC('X', 'M', 'P', ' '): { + store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); + goto Skip; + } Skip: default: { if (chunk_size_padded <= MemDataSize(mem)) { @@ -588,6 +563,37 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { return status; } +static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { + MemBuffer* const mem = &dmux->mem_; + uint32_t vp8x_size; + + if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; + + dmux->is_ext_format_ = 1; + Skip(mem, TAG_SIZE); // VP8X + vp8x_size = ReadLE32(mem); + if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR; + vp8x_size += vp8x_size & 1; + if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; + if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; + + dmux->feature_flags_ = ReadByte(mem); + Skip(mem, 3); // Reserved. + dmux->canvas_width_ = 1 + ReadLE24s(mem); + dmux->canvas_height_ = 1 + ReadLE24s(mem); + if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { + return PARSE_ERROR; // image final dimension is too large + } + Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. + dmux->state_ = WEBP_DEMUX_PARSED_HEADER; + + if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; + if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; + + return ParseVP8XChunks(dmux); +} + // ----------------------------------------------------------------------------- // Format validation @@ -697,6 +703,7 @@ static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { dmux->canvas_width_ = -1; dmux->canvas_height_ = -1; dmux->frames_tail_ = &dmux->frames_; + dmux->chunks_tail_ = &dmux->chunks_; dmux->mem_ = *mem; }