Fix -fbounds-safety errors in dec.

This change adds -fbounds-safety annotations to several pointers in the
`dec` directory. These annotations resolve errors and warnings that
arose from interactions with annotated functions in `utils`.

Bug: 465196207
Change-Id: I89554b85b19cd068c619c3ed2a31c36eb93d552a
This commit is contained in:
Arman Hasanzadeh
2025-12-01 12:38:33 -08:00
parent 3532891de4
commit b81f462050
13 changed files with 331 additions and 208 deletions

View File

@@ -423,10 +423,12 @@ target_include_directories(webputils PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
add_library(webp $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdsp> add_library(webp $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdsp>
$<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>) $<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>)
if(WEBP_ENABLE_FBOUNDS_SAFETY) if(WEBP_ENABLE_FBOUNDS_SAFETY)
# Enable -fbounds-safety only for webputils for now. # Enable -fbounds-safety only for webputils and webpdecode(r) for now.
add_definitions(-DWEBP_SUPPORT_FBOUNDS_SAFETY=1) add_definitions(-DWEBP_SUPPORT_FBOUNDS_SAFETY=1)
target_compile_options(webputils PRIVATE -fbounds-safety) target_compile_options(webputils PRIVATE -fbounds-safety)
target_compile_options(webputilsdecode PRIVATE -fbounds-safety) target_compile_options(webputilsdecode PRIVATE -fbounds-safety)
target_compile_options(webpdecode PRIVATE -fbounds-safety)
target_compile_options(webpdecoder PRIVATE -fbounds-safety)
endif() endif()
target_link_libraries(webp sharpyuv) target_link_libraries(webp sharpyuv)

View File

@@ -106,7 +106,12 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
ok = (alpha_data_size >= alpha_decoded_size); ok = (alpha_data_size >= alpha_decoded_size);
} else { } else {
assert(dec->method == ALPHA_LOSSLESS_COMPRESSION); assert(dec->method == ALPHA_LOSSLESS_COMPRESSION);
ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size); {
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_alpha_data =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, alpha_data,
alpha_data_size);
ok = VP8LDecodeAlphaHeader(dec, bounded_alpha_data, alpha_data_size);
}
} }
return ok; return ok;
@@ -225,7 +230,11 @@ WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
if (dec->alpha_dithering > 0) { if (dec->alpha_dithering > 0) {
uint8_t* const alpha = uint8_t* const alpha =
dec->alpha_plane + io->crop_top * width + io->crop_left; dec->alpha_plane + io->crop_top * width + io->crop_left;
if (!WebPDequantizeLevels(alpha, io->crop_right - io->crop_left, uint8_t* WEBP_BIDI_INDEXABLE const bounded_alpha =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
uint8_t*, alpha,
(size_t)width*(io->crop_bottom - io->crop_top));
if (!WebPDequantizeLevels(bounded_alpha, io->crop_right - io->crop_left,
io->crop_bottom - io->crop_top, width, io->crop_bottom - io->crop_top, width,
dec->alpha_dithering)) { dec->alpha_dithering)) {
goto Error; goto Error;

View File

@@ -144,20 +144,30 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
// parse the partitions). The bitreader is only used meaningfully when // parse the partitions). The bitreader is only used meaningfully when
// there is enough data to begin parsing partition 0. // there is enough data to begin parsing partition 0.
if (last_start != NULL) { if (last_start != NULL) {
VP8BitReaderSetBuffer(&dec->parts[last_part], last_start, const size_t part_size = mem->buf + mem->end - last_start;
mem->buf + mem->end - last_start); const uint8_t* WEBP_BIDI_INDEXABLE const bounded_last_start =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, last_start,
part_size);
VP8BitReaderSetBuffer(&dec->parts[last_part], bounded_last_start,
part_size);
} }
} }
if (NeedCompressedAlpha(idec)) { if (NeedCompressedAlpha(idec)) {
ALPHDecoder* const alph_dec = dec->alph_dec; ALPHDecoder* const alph_dec = dec->alph_dec;
dec->alpha_data += offset; dec->alpha_data += offset;
dec->alpha_data_size = dec->alpha_data_size;
if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) { if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) {
if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) { if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) {
VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec; VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec;
size_t data_size;
const uint8_t* WEBP_BIDI_INDEXABLE bounded_alpha_data;
assert(dec->alpha_data_size >= ALPHA_HEADER_LEN); assert(dec->alpha_data_size >= ALPHA_HEADER_LEN);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br, data_size = dec->alpha_data_size - ALPHA_HEADER_LEN;
dec->alpha_data + ALPHA_HEADER_LEN, bounded_alpha_data = WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
dec->alpha_data_size - ALPHA_HEADER_LEN); const uint8_t*, dec->alpha_data + ALPHA_HEADER_LEN, data_size);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br, bounded_alpha_data,
data_size);
} else { // alph_dec->method == ALPHA_NO_COMPRESSION } else { // alph_dec->method == ALPHA_NO_COMPRESSION
// Nothing special to do in this case. // Nothing special to do in this case.
} }
@@ -165,7 +175,10 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
} }
} else { // Resize lossless bitreader } else { // Resize lossless bitreader
VP8LDecoder* const dec = (VP8LDecoder*)idec->dec; VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
VP8LBitReaderSetBuffer(&dec->br, new_base, MemDataSize(mem)); const size_t data_size = MemDataSize(mem);
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_new_base =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, new_base, data_size);
VP8LBitReaderSetBuffer(&dec->br, bounded_new_base, data_size);
} }
} }
} }
@@ -328,7 +341,8 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
VP8StatusCode status; VP8StatusCode status;
WebPHeaderStructure headers; WebPHeaderStructure headers;
headers.data = data; headers.data =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, data, curr_size);
headers.data_size = curr_size; headers.data_size = curr_size;
headers.have_all_data = 0; headers.have_all_data = 0;
status = WebPParseHeaders(&headers); status = WebPParseHeaders(&headers);
@@ -371,8 +385,13 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
// Not enough data bytes to extract VP8 Frame Header. // Not enough data bytes to extract VP8 Frame Header.
return VP8_STATUS_SUSPENDED; return VP8_STATUS_SUSPENDED;
} }
if (!VP8GetInfo(data, curr_size, idec->chunk_size, &width, &height)) { {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); const uint8_t* WEBP_BIDI_INDEXABLE const bounded_data =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, data, curr_size);
if (!VP8GetInfo(bounded_data, curr_size, idec->chunk_size, &width,
&height)) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
} }
bits = data[0] | (data[1] << 8) | (data[2] << 16); bits = data[0] | (data[1] << 8) | (data[2] << 16);
@@ -399,7 +418,8 @@ static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
} }
if (mem->mode == MEM_MODE_APPEND) { if (mem->mode == MEM_MODE_APPEND) {
// We copy and grab ownership of the partition #0 data. // We copy and grab ownership of the partition #0 data.
uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size); uint8_t* WEBP_BIDI_INDEXABLE const part0_buf =
(uint8_t*)WebPSafeMalloc(1ULL, part_size);
if (part0_buf == NULL) { if (part0_buf == NULL) {
return VP8_STATUS_OUT_OF_MEMORY; return VP8_STATUS_OUT_OF_MEMORY;
} }
@@ -660,8 +680,8 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
return NewDecoder(output_buffer, NULL); return NewDecoder(output_buffer, NULL);
} }
WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, WebPIDecoder* WebPIDecode(const uint8_t* WEBP_COUNTED_BY(data_size) data,
WebPDecoderConfig* config) { size_t data_size, WebPDecoderConfig* config) {
WebPIDecoder* idec; WebPIDecoder* idec;
WebPBitstreamFeatures tmp_features; WebPBitstreamFeatures tmp_features;
WebPBitstreamFeatures* const features = WebPBitstreamFeatures* const features =
@@ -710,13 +730,16 @@ void WebPIDelete(WebPIDecoder* idec) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Wrapper toward WebPINewDecoder // Wrapper toward WebPINewDecoder
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer, WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp,
uint8_t* WEBP_COUNTED_BY(output_buffer_size)
output_buffer,
size_t output_buffer_size, int output_stride) { size_t output_buffer_size, int output_stride) {
const int is_external_memory = (output_buffer != NULL) ? 1 : 0; const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
WebPIDecoder* idec; WebPIDecoder* idec;
if (csp >= MODE_YUV) return NULL; if (csp >= MODE_YUV) return NULL;
if (is_external_memory == 0) { // Overwrite parameters to sane values. if (is_external_memory == 0) { // Overwrite parameters to sane values.
output_buffer = NULL;
output_buffer_size = 0; output_buffer_size = 0;
output_stride = 0; output_stride = 0;
} else { // A buffer was passed. Validate the other params. } else { // A buffer was passed. Validate the other params.
@@ -734,18 +757,27 @@ WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
return idec; return idec;
} }
WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride, WebPIDecoder* WebPINewYUVA(uint8_t* WEBP_COUNTED_BY(luma_size) luma,
uint8_t* u, size_t u_size, int u_stride, uint8_t* v, size_t luma_size, int luma_stride,
size_t v_size, int v_stride, uint8_t* a, uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size,
size_t a_size, int a_stride) { int u_stride, uint8_t* WEBP_COUNTED_BY(v_size) v,
size_t v_size, int v_stride,
uint8_t* WEBP_COUNTED_BY(a_size) a, size_t a_size,
int a_stride) {
const int is_external_memory = (luma != NULL) ? 1 : 0; const int is_external_memory = (luma != NULL) ? 1 : 0;
WebPIDecoder* idec; WebPIDecoder* idec;
WEBP_CSP_MODE colorspace; WEBP_CSP_MODE colorspace;
if (is_external_memory == 0) { // Overwrite parameters to sane values. if (is_external_memory == 0) { // Overwrite parameters to sane values.
luma_size = u_size = v_size = a_size = 0; luma = NULL;
luma_size = 0;
u = NULL;
u_size = 0;
v = NULL;
v_size = 0;
a = NULL;
a_size = 0;
luma_stride = u_stride = v_stride = a_stride = 0; luma_stride = u_stride = v_stride = a_stride = 0;
u = v = a = NULL;
colorspace = MODE_YUVA; colorspace = MODE_YUVA;
} else { // A luma buffer was passed. Validate the other parameters. } else { // A luma buffer was passed. Validate the other parameters.
if (u == NULL || v == NULL) return NULL; if (u == NULL || v == NULL) return NULL;
@@ -777,8 +809,10 @@ WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
return idec; return idec;
} }
WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride, WebPIDecoder* WebPINewYUV(uint8_t* WEBP_COUNTED_BY(luma_size) luma,
uint8_t* u, size_t u_size, int u_stride, uint8_t* v, size_t luma_size, int luma_stride,
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size,
int u_stride, uint8_t* WEBP_COUNTED_BY(v_size) v,
size_t v_size, int v_stride) { size_t v_size, int v_stride) {
return WebPINewYUVA(luma, luma_size, luma_stride, u, u_size, u_stride, v, return WebPINewYUVA(luma, luma_size, luma_stride, u, u_size, u_stride, v,
v_size, v_stride, NULL, 0, 0); v_size, v_stride, NULL, 0, 0);
@@ -797,7 +831,8 @@ static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
return VP8_STATUS_SUSPENDED; return VP8_STATUS_SUSPENDED;
} }
VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data, VP8StatusCode WebPIAppend(WebPIDecoder* idec,
const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size) { size_t data_size) {
VP8StatusCode status; VP8StatusCode status;
if (idec == NULL || data == NULL) { if (idec == NULL || data == NULL) {
@@ -818,7 +853,8 @@ VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data,
return IDecode(idec); return IDecode(idec);
} }
VP8StatusCode WebPIUpdate(WebPIDecoder* idec, const uint8_t* data, VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size) { size_t data_size) {
VP8StatusCode status; VP8StatusCode status;
if (idec == NULL || data == NULL) { if (idec == NULL || data == NULL) {

View File

@@ -311,7 +311,7 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
uint64_t total_size; uint64_t total_size;
size_t rescaler_size; size_t rescaler_size;
rescaler_t* work; rescaler_t* WEBP_BIDI_INDEXABLE work;
WebPRescaler* scalers; WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3; const int num_rescalers = has_alpha ? 4 : 3;
@@ -325,11 +325,11 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
return 0; return 0;
} }
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size); work = (rescaler_t*)WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) { if (work == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (rescaler_t*)p->memory; p->memory = work;
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size - scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size -
rescaler_size); rescaler_size);
@@ -499,8 +499,9 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int uv_in_height = (io->mb_h + 1) >> 1; const int uv_in_height = (io->mb_h + 1) >> 1;
// scratch memory for one rescaler // scratch memory for one rescaler
const size_t work_size = 2 * (size_t)out_width; const size_t work_size = 2 * (size_t)out_width;
rescaler_t* work; // rescalers work area rescaler_t* WEBP_BIDI_INDEXABLE work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion uint8_t* WEBP_BIDI_INDEXABLE
tmp; // tmp storage for scaled YUV444 samples before RGB conversion
uint64_t tmp_size1, tmp_size2, total_size; uint64_t tmp_size1, tmp_size2, total_size;
size_t rescaler_size; size_t rescaler_size;
WebPRescaler* scalers; WebPRescaler* scalers;
@@ -515,11 +516,11 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
return 0; return 0;
} }
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size); work = (rescaler_t*)WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) { if (work == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (rescaler_t*)p->memory; p->memory = work;
tmp = (uint8_t*)(work + tmp_size1); tmp = (uint8_t*)(work + tmp_size1);
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size - scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size -

View File

@@ -113,13 +113,14 @@ int VP8SetError(VP8Decoder* const dec, VP8StatusCode error,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int VP8CheckSignature(const uint8_t* const data, size_t data_size) { int VP8CheckSignature(const uint8_t* const WEBP_COUNTED_BY(data_size) data,
size_t data_size) {
return (data_size >= 3 && data[0] == 0x9d && data[1] == 0x01 && return (data_size >= 3 && data[0] == 0x9d && data[1] == 0x01 &&
data[2] == 0x2a); data[2] == 0x2a);
} }
int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size, int VP8GetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* const width, int* const height) { size_t chunk_size, int* const width, int* const height) {
if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) { if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) {
return 0; // not enough data return 0; // not enough data
} }
@@ -218,12 +219,13 @@ static int ParseSegmentHeader(VP8BitReader* br, VP8SegmentHeader* hdr,
// If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA // If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA
// is returned, and this is an unrecoverable error. // is returned, and this is an unrecoverable error.
// If the partitions were positioned ok, VP8_STATUS_OK is returned. // If the partitions were positioned ok, VP8_STATUS_OK is returned.
static VP8StatusCode ParsePartitions(VP8Decoder* const dec, const uint8_t* buf, static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
const uint8_t* WEBP_COUNTED_BY(size) buf,
size_t size) { size_t size) {
VP8BitReader* const br = &dec->br; VP8BitReader* const br = &dec->br;
const uint8_t* sz = buf; const uint8_t* WEBP_BIDI_INDEXABLE sz = buf;
const uint8_t* buf_end = buf + size; const uint8_t* buf_end = buf + size;
const uint8_t* part_start; const uint8_t* WEBP_BIDI_INDEXABLE part_start;
size_t size_left = size; size_t size_left = size;
size_t last_part; size_t last_part;
size_t p; size_t p;
@@ -279,8 +281,8 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
// Topmost call // Topmost call
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
const uint8_t* buf;
size_t buf_size; size_t buf_size;
const uint8_t* WEBP_COUNTED_BY(buf_size) buf;
VP8FrameHeader* frm_hdr; VP8FrameHeader* frm_hdr;
VP8PictureHeader* pic_hdr; VP8PictureHeader* pic_hdr;
VP8BitReader* br; VP8BitReader* br;
@@ -294,8 +296,9 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
"null VP8Io passed to VP8GetHeaders()"); "null VP8Io passed to VP8GetHeaders()");
} }
buf = io->data;
buf_size = io->data_size; buf_size = io->data_size;
buf =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, io->data, io->data_size);
if (buf_size < 4) { if (buf_size < 4) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Truncated header."); return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Truncated header.");
} }

View File

@@ -160,24 +160,27 @@ void VP8Delete(VP8Decoder* const dec);
// Miscellaneous VP8/VP8L bitstream probing functions. // Miscellaneous VP8/VP8L bitstream probing functions.
// Returns true if the next 3 bytes in data contain the VP8 signature. // Returns true if the next 3 bytes in data contain the VP8 signature.
WEBP_EXTERN int VP8CheckSignature(const uint8_t* const data, size_t data_size); WEBP_EXTERN int VP8CheckSignature(
const uint8_t* const WEBP_COUNTED_BY(data_size) data, size_t data_size);
// Validates the VP8 data-header and retrieves basic header information viz // Validates the VP8 data-header and retrieves basic header information viz
// width and height. Returns 0 in case of formatting error. *width/*height // width and height. Returns 0 in case of formatting error. *width/*height
// can be passed NULL. // can be passed NULL.
WEBP_EXTERN int VP8GetInfo( WEBP_EXTERN int VP8GetInfo(
const uint8_t* data, const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, // data available so far size_t data_size, // data available so far
size_t chunk_size, // total data size expected in the chunk size_t chunk_size, // total data size expected in the chunk
int* const width, int* const height); int* const width, int* const height);
// Returns true if the next byte(s) in data is a VP8L signature. // Returns true if the next byte(s) in data is a VP8L signature.
WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const data, size_t size); WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const WEBP_COUNTED_BY(size)
data,
size_t size);
// Validates the VP8L data-header and retrieves basic header information viz // Validates the VP8L data-header and retrieves basic header information viz
// width, height and alpha. Returns 0 in case of formatting error. // width, height and alpha. Returns 0 in case of formatting error.
// width/height/has_alpha can be passed NULL. // width/height/has_alpha can be passed NULL.
WEBP_EXTERN int VP8LGetInfo(const uint8_t* data, WEBP_EXTERN int VP8LGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, // data available so far size_t data_size, // data available so far
int* const width, int* const height, int* const width, int* const height,
int* const has_alpha); int* const has_alpha);

View File

@@ -263,7 +263,8 @@ struct VP8Decoder {
// Alpha // Alpha
struct ALPHDecoder* alph_dec; // alpha-plane decoder object struct ALPHDecoder* alph_dec; // alpha-plane decoder object
const uint8_t* alpha_data; // compressed alpha data (if present) const uint8_t* WEBP_COUNTED_BY(alpha_data_size)
alpha_data; // compressed alpha data (if present)
size_t alpha_data_size; size_t alpha_data_size;
int is_alpha_decoded; // true if alpha_data is decoded in alpha_plane int is_alpha_decoded; // true if alpha_data is decoded in alpha_plane
uint8_t* alpha_plane_mem; // memory allocated for alpha_plane uint8_t* alpha_plane_mem; // memory allocated for alpha_plane

View File

@@ -104,7 +104,8 @@ static int DecodeImageStream(int xsize, int ysize, int is_level0,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int VP8LCheckSignature(const uint8_t* const data, size_t size) { int VP8LCheckSignature(const uint8_t* const WEBP_COUNTED_BY(size) data,
size_t size) {
return (size >= VP8L_FRAME_HEADER_SIZE && data[0] == VP8L_MAGIC_BYTE && return (size >= VP8L_FRAME_HEADER_SIZE && data[0] == VP8L_MAGIC_BYTE &&
(data[4] >> 5) == 0); // version (data[4] >> 5) == 0); // version
} }
@@ -119,8 +120,9 @@ static int ReadImageInfo(VP8LBitReader* const br, int* const width,
return !br->eos; return !br->eos;
} }
int VP8LGetInfo(const uint8_t* data, size_t data_size, int* const width, int VP8LGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* const height, int* const has_alpha) { size_t data_size, int* const width, int* const height,
int* const has_alpha) {
if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) { if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
return 0; // not enough data return 0; // not enough data
} else if (!VP8LCheckSignature(data, data_size)) { } else if (!VP8LCheckSignature(data, data_size)) {
@@ -248,10 +250,14 @@ static int ReadHuffmanCodeLengths(VP8LDecoder* const dec,
int max_symbol; int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH; int prev_code_len = DEFAULT_CODE_LENGTH;
HuffmanTables tables; HuffmanTables tables;
const int* WEBP_BIDI_INDEXABLE const bounded_code_lengths =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
const int*, code_length_code_lengths,
NUM_CODE_LENGTH_CODES * sizeof(*code_length_code_lengths));
if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) || if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS, !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS, bounded_code_lengths,
code_length_code_lengths, NUM_CODE_LENGTH_CODES)) { NUM_CODE_LENGTH_CODES)) {
goto End; goto End;
} }
@@ -338,8 +344,11 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
ok = ok && !br->eos; ok = ok && !br->eos;
if (ok) { if (ok) {
size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS, code_lengths, const int* WEBP_BIDI_INDEXABLE const bounded_code_lengths =
alphabet_size); WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const int*, code_lengths,
alphabet_size * sizeof(int));
size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
bounded_code_lengths, alphabet_size);
} }
if (!ok || size == 0) { if (!ok || size == 0) {
return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
@@ -553,13 +562,15 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
const int in_height = io->mb_h; const int in_height = io->mb_h;
const int out_height = io->scaled_height; const int out_height = io->scaled_height;
const uint64_t work_size = 2 * num_channels * (uint64_t)out_width; const uint64_t work_size = 2 * num_channels * (uint64_t)out_width;
rescaler_t* work; // Rescaler work area. rescaler_t* WEBP_BIDI_INDEXABLE work; // Rescaler work area.
const uint64_t scaled_data_size = (uint64_t)out_width; const uint64_t scaled_data_size = (uint64_t)out_width;
uint32_t* scaled_data; // Temporary storage for scaled BGRA data. uint32_t* WEBP_BIDI_INDEXABLE
scaled_data; // Temporary storage for scaled BGRA data.
const uint64_t memory_size = sizeof(*dec->rescaler) + const uint64_t memory_size = sizeof(*dec->rescaler) +
work_size * sizeof(*work) + work_size * sizeof(*work) +
scaled_data_size * sizeof(*scaled_data); scaled_data_size * sizeof(*scaled_data);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory)); uint8_t* WEBP_BIDI_INDEXABLE memory =
(uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
if (memory == NULL) { if (memory == NULL) {
return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
} }
@@ -1684,7 +1695,8 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row,
} }
int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
const uint8_t* const data, size_t data_size) { const uint8_t* const WEBP_COUNTED_BY(data_size) data,
size_t data_size) {
int ok = 0; int ok = 0;
VP8LDecoder* dec = VP8LNew(); VP8LDecoder* dec = VP8LNew();
@@ -1763,7 +1775,12 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
dec->io = io; dec->io = io;
dec->status = VP8_STATUS_OK; dec->status = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br, io->data, io->data_size); {
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_data =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, io->data,
io->data_size);
VP8LInitBitReader(&dec->br, bounded_data, io->data_size);
}
if (!ReadImageInfo(&dec->br, &width, &height, &has_alpha)) { if (!ReadImageInfo(&dec->br, &width, &height, &has_alpha)) {
VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto Error; goto Error;

View File

@@ -105,9 +105,9 @@ struct ALPHDecoder; // Defined in dec/alphai.h.
// Decodes image header for alpha data stored using lossless compression. // Decodes image header for alpha data stored using lossless compression.
// Returns false in case of error. // Returns false in case of error.
WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec, WEBP_NODISCARD int VP8LDecodeAlphaHeader(
const uint8_t* const data, struct ALPHDecoder* const alph_dec,
size_t data_size); const uint8_t* const WEBP_COUNTED_BY(data_size) data, size_t data_size);
// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are // Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
// already decoded in previous call(s), it will resume decoding from where it // already decoded in previous call(s), it will resume decoding from where it

View File

@@ -61,9 +61,11 @@ WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// and VP8_STATUS_OK otherwise. // and VP8_STATUS_OK otherwise.
// In case there are not enough bytes (partial RIFF container), return 0 for // In case there are not enough bytes (partial RIFF container), return 0 for
// *riff_size. Else return the RIFF size extracted from the header. // *riff_size. Else return the RIFF size extracted from the header.
static VP8StatusCode ParseRIFF(const uint8_t** const data, static VP8StatusCode ParseRIFF(const uint8_t* WEBP_COUNTED_BY(*data_size) *
size_t* const data_size, int have_all_data, WEBP_SINGLE const data,
size_t* const riff_size) { size_t* WEBP_SINGLE const data_size,
int have_all_data,
size_t* WEBP_SINGLE const riff_size) {
assert(data != NULL); assert(data != NULL);
assert(data_size != NULL); assert(data_size != NULL);
assert(riff_size != NULL); assert(riff_size != NULL);
@@ -86,8 +88,8 @@ static VP8StatusCode ParseRIFF(const uint8_t** const data,
} }
// We have a RIFF container. Skip it. // We have a RIFF container. Skip it.
*riff_size = size; *riff_size = size;
*data += RIFF_HEADER_SIZE;
*data_size -= RIFF_HEADER_SIZE; *data_size -= RIFF_HEADER_SIZE;
*data += RIFF_HEADER_SIZE;
} }
} }
return VP8_STATUS_OK; return VP8_STATUS_OK;
@@ -100,10 +102,13 @@ static VP8StatusCode ParseRIFF(const uint8_t** const data,
// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr, // If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
// *height_ptr and *flags_ptr are set to the corresponding values extracted // *height_ptr and *flags_ptr are set to the corresponding values extracted
// from the VP8X chunk. // from the VP8X chunk.
static VP8StatusCode ParseVP8X(const uint8_t** const data, static VP8StatusCode ParseVP8X(const uint8_t* WEBP_COUNTED_BY(*data_size) *
size_t* const data_size, int* const found_vp8x, WEBP_SINGLE const data,
int* const width_ptr, int* const height_ptr, size_t* WEBP_SINGLE const data_size,
uint32_t* const flags_ptr) { int* WEBP_SINGLE const found_vp8x,
int* WEBP_SINGLE const width_ptr,
int* WEBP_SINGLE const height_ptr,
uint32_t* WEBP_SINGLE const flags_ptr) {
const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
assert(data != NULL); assert(data != NULL);
assert(data_size != NULL); assert(data_size != NULL);
@@ -138,8 +143,8 @@ static VP8StatusCode ParseVP8X(const uint8_t** const data,
if (width_ptr != NULL) *width_ptr = width; if (width_ptr != NULL) *width_ptr = width;
if (height_ptr != NULL) *height_ptr = height; if (height_ptr != NULL) *height_ptr = height;
// Skip over VP8X header bytes. // Skip over VP8X header bytes.
*data += vp8x_size;
*data_size -= vp8x_size; *data_size -= vp8x_size;
*data += vp8x_size;
*found_vp8x = 1; *found_vp8x = 1;
} }
return VP8_STATUS_OK; return VP8_STATUS_OK;
@@ -152,13 +157,13 @@ static VP8StatusCode ParseVP8X(const uint8_t** const data,
// VP8_STATUS_OK otherwise. // VP8_STATUS_OK otherwise.
// If an alpha chunk is found, *alpha_data and *alpha_size are set // If an alpha chunk is found, *alpha_data and *alpha_size are set
// appropriately. // appropriately.
static VP8StatusCode ParseOptionalChunks(const uint8_t** const data, static VP8StatusCode ParseOptionalChunks(
size_t* const data_size, const uint8_t* WEBP_COUNTED_BY(*data_size) * WEBP_SINGLE const data,
size_t const riff_size, size_t* WEBP_SINGLE const data_size, size_t const riff_size,
const uint8_t** const alpha_data, const uint8_t* WEBP_COUNTED_BY(*alpha_size) * WEBP_SINGLE const alpha_data,
size_t* const alpha_size) { size_t* WEBP_SINGLE const alpha_size) {
const uint8_t* buf;
size_t buf_size; size_t buf_size;
const uint8_t* WEBP_COUNTED_BY(buf_size) buf;
uint32_t total_size = TAG_SIZE + // "WEBP". uint32_t total_size = TAG_SIZE + // "WEBP".
CHUNK_HEADER_SIZE + // "VP8Xnnnn". CHUNK_HEADER_SIZE + // "VP8Xnnnn".
VP8X_CHUNK_SIZE; // data. VP8X_CHUNK_SIZE; // data.
@@ -176,8 +181,8 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
uint32_t chunk_size; uint32_t chunk_size;
uint32_t disk_chunk_size; // chunk_size with padding uint32_t disk_chunk_size; // chunk_size with padding
*data = buf;
*data_size = buf_size; *data_size = buf_size;
*data = buf;
if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data. if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data.
return VP8_STATUS_NOT_ENOUGH_DATA; return VP8_STATUS_NOT_ENOUGH_DATA;
@@ -227,16 +232,20 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes // If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
// extracted from the VP8/VP8L chunk header. // extracted from the VP8/VP8L chunk header.
// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data. // The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr, static VP8StatusCode ParseVP8Header(const uint8_t* WEBP_COUNTED_BY(*data_size) *
size_t* const data_size, int have_all_data, WEBP_SINGLE const data_ptr,
size_t riff_size, size_t* const chunk_size, size_t* WEBP_SINGLE const data_size,
int* const is_lossless) { int have_all_data, size_t riff_size,
const uint8_t* const data = *data_ptr; size_t* WEBP_SINGLE const chunk_size,
int* WEBP_SINGLE const is_lossless) {
const size_t local_data_size = *data_size;
const uint8_t* WEBP_COUNTED_BY(local_data_size) const data = *data_ptr;
const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE); const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE); const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
const uint32_t minimal_size = const uint32_t minimal_size =
TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR
// "WEBP" + "VP8Lnnnn" // "WEBP" + "VP8Lnnnn"
(void)local_data_size;
assert(data != NULL); assert(data != NULL);
assert(data_size != NULL); assert(data_size != NULL);
assert(chunk_size != NULL); assert(chunk_size != NULL);
@@ -257,8 +266,8 @@ static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
} }
// Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header. // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
*chunk_size = size; *chunk_size = size;
*data_ptr += CHUNK_HEADER_SIZE;
*data_size -= CHUNK_HEADER_SIZE; *data_size -= CHUNK_HEADER_SIZE;
*data_ptr += CHUNK_HEADER_SIZE;
*is_lossless = is_vp8l; *is_lossless = is_vp8l;
} else { } else {
// Raw VP8/VP8L bitstream (no header). // Raw VP8/VP8L bitstream (no header).
@@ -282,12 +291,13 @@ static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
// RIFF + VP8X + (optional chunks) + VP8(L) // RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
static VP8StatusCode ParseHeadersInternal(const uint8_t* data, size_t data_size, static VP8StatusCode ParseHeadersInternal(
int* const width, int* const height, const uint8_t* WEBP_COUNTED_BY(data_size_param) data_param,
int* const has_alpha, size_t data_size_param, int* const width, int* const height,
int* const has_animation, int* const has_alpha, int* const has_animation, int* const format,
int* const format, WebPHeaderStructure* const headers) {
WebPHeaderStructure* const headers) { size_t data_size = data_size_param;
const uint8_t* WEBP_COUNTED_BY(data_size) data = data_param;
int canvas_width = 0; int canvas_width = 0;
int canvas_height = 0; int canvas_height = 0;
int image_width = 0; int image_width = 0;
@@ -348,11 +358,16 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data, size_t data_size,
// Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
if ((found_riff && found_vp8x) || if ((found_riff && found_vp8x) ||
(!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
size_t local_alpha_data_size = 0;
const uint8_t* WEBP_COUNTED_BY(local_alpha_data_size) local_alpha_data =
NULL;
status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
&hdrs.alpha_data, &hdrs.alpha_data_size); &local_alpha_data, &local_alpha_data_size);
if (status != VP8_STATUS_OK) { if (status != VP8_STATUS_OK) {
goto ReturnWidthHeight; // Invalid chunk size / insufficient data. goto ReturnWidthHeight; // Invalid chunk size / insufficient data.
} }
hdrs.alpha_data = local_alpha_data;
hdrs.alpha_data_size = local_alpha_data_size;
} }
// Skip over VP8/VP8L header. // Skip over VP8/VP8L header.
@@ -423,8 +438,13 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
int has_animation = 0; int has_animation = 0;
assert(headers != NULL); assert(headers != NULL);
// fill out headers, ignore width/height/has_alpha. // fill out headers, ignore width/height/has_alpha.
status = ParseHeadersInternal(headers->data, headers->data_size, NULL, NULL, {
NULL, &has_animation, NULL, headers); const uint8_t* WEBP_BIDI_INDEXABLE const bounded_data =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, headers->data,
headers->data_size);
status = ParseHeadersInternal(bounded_data, headers->data_size, NULL, NULL,
NULL, &has_animation, NULL, headers);
}
if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) { if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
// The WebPDemux API + libwebp can be used to decode individual // The WebPDemux API + libwebp can be used to decode individual
// uncomposited frames or the WebPAnimDecoder can be used to fully // uncomposited frames or the WebPAnimDecoder can be used to fully
@@ -449,9 +469,9 @@ void WebPResetDecParams(WebPDecParams* const params) {
// "Into" decoding variants // "Into" decoding variants
// Main flow // Main flow
WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data, WEBP_NODISCARD static VP8StatusCode DecodeInto(
size_t data_size, const uint8_t* WEBP_COUNTED_BY(data_size) const data, size_t data_size,
WebPDecParams* const params) { WebPDecParams* const params) {
VP8StatusCode status; VP8StatusCode status;
VP8Io io; VP8Io io;
WebPHeaderStructure headers; WebPHeaderStructure headers;
@@ -531,11 +551,10 @@ WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
} }
// Helpers // Helpers
WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace, WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(
const uint8_t* const data, WEBP_CSP_MODE colorspace,
size_t data_size, const uint8_t* WEBP_COUNTED_BY(data_size) const data, size_t data_size,
uint8_t* const rgba, uint8_t* WEBP_COUNTED_BY(size) const rgba, int stride, size_t size) {
int stride, size_t size) {
WebPDecParams params; WebPDecParams params;
WebPDecBuffer buf; WebPDecBuffer buf;
if (rgba == NULL || !WebPInitDecBuffer(&buf)) { if (rgba == NULL || !WebPInitDecBuffer(&buf)) {
@@ -554,34 +573,47 @@ WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
return rgba; return rgba;
} }
uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size, uint8_t* WebPDecodeRGBInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
uint8_t* output, size_t size, int stride) { size_t data_size,
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
int stride) {
return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size); return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
} }
uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size, uint8_t* WebPDecodeRGBAInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
uint8_t* output, size_t size, int stride) { size_t data_size,
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
int stride) {
return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size); return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size);
} }
uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size, uint8_t* WebPDecodeARGBInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
uint8_t* output, size_t size, int stride) { size_t data_size,
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
int stride) {
return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size); return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
} }
uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size, uint8_t* WebPDecodeBGRInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
uint8_t* output, size_t size, int stride) { size_t data_size,
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
int stride) {
return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size); return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
} }
uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size, uint8_t* WebPDecodeBGRAInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
uint8_t* output, size_t size, int stride) { size_t data_size,
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
int stride) {
return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size); return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
} }
uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size, uint8_t* luma, uint8_t* WebPDecodeYUVInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t luma_size, int luma_stride, uint8_t* u, size_t data_size,
size_t u_size, int u_stride, uint8_t* v, uint8_t* WEBP_COUNTED_BY(luma_size) luma,
size_t luma_size, int luma_stride,
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size,
int u_stride, uint8_t* WEBP_COUNTED_BY(v_size) v,
size_t v_size, int v_stride) { size_t v_size, int v_stride) {
WebPDecParams params; WebPDecParams params;
WebPDecBuffer output; WebPDecBuffer output;
@@ -608,7 +640,8 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size, uint8_t* luma,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode, WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
const uint8_t* const data, const uint8_t* WEBP_COUNTED_BY(data_size)
const data,
size_t data_size, int* const width, size_t data_size, int* const width,
int* const height, int* const height,
WebPDecBuffer* const keep_info) { WebPDecBuffer* const keep_info) {
@@ -640,34 +673,34 @@ WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y; return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y;
} }
uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, int* width, uint8_t* WebPDecodeRGB(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* height) { size_t data_size, int* width, int* height) {
return Decode(MODE_RGB, data, data_size, width, height, NULL); return Decode(MODE_RGB, data, data_size, width, height, NULL);
} }
uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, int* width, uint8_t* WebPDecodeRGBA(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* height) { size_t data_size, int* width, int* height) {
return Decode(MODE_RGBA, data, data_size, width, height, NULL); return Decode(MODE_RGBA, data, data_size, width, height, NULL);
} }
uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, int* width, uint8_t* WebPDecodeARGB(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* height) { size_t data_size, int* width, int* height) {
return Decode(MODE_ARGB, data, data_size, width, height, NULL); return Decode(MODE_ARGB, data, data_size, width, height, NULL);
} }
uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, int* width, uint8_t* WebPDecodeBGR(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* height) { size_t data_size, int* width, int* height) {
return Decode(MODE_BGR, data, data_size, width, height, NULL); return Decode(MODE_BGR, data, data_size, width, height, NULL);
} }
uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, int* width, uint8_t* WebPDecodeBGRA(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* height) { size_t data_size, int* width, int* height) {
return Decode(MODE_BGRA, data, data_size, width, height, NULL); return Decode(MODE_BGRA, data, data_size, width, height, NULL);
} }
uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size, int* width, uint8_t* WebPDecodeYUV(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* height, uint8_t** u, uint8_t** v, int* stride, size_t data_size, int* width, int* height, uint8_t** u,
int* uv_stride) { uint8_t** v, int* stride, int* uv_stride) {
// data, width and height are checked by Decode(). // data, width and height are checked by Decode().
if (u == NULL || v == NULL || stride == NULL || uv_stride == NULL) { if (u == NULL || v == NULL || stride == NULL || uv_stride == NULL) {
return NULL; return NULL;
@@ -695,7 +728,9 @@ static void DefaultFeatures(WebPBitstreamFeatures* const features) {
WEBP_UNSAFE_MEMSET(features, 0, sizeof(*features)); WEBP_UNSAFE_MEMSET(features, 0, sizeof(*features));
} }
static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size, static VP8StatusCode GetFeatures(const uint8_t* WEBP_COUNTED_BY(data_size)
const data,
size_t data_size,
WebPBitstreamFeatures* const features) { WebPBitstreamFeatures* const features) {
if (features == NULL || data == NULL) { if (features == NULL || data == NULL) {
return VP8_STATUS_INVALID_PARAM; return VP8_STATUS_INVALID_PARAM;
@@ -711,8 +746,8 @@ static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// WebPGetInfo() // WebPGetInfo()
int WebPGetInfo(const uint8_t* data, size_t data_size, int* width, int WebPGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
int* height) { size_t data_size, int* width, int* height) {
WebPBitstreamFeatures features; WebPBitstreamFeatures features;
if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) { if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
@@ -802,7 +837,9 @@ int WebPValidateDecoderConfig(const WebPDecoderConfig* config) {
return 1; return 1;
} }
VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, VP8StatusCode WebPGetFeaturesInternal(const uint8_t* WEBP_COUNTED_BY(data_size)
data,
size_t data_size,
WebPBitstreamFeatures* features, WebPBitstreamFeatures* features,
int version) { int version) {
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
@@ -814,8 +851,8 @@ VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
return GetFeatures(data, data_size, features); return GetFeatures(data, data_size, features);
} }
VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, VP8StatusCode WebPDecode(const uint8_t* WEBP_COUNTED_BY(data_size) data,
WebPDecoderConfig* config) { size_t data_size, WebPDecoderConfig* config) {
WebPDecParams params; WebPDecParams params;
VP8StatusCode status; VP8StatusCode status;

View File

@@ -61,15 +61,16 @@ void WebPResetDecParams(WebPDecParams* const params);
// Structure storing a description of the RIFF headers. // Structure storing a description of the RIFF headers.
typedef struct { typedef struct {
const uint8_t* data; // input buffer const uint8_t* WEBP_COUNTED_BY(data_size) data; // input buffer
size_t data_size; // input buffer size size_t data_size; // input buffer size
int have_all_data; // true if all data is known to be available int have_all_data; // true if all data is known to be available
size_t offset; // offset to main data chunk (VP8 or VP8L) size_t offset; // offset to main data chunk (VP8 or VP8L)
const uint8_t* alpha_data; // points to alpha chunk (if present) const uint8_t* WEBP_COUNTED_BY(alpha_data_size)
size_t alpha_data_size; // alpha chunk size alpha_data; // points to alpha chunk (if present)
size_t compressed_size; // VP8/VP8L compressed data size size_t alpha_data_size; // alpha chunk size
size_t riff_size; // size of the riff payload (or 0 if absent) size_t compressed_size; // VP8/VP8L compressed data size
int is_lossless; // true if a VP8L chunk is present size_t riff_size; // size of the riff payload (or 0 if absent)
int is_lossless; // true if a VP8L chunk is present
} WebPHeaderStructure; } WebPHeaderStructure;
// Skips over all valid chunks prior to the first VP8/VP8L frame header. // Skips over all valid chunks prior to the first VP8/VP8L frame header.

View File

@@ -18,8 +18,10 @@
#include "src/webp/config.h" #include "src/webp/config.h"
#endif #endif
#include "src/dec/common_dec.h"
#include "src/dsp/cpu.h" #include "src/dsp/cpu.h"
#include "src/utils/bounds_safety.h" #include "src/utils/bounds_safety.h"
#include "src/webp/decode.h"
#include "src/webp/types.h" #include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
@@ -229,9 +231,9 @@ extern VP8WHT VP8TransformWHT;
// *dst is the destination block, with stride BPS. Boundary samples are // *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed. // assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst); typedef void (*VP8PredFunc)(uint8_t* dst);
extern VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */]; extern VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
extern VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */]; extern VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
extern VP8PredFunc VP8PredLuma4[/* NUM_BMODES */]; extern VP8PredFunc VP8PredLuma4[NUM_BMODES];
// clipping tables (for filtering) // clipping tables (for filtering)
extern const int8_t* const VP8ksclip1; // clips [-1020, 1020] to [-128, 127] extern const int8_t* const VP8ksclip1; // clips [-1020, 1020] to [-128, 127]
@@ -294,7 +296,7 @@ typedef void (*WebPUpsampleLinePairFunc)(
#ifdef FANCY_UPSAMPLING #ifdef FANCY_UPSAMPLING
// Fancy upsampling functions to convert YUV to RGB(A) modes // Fancy upsampling functions to convert YUV to RGB(A) modes
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; extern WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
#endif // FANCY_UPSAMPLING #endif // FANCY_UPSAMPLING
@@ -311,7 +313,7 @@ void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride,
int width, int height, WebPSamplerRowFunc func); int width, int height, WebPSamplerRowFunc func);
// Sampling functions to convert rows of YUV to RGB(A) // Sampling functions to convert rows of YUV to RGB(A)
extern WebPSamplerRowFunc WebPSamplers[/* MODE_LAST */]; extern WebPSamplerRowFunc WebPSamplers[MODE_LAST];
// General function for converting two lines of ARGB or RGBA. // General function for converting two lines of ARGB or RGBA.
// 'alpha_is_last' should be true if 0xff000000 is stored in memory as // 'alpha_is_last' should be true if 0xff000000 is stored in memory as
@@ -324,7 +326,7 @@ typedef void (*WebPYUV444Converter)(const uint8_t* WEBP_RESTRICT y,
const uint8_t* WEBP_RESTRICT v, const uint8_t* WEBP_RESTRICT v,
uint8_t* WEBP_RESTRICT dst, int len); uint8_t* WEBP_RESTRICT dst, int len);
extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; extern WebPYUV444Converter WebPYUV444Converters[MODE_LAST];
// Must be called before using the WebPUpsamplers[] (and for premultiplied // Must be called before using the WebPUpsamplers[] (and for premultiplied
// colorspaces like rgbA, rgbA4444, etc) // colorspaces like rgbA, rgbA4444, etc)

View File

@@ -52,39 +52,39 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
// RIFF + VP8X + (optional chunks) + VP8(L) // RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(
size_t data_size, int* width, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* height); int* width, int* height);
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along // Decodes WebP images pointed to by 'data' and returns RGBA samples, along
// with the dimensions in *width and *height. The ordering of samples in // with the dimensions in *width and *height. The ordering of samples in
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent). // memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
// The returned pointer should be deleted calling WebPFree(). // The returned pointer should be deleted calling WebPFree().
// Returns NULL in case of error. // Returns NULL in case of error.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(
size_t data_size, int* width, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* height); int* width, int* height);
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data. // Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(
size_t data_size, int* width, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* height); int* width, int* height);
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data. // Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(
size_t data_size, int* width, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* height); int* width, int* height);
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data. // Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
// If the bitstream contains transparency, it is ignored. // If the bitstream contains transparency, it is ignored.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(
size_t data_size, int* width, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* height); int* width, int* height);
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data. // Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(
size_t data_size, int* width, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* height); int* width, int* height);
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer // Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
// returned is the Y samples buffer. Upon return, *u and *v will point to // returned is the Y samples buffer. Upon return, *u and *v will point to
@@ -96,11 +96,10 @@ WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data,
// 'width' and 'height' may be NULL, the other pointers must not be. // 'width' and 'height' may be NULL, the other pointers must not be.
// Returns NULL in case of error. // Returns NULL in case of error.
// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr // (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(
size_t data_size, int* width, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* height, uint8_t** u, int* width, int* height, uint8_t** u, uint8_t** v, int* stride,
uint8_t** v, int* stride, int* uv_stride);
int* uv_stride);
// These five functions are variants of the above ones, that decode the image // These five functions are variants of the above ones, that decode the image
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage // directly into a pre-allocated buffer 'output_buffer'. The maximum storage
@@ -111,27 +110,28 @@ WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data,
// between scanlines. Hence, output_buffer_size is expected to be at least // between scanlines. Hence, output_buffer_size is expected to be at least
// output_stride x picture-height. // output_stride x picture-height.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBAInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
const uint8_t* data, size_t data_size, uint8_t* output_buffer, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
size_t output_buffer_size, int output_stride); size_t output_buffer_size, int output_stride);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGBInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
const uint8_t* data, size_t data_size, uint8_t* output_buffer, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
size_t output_buffer_size, int output_stride); size_t output_buffer_size, int output_stride);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRAInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
const uint8_t* data, size_t data_size, uint8_t* output_buffer, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
size_t output_buffer_size, int output_stride); size_t output_buffer_size, int output_stride);
// RGB and BGR variants. Here too the transparency information, if present, // RGB and BGR variants. Here too the transparency information, if present,
// will be dropped and ignored. // will be dropped and ignored.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
size_t data_size, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
uint8_t* output_buffer, uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
size_t output_buffer_size, size_t output_buffer_size, int output_stride);
int output_stride); WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(const uint8_t* data, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
size_t data_size, uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
size_t output_buffer_size,
int output_stride);
// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly // WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly
// into pre-allocated luma/chroma plane buffers. This function requires the // into pre-allocated luma/chroma plane buffers. This function requires the
@@ -141,9 +141,10 @@ WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(const uint8_t* data,
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred // Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
// during decoding (or because some buffers were found to be too small). // during decoding (or because some buffers were found to be too small).
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto( WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
const uint8_t* data, size_t data_size, uint8_t* luma, size_t luma_size, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int luma_stride, uint8_t* u, size_t u_size, int u_stride, uint8_t* v, uint8_t* WEBP_COUNTED_BY(luma_size) luma, size_t luma_size, int luma_stride,
size_t v_size, int v_stride); uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size, int u_stride,
uint8_t* WEBP_COUNTED_BY(v_size) v, size_t v_size, int v_stride);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Output colorspaces and buffer // Output colorspaces and buffer
@@ -312,10 +313,10 @@ WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewDecoder(
// colorspace 'csp' is taken into account for allocating this buffer. All other // colorspace 'csp' is taken into account for allocating this buffer. All other
// parameters are ignored. // parameters are ignored.
// Returns NULL if the allocation failed, or if some parameters are invalid. // Returns NULL if the allocation failed, or if some parameters are invalid.
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(
uint8_t* output_buffer, WEBP_CSP_MODE csp,
size_t output_buffer_size, uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
int output_stride); size_t output_buffer_size, int output_stride);
// This function allocates and initializes an incremental-decoder object, which // This function allocates and initializes an incremental-decoder object, which
// will output the raw luma/chroma samples into a preallocated planes if // will output the raw luma/chroma samples into a preallocated planes if
@@ -329,15 +330,17 @@ WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp,
// MODE_YUVA) when decoding starts. All parameters are then ignored. // MODE_YUVA) when decoding starts. All parameters are then ignored.
// Returns NULL if the allocation failed or if a parameter is invalid. // Returns NULL if the allocation failed or if a parameter is invalid.
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA( WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size, uint8_t* WEBP_COUNTED_BY(luma_size) luma, size_t luma_size, int luma_stride,
int u_stride, uint8_t* v, size_t v_size, int v_stride, uint8_t* a, uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size, int u_stride,
size_t a_size, int a_stride); uint8_t* WEBP_COUNTED_BY(v_size) v, size_t v_size, int v_stride,
uint8_t* WEBP_COUNTED_BY(a_size) a, size_t a_size, int a_stride);
// Deprecated version of the above, without the alpha plane. // Deprecated version of the above, without the alpha plane.
// Kept for backward compatibility. // Kept for backward compatibility.
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV( WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV(
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size, uint8_t* WEBP_COUNTED_BY(luma_size) luma, size_t luma_size, int luma_stride,
int u_stride, uint8_t* v, size_t v_size, int v_stride); uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size, int u_stride,
uint8_t* WEBP_COUNTED_BY(v_size) v, size_t v_size, int v_stride);
// Deletes the WebPIDecoder object and associated memory. Must always be called // Deletes the WebPIDecoder object and associated memory. Must always be called
// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded. // if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
@@ -346,7 +349,9 @@ WEBP_EXTERN void WebPIDelete(WebPIDecoder* idec);
// Copies and decodes the next available data. Returns VP8_STATUS_OK when // Copies and decodes the next available data. Returns VP8_STATUS_OK when
// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more // the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
// data is expected. Returns error in other cases. // data is expected. Returns error in other cases.
WEBP_EXTERN VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data, WEBP_EXTERN VP8StatusCode WebPIAppend(WebPIDecoder* idec,
const uint8_t* WEBP_COUNTED_BY(data_size)
data,
size_t data_size); size_t data_size);
// A variant of the above function to be used when data buffer contains // A variant of the above function to be used when data buffer contains
@@ -354,7 +359,9 @@ WEBP_EXTERN VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data,
// to the internal memory. // to the internal memory.
// Note that the value of the 'data' pointer can change between calls to // Note that the value of the 'data' pointer can change between calls to
// WebPIUpdate, for instance when the data buffer is resized to fit larger data. // WebPIUpdate, for instance when the data buffer is resized to fit larger data.
WEBP_EXTERN VP8StatusCode WebPIUpdate(WebPIDecoder* idec, const uint8_t* data, WEBP_EXTERN VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
const uint8_t* WEBP_COUNTED_BY(data_size)
data,
size_t data_size); size_t data_size);
// Returns the RGB/A image decoded so far. Returns NULL if output params // Returns the RGB/A image decoded so far. Returns NULL if output params
@@ -441,8 +448,9 @@ struct WebPBitstreamFeatures {
}; };
// Internal, version-checked, entry point // Internal, version-checked, entry point
WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(const uint8_t*, size_t, WEBP_EXTERN VP8StatusCode
WebPBitstreamFeatures*, int); WebPGetFeaturesInternal(const uint8_t* WEBP_COUNTED_BY(data_size),
size_t data_size, WebPBitstreamFeatures*, int);
// Retrieve features from the bitstream. The *features structure is filled // Retrieve features from the bitstream. The *features structure is filled
// with information gathered from the bitstream. // with information gathered from the bitstream.
@@ -455,8 +463,9 @@ WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(const uint8_t*, size_t,
// RIFF + VP8X + (optional chunks) + VP8(L) // RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
static WEBP_INLINE VP8StatusCode WebPGetFeatures( static WEBP_INLINE VP8StatusCode
const uint8_t* data, size_t data_size, WebPBitstreamFeatures* features) { WebPGetFeatures(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, WebPBitstreamFeatures* features) {
return WebPGetFeaturesInternal(data, data_size, features, return WebPGetFeaturesInternal(data, data_size, features,
WEBP_DECODER_ABI_VERSION); WEBP_DECODER_ABI_VERSION);
} }
@@ -516,14 +525,16 @@ WEBP_NODISCARD WEBP_EXTERN int WebPValidateDecoderConfig(
// The return WebPIDecoder object must always be deleted calling WebPIDelete(). // The return WebPIDecoder object must always be deleted calling WebPIDelete().
// Returns NULL in case of error (and config->status will then reflect // Returns NULL in case of error (and config->status will then reflect
// the error condition, if available). // the error condition, if available).
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data, WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(
size_t data_size, const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
WebPDecoderConfig* config); WebPDecoderConfig* config);
// Non-incremental version. This version decodes the full data at once, taking // Non-incremental version. This version decodes the full data at once, taking
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK // 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
// if the decoding was successful). Note that 'config' cannot be NULL. // if the decoding was successful). Note that 'config' cannot be NULL.
WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* WEBP_COUNTED_BY(data_size)
data,
size_t data_size,
WebPDecoderConfig* config); WebPDecoderConfig* config);
#ifdef __cplusplus #ifdef __cplusplus