diff options
Diffstat (limited to 'thirdparty/libwebp/src/mux')
-rw-r--r-- | thirdparty/libwebp/src/mux/animi.h | 2 | ||||
-rw-r--r-- | thirdparty/libwebp/src/mux/muxedit.c | 18 | ||||
-rw-r--r-- | thirdparty/libwebp/src/mux/muxi.h | 18 | ||||
-rw-r--r-- | thirdparty/libwebp/src/mux/muxinternal.c | 53 | ||||
-rw-r--r-- | thirdparty/libwebp/src/mux/muxread.c | 61 |
5 files changed, 86 insertions, 66 deletions
diff --git a/thirdparty/libwebp/src/mux/animi.h b/thirdparty/libwebp/src/mux/animi.h index 88899532aa..34c45ba4da 100644 --- a/thirdparty/libwebp/src/mux/animi.h +++ b/thirdparty/libwebp/src/mux/animi.h @@ -40,4 +40,4 @@ int WebPAnimEncoderRefineRect( } // extern "C" #endif -#endif /* WEBP_MUX_ANIMI_H_ */ +#endif // WEBP_MUX_ANIMI_H_ diff --git a/thirdparty/libwebp/src/mux/muxedit.c b/thirdparty/libwebp/src/mux/muxedit.c index 7a027b3cb4..ccf14b2a0c 100644 --- a/thirdparty/libwebp/src/mux/muxedit.c +++ b/thirdparty/libwebp/src/mux/muxedit.c @@ -69,12 +69,12 @@ void WebPMuxDelete(WebPMux* mux) { if (idx == (INDEX)) { \ err = ChunkAssignData(&chunk, data, copy_data, tag); \ if (err == WEBP_MUX_OK) { \ - err = ChunkSetNth(&chunk, (LIST), nth); \ + err = ChunkSetHead(&chunk, (LIST)); \ } \ return err; \ } -static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, uint32_t nth, +static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, const WebPData* const data, int copy_data) { WebPChunk chunk; WebPMuxError err = WEBP_MUX_NOT_FOUND; @@ -190,7 +190,7 @@ WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4], if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; // Add the given chunk. - return MuxSet(mux, tag, 1, chunk_data, copy_data); + return MuxSet(mux, tag, chunk_data, copy_data); } // Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'. @@ -202,7 +202,7 @@ static WebPMuxError AddDataToChunkList( ChunkInit(&chunk); err = ChunkAssignData(&chunk, data, copy_data, tag); if (err != WEBP_MUX_OK) goto Err; - err = ChunkSetNth(&chunk, chunk_list, 1); + err = ChunkSetHead(&chunk, chunk_list); if (err != WEBP_MUX_OK) goto Err; return WEBP_MUX_OK; Err: @@ -266,14 +266,14 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info, int copy_data) { WebPMuxImage wpi; WebPMuxError err; - const WebPData* const bitstream = &info->bitstream; // Sanity checks. if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT; if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT; - if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) { + if (info->bitstream.bytes == NULL || + info->bitstream.size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } @@ -287,7 +287,7 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info, } MuxImageInit(&wpi); - err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi); + err = SetAlphaAndImageChunks(&info->bitstream, copy_data, &wpi); if (err != WEBP_MUX_OK) goto Err; assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful. @@ -342,7 +342,7 @@ WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux, // Set the animation parameters. PutLE32(data, params->bgcolor); PutLE16(data + 4, params->loop_count); - return MuxSet(mux, kChunks[IDX_ANIM].tag, 1, &anim, 1); + return MuxSet(mux, kChunks[IDX_ANIM].tag, &anim, 1); } WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux, @@ -540,7 +540,7 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { PutLE24(data + 4, width - 1); // canvas width. PutLE24(data + 7, height - 1); // canvas height. - return MuxSet(mux, kChunks[IDX_VP8X].tag, 1, &vp8x, 1); + return MuxSet(mux, kChunks[IDX_VP8X].tag, &vp8x, 1); } // Cleans up 'mux' by removing any unnecessary chunks. diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h index 6b57eea30f..df9f74c63c 100644 --- a/thirdparty/libwebp/src/mux/muxi.h +++ b/thirdparty/libwebp/src/mux/muxi.h @@ -14,6 +14,7 @@ #ifndef WEBP_MUX_MUXI_H_ #define WEBP_MUX_MUXI_H_ +#include <assert.h> #include <stdlib.h> #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" @@ -28,7 +29,7 @@ extern "C" { #define MUX_MAJ_VERSION 1 #define MUX_MIN_VERSION 0 -#define MUX_REV_VERSION 0 +#define MUX_REV_VERSION 1 // Chunk object. typedef struct WebPChunk WebPChunk; @@ -126,11 +127,14 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag); WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, int copy_data, uint32_t tag); -// Sets 'chunk' at nth position in the 'chunk_list'. -// nth = 0 has the special meaning "last of the list". +// Sets 'chunk' as the only element in 'chunk_list' if it is empty. // On success ownership is transferred from 'chunk' to the 'chunk_list'. -WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list, - uint32_t nth); +WebPMuxError ChunkSetHead(WebPChunk* const chunk, WebPChunk** const chunk_list); +// Sets 'chunk' at last position in the 'chunk_list'. +// On success ownership is transferred from 'chunk' to the 'chunk_list'. +// *chunk_list also points towards the last valid element of the initial +// *chunk_list. +WebPMuxError ChunkAppend(WebPChunk* const chunk, WebPChunk*** const chunk_list); // Releases chunk and returns chunk->next_. WebPChunk* ChunkRelease(WebPChunk* const chunk); @@ -143,13 +147,13 @@ void ChunkListDelete(WebPChunk** const chunk_list); // Returns size of the chunk including chunk header and padding byte (if any). static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) { + assert(chunk_size <= MAX_CHUNK_PAYLOAD); return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U); } // Size of a chunk including header and padding. static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) { const size_t data_size = chunk->data_.size; - assert(data_size < MAX_CHUNK_PAYLOAD); return SizeWithPadding(data_size); } @@ -227,4 +231,4 @@ WebPMuxError MuxValidate(const WebPMux* const mux); } // extern "C" #endif -#endif /* WEBP_MUX_MUXI_H_ */ +#endif // WEBP_MUX_MUXI_H_ diff --git a/thirdparty/libwebp/src/mux/muxinternal.c b/thirdparty/libwebp/src/mux/muxinternal.c index 1473f100e5..b9ee6717d3 100644 --- a/thirdparty/libwebp/src/mux/muxinternal.c +++ b/thirdparty/libwebp/src/mux/muxinternal.c @@ -111,27 +111,6 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) { return ((nth > 0) && (iter > 0)) ? NULL : first; } -// Outputs a pointer to 'prev_chunk->next_', -// where 'prev_chunk' is the pointer to the chunk at position (nth - 1). -// Returns true if nth chunk was found. -static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth, - WebPChunk*** const location) { - uint32_t count = 0; - assert(chunk_list != NULL); - *location = chunk_list; - - while (*chunk_list != NULL) { - WebPChunk* const cur_chunk = *chunk_list; - ++count; - if (count == nth) return 1; // Found. - chunk_list = &cur_chunk->next_; - *location = chunk_list; - } - - // *chunk_list is ok to be NULL if adding at last location. - return (nth == 0 || (count == nth - 1)) ? 1 : 0; -} - //------------------------------------------------------------------------------ // Chunk writer methods. @@ -156,11 +135,12 @@ WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, return WEBP_MUX_OK; } -WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list, - uint32_t nth) { +WebPMuxError ChunkSetHead(WebPChunk* const chunk, + WebPChunk** const chunk_list) { WebPChunk* new_chunk; - if (!ChunkSearchListToSet(chunk_list, nth, &chunk_list)) { + assert(chunk_list != NULL); + if (*chunk_list != NULL) { return WEBP_MUX_NOT_FOUND; } @@ -168,11 +148,26 @@ WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list, if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR; *new_chunk = *chunk; chunk->owner_ = 0; - new_chunk->next_ = *chunk_list; + new_chunk->next_ = NULL; *chunk_list = new_chunk; return WEBP_MUX_OK; } +WebPMuxError ChunkAppend(WebPChunk* const chunk, + WebPChunk*** const chunk_list) { + assert(chunk_list != NULL && *chunk_list != NULL); + + if (**chunk_list == NULL) { + ChunkSetHead(chunk, *chunk_list); + } else { + WebPChunk* last_chunk = **chunk_list; + while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_; + ChunkSetHead(chunk, &last_chunk->next_); + *chunk_list = &last_chunk->next_; + } + return WEBP_MUX_OK; +} + //------------------------------------------------------------------------------ // Chunk deletion method(s). @@ -232,9 +227,11 @@ void MuxImageInit(WebPMuxImage* const wpi) { WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) { WebPMuxImage* next; if (wpi == NULL) return NULL; - ChunkDelete(wpi->header_); - ChunkDelete(wpi->alpha_); - ChunkDelete(wpi->img_); + // There should be at most one chunk of header_, alpha_, img_ but we call + // ChunkListDelete to be safe + ChunkListDelete(&wpi->header_); + ChunkListDelete(&wpi->alpha_); + ChunkListDelete(&wpi->img_); ChunkListDelete(&wpi->unknown_); next = wpi->next_; diff --git a/thirdparty/libwebp/src/mux/muxread.c b/thirdparty/libwebp/src/mux/muxread.c index 0b55286862..268f6acb53 100644 --- a/thirdparty/libwebp/src/mux/muxread.c +++ b/thirdparty/libwebp/src/mux/muxread.c @@ -59,6 +59,7 @@ static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk, // Sanity checks. if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA; chunk_size = GetLE32(data + TAG_SIZE); + if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA; { const size_t chunk_disk_size = SizeWithPadding(chunk_size); @@ -102,6 +103,7 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data, const uint8_t* const last = bytes + size; WebPChunk subchunk; size_t subchunk_size; + WebPChunk** unknown_chunk_list = &wpi->unknown_; ChunkInit(&subchunk); assert(chunk->tag_ == kChunks[IDX_ANMF].tag); @@ -116,7 +118,7 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data, if (size < hdr_size) goto Fail; ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_); } - ChunkSetNth(&subchunk, &wpi->header_, 1); + ChunkSetHead(&subchunk, &wpi->header_); wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks. // Rest of the chunks. @@ -133,18 +135,23 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data, switch (ChunkGetIdFromTag(subchunk.tag_)) { case WEBP_CHUNK_ALPHA: if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks. - if (ChunkSetNth(&subchunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Fail; + if (ChunkSetHead(&subchunk, &wpi->alpha_) != WEBP_MUX_OK) goto Fail; wpi->is_partial_ = 1; // Waiting for a VP8 chunk. break; case WEBP_CHUNK_IMAGE: - if (ChunkSetNth(&subchunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Fail; + if (wpi->img_ != NULL) goto Fail; // Only 1 image chunk allowed. + if (ChunkSetHead(&subchunk, &wpi->img_) != WEBP_MUX_OK) goto Fail; if (!MuxImageFinalize(wpi)) goto Fail; wpi->is_partial_ = 0; // wpi is completely filled. break; case WEBP_CHUNK_UNKNOWN: - if (wpi->is_partial_) goto Fail; // Encountered an unknown chunk - // before some image chunks. - if (ChunkSetNth(&subchunk, &wpi->unknown_, 0) != WEBP_MUX_OK) goto Fail; + if (wpi->is_partial_) { + goto Fail; // Encountered an unknown chunk + // before some image chunks. + } + if (ChunkAppend(&subchunk, &unknown_chunk_list) != WEBP_MUX_OK) { + goto Fail; + } break; default: goto Fail; @@ -175,6 +182,9 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, const uint8_t* data; size_t size; WebPChunk chunk; + // Stores the end of the chunk lists so that it is faster to append data to + // their ends. + WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL }; ChunkInit(&chunk); // Sanity checks. @@ -187,7 +197,7 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, size = bitstream->size; if (data == NULL) return NULL; - if (size < RIFF_HEADER_SIZE) return NULL; + if (size < RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE) return NULL; if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') || GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) { return NULL; @@ -196,8 +206,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, mux = WebPMuxNew(); if (mux == NULL) return NULL; - if (size < RIFF_HEADER_SIZE + TAG_SIZE) goto Err; - tag = GetLE32(data + RIFF_HEADER_SIZE); if (tag != kChunks[IDX_VP8].tag && tag != kChunks[IDX_VP8L].tag && @@ -205,13 +213,17 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, goto Err; // First chunk should be VP8, VP8L or VP8X. } - riff_size = SizeWithPadding(GetLE32(data + TAG_SIZE)); - if (riff_size > MAX_CHUNK_PAYLOAD || riff_size > size) { - goto Err; - } else { - if (riff_size < size) { // Redundant data after last chunk. - size = riff_size; // To make sure we don't read any data beyond mux_size. - } + riff_size = GetLE32(data + TAG_SIZE); + if (riff_size > MAX_CHUNK_PAYLOAD) goto Err; + + // Note this padding is historical and differs from demux.c which does not + // pad the file size. + riff_size = SizeWithPadding(riff_size); + if (riff_size < CHUNK_HEADER_SIZE) goto Err; + if (riff_size > size) goto Err; + // There's no point in reading past the end of the RIFF chunk. + if (size > riff_size + CHUNK_HEADER_SIZE) { + size = riff_size + CHUNK_HEADER_SIZE; } end = data + size; @@ -226,7 +238,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, while (data != end) { size_t data_size; WebPChunkId id; - WebPChunk** chunk_list; if (ChunkVerifyAndAssign(&chunk, data, size, riff_size, copy_data) != WEBP_MUX_OK) { goto Err; @@ -236,11 +247,11 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, switch (id) { case WEBP_CHUNK_ALPHA: if (wpi->alpha_ != NULL) goto Err; // Consecutive ALPH chunks. - if (ChunkSetNth(&chunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Err; + if (ChunkSetHead(&chunk, &wpi->alpha_) != WEBP_MUX_OK) goto Err; wpi->is_partial_ = 1; // Waiting for a VP8 chunk. break; case WEBP_CHUNK_IMAGE: - if (ChunkSetNth(&chunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Err; + if (ChunkSetHead(&chunk, &wpi->img_) != WEBP_MUX_OK) goto Err; if (!MuxImageFinalize(wpi)) goto Err; wpi->is_partial_ = 0; // wpi is completely filled. PushImage: @@ -257,9 +268,13 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, default: // A non-image chunk. if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before // getting all chunks of an image. - chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk. - if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err; + if (chunk_list_ends[id] == NULL) { + chunk_list_ends[id] = + MuxGetChunkListFromId(mux, id); // List to add this chunk. + } + if (ChunkAppend(&chunk, &chunk_list_ends[id]) != WEBP_MUX_OK) goto Err; if (id == WEBP_CHUNK_VP8X) { // grab global specs + if (data_size < CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE) goto Err; mux->canvas_width_ = GetLE24(data + 12) + 1; mux->canvas_height_ = GetLE24(data + 15) + 1; } @@ -385,6 +400,10 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size); if (data == NULL) return WEBP_MUX_MEMORY_ERROR; + // There should be at most one alpha_ chunk and exactly one img_ chunk. + assert(wpi->alpha_ == NULL || wpi->alpha_->next_ == NULL); + assert(wpi->img_ != NULL && wpi->img_->next_ == NULL); + // Main RIFF header. dst = MuxEmitRiffHeader(data, size); |