summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/mux
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/libwebp/src/mux')
-rw-r--r--src/3rdparty/libwebp/src/mux/anim_encode.c56
-rw-r--r--src/3rdparty/libwebp/src/mux/animi.h4
-rw-r--r--src/3rdparty/libwebp/src/mux/muxedit.c22
-rw-r--r--src/3rdparty/libwebp/src/mux/muxi.h28
-rw-r--r--src/3rdparty/libwebp/src/mux/muxinternal.c74
-rw-r--r--src/3rdparty/libwebp/src/mux/muxread.c70
6 files changed, 146 insertions, 108 deletions
diff --git a/src/3rdparty/libwebp/src/mux/anim_encode.c b/src/3rdparty/libwebp/src/mux/anim_encode.c
index 6066388..7be9906 100644
--- a/src/3rdparty/libwebp/src/mux/anim_encode.c
+++ b/src/3rdparty/libwebp/src/mux/anim_encode.c
@@ -16,12 +16,12 @@
#include <stdio.h>
#include <stdlib.h> // for abs()
-#include "../mux/animi.h"
-#include "../utils/utils.h"
-#include "../webp/decode.h"
-#include "../webp/encode.h"
-#include "../webp/format_constants.h"
-#include "../webp/mux.h"
+#include "src/mux/animi.h"
+#include "src/utils/utils.h"
+#include "src/webp/decode.h"
+#include "src/webp/encode.h"
+#include "src/webp/format_constants.h"
+#include "src/webp/mux.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
@@ -35,7 +35,7 @@
// Stores frame rectangle dimensions.
typedef struct {
int x_offset_, y_offset_, width_, height_;
-} FrameRect;
+} FrameRectangle;
// Used to store two candidates of encoded data for an animation frame. One of
// the two will be chosen later.
@@ -50,7 +50,7 @@ struct WebPAnimEncoder {
const int canvas_height_; // Canvas height.
const WebPAnimEncoderOptions options_; // Global encoding options.
- FrameRect prev_rect_; // Previous WebP frame rectangle.
+ FrameRectangle prev_rect_; // Previous WebP frame rectangle.
WebPConfig last_config_; // Cached in case a re-encode is needed.
WebPConfig last_config_reversed_; // If 'last_config_' uses lossless, then
// this config uses lossy and vice versa;
@@ -206,7 +206,7 @@ static void ClearRectangle(WebPPicture* const picture,
}
static void WebPUtilClearPic(WebPPicture* const picture,
- const FrameRect* const rect) {
+ const FrameRectangle* const rect) {
if (rect != NULL) {
ClearRectangle(picture, rect->x_offset_, rect->y_offset_,
rect->width_, rect->height_);
@@ -400,7 +400,7 @@ static WEBP_INLINE int ComparePixelsLossy(const uint32_t* src, int src_step,
return 1;
}
-static int IsEmptyRect(const FrameRect* const rect) {
+static int IsEmptyRect(const FrameRectangle* const rect) {
return (rect->width_ == 0) || (rect->height_ == 0);
}
@@ -413,7 +413,7 @@ static int QualityToMaxDiff(float quality) {
// Assumes that an initial valid guess of change rectangle 'rect' is passed.
static void MinimizeChangeRectangle(const WebPPicture* const src,
const WebPPicture* const dst,
- FrameRect* const rect,
+ FrameRectangle* const rect,
int is_lossless, float quality) {
int i, j;
const ComparePixelsFunc compare_pixels =
@@ -498,7 +498,7 @@ static void MinimizeChangeRectangle(const WebPPicture* const src,
}
// Snap rectangle to even offsets (and adjust dimensions if needed).
-static WEBP_INLINE void SnapToEvenOffsets(FrameRect* const rect) {
+static WEBP_INLINE void SnapToEvenOffsets(FrameRectangle* const rect) {
rect->width_ += (rect->x_offset_ & 1);
rect->height_ += (rect->y_offset_ & 1);
rect->x_offset_ &= ~1;
@@ -508,9 +508,9 @@ static WEBP_INLINE void SnapToEvenOffsets(FrameRect* const rect) {
typedef struct {
int should_try_; // Should try this set of parameters.
int empty_rect_allowed_; // Frame with empty rectangle can be skipped.
- FrameRect rect_ll_; // Frame rectangle for lossless compression.
+ FrameRectangle rect_ll_; // Frame rectangle for lossless compression.
WebPPicture sub_frame_ll_; // Sub-frame pic for lossless compression.
- FrameRect rect_lossy_; // Frame rectangle for lossy compression.
+ FrameRectangle rect_lossy_; // Frame rectangle for lossy compression.
// Could be smaller than rect_ll_ as pixels
// with small diffs can be ignored.
WebPPicture sub_frame_lossy_; // Sub-frame pic for lossless compression.
@@ -538,7 +538,8 @@ static void SubFrameParamsFree(SubFrameParams* const params) {
static int GetSubRect(const WebPPicture* const prev_canvas,
const WebPPicture* const curr_canvas, int is_key_frame,
int is_first_frame, int empty_rect_allowed,
- int is_lossless, float quality, FrameRect* const rect,
+ int is_lossless, float quality,
+ FrameRectangle* const rect,
WebPPicture* const sub_frame) {
if (!is_key_frame || is_first_frame) { // Optimize frame rectangle.
// Note: This behaves as expected for first frame, as 'prev_canvas' is
@@ -594,7 +595,7 @@ int WebPAnimEncoderRefineRect(
const WebPPicture* const prev_canvas, const WebPPicture* const curr_canvas,
int is_lossless, float quality, int* const x_offset, int* const y_offset,
int* const width, int* const height) {
- FrameRect rect;
+ FrameRectangle rect;
const int right = clip(*x_offset + *width, 0, curr_canvas->width);
const int left = clip(*x_offset, 0, curr_canvas->width - 1);
const int bottom = clip(*y_offset + *height, 0, curr_canvas->height);
@@ -620,7 +621,7 @@ int WebPAnimEncoderRefineRect(
}
static void DisposeFrameRectangle(int dispose_method,
- const FrameRect* const rect,
+ const FrameRectangle* const rect,
WebPPicture* const curr_canvas) {
assert(rect != NULL);
if (dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
@@ -628,13 +629,13 @@ static void DisposeFrameRectangle(int dispose_method,
}
}
-static uint32_t RectArea(const FrameRect* const rect) {
+static uint32_t RectArea(const FrameRectangle* const rect) {
return (uint32_t)rect->width_ * rect->height_;
}
static int IsLosslessBlendingPossible(const WebPPicture* const src,
const WebPPicture* const dst,
- const FrameRect* const rect) {
+ const FrameRectangle* const rect) {
int i, j;
assert(src->width == dst->width && src->height == dst->height);
assert(rect->x_offset_ + rect->width_ <= dst->width);
@@ -656,7 +657,7 @@ static int IsLosslessBlendingPossible(const WebPPicture* const src,
static int IsLossyBlendingPossible(const WebPPicture* const src,
const WebPPicture* const dst,
- const FrameRect* const rect,
+ const FrameRectangle* const rect,
float quality) {
const int max_allowed_diff_lossy = QualityToMaxDiff(quality);
int i, j;
@@ -683,7 +684,7 @@ static int IsLossyBlendingPossible(const WebPPicture* const src,
// transparent pixels.
// Returns true if at least one pixel gets modified.
static int IncreaseTransparency(const WebPPicture* const src,
- const FrameRect* const rect,
+ const FrameRectangle* const rect,
WebPPicture* const dst) {
int i, j;
int modified = 0;
@@ -709,7 +710,7 @@ static int IncreaseTransparency(const WebPPicture* const src,
// Assumes lossy compression is being used.
// Returns true if at least one pixel gets modified.
static int FlattenSimilarBlocks(const WebPPicture* const src,
- const FrameRect* const rect,
+ const FrameRectangle* const rect,
WebPPicture* const dst, float quality) {
const int max_allowed_diff_lossy = QualityToMaxDiff(quality);
int i, j;
@@ -778,13 +779,13 @@ static int EncodeFrame(const WebPConfig* const config, WebPPicture* const pic,
typedef struct {
WebPMemoryWriter mem_;
WebPMuxFrameInfo info_;
- FrameRect rect_;
+ FrameRectangle rect_;
int evaluate_; // True if this candidate should be evaluated.
} Candidate;
// Generates a candidate encoded frame given a picture and metadata.
static WebPEncodingError EncodeCandidate(WebPPicture* const sub_frame,
- const FrameRect* const rect,
+ const FrameRectangle* const rect,
const WebPConfig* const encoder_config,
int use_blending,
Candidate* const candidate) {
@@ -958,7 +959,7 @@ static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
if (new_duration >= MAX_DURATION) { // Special case.
// Separate out previous frame from earlier merged frames to avoid overflow.
// We add a 1x1 transparent frame for the previous frame, with blending on.
- const FrameRect rect = { 0, 0, 1, 1 };
+ const FrameRectangle rect = { 0, 0, 1, 1 };
const uint8_t lossless_1x1_bytes[] = {
0x52, 0x49, 0x46, 0x46, 0x14, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
0x56, 0x50, 0x38, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
@@ -1223,7 +1224,7 @@ static int CacheFrame(WebPAnimEncoder* const enc,
enc->prev_candidate_undecided_ = 0;
} else {
int64_t curr_delta;
- FrameRect prev_rect_key, prev_rect_sub;
+ FrameRectangle prev_rect_key, prev_rect_sub;
// Add this as a frame rectangle to enc.
error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped);
@@ -1535,7 +1536,8 @@ int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WebPData* webp_data) {
if (!enc->got_null_frame_ && enc->in_frame_count_ > 1 && enc->count_ > 0) {
// set duration of the last frame to be avg of durations of previous frames.
- const double delta_time = enc->prev_timestamp_ - enc->first_timestamp_;
+ const double delta_time =
+ (uint32_t)enc->prev_timestamp_ - enc->first_timestamp_;
const int average_duration = (int)(delta_time / (enc->in_frame_count_ - 1));
if (!IncreasePreviousDuration(enc, average_duration)) {
return 0;
diff --git a/src/3rdparty/libwebp/src/mux/animi.h b/src/3rdparty/libwebp/src/mux/animi.h
index cecaf1f..34c45ba 100644
--- a/src/3rdparty/libwebp/src/mux/animi.h
+++ b/src/3rdparty/libwebp/src/mux/animi.h
@@ -14,7 +14,7 @@
#ifndef WEBP_MUX_ANIMI_H_
#define WEBP_MUX_ANIMI_H_
-#include "../webp/mux.h"
+#include "src/webp/mux.h"
#ifdef __cplusplus
extern "C" {
@@ -40,4 +40,4 @@ int WebPAnimEncoderRefineRect(
} // extern "C"
#endif
-#endif /* WEBP_MUX_ANIMI_H_ */
+#endif // WEBP_MUX_ANIMI_H_
diff --git a/src/3rdparty/libwebp/src/mux/muxedit.c b/src/3rdparty/libwebp/src/mux/muxedit.c
index d2c5305..ccf14b2 100644
--- a/src/3rdparty/libwebp/src/mux/muxedit.c
+++ b/src/3rdparty/libwebp/src/mux/muxedit.c
@@ -13,8 +13,8 @@
// Vikas (vikasa@google.com)
#include <assert.h>
-#include "./muxi.h"
-#include "../utils/utils.h"
+#include "src/mux/muxi.h"
+#include "src/utils/utils.h"
//------------------------------------------------------------------------------
// Life of a mux object.
@@ -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/src/3rdparty/libwebp/src/mux/muxi.h b/src/3rdparty/libwebp/src/mux/muxi.h
index e6606aa..7bc0b07 100644
--- a/src/3rdparty/libwebp/src/mux/muxi.h
+++ b/src/3rdparty/libwebp/src/mux/muxi.h
@@ -14,10 +14,11 @@
#ifndef WEBP_MUX_MUXI_H_
#define WEBP_MUX_MUXI_H_
+#include <assert.h>
#include <stdlib.h>
-#include "../dec/vp8i_dec.h"
-#include "../dec/vp8li_dec.h"
-#include "../webp/mux.h"
+#include "src/dec/vp8i_dec.h"
+#include "src/dec/vp8li_dec.h"
+#include "src/webp/mux.h"
#ifdef __cplusplus
extern "C" {
@@ -26,9 +27,9 @@ extern "C" {
//------------------------------------------------------------------------------
// Defines and constants.
-#define MUX_MAJ_VERSION 0
-#define MUX_MIN_VERSION 4
-#define MUX_REV_VERSION 0
+#define MUX_MAJ_VERSION 1
+#define MUX_MIN_VERSION 0
+#define MUX_REV_VERSION 3
// 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/src/3rdparty/libwebp/src/mux/muxinternal.c b/src/3rdparty/libwebp/src/mux/muxinternal.c
index 387b57e..b9ee671 100644
--- a/src/3rdparty/libwebp/src/mux/muxinternal.c
+++ b/src/3rdparty/libwebp/src/mux/muxinternal.c
@@ -13,8 +13,8 @@
// Vikas (vikasa@google.com)
#include <assert.h>
-#include "./muxi.h"
-#include "../utils/utils.h"
+#include "src/mux/muxi.h"
+#include "src/utils/utils.h"
#define UNDEFINED_CHUNK_SIZE ((uint32_t)(-1))
@@ -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_;
@@ -504,6 +501,20 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
if (!has_animation && (num_anim == 1 || num_frames > 0)) {
return WEBP_MUX_INVALID_ARGUMENT;
}
+ if (!has_animation) {
+ const WebPMuxImage* images = mux->images_;
+ // There can be only one image.
+ if (images == NULL || images->next_ != NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ // Size must match.
+ if (mux->canvas_width_ > 0) {
+ if (images->width_ != mux->canvas_width_ ||
+ images->height_ != mux->canvas_height_) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ }
+ }
}
// Verify either VP8X chunk is present OR there is only one elem in
@@ -515,6 +526,7 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT;
// ALPHA_FLAG & alpha chunk(s) are consistent.
+ // Note: ALPHA_FLAG can be set when there is actually no Alpha data present.
if (MuxHasAlpha(mux->images_)) {
if (num_vp8x > 0) {
// VP8X chunk is present, so it should contain ALPHA_FLAG.
@@ -525,8 +537,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
if (err != WEBP_MUX_OK) return err;
if (num_alpha > 0) return WEBP_MUX_INVALID_ARGUMENT;
}
- } else { // Mux doesn't need alpha. So, ALPHA_FLAG should NOT be present.
- if (flags & ALPHA_FLAG) return WEBP_MUX_INVALID_ARGUMENT;
}
return WEBP_MUX_OK;
diff --git a/src/3rdparty/libwebp/src/mux/muxread.c b/src/3rdparty/libwebp/src/mux/muxread.c
index 410acd9..268f6ac 100644
--- a/src/3rdparty/libwebp/src/mux/muxread.c
+++ b/src/3rdparty/libwebp/src/mux/muxread.c
@@ -13,8 +13,8 @@
// Vikas (vikasa@google.com)
#include <assert.h>
-#include "./muxi.h"
-#include "../utils/utils.h"
+#include "src/mux/muxi.h"
+#include "src/utils/utils.h"
//------------------------------------------------------------------------------
// Helper method(s).
@@ -43,7 +43,7 @@ static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
SWITCH_ID_LIST(IDX_ANIM, mux->anim_);
SWITCH_ID_LIST(IDX_EXIF, mux->exif_);
SWITCH_ID_LIST(IDX_XMP, mux->xmp_);
- SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_);
+ assert(idx != IDX_UNKNOWN);
return WEBP_MUX_NOT_FOUND;
}
#undef SWITCH_ID_LIST
@@ -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;
}
@@ -270,6 +285,9 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
ChunkInit(&chunk);
}
+ // Incomplete image.
+ if (wpi->is_partial_) goto Err;
+
// Validate mux if complete.
if (MuxValidate(mux) != WEBP_MUX_OK) goto Err;
@@ -382,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);