Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Unified Diff: third_party/libwebp/demux/demux.c

Issue 116213006: Update libwebp to 0.4.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: After Blink Roll Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/libwebp/dec/webpi.h ('k') | third_party/libwebp/dsp/cpu.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/libwebp/demux/demux.c
diff --git a/third_party/libwebp/demux/demux.c b/third_party/libwebp/demux/demux.c
index c6e4acdcb866c1984a8accf6329f357ce6eed556..f66ac6d82bdf1ee9998726e58f39ca1876c259d6 100644
--- a/third_party/libwebp/demux/demux.c
+++ b/third_party/libwebp/demux/demux.c
@@ -23,13 +23,9 @@
#include "../webp/demux.h"
#include "../webp/format_constants.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#define DMUX_MAJ_VERSION 0
-#define DMUX_MIN_VERSION 1
-#define DMUX_REV_VERSION 1
+#define DMUX_MIN_VERSION 2
+#define DMUX_REV_VERSION 0
typedef struct {
size_t start_; // start location of the data
@@ -75,6 +71,7 @@ struct WebPDemuxer {
Frame* frames_;
Frame** frames_tail_;
Chunk* chunks_; // non-image chunks
+ Chunk** chunks_tail_;
};
typedef enum {
@@ -179,10 +176,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.
@@ -301,7 +297,7 @@ static ParseStatus NewFrame(const MemBuffer* const mem,
// 'frame_chunk_size' is the previously validated, padded chunk size.
static ParseStatus ParseAnimationFrame(
WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
- const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
+ const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
int added_frame = 0;
int bits;
@@ -328,7 +324,7 @@ static ParseStatus ParseAnimationFrame(
// Store a frame only if the animation flag is set there is some data for
// this frame is available.
status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
- if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) {
+ if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) {
added_frame = AddFrame(dmux, frame);
if (added_frame) {
++dmux->num_frames_;
@@ -347,7 +343,7 @@ static ParseStatus ParseAnimationFrame(
static ParseStatus ParseFragment(WebPDemuxer* const dmux,
uint32_t fragment_chunk_size) {
const int frame_num = 1; // All fragments belong to the 1st (and only) frame.
- const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
+ const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
const uint32_t frgm_payload_size = fragment_chunk_size - FRGM_CHUNK_SIZE;
int added_fragment = 0;
MemBuffer* const mem = &dmux->mem_;
@@ -360,10 +356,10 @@ static ParseStatus ParseFragment(WebPDemuxer* const dmux,
frame->x_offset_ = 2 * ReadLE24s(mem);
frame->y_offset_ = 2 * ReadLE24s(mem);
- // Store a fragment only if the fragments flag is set there is some data for
- // this fragment is available.
+ // Store a fragment only if the 'fragments' flag is set and there is some
+ // data available.
status = StoreFrame(frame_num, frgm_payload_size, mem, frame);
- if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) {
+ if (status != PARSE_ERROR && is_fragmented && frame->frame_num_ > 0) {
added_fragment = AddFrame(dmux, frame);
if (!added_fragment) {
status = PARSE_ERROR;
@@ -395,20 +391,20 @@ static int StoreChunk(WebPDemuxer* const dmux,
// -----------------------------------------------------------------------------
// Primary chunk parsing
-static int ReadHeader(MemBuffer* const mem) {
+static ParseStatus ReadHeader(MemBuffer* const mem) {
const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE;
uint32_t riff_size;
// Basic file level validation.
- if (MemDataSize(mem) < min_size) return 0;
+ if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) ||
memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) {
- return 0;
+ return PARSE_ERROR;
}
riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE);
- if (riff_size < CHUNK_HEADER_SIZE) return 0;
- if (riff_size > MAX_CHUNK_PAYLOAD) return 0;
+ if (riff_size < CHUNK_HEADER_SIZE) return PARSE_ERROR;
+ if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
// There's no point in reading past the end of the RIFF chunk
mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE;
@@ -417,7 +413,7 @@ static int ReadHeader(MemBuffer* const mem) {
}
Skip(mem, RIFF_HEADER_SIZE);
- return 1;
+ return PARSE_OK;
}
static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
@@ -425,6 +421,7 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
MemBuffer* const mem = &dmux->mem_;
Frame* frame;
ParseStatus status;
+ int image_added = 0;
if (dmux->frames_ != NULL) return PARSE_ERROR;
if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
@@ -453,45 +450,24 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
dmux->canvas_height_ = frame->height_;
dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
}
- AddFrame(dmux, frame);
- dmux->num_frames_ = 1;
- } else {
- free(frame);
+ if (!AddFrame(dmux, frame)) {
+ status = PARSE_ERROR; // last frame was left incomplete
+ } else {
+ image_added = 1;
+ dmux->num_frames_ = 1;
+ }
}
+ if (!image_added) free(frame);
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_;
@@ -509,9 +485,8 @@ 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 has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
// check that this isn't an animation (all frames should be in an ANMF).
- if (anim_chunks > 0 || has_frames) return PARSE_ERROR;
+ if (anim_chunks > 0 || is_animation) return PARSE_ERROR;
Rewind(mem, CHUNK_HEADER_SIZE);
status = ParseSingleImage(dmux);
@@ -548,14 +523,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)) {
@@ -584,6 +559,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
@@ -620,8 +626,8 @@ static int CheckFrameBounds(const Frame* const frame, int exact,
}
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
- const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
- const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
+ const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
+ const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
const Frame* f = dmux->frames_;
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
@@ -630,7 +636,7 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
if (dmux->loop_count_ < 0) return 0;
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
#ifndef WEBP_EXPERIMENTAL_FEATURES
- if (has_fragments) return 0;
+ if (is_fragmented) return 0;
#endif
while (f != NULL) {
@@ -643,9 +649,9 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
const ChunkData* const image = f->img_components_;
const ChunkData* const alpha = f->img_components_ + 1;
- if (has_fragments && !f->is_fragment_) return 0;
- if (!has_fragments && f->is_fragment_) return 0;
- if (!has_frames && f->frame_num_ > 1) return 0;
+ if (is_fragmented && !f->is_fragment_) return 0;
+ if (!is_fragmented && f->is_fragment_) return 0;
+ if (!is_animation && f->frame_num_ > 1) return 0;
if (f->complete_) {
if (alpha->size_ == 0 && image->size_ == 0) return 0;
@@ -669,7 +675,7 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
}
if (f->width_ > 0 && f->height_ > 0 &&
- !CheckFrameBounds(f, !(has_frames || has_fragments),
+ !CheckFrameBounds(f, !(is_animation || is_fragmented),
dmux->canvas_width_, dmux->canvas_height_)) {
return 0;
}
@@ -677,9 +683,8 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
fragment_count += f->is_fragment_;
++frame_count;
}
- if (!has_fragments && frame_count > 1) return 0;
+ if (!is_fragmented && frame_count > 1) return 0;
if (fragment_count > 0 && frame_count != fragment_count) return 0;
- if (f == NULL) break;
}
return 1;
}
@@ -694,6 +699,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;
}
@@ -705,11 +711,20 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
MemBuffer mem;
WebPDemuxer* dmux;
+ if (state != NULL) *state = WEBP_DEMUX_PARSE_ERROR;
+
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL;
if (data == NULL || data->bytes == NULL || data->size == 0) return NULL;
if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL;
- if (!ReadHeader(&mem)) return NULL;
+ status = ReadHeader(&mem);
+ if (status != PARSE_OK) {
+ if (state != NULL) {
+ *state = (status == PARSE_NEED_MORE_DATA) ? WEBP_DEMUX_PARSING_HEADER
+ : WEBP_DEMUX_PARSE_ERROR;
+ }
+ return NULL;
+ }
partial = (mem.buf_size_ < mem.riff_end_);
if (!allow_partial && partial) return NULL;
@@ -718,16 +733,18 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
if (dmux == NULL) return NULL;
InitDemux(dmux, &mem);
+ status = PARSE_ERROR;
for (parser = kMasterChunks; parser->parse != NULL; ++parser) {
if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) {
status = parser->parse(dmux);
if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE;
if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR;
if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR;
+ if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR;
break;
}
}
- if (state) *state = dmux->state_;
+ if (state != NULL) *state = dmux->state_;
if (status == PARSE_ERROR) {
WebPDemuxDelete(dmux);
@@ -983,6 +1000,3 @@ void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) {
(void)iter;
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
« no previous file with comments | « third_party/libwebp/dec/webpi.h ('k') | third_party/libwebp/dsp/cpu.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698