From 1693fd9b168be16776c05d2aaa025003e0df1126 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Fri, 26 Jul 2013 14:35:46 -0700 Subject: [PATCH] Demux: A new state WEBP_DEMUX_PARSE_ERROR WebPDemuxPartial() returns NULL for both of the following cases: - There was a parsing error. - It doesn't have enough data to start parsing. Now, one can differentiate between these two cases by checking the value of 'state' returned by WebPDemuxPartial(). Change-Id: Ia2377f0c516b3fcfae475c0662c4932d2eddcd0b --- src/demux/demux.c | 27 +++++++++++++++++++-------- src/webp/demux.h | 11 +++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/demux/demux.c b/src/demux/demux.c index 4eca1f73..8711baa3 100644 --- a/src/demux/demux.c +++ b/src/demux/demux.c @@ -390,20 +390,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; @@ -412,7 +412,7 @@ static int ReadHeader(MemBuffer* const mem) { } Skip(mem, RIFF_HEADER_SIZE); - return 1; + return PARSE_OK; } static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { @@ -692,11 +692,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; @@ -705,16 +714,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); diff --git a/src/webp/demux.h b/src/webp/demux.h index e89ff012..f9b3fd1e 100644 --- a/src/webp/demux.h +++ b/src/webp/demux.h @@ -73,9 +73,11 @@ WEBP_EXTERN(int) WebPGetDemuxVersion(void); // Life of a Demux object typedef enum WebPDemuxState { - WEBP_DEMUX_PARSING_HEADER, // Not enough data to parse full header. - WEBP_DEMUX_PARSED_HEADER, // Header parsing complete, data may be available. - WEBP_DEMUX_DONE // Entire file has been parsed. + WEBP_DEMUX_PARSE_ERROR = -1, // An error occurred while parsing. + WEBP_DEMUX_PARSING_HEADER = 0, // Not enough data to parse full header. + WEBP_DEMUX_PARSED_HEADER = 1, // Header parsing complete, + // data may be available. + WEBP_DEMUX_DONE = 2 // Entire file has been parsed. } WebPDemuxState; // Internal, version-checked, entry point @@ -90,7 +92,8 @@ static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) { // Parses the possibly incomplete WebP file given by 'data'. // If 'state' is non-NULL it will be set to indicate the status of the demuxer. -// Returns a WebPDemuxer object on successful parse, NULL otherwise. +// Returns NULL in case of error or if there isn't enough data to start parsing; +// and a WebPDemuxer object on successful parse. static WEBP_INLINE WebPDemuxer* WebPDemuxPartial( const WebPData* data, WebPDemuxState* state) { return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);