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>
$<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>)
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)
target_compile_options(webputils 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()
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);
} else {
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;
@@ -225,7 +230,11 @@ WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
if (dec->alpha_dithering > 0) {
uint8_t* const alpha =
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,
dec->alpha_dithering)) {
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
// there is enough data to begin parsing partition 0.
if (last_start != NULL) {
VP8BitReaderSetBuffer(&dec->parts[last_part], last_start,
mem->buf + mem->end - last_start);
const size_t part_size = 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)) {
ALPHDecoder* const alph_dec = dec->alph_dec;
dec->alpha_data += offset;
dec->alpha_data_size = dec->alpha_data_size;
if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) {
if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) {
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);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br,
dec->alpha_data + ALPHA_HEADER_LEN,
dec->alpha_data_size - ALPHA_HEADER_LEN);
data_size = dec->alpha_data_size - ALPHA_HEADER_LEN;
bounded_alpha_data = WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
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
// Nothing special to do in this case.
}
@@ -165,7 +175,10 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
}
} else { // Resize lossless bitreader
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;
WebPHeaderStructure headers;
headers.data = data;
headers.data =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, data, curr_size);
headers.data_size = curr_size;
headers.have_all_data = 0;
status = WebPParseHeaders(&headers);
@@ -371,8 +385,13 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
// Not enough data bytes to extract VP8 Frame Header.
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);
@@ -399,7 +418,8 @@ static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
}
if (mem->mode == MEM_MODE_APPEND) {
// 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) {
return VP8_STATUS_OUT_OF_MEMORY;
}
@@ -660,8 +680,8 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
return NewDecoder(output_buffer, NULL);
}
WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
WebPDecoderConfig* config) {
WebPIDecoder* WebPIDecode(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, WebPDecoderConfig* config) {
WebPIDecoder* idec;
WebPBitstreamFeatures tmp_features;
WebPBitstreamFeatures* const features =
@@ -710,13 +730,16 @@ void WebPIDelete(WebPIDecoder* idec) {
//------------------------------------------------------------------------------
// 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) {
const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
WebPIDecoder* idec;
if (csp >= MODE_YUV) return NULL;
if (is_external_memory == 0) { // Overwrite parameters to sane values.
output_buffer = NULL;
output_buffer_size = 0;
output_stride = 0;
} 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;
}
WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride, uint8_t* v,
size_t v_size, int v_stride, uint8_t* a,
size_t a_size, int a_stride) {
WebPIDecoder* WebPINewYUVA(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,
uint8_t* WEBP_COUNTED_BY(a_size) a, size_t a_size,
int a_stride) {
const int is_external_memory = (luma != NULL) ? 1 : 0;
WebPIDecoder* idec;
WEBP_CSP_MODE colorspace;
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;
u = v = a = NULL;
colorspace = MODE_YUVA;
} else { // A luma buffer was passed. Validate the other parameters.
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;
}
WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride, uint8_t* v,
WebPIDecoder* WebPINewYUV(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) {
return WebPINewYUVA(luma, luma_size, luma_stride, u, u_size, u_stride, v,
v_size, v_stride, NULL, 0, 0);
@@ -797,7 +831,8 @@ static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
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) {
VP8StatusCode status;
if (idec == NULL || data == NULL) {
@@ -818,7 +853,8 @@ VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data,
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) {
VP8StatusCode status;
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
uint64_t total_size;
size_t rescaler_size;
rescaler_t* work;
rescaler_t* WEBP_BIDI_INDEXABLE work;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
@@ -325,11 +325,11 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
return 0;
}
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) {
work = (rescaler_t*)WebPSafeMalloc(1ULL, (size_t)total_size);
if (work == NULL) {
return 0; // memory error
}
work = (rescaler_t*)p->memory;
p->memory = work;
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_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;
// scratch memory for one rescaler
const size_t work_size = 2 * (size_t)out_width;
rescaler_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
rescaler_t* WEBP_BIDI_INDEXABLE work; // rescalers work area
uint8_t* WEBP_BIDI_INDEXABLE
tmp; // tmp storage for scaled YUV444 samples before RGB conversion
uint64_t tmp_size1, tmp_size2, total_size;
size_t rescaler_size;
WebPRescaler* scalers;
@@ -515,11 +516,11 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
return 0;
}
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) {
work = (rescaler_t*)WebPSafeMalloc(1ULL, (size_t)total_size);
if (work == NULL) {
return 0; // memory error
}
work = (rescaler_t*)p->memory;
p->memory = work;
tmp = (uint8_t*)(work + tmp_size1);
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 &&
data[2] == 0x2a);
}
int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
int* const width, int* const height) {
int VP8GetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
size_t chunk_size, int* const width, int* const height) {
if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) {
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
// is returned, and this is an unrecoverable error.
// 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) {
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* part_start;
const uint8_t* WEBP_BIDI_INDEXABLE part_start;
size_t size_left = size;
size_t last_part;
size_t p;
@@ -279,8 +281,8 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
// Topmost call
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
const uint8_t* buf;
size_t buf_size;
const uint8_t* WEBP_COUNTED_BY(buf_size) buf;
VP8FrameHeader* frm_hdr;
VP8PictureHeader* pic_hdr;
VP8BitReader* br;
@@ -294,8 +296,9 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
"null VP8Io passed to VP8GetHeaders()");
}
buf = io->data;
buf_size = io->data_size;
buf =
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, io->data, io->data_size);
if (buf_size < 4) {
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.
// 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
// width and height. Returns 0 in case of formatting error. *width/*height
// can be passed NULL.
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 chunk_size, // total data size expected in the chunk
int* const width, int* const height);
// 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
// width, height and alpha. Returns 0 in case of formatting error.
// 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
int* const width, int* const height,
int* const has_alpha);

View File

@@ -263,7 +263,8 @@ struct VP8Decoder {
// Alpha
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;
int is_alpha_decoded; // true if alpha_data is decoded in 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 &&
(data[4] >> 5) == 0); // version
}
@@ -119,8 +120,9 @@ static int ReadImageInfo(VP8LBitReader* const br, int* const width,
return !br->eos;
}
int VP8LGetInfo(const uint8_t* data, size_t data_size, int* const width,
int* const height, int* const has_alpha) {
int VP8LGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* const width, int* const height,
int* const has_alpha) {
if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
return 0; // not enough data
} else if (!VP8LCheckSignature(data, data_size)) {
@@ -248,10 +250,14 @@ static int ReadHuffmanCodeLengths(VP8LDecoder* const dec,
int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH;
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) ||
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS, bounded_code_lengths,
NUM_CODE_LENGTH_CODES)) {
goto End;
}
@@ -338,8 +344,11 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
ok = ok && !br->eos;
if (ok) {
size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS, code_lengths,
alphabet_size);
const int* WEBP_BIDI_INDEXABLE const bounded_code_lengths =
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) {
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 out_height = io->scaled_height;
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;
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) +
work_size * sizeof(*work) +
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) {
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,
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;
VP8LDecoder* dec = VP8LNew();
@@ -1763,7 +1775,12 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
dec->io = io;
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)) {
VP8LSetError(dec, VP8_STATUS_BITSTREAM_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.
// Returns false in case of error.
WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
const uint8_t* const data,
size_t data_size);
WEBP_NODISCARD int VP8LDecodeAlphaHeader(
struct ALPHDecoder* const alph_dec,
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
// 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.
// In case there are not enough bytes (partial RIFF container), return 0 for
// *riff_size. Else return the RIFF size extracted from the header.
static VP8StatusCode ParseRIFF(const uint8_t** const data,
size_t* const data_size, int have_all_data,
size_t* const riff_size) {
static VP8StatusCode ParseRIFF(const uint8_t* WEBP_COUNTED_BY(*data_size) *
WEBP_SINGLE const data,
size_t* WEBP_SINGLE const data_size,
int have_all_data,
size_t* WEBP_SINGLE const riff_size) {
assert(data != NULL);
assert(data_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.
*riff_size = size;
*data += RIFF_HEADER_SIZE;
*data_size -= RIFF_HEADER_SIZE;
*data += RIFF_HEADER_SIZE;
}
}
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,
// *height_ptr and *flags_ptr are set to the corresponding values extracted
// from the VP8X chunk.
static VP8StatusCode ParseVP8X(const uint8_t** const data,
size_t* const data_size, int* const found_vp8x,
int* const width_ptr, int* const height_ptr,
uint32_t* const flags_ptr) {
static VP8StatusCode ParseVP8X(const uint8_t* WEBP_COUNTED_BY(*data_size) *
WEBP_SINGLE const data,
size_t* WEBP_SINGLE const data_size,
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;
assert(data != 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 (height_ptr != NULL) *height_ptr = height;
// Skip over VP8X header bytes.
*data += vp8x_size;
*data_size -= vp8x_size;
*data += vp8x_size;
*found_vp8x = 1;
}
return VP8_STATUS_OK;
@@ -152,13 +157,13 @@ static VP8StatusCode ParseVP8X(const uint8_t** const data,
// VP8_STATUS_OK otherwise.
// If an alpha chunk is found, *alpha_data and *alpha_size are set
// appropriately.
static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
size_t* const data_size,
size_t const riff_size,
const uint8_t** const alpha_data,
size_t* const alpha_size) {
const uint8_t* buf;
static VP8StatusCode ParseOptionalChunks(
const uint8_t* WEBP_COUNTED_BY(*data_size) * WEBP_SINGLE const data,
size_t* WEBP_SINGLE const data_size, size_t const riff_size,
const uint8_t* WEBP_COUNTED_BY(*alpha_size) * WEBP_SINGLE const alpha_data,
size_t* WEBP_SINGLE const alpha_size) {
size_t buf_size;
const uint8_t* WEBP_COUNTED_BY(buf_size) buf;
uint32_t total_size = TAG_SIZE + // "WEBP".
CHUNK_HEADER_SIZE + // "VP8Xnnnn".
VP8X_CHUNK_SIZE; // data.
@@ -176,8 +181,8 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
uint32_t chunk_size;
uint32_t disk_chunk_size; // chunk_size with padding
*data = buf;
*data_size = buf_size;
*data = buf;
if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient 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
// extracted from the VP8/VP8L chunk header.
// 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,
size_t* const data_size, int have_all_data,
size_t riff_size, size_t* const chunk_size,
int* const is_lossless) {
const uint8_t* const data = *data_ptr;
static VP8StatusCode ParseVP8Header(const uint8_t* WEBP_COUNTED_BY(*data_size) *
WEBP_SINGLE const data_ptr,
size_t* WEBP_SINGLE const data_size,
int have_all_data, size_t riff_size,
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_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
const uint32_t minimal_size =
TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR
// "WEBP" + "VP8Lnnnn"
(void)local_data_size;
assert(data != NULL);
assert(data_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.
*chunk_size = size;
*data_ptr += CHUNK_HEADER_SIZE;
*data_size -= CHUNK_HEADER_SIZE;
*data_ptr += CHUNK_HEADER_SIZE;
*is_lossless = is_vp8l;
} else {
// 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)
// ALPH + VP8 <-- 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,
int* const width, int* const height,
int* const has_alpha,
int* const has_animation,
int* const format,
WebPHeaderStructure* const headers) {
static VP8StatusCode ParseHeadersInternal(
const uint8_t* WEBP_COUNTED_BY(data_size_param) data_param,
size_t data_size_param, int* const width, int* const height,
int* const has_alpha, int* const has_animation, int* const format,
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_height = 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".
if ((found_riff && found_vp8x) ||
(!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,
&hdrs.alpha_data, &hdrs.alpha_data_size);
&local_alpha_data, &local_alpha_data_size);
if (status != VP8_STATUS_OK) {
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.
@@ -423,8 +438,13 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
int has_animation = 0;
assert(headers != NULL);
// 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) {
// The WebPDemux API + libwebp can be used to decode individual
// uncomposited frames or the WebPAnimDecoder can be used to fully
@@ -449,9 +469,9 @@ void WebPResetDecParams(WebPDecParams* const params) {
// "Into" decoding variants
// Main flow
WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
size_t data_size,
WebPDecParams* const params) {
WEBP_NODISCARD static VP8StatusCode DecodeInto(
const uint8_t* WEBP_COUNTED_BY(data_size) const data, size_t data_size,
WebPDecParams* const params) {
VP8StatusCode status;
VP8Io io;
WebPHeaderStructure headers;
@@ -531,11 +551,10 @@ WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
}
// Helpers
WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
const uint8_t* const data,
size_t data_size,
uint8_t* const rgba,
int stride, size_t size) {
WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(
WEBP_CSP_MODE colorspace,
const uint8_t* WEBP_COUNTED_BY(data_size) const data, size_t data_size,
uint8_t* WEBP_COUNTED_BY(size) const rgba, int stride, size_t size) {
WebPDecParams params;
WebPDecBuffer buf;
if (rgba == NULL || !WebPInitDecBuffer(&buf)) {
@@ -554,34 +573,47 @@ WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
return rgba;
}
uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
uint8_t* output, size_t size, int stride) {
uint8_t* WebPDecodeRGBInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
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);
}
uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
uint8_t* output, size_t size, int stride) {
uint8_t* WebPDecodeRGBAInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
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);
}
uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
uint8_t* output, size_t size, int stride) {
uint8_t* WebPDecodeARGBInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
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);
}
uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
uint8_t* output, size_t size, int stride) {
uint8_t* WebPDecodeBGRInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
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);
}
uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
uint8_t* output, size_t size, int stride) {
uint8_t* WebPDecodeBGRAInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
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);
}
uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size, uint8_t* luma,
size_t luma_size, int luma_stride, uint8_t* u,
size_t u_size, int u_stride, uint8_t* v,
uint8_t* WebPDecodeYUVInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size,
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) {
WebPDecParams params;
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,
const uint8_t* const data,
const uint8_t* WEBP_COUNTED_BY(data_size)
const data,
size_t data_size, int* const width,
int* const height,
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;
}
uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, int* width,
int* height) {
uint8_t* WebPDecodeRGB(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* width, int* height) {
return Decode(MODE_RGB, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, int* width,
int* height) {
uint8_t* WebPDecodeRGBA(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* width, int* height) {
return Decode(MODE_RGBA, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, int* width,
int* height) {
uint8_t* WebPDecodeARGB(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* width, int* height) {
return Decode(MODE_ARGB, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, int* width,
int* height) {
uint8_t* WebPDecodeBGR(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* width, int* height) {
return Decode(MODE_BGR, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, int* width,
int* height) {
uint8_t* WebPDecodeBGRA(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* width, int* height) {
return Decode(MODE_BGRA, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size, int* width,
int* height, uint8_t** u, uint8_t** v, int* stride,
int* uv_stride) {
uint8_t* WebPDecodeYUV(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* width, int* height, uint8_t** u,
uint8_t** v, int* stride, int* uv_stride) {
// data, width and height are checked by Decode().
if (u == NULL || v == NULL || stride == NULL || uv_stride == NULL) {
return NULL;
@@ -695,7 +728,9 @@ static void DefaultFeatures(WebPBitstreamFeatures* const 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) {
if (features == NULL || data == NULL) {
return VP8_STATUS_INVALID_PARAM;
@@ -711,8 +746,8 @@ static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
//------------------------------------------------------------------------------
// WebPGetInfo()
int WebPGetInfo(const uint8_t* data, size_t data_size, int* width,
int* height) {
int WebPGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, int* width, int* height) {
WebPBitstreamFeatures features;
if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
@@ -802,7 +837,9 @@ int WebPValidateDecoderConfig(const WebPDecoderConfig* config) {
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,
int 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);
}
VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
WebPDecoderConfig* config) {
VP8StatusCode WebPDecode(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, WebPDecoderConfig* config) {
WebPDecParams params;
VP8StatusCode status;

View File

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

View File

@@ -18,8 +18,10 @@
#include "src/webp/config.h"
#endif
#include "src/dec/common_dec.h"
#include "src/dsp/cpu.h"
#include "src/utils/bounds_safety.h"
#include "src/webp/decode.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
@@ -229,9 +231,9 @@ extern VP8WHT VP8TransformWHT;
// *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst);
extern VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
extern VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
extern VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
extern VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
extern VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
extern VP8PredFunc VP8PredLuma4[NUM_BMODES];
// clipping tables (for filtering)
extern const int8_t* const VP8ksclip1; // clips [-1020, 1020] to [-128, 127]
@@ -294,7 +296,7 @@ typedef void (*WebPUpsampleLinePairFunc)(
#ifdef FANCY_UPSAMPLING
// Fancy upsampling functions to convert YUV to RGB(A) modes
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
extern WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
#endif // FANCY_UPSAMPLING
@@ -311,7 +313,7 @@ void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride,
int width, int height, WebPSamplerRowFunc func);
// 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.
// '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,
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
// colorspaces like rgbA, rgbA4444, etc)

View File

@@ -52,39 +52,39 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
// RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- 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,
size_t data_size, int* width,
int* height);
WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* width, int* height);
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
// 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).
// The returned pointer should be deleted calling WebPFree().
// Returns NULL in case of error.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data,
size_t data_size, int* width,
int* height);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* width, int* height);
// 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,
size_t data_size, int* width,
int* height);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* width, int* height);
// 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,
size_t data_size, int* width,
int* height);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* width, int* height);
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
// If the bitstream contains transparency, it is ignored.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data,
size_t data_size, int* width,
int* height);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* width, int* height);
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data,
size_t data_size, int* width,
int* height);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* width, int* height);
// 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
@@ -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.
// Returns NULL in case of error.
// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data,
size_t data_size, int* width,
int* height, uint8_t** u,
uint8_t** v, int* stride,
int* uv_stride);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
int* width, int* height, uint8_t** u, uint8_t** v, int* stride,
int* uv_stride);
// These five functions are variants of the above ones, that decode the image
// 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
// output_stride x picture-height.
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);
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);
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);
// RGB and BGR variants. Here too the transparency information, if present,
// will be dropped and ignored.
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(const uint8_t* data,
size_t data_size,
uint8_t* output_buffer,
size_t output_buffer_size,
int output_stride);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(const uint8_t* data,
size_t data_size,
uint8_t* output_buffer,
size_t output_buffer_size,
int output_stride);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
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);
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
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);
// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly
// 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
// during decoding (or because some buffers were found to be too small).
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
const uint8_t* data, size_t data_size, uint8_t* luma, size_t luma_size,
int luma_stride, uint8_t* u, size_t u_size, int u_stride, uint8_t* v,
size_t v_size, int v_stride);
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
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);
//------------------------------------------------------------------------------
// 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
// parameters are ignored.
// Returns NULL if the allocation failed, or if some parameters are invalid.
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp,
uint8_t* output_buffer,
size_t output_buffer_size,
int output_stride);
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(
WEBP_CSP_MODE csp,
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
size_t output_buffer_size, int output_stride);
// This function allocates and initializes an incremental-decoder object, which
// 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.
// Returns NULL if the allocation failed or if a parameter is invalid.
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size,
int u_stride, uint8_t* v, size_t v_size, int v_stride, uint8_t* a,
size_t a_size, int a_stride);
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,
uint8_t* WEBP_COUNTED_BY(a_size) a, size_t a_size, int a_stride);
// Deprecated version of the above, without the alpha plane.
// Kept for backward compatibility.
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV(
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size,
int u_stride, uint8_t* v, size_t v_size, int v_stride);
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);
// Deletes the WebPIDecoder object and associated memory. Must always be called
// 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
// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
// 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);
// 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.
// 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.
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);
// Returns the RGB/A image decoded so far. Returns NULL if output params
@@ -441,8 +448,9 @@ struct WebPBitstreamFeatures {
};
// Internal, version-checked, entry point
WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(const uint8_t*, size_t,
WebPBitstreamFeatures*, int);
WEBP_EXTERN VP8StatusCode
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
// 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)
// ALPH + VP8 <-- 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(
const uint8_t* data, size_t data_size, WebPBitstreamFeatures* features) {
static WEBP_INLINE VP8StatusCode
WebPGetFeatures(const uint8_t* WEBP_COUNTED_BY(data_size) data,
size_t data_size, WebPBitstreamFeatures* features) {
return WebPGetFeaturesInternal(data, data_size, features,
WEBP_DECODER_ABI_VERSION);
}
@@ -516,14 +525,16 @@ WEBP_NODISCARD WEBP_EXTERN int WebPValidateDecoderConfig(
// The return WebPIDecoder object must always be deleted calling WebPIDelete().
// Returns NULL in case of error (and config->status will then reflect
// the error condition, if available).
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data,
size_t data_size,
WebPDecoderConfig* config);
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
WebPDecoderConfig* config);
// Non-incremental version. This version decodes the full data at once, taking
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
// 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);
#ifdef __cplusplus