(RPNG) PNG decoder - proper namespacing of functions, general cleanups

This commit is contained in:
LibretroAdmin 2022-08-02 15:55:26 +02:00
parent 342d3da620
commit 33c9f56df0

View file

@ -126,7 +126,7 @@ struct rpng
bool has_trns;
};
static const struct adam7_pass passes[] = {
static const struct adam7_pass rpng_passes[] = {
{ 0, 0, 8, 8 },
{ 4, 0, 8, 8 },
{ 0, 4, 4, 8 },
@ -136,13 +136,13 @@ static const struct adam7_pass passes[] = {
{ 0, 1, 1, 2 },
};
static INLINE uint32_t dword_be(const uint8_t *buf)
static INLINE uint32_t rpng_dword_be(const uint8_t *buf)
{
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
}
#if defined(DEBUG) || defined(RPNG_TEST)
static bool png_process_ihdr(struct png_ihdr *ihdr)
static bool rpng_process_ihdr(struct png_ihdr *ihdr)
{
uint8_t ihdr_depth = ihdr->depth;
@ -190,7 +190,7 @@ static bool png_process_ihdr(struct png_ihdr *ihdr)
return true;
}
#else
static bool png_process_ihdr(struct png_ihdr *ihdr)
static bool rpng_process_ihdr(struct png_ihdr *ihdr)
{
uint8_t ihdr_depth = ihdr->depth;
@ -220,10 +220,10 @@ static bool png_process_ihdr(struct png_ihdr *ihdr)
}
#endif
static void png_reverse_filter_copy_line_rgb(uint32_t *data,
static void rpng_reverse_filter_copy_line_rgb(uint32_t *data,
const uint8_t *decoded, unsigned width, unsigned bpp)
{
unsigned i;
int i;
bpp /= 8;
@ -241,10 +241,10 @@ static void png_reverse_filter_copy_line_rgb(uint32_t *data,
}
}
static void png_reverse_filter_copy_line_rgba(uint32_t *data,
static void rpng_reverse_filter_copy_line_rgba(uint32_t *data,
const uint8_t *decoded, unsigned width, unsigned bpp)
{
unsigned i;
int i;
bpp /= 8;
@ -263,10 +263,11 @@ static void png_reverse_filter_copy_line_rgba(uint32_t *data,
}
}
static void png_reverse_filter_copy_line_bw(uint32_t *data,
static void rpng_reverse_filter_copy_line_bw(uint32_t *data,
const uint8_t *decoded, unsigned width, unsigned depth)
{
unsigned i, bit;
int i;
unsigned bit;
static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
unsigned mul, mask;
@ -295,11 +296,11 @@ static void png_reverse_filter_copy_line_bw(uint32_t *data,
}
}
static void png_reverse_filter_copy_line_gray_alpha(uint32_t *data,
static void rpng_reverse_filter_copy_line_gray_alpha(uint32_t *data,
const uint8_t *decoded, unsigned width,
unsigned bpp)
{
unsigned i;
int i;
bpp /= 8;
@ -316,7 +317,7 @@ static void png_reverse_filter_copy_line_gray_alpha(uint32_t *data,
}
}
static void png_reverse_filter_copy_line_plt(uint32_t *data,
static void rpng_reverse_filter_copy_line_plt(uint32_t *data,
const uint8_t *decoded, unsigned width,
unsigned depth, const uint32_t *palette)
{
@ -325,7 +326,7 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
case 1:
{
unsigned w = width / 8;
unsigned i;
int i;
for (i = 0; i < w; i++, decoded++)
{
@ -363,7 +364,7 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
case 2:
{
unsigned w = width / 4;
unsigned i;
int i;
for (i = 0; i < w; i++, decoded++)
{
@ -389,7 +390,7 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
case 4:
{
unsigned w = width / 2;
unsigned i;
int i;
for (i = 0; i < w; i++, decoded++)
{
@ -404,7 +405,7 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
case 8:
{
unsigned i;
int i;
for (i = 0; i < width; i++, decoded++, data++)
*data = palette[*decoded];
@ -413,7 +414,7 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
}
}
static void png_pass_geom(const struct png_ihdr *ihdr,
static void rpng_pass_geom(const struct png_ihdr *ihdr,
unsigned width, unsigned height,
unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size)
{
@ -454,7 +455,7 @@ static void png_pass_geom(const struct png_ihdr *ihdr,
*pitch_out = pitch;
}
static void png_reverse_filter_adam7_deinterlace_pass(uint32_t *data,
static void rpng_reverse_filter_adam7_deinterlace_pass(uint32_t *data,
const struct png_ihdr *ihdr,
const uint32_t *input, unsigned pass_width, unsigned pass_height,
const struct adam7_pass *pass)
@ -473,7 +474,7 @@ static void png_reverse_filter_adam7_deinterlace_pass(uint32_t *data,
}
}
static void png_reverse_filter_deinit(struct rpng_process *pngp)
static void rpng_reverse_filter_deinit(struct rpng_process *pngp)
{
if (!pngp)
return;
@ -488,33 +489,32 @@ static void png_reverse_filter_deinit(struct rpng_process *pngp)
pngp->h = 0;
}
static int png_reverse_filter_init(const struct png_ihdr *ihdr,
static int rpng_reverse_filter_init(const struct png_ihdr *ihdr,
struct rpng_process *pngp)
{
size_t pass_size;
if (!pngp->adam7_pass_initialized && ihdr->interlace)
{
if (ihdr->width <= passes[pngp->pass_pos].x ||
ihdr->height <= passes[pngp->pass_pos].y) /* Empty pass */
if ( ihdr->width <= rpng_passes[pngp->pass_pos].x
|| ihdr->height <= rpng_passes[pngp->pass_pos].y) /* Empty pass */
return 1;
pngp->pass_width = (ihdr->width -
passes[pngp->pass_pos].x + passes[pngp->pass_pos].stride_x - 1) / passes[pngp->pass_pos].stride_x;
pngp->pass_height = (ihdr->height - passes[pngp->pass_pos].y +
passes[pngp->pass_pos].stride_y - 1) / passes[pngp->pass_pos].stride_y;
rpng_passes[pngp->pass_pos].x + rpng_passes[pngp->pass_pos].stride_x
- 1) / rpng_passes[pngp->pass_pos].stride_x;
pngp->pass_height = (ihdr->height - rpng_passes[pngp->pass_pos].y +
rpng_passes[pngp->pass_pos].stride_y - 1) / rpng_passes[pngp->pass_pos].stride_y;
pngp->data = (uint32_t*)malloc(
pngp->pass_width * pngp->pass_height * sizeof(uint32_t));
if (!pngp->data)
if (!(pngp->data = (uint32_t*)malloc(
pngp->pass_width * pngp->pass_height * sizeof(uint32_t))))
return -1;
pngp->ihdr = *ihdr;
pngp->ihdr.width = pngp->pass_width;
pngp->ihdr.height = pngp->pass_height;
png_pass_geom(&pngp->ihdr, pngp->pass_width,
rpng_pass_geom(&pngp->ihdr, pngp->pass_width,
pngp->pass_height, NULL, NULL, &pngp->pass_size);
if (pngp->pass_size > pngp->total_out)
@ -532,7 +532,7 @@ static int png_reverse_filter_init(const struct png_ihdr *ihdr,
if (pngp->pass_initialized)
return 0;
png_pass_geom(ihdr, ihdr->width, ihdr->height, &pngp->bpp, &pngp->pitch, &pass_size);
rpng_pass_geom(ihdr, ihdr->width, ihdr->height, &pngp->bpp, &pngp->pitch, &pass_size);
if (pngp->total_out < pass_size)
return -1;
@ -551,11 +551,12 @@ static int png_reverse_filter_init(const struct png_ihdr *ihdr,
return 0;
error:
png_reverse_filter_deinit(pngp);
rpng_reverse_filter_deinit(pngp);
return -1;
}
static int png_reverse_filter_copy_line(uint32_t *data, const struct png_ihdr *ihdr,
static int rpng_reverse_filter_copy_line(uint32_t *data,
const struct png_ihdr *ihdr,
struct rpng_process *pngp, unsigned filter)
{
unsigned i;
@ -603,21 +604,22 @@ static int png_reverse_filter_copy_line(uint32_t *data, const struct png_ihdr *i
switch (ihdr->color_type)
{
case PNG_IHDR_COLOR_GRAY:
png_reverse_filter_copy_line_bw(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
rpng_reverse_filter_copy_line_bw(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
break;
case PNG_IHDR_COLOR_RGB:
png_reverse_filter_copy_line_rgb(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
rpng_reverse_filter_copy_line_rgb(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
break;
case PNG_IHDR_COLOR_PLT:
png_reverse_filter_copy_line_plt(data, pngp->decoded_scanline, ihdr->width,
rpng_reverse_filter_copy_line_plt(
data, pngp->decoded_scanline, ihdr->width,
ihdr->depth, pngp->palette);
break;
case PNG_IHDR_COLOR_GRAY_ALPHA:
png_reverse_filter_copy_line_gray_alpha(data, pngp->decoded_scanline, ihdr->width,
rpng_reverse_filter_copy_line_gray_alpha(data, pngp->decoded_scanline, ihdr->width,
ihdr->depth);
break;
case PNG_IHDR_COLOR_RGBA:
png_reverse_filter_copy_line_rgba(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
rpng_reverse_filter_copy_line_rgba(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
break;
}
@ -626,7 +628,8 @@ static int png_reverse_filter_copy_line(uint32_t *data, const struct png_ihdr *i
return IMAGE_PROCESS_NEXT;
}
static int png_reverse_filter_regular_iterate(uint32_t **data, const struct png_ihdr *ihdr,
static int rpng_reverse_filter_regular_iterate(
uint32_t **data, const struct png_ihdr *ihdr,
struct rpng_process *pngp)
{
int ret = IMAGE_PROCESS_END;
@ -634,7 +637,7 @@ static int png_reverse_filter_regular_iterate(uint32_t **data, const struct png_
{
unsigned filter = *pngp->inflate_buf++;
pngp->restore_buf_size += 1;
ret = png_reverse_filter_copy_line(*data,
ret = rpng_reverse_filter_copy_line(*data,
ihdr, pngp, filter);
if (ret == IMAGE_PROCESS_END || ret == IMAGE_PROCESS_ERROR_END)
goto end;
@ -652,7 +655,7 @@ static int png_reverse_filter_regular_iterate(uint32_t **data, const struct png_
return IMAGE_PROCESS_NEXT;
end:
png_reverse_filter_deinit(pngp);
rpng_reverse_filter_deinit(pngp);
pngp->inflate_buf -= pngp->restore_buf_size;
*data -= pngp->data_restore_buf_size;
@ -660,28 +663,28 @@ end:
return ret;
}
static int png_reverse_filter_adam7_iterate(uint32_t **data_,
static int rpng_reverse_filter_adam7_iterate(uint32_t **data_,
const struct png_ihdr *ihdr,
struct rpng_process *pngp)
{
int ret = 0;
bool to_next = pngp->pass_pos < ARRAY_SIZE(passes);
bool to_next = pngp->pass_pos < ARRAY_SIZE(rpng_passes);
uint32_t *data = *data_;
if (!to_next)
return IMAGE_PROCESS_END;
if ((ret = png_reverse_filter_init(ihdr, pngp)) == 1)
if ((ret = rpng_reverse_filter_init(ihdr, pngp)) == 1)
return IMAGE_PROCESS_NEXT;
else if (ret == -1)
return IMAGE_PROCESS_ERROR_END;
if (png_reverse_filter_init(&pngp->ihdr, pngp) == -1)
if (rpng_reverse_filter_init(&pngp->ihdr, pngp) == -1)
return IMAGE_PROCESS_ERROR;
do
{
ret = png_reverse_filter_regular_iterate(&pngp->data,
ret = rpng_reverse_filter_regular_iterate(&pngp->data,
&pngp->ihdr, pngp);
} while (ret == IMAGE_PROCESS_NEXT);
@ -693,8 +696,9 @@ static int png_reverse_filter_adam7_iterate(uint32_t **data_,
pngp->total_out -= pngp->pass_size;
png_reverse_filter_adam7_deinterlace_pass(data,
ihdr, pngp->data, pngp->pass_width, pngp->pass_height, &passes[pngp->pass_pos]);
rpng_reverse_filter_adam7_deinterlace_pass(data,
ihdr, pngp->data, pngp->pass_width, pngp->pass_height,
&rpng_passes[pngp->pass_pos]);
free(pngp->data);
@ -707,11 +711,11 @@ static int png_reverse_filter_adam7_iterate(uint32_t **data_,
return IMAGE_PROCESS_NEXT;
}
static int png_reverse_filter_adam7(uint32_t **data_,
static int rpng_reverse_filter_adam7(uint32_t **data_,
const struct png_ihdr *ihdr,
struct rpng_process *pngp)
{
int ret = png_reverse_filter_adam7_iterate(data_,
int ret = rpng_reverse_filter_adam7_iterate(data_,
ihdr, pngp);
switch (ret)
@ -738,18 +742,8 @@ static int png_reverse_filter_adam7(uint32_t **data_,
return ret;
}
static int png_reverse_filter_iterate(rpng_t *rpng, uint32_t **data)
{
if (!rpng)
return false;
if (rpng->ihdr.interlace && rpng->process)
return png_reverse_filter_adam7(data, &rpng->ihdr, rpng->process);
return png_reverse_filter_regular_iterate(data, &rpng->ihdr, rpng->process);
}
static int rpng_load_image_argb_process_inflate_init(rpng_t *rpng, uint32_t **data)
static int rpng_load_image_argb_process_inflate_init(
rpng_t *rpng, uint32_t **data)
{
bool zstatus;
enum trans_stream_error terror;
@ -793,7 +787,7 @@ end:
process->palette = rpng->palette;
if (rpng->ihdr.interlace != 1)
if (png_reverse_filter_init(&rpng->ihdr, process) == -1)
if (rpng_reverse_filter_init(&rpng->ihdr, process) == -1)
goto false_end;
process->inflate_initialized = true;
@ -805,33 +799,7 @@ false_end:
return -1;
}
static bool png_read_plte(uint8_t *buf,
uint32_t *buffer, unsigned entries)
{
unsigned i;
for (i = 0; i < entries; i++)
{
uint32_t r = buf[3 * i + 0];
uint32_t g = buf[3 * i + 1];
uint32_t b = buf[3 * i + 2];
buffer[i] = (r << 16) | (g << 8) | (b << 0) | (0xffu << 24);
}
return true;
}
static bool png_read_trns(uint8_t *buf, uint32_t *palette, unsigned entries)
{
unsigned i;
for (i = 0; i < entries; i++, buf++, palette++)
*palette = (*palette & 0x00ffffff) | (unsigned)*buf << 24;
return true;
}
bool png_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)
static bool rpng_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)
{
uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk_size);
@ -884,7 +852,7 @@ static struct rpng_process *rpng_process_init(rpng_t *rpng)
process->stream = NULL;
process->stream_backend = trans_stream_get_zlib_inflate_backend();
png_pass_geom(&rpng->ihdr, rpng->ihdr.width,
rpng_pass_geom(&rpng->ihdr, rpng->ihdr.width,
rpng->ihdr.height, NULL, NULL, &process->inflate_buf_size);
if (rpng->ihdr.interlace == 1) /* To be sure. */
process->inflate_buf_size *= 2;
@ -926,10 +894,18 @@ error:
return NULL;
}
static enum png_chunk_type read_chunk_header(
/**
* rpng_read_chunk_header:
*
* Leaf function.
*
* @return The PNG type of the memory chunk (i.e. IHDR, IDAT, IEND,
PLTE, and/or tRNS)
**/
static enum png_chunk_type rpng_read_chunk_header(
uint8_t *buf, uint32_t chunk_size)
{
unsigned i;
int i;
char type[4];
for (i = 0; i < 4; i++)
@ -1001,13 +977,13 @@ bool rpng_iterate_image(rpng_t *rpng)
if (rpng->buff_end - buf < 8)
return false;
chunk_size = dword_be(buf);
chunk_size = rpng_dword_be(buf);
/* Check whether chunk will overflow the data buffer */
if (buf + 8 + chunk_size > rpng->buff_end)
return false;
switch (read_chunk_header(buf, chunk_size))
switch (rpng_read_chunk_header(buf, chunk_size))
{
case PNG_CHUNK_NOOP:
default:
@ -1025,8 +1001,8 @@ bool rpng_iterate_image(rpng_t *rpng)
buf += 4 + 4;
rpng->ihdr.width = dword_be(buf + 0);
rpng->ihdr.height = dword_be(buf + 4);
rpng->ihdr.width = rpng_dword_be(buf + 0);
rpng->ihdr.height = rpng_dword_be(buf + 4);
rpng->ihdr.depth = buf[8];
rpng->ihdr.color_type = buf[9];
rpng->ihdr.compression = buf[10];
@ -1039,7 +1015,7 @@ bool rpng_iterate_image(rpng_t *rpng)
|| (uint64_t)rpng->ihdr.width*rpng->ihdr.height*sizeof(uint32_t) >= 0x80000000)
return false;
if (!png_process_ihdr(&rpng->ihdr))
if (!rpng_process_ihdr(&rpng->ihdr))
return false;
if (rpng->ihdr.compression != 0)
@ -1055,8 +1031,14 @@ bool rpng_iterate_image(rpng_t *rpng)
case PNG_CHUNK_PLTE:
{
int i;
unsigned entries = chunk_size / 3;
if (entries > 256)
return false;
if (chunk_size % 3)
return false;
if ( !rpng->has_ihdr
|| rpng->has_plte
|| rpng->has_iend
@ -1064,16 +1046,15 @@ bool rpng_iterate_image(rpng_t *rpng)
|| rpng->has_trns)
return false;
if (chunk_size % 3)
return false;
if (entries > 256)
return false;
buf += 8;
if (!png_read_plte(buf, rpng->palette, entries))
return false;
for (i = 0; i < (int)entries; i++)
{
uint32_t r = buf[3 * i + 0];
uint32_t g = buf[3 * i + 1];
uint32_t b = buf[3 * i + 2];
rpng->palette[i] = (r << 16) | (g << 8) | (b << 0) | (0xffu << 24);
}
rpng->has_plte = true;
}
@ -1085,14 +1066,17 @@ bool rpng_iterate_image(rpng_t *rpng)
if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT)
{
int i;
uint32_t *palette;
/* we should compare with the number of palette entries */
if (chunk_size > 256)
return false;
buf += 8;
buf += 8;
palette = rpng->palette;
if (!png_read_trns(buf, rpng->palette, chunk_size))
return false;
for (i = 0; i < chunk_size; i++, buf++, palette++)
*palette = (*palette & 0x00ffffff) | (unsigned)*buf << 24;
}
/* TODO: support colorkey in grayscale and truecolor images */
@ -1103,7 +1087,7 @@ bool rpng_iterate_image(rpng_t *rpng)
if (!(rpng->has_ihdr) || rpng->has_iend || (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT && !(rpng->has_plte)))
return false;
if (!png_realloc_idat(&rpng->idat_buf, chunk_size))
if (!rpng_realloc_idat(&rpng->idat_buf, chunk_size))
return false;
buf += 8;
@ -1137,8 +1121,6 @@ int rpng_process_image(rpng_t *rpng,
{
uint32_t **data = (uint32_t**)_data;
(void)size;
if (!rpng->process)
{
struct rpng_process *process = rpng_process_init(rpng);
@ -1160,7 +1142,9 @@ int rpng_process_image(rpng_t *rpng,
*width = rpng->ihdr.width;
*height = rpng->ihdr.height;
return png_reverse_filter_iterate(rpng, data);
if (rpng->ihdr.interlace && rpng->process)
return rpng_reverse_filter_adam7(data, &rpng->ihdr, rpng->process);
return rpng_reverse_filter_regular_iterate(data, &rpng->ihdr, rpng->process);
error:
if (rpng->process)
@ -1218,14 +1202,20 @@ bool rpng_start(rpng_t *rpng)
return true;
}
/**
* rpng_is_valid:
*
* Check if @rpng is a valid PNG image.
* Must contain an IHDR chunk, one or more IDAT
* chunks, and an IEND chunk.
*
* Leaf function.
*
* @return true if it's a valid PNG image, otherwise false.
**/
bool rpng_is_valid(rpng_t *rpng)
{
/* A valid PNG image must contain an IHDR chunk,
* one or more IDAT chunks, and an IEND chunk */
if (rpng && rpng->has_ihdr && rpng->has_idat && rpng->has_iend)
return true;
return false;
return (rpng && rpng->has_ihdr && rpng->has_idat && rpng->has_iend);
}
bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len)