From 2ac62e0cd3bdd1431ae666e0f37f09fda24dbfa7 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 20 Feb 2015 22:49:49 +0100 Subject: [PATCH] Restore original rpng.c --- libretro-common/formats/png/Makefile | 2 +- libretro-common/formats/png/rpng.c | 355 +++++++++++---------------- 2 files changed, 148 insertions(+), 209 deletions(-) diff --git a/libretro-common/formats/png/Makefile b/libretro-common/formats/png/Makefile index b757cf4da2..ea84697cb4 100644 --- a/libretro-common/formats/png/Makefile +++ b/libretro-common/formats/png/Makefile @@ -8,7 +8,7 @@ CFLAGS += -DHAVE_IMLIB2 LDFLAGS += -lImlib2 endif -SOURCES := rpng.c rpng_test.c ../../file/nbio/nbio_stdio.c +SOURCES := rpng_nbio.c rpng_test.c ../../file/nbio/nbio_stdio.c OBJS := $(SOURCES:.c=.o) CFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB -DHAVE_ZLIB_DEFLATE -DRPNG_TEST -I../../include diff --git a/libretro-common/formats/png/rpng.c b/libretro-common/formats/png/rpng.c index e7814be07b..5126fee593 100644 --- a/libretro-common/formats/png/rpng.c +++ b/libretro-common/formats/png/rpng.c @@ -28,8 +28,6 @@ #include #include -#include - #ifdef GEKKO #include #endif @@ -127,12 +125,21 @@ static enum png_chunk_type png_chunk_type(const struct png_chunk *chunk) return PNG_CHUNK_NOOP; } -static bool png_alloc_chunk(struct png_chunk *chunk) +static bool png_read_chunk(FILE *file, struct png_chunk *chunk) { free(chunk->data); chunk->data = (uint8_t*)calloc(1, chunk->size + sizeof(uint32_t)); /* CRC32 */ if (!chunk->data) return false; + + if (fread(chunk->data, 1, chunk->size + + sizeof(uint32_t), file) != (chunk->size + sizeof(uint32_t))) + { + free(chunk->data); + return false; + } + + /* Ignore CRC. */ return true; } @@ -145,12 +152,15 @@ static void png_free_chunk(struct png_chunk *chunk) chunk->data = NULL; } -static bool png_parse_ihdr(struct png_chunk *chunk, - struct png_ihdr *ihdr) +static bool png_parse_ihdr(FILE *file, + struct png_chunk *chunk, struct png_ihdr *ihdr) { unsigned i; bool ret = true; + if (!png_read_chunk(file, chunk)) + return false; + if (chunk->size != 13) GOTO_END_ERROR(); @@ -597,7 +607,8 @@ static bool png_reverse_filter_adam7(uint32_t *data, return true; } -static bool png_realloc_idat(const struct png_chunk *chunk, struct idat_buffer *buf) +static bool png_append_idat(FILE *file, + const struct png_chunk *chunk, struct idat_buffer *buf) { uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk->size); @@ -605,14 +616,25 @@ static bool png_realloc_idat(const struct png_chunk *chunk, struct idat_buffer * return false; buf->data = new_buffer; + if (fread(buf->data + buf->size, 1, chunk->size, file) != chunk->size) + return false; + if (fseek(file, sizeof(uint32_t), SEEK_CUR) < 0) + return false; + buf->size += chunk->size; return true; } -static bool png_read_plte_into_buf(uint32_t *buffer, unsigned entries) +static bool png_read_plte(FILE *file, uint32_t *buffer, unsigned entries) { unsigned i; uint8_t buf[256 * 3]; + if (entries > 256) + return false; + + if (fread(buf, 3, entries, file) != entries) + return false; + for (i = 0; i < entries; i++) { uint32_t r = buf[3 * i + 0]; @@ -621,172 +643,9 @@ static bool png_read_plte_into_buf(uint32_t *buffer, unsigned entries) buffer[i] = (r << 16) | (g << 8) | (b << 0) | (0xffu << 24); } - return true; -} - -bool rpng_load_image_argb_iterate(FILE *file, struct png_chunk *chunk, - uint32_t *palette, - struct png_ihdr *ihdr, struct idat_buffer *idat_buf, - bool *has_ihdr, bool *has_idat, - bool *has_iend, bool *has_plte, size_t *increment_size) -{ - switch (png_chunk_type(chunk)) - { - case PNG_CHUNK_NOOP: - default: - *increment_size = chunk->size + sizeof(uint32_t); - break; - - case PNG_CHUNK_ERROR: - return false; - - case PNG_CHUNK_IHDR: - if (*has_ihdr || *has_idat || *has_iend) - return false; - - if (!png_alloc_chunk(chunk)) - return false; - - if (fread(chunk->data, 1, chunk->size + - sizeof(uint32_t), file) != (chunk->size + sizeof(uint32_t))) - { - free(chunk->data); - return false; - } - - if (!png_parse_ihdr(chunk, ihdr)) - return false; - - *has_ihdr = true; - break; - - case PNG_CHUNK_PLTE: - { - unsigned entries = chunk->size / 3; - - if (!*has_ihdr || *has_plte || *has_iend || *has_idat) - return false; - - if (chunk->size % 3) - return false; - - if (entries > 256) - return false; - - if (fread(&palette, 3, entries, file) != entries) - return false; - - if (!png_read_plte_into_buf(palette, entries)) - return false; - - *increment_size = sizeof(uint32_t); - *has_plte = true; - } - break; - - case PNG_CHUNK_IDAT: - { - if (!(*has_ihdr) || *has_iend || (ihdr->color_type == 3 && !(*has_plte))) - return false; - - if (!png_realloc_idat(chunk, idat_buf)) - return false; - - if (fread(idat_buf->data + idat_buf->size, 1, chunk->size, file) != chunk->size) - return false; - - *increment_size = sizeof(uint32_t); - idat_buf->size += chunk->size; - - *has_idat = true; - } - break; - - case PNG_CHUNK_IEND: - if (!(*has_ihdr) || !(*has_idat)) - return false; - - - *increment_size = sizeof(uint32_t); - *has_iend = true; - break; - } - - return true; -} - -bool rpng_load_image_argb_process(uint8_t *inflate_buf, - struct png_ihdr *ihdr, - struct idat_buffer *idat_buf, uint32_t **data, - uint32_t *palette, - unsigned *width, unsigned *height) -{ - z_stream stream = {0}; - size_t inflate_buf_size = 0; - - if (inflateInit(&stream) != Z_OK) + if (fseek(file, sizeof(uint32_t), SEEK_CUR) < 0) return false; - png_pass_geom(ihdr, ihdr->width, - ihdr->height, NULL, NULL, &inflate_buf_size); - if (ihdr->interlace == 1) /* To be sure. */ - inflate_buf_size *= 2; - - inflate_buf = (uint8_t*)malloc(inflate_buf_size); - if (!inflate_buf) - return false; - - stream.next_in = idat_buf->data; - stream.avail_in = idat_buf->size; - stream.avail_out = inflate_buf_size; - stream.next_out = inflate_buf; - - if (inflate(&stream, Z_FINISH) != Z_STREAM_END) - { - inflateEnd(&stream); - return false; - } - inflateEnd(&stream); - - *width = ihdr->width; - *height = ihdr->height; -#ifdef GEKKO - /* we often use these in textures, make sure they're 32-byte aligned */ - *data = (uint32_t*)memalign(32, ihdr->width * ihdr->height * sizeof(uint32_t)); -#else - *data = (uint32_t*)malloc(ihdr->width * ihdr->height * sizeof(uint32_t)); -#endif - if (!*data) - return false; - - if (ihdr->interlace == 1) - { - if (!png_reverse_filter_adam7(*data, - ihdr, inflate_buf, stream.total_out, palette)) - return false; - } - else if (!png_reverse_filter(*data, - ihdr, inflate_buf, stream.total_out, palette)) - return false; - - return true; -} - -static bool rpng_load_image_argb_init(FILE *file, - uint32_t **data, - unsigned *width, unsigned *height, - long *file_len) -{ - - *data = NULL; - *width = 0; - *height = 0; - - fseek(file, 0, SEEK_END); - *file_len = ftell(file); - rewind(file); - - return true; } @@ -794,7 +653,11 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, unsigned *width, unsigned *height) { long pos, file_len; + FILE *file; + char header[8]; uint8_t *inflate_buf = NULL; + size_t inflate_buf_size = 0; + z_stream stream = {0}; struct idat_buffer idat_buf = {0}; struct png_ihdr ihdr = {0}; uint32_t palette[256] = {0}; @@ -803,68 +666,144 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, bool has_iend = false; bool has_plte = false; bool ret = true; - FILE *file; + + *data = NULL; + *width = 0; + *height = 0; + file = fopen(path, "rb"); - if (!file) - { - fprintf(stderr, "Tried to open file: %s\n", path); - GOTO_END_ERROR(); - } + return false; - if (!rpng_load_image_argb_init(file, data, width, height, &file_len)) + fseek(file, 0, SEEK_END); + file_len = ftell(file); + rewind(file); + + if (fread(header, 1, sizeof(header), file) != sizeof(header)) GOTO_END_ERROR(); - { - char header[8]; - - if (fread(header, 1, sizeof(header), file) != sizeof(header)) - return false; - - if (memcmp(header, png_magic, sizeof(png_magic)) != 0) - return false; - } + if (memcmp(header, png_magic, sizeof(png_magic)) != 0) + GOTO_END_ERROR(); /* feof() apparently isn't triggered after a seek (IEND). */ - - for (pos = 0; pos < file_len && pos >= 0; pos = ftell(file)) + for (pos = ftell(file); + pos < file_len && pos >= 0; pos = ftell(file)) { - size_t increment = 0; struct png_chunk chunk = {0}; if (!read_chunk_header(file, &chunk)) GOTO_END_ERROR(); - if (!rpng_load_image_argb_iterate( - file, &chunk, palette, &ihdr, &idat_buf, - &has_ihdr, &has_idat, &has_iend, &has_plte, - &increment)) - GOTO_END_ERROR(); - - if (increment != 0) + switch (png_chunk_type(&chunk)) { - if (fseek(file, increment, SEEK_CUR) < 0) - GOTO_END_ERROR(); - } + case PNG_CHUNK_NOOP: + default: + if (fseek(file, chunk.size + sizeof(uint32_t), SEEK_CUR) < 0) + GOTO_END_ERROR(); + break; + case PNG_CHUNK_ERROR: + GOTO_END_ERROR(); + + case PNG_CHUNK_IHDR: + if (has_ihdr || has_idat || has_iend) + GOTO_END_ERROR(); + + if (!png_parse_ihdr(file, &chunk, &ihdr)) + GOTO_END_ERROR(); + + has_ihdr = true; + break; + + case PNG_CHUNK_PLTE: + if (!has_ihdr || has_plte || has_iend || has_idat) + GOTO_END_ERROR(); + + if (chunk.size % 3) + GOTO_END_ERROR(); + + if (!png_read_plte(file, palette, chunk.size / 3)) + GOTO_END_ERROR(); + + has_plte = true; + break; + + case PNG_CHUNK_IDAT: + if (!has_ihdr || has_iend || (ihdr.color_type == 3 && !has_plte)) + GOTO_END_ERROR(); + + if (!png_append_idat(file, &chunk, &idat_buf)) + GOTO_END_ERROR(); + + has_idat = true; + break; + + case PNG_CHUNK_IEND: + if (!has_ihdr || !has_idat) + GOTO_END_ERROR(); + + if (fseek(file, sizeof(uint32_t), SEEK_CUR) < 0) + GOTO_END_ERROR(); + + has_iend = true; + break; + } } if (!has_ihdr || !has_idat || !has_iend) GOTO_END_ERROR(); - - rpng_load_image_argb_process(inflate_buf, - &ihdr, &idat_buf, data, palette, - width, height); + + if (inflateInit(&stream) != Z_OK) + GOTO_END_ERROR(); + + png_pass_geom(&ihdr, ihdr.width, ihdr.height, NULL, NULL, &inflate_buf_size); + if (ihdr.interlace == 1) /* To be sure. */ + inflate_buf_size *= 2; + + inflate_buf = (uint8_t*)malloc(inflate_buf_size); + if (!inflate_buf) + GOTO_END_ERROR(); + + stream.next_in = idat_buf.data; + stream.avail_in = idat_buf.size; + stream.avail_out = inflate_buf_size; + stream.next_out = inflate_buf; + + if (inflate(&stream, Z_FINISH) != Z_STREAM_END) + { + inflateEnd(&stream); + GOTO_END_ERROR(); + } + inflateEnd(&stream); + + *width = ihdr.width; + *height = ihdr.height; +#ifdef GEKKO + /* we often use these in textures, make sure they're 32-byte aligned */ + *data = (uint32_t*)memalign(32, ihdr.width * ihdr.height * sizeof(uint32_t)); +#else + *data = (uint32_t*)malloc(ihdr.width * ihdr.height * sizeof(uint32_t)); +#endif + if (!*data) + GOTO_END_ERROR(); + + if (ihdr.interlace == 1) + { + if (!png_reverse_filter_adam7(*data, + &ihdr, inflate_buf, stream.total_out, palette)) + GOTO_END_ERROR(); + } + else if (!png_reverse_filter(*data, + &ihdr, inflate_buf, stream.total_out, palette)) + GOTO_END_ERROR(); end: if (file) fclose(file); if (!ret) free(*data); - if (idat_buf.data) - free(idat_buf.data); - if (inflate_buf) - free(inflate_buf); + free(idat_buf.data); + free(inflate_buf); return ret; }