summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2016-08-23 10:30:57 +0100
committerVincent Sanders <vince@kyllikki.org>2016-08-23 10:30:57 +0100
commit30b1b0baa029c809fd104f0013454c408cdc1418 (patch)
tree11cb53d747d850f0bb76aedf32c86b71016fbd02
parentee6294d3f46d41a3f279adb147a386b10e96a5aa (diff)
downloadlibnsgif-30b1b0baa029c809fd104f0013454c408cdc1418.tar.gz
libnsgif-30b1b0baa029c809fd104f0013454c408cdc1418.tar.bz2
improve gif test decoder to limit image size and output to file
-rw-r--r--test/decode_gif.c339
1 files changed, 178 insertions, 161 deletions
diff --git a/test/decode_gif.c b/test/decode_gif.c
index 2d2f37a..3ada667 100644
--- a/test/decode_gif.c
+++ b/test/decode_gif.c
@@ -17,199 +17,216 @@
#include "../include/libnsgif.h"
-unsigned char *load_file(const char *path, size_t *data_size);
-void warning(const char *context, int code);
-void *bitmap_create(int width, int height);
-void bitmap_set_opaque(void *bitmap, bool opaque);
-bool bitmap_test_opaque(void *bitmap);
-unsigned char *bitmap_get_buffer(void *bitmap);
-void bitmap_destroy(void *bitmap);
-void bitmap_modified(void *bitmap);
+#define BYTES_PER_PIXEL 4
+#define MAX_IMAGE_BYTES (48 * 1024 * 1024)
-int main(int argc, char *argv[])
+static void *bitmap_create(int width, int height)
{
- gif_bitmap_callback_vt bitmap_callbacks = {
- bitmap_create,
- bitmap_destroy,
- bitmap_get_buffer,
- bitmap_set_opaque,
- bitmap_test_opaque,
- bitmap_modified
- };
- gif_animation gif;
- size_t size;
- gif_result code;
- unsigned int i;
-
- if (argc != 2) {
- fprintf(stderr, "Usage: %s image.gif\n", argv[0]);
- return 1;
- }
-
- /* create our gif animation */
- gif_create(&gif, &bitmap_callbacks);
-
- /* load file into memory */
- unsigned char *data = load_file(argv[1], &size);
-
- /* begin decoding */
- do {
- code = gif_initialise(&gif, size, data);
- if (code != GIF_OK && code != GIF_WORKING) {
- warning("gif_initialise", code);
- exit(1);
- }
- } while (code != GIF_OK);
-
- printf("P3\n");
- printf("# %s\n", argv[1]);
- printf("# width %u \n", gif.width);
- printf("# height %u \n", gif.height);
- printf("# frame_count %u \n", gif.frame_count);
- printf("# frame_count_partial %u \n", gif.frame_count_partial);
- printf("# loop_count %u \n", gif.loop_count);
- printf("%u %u 256\n", gif.width, gif.height * gif.frame_count);
-
- /* decode the frames */
- for (i = 0; i != gif.frame_count; i++) {
- unsigned int row, col;
- unsigned char *image;
-
- code = gif_decode_frame(&gif, i);
- if (code != GIF_OK)
- warning("gif_decode_frame", code);
-
- printf("# frame %u:\n", i);
- image = (unsigned char *) gif.frame_image;
- for (row = 0; row != gif.height; row++) {
- for (col = 0; col != gif.width; col++) {
- size_t z = (row * gif.width + col) * 4;
- printf("%u %u %u ",
- (unsigned char) image[z],
- (unsigned char) image[z + 1],
- (unsigned char) image[z + 2]);
- }
- printf("\n");
- }
- }
-
- /* clean up */
- gif_finalise(&gif);
- free(data);
-
- return 0;
+ /* ensure a stupidly large bitmap is not created */
+ if (((long long)width * (long long)height) > (MAX_IMAGE_BYTES/BYTES_PER_PIXEL)) {
+ return NULL;
+ }
+ return calloc(width * height, BYTES_PER_PIXEL);
}
-unsigned char *load_file(const char *path, size_t *data_size)
+static void bitmap_set_opaque(void *bitmap, bool opaque)
{
- FILE *fd;
- struct stat sb;
- unsigned char *buffer;
- size_t size;
- size_t n;
-
- fd = fopen(path, "rb");
- if (!fd) {
- perror(path);
- exit(EXIT_FAILURE);
- }
-
- if (stat(path, &sb)) {
- perror(path);
- exit(EXIT_FAILURE);
- }
- size = sb.st_size;
-
- buffer = malloc(size);
- if (!buffer) {
- fprintf(stderr, "Unable to allocate %lld bytes\n",
- (long long) size);
- exit(EXIT_FAILURE);
- }
-
- n = fread(buffer, 1, size, fd);
- if (n != size) {
- perror(path);
- exit(EXIT_FAILURE);
- }
-
- fclose(fd);
-
- *data_size = size;
- return buffer;
+ (void) opaque; /* unused */
+ (void) bitmap; /* unused */
+ assert(bitmap);
}
-void warning(const char *context, gif_result code)
+static bool bitmap_test_opaque(void *bitmap)
{
- fprintf(stderr, "%s failed: ", context);
- switch (code)
- {
- case GIF_INSUFFICIENT_FRAME_DATA:
- fprintf(stderr, "GIF_INSUFFICIENT_FRAME_DATA");
- break;
- case GIF_FRAME_DATA_ERROR:
- fprintf(stderr, "GIF_FRAME_DATA_ERROR");
- break;
- case GIF_INSUFFICIENT_DATA:
- fprintf(stderr, "GIF_INSUFFICIENT_DATA");
- break;
- case GIF_DATA_ERROR:
- fprintf(stderr, "GIF_DATA_ERROR");
- break;
- case GIF_INSUFFICIENT_MEMORY:
- fprintf(stderr, "GIF_INSUFFICIENT_MEMORY");
- break;
- default:
- fprintf(stderr, "unknown code %i", code);
- break;
- }
- fprintf(stderr, "\n");
+ (void) bitmap; /* unused */
+ assert(bitmap);
+ return false;
}
-void *bitmap_create(int width, int height)
+static unsigned char *bitmap_get_buffer(void *bitmap)
{
- return calloc(width * height, 4);
+ assert(bitmap);
+ return bitmap;
}
-void bitmap_set_opaque(void *bitmap, bool opaque)
+static void bitmap_destroy(void *bitmap)
{
- (void) opaque; /* unused */
- (void) bitmap; /* unused */
- assert(bitmap);
+ assert(bitmap);
+ free(bitmap);
}
-bool bitmap_test_opaque(void *bitmap)
+static void bitmap_modified(void *bitmap)
{
- (void) bitmap; /* unused */
- assert(bitmap);
- return false;
+ (void) bitmap; /* unused */
+ assert(bitmap);
+ return;
}
-
-unsigned char *bitmap_get_buffer(void *bitmap)
+static unsigned char *load_file(const char *path, size_t *data_size)
{
- assert(bitmap);
- return bitmap;
+ FILE *fd;
+ struct stat sb;
+ unsigned char *buffer;
+ size_t size;
+ size_t n;
+
+ fd = fopen(path, "rb");
+ if (!fd) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(path, &sb)) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+ size = sb.st_size;
+
+ buffer = malloc(size);
+ if (!buffer) {
+ fprintf(stderr, "Unable to allocate %lld bytes\n",
+ (long long) size);
+ exit(EXIT_FAILURE);
+ }
+
+ n = fread(buffer, 1, size, fd);
+ if (n != size) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(fd);
+
+ *data_size = size;
+ return buffer;
}
-void bitmap_destroy(void *bitmap)
+static void warning(const char *context, gif_result code)
{
- assert(bitmap);
- free(bitmap);
+ fprintf(stderr, "%s failed: ", context);
+ switch (code)
+ {
+ case GIF_INSUFFICIENT_FRAME_DATA:
+ fprintf(stderr, "GIF_INSUFFICIENT_FRAME_DATA");
+ break;
+ case GIF_FRAME_DATA_ERROR:
+ fprintf(stderr, "GIF_FRAME_DATA_ERROR");
+ break;
+ case GIF_INSUFFICIENT_DATA:
+ fprintf(stderr, "GIF_INSUFFICIENT_DATA");
+ break;
+ case GIF_DATA_ERROR:
+ fprintf(stderr, "GIF_DATA_ERROR");
+ break;
+ case GIF_INSUFFICIENT_MEMORY:
+ fprintf(stderr, "GIF_INSUFFICIENT_MEMORY");
+ break;
+ default:
+ fprintf(stderr, "unknown code %i", code);
+ break;
+ }
+ fprintf(stderr, "\n");
}
-
-void bitmap_modified(void *bitmap)
+static void write_ppm(FILE* fh, const char *name, gif_animation *gif)
{
- (void) bitmap; /* unused */
- assert(bitmap);
- return;
+ unsigned int i;
+ gif_result code;
+
+ fprintf(fh, "P3\n");
+ fprintf(fh, "# %s\n", name);
+ fprintf(fh, "# width %u \n", gif->width);
+ fprintf(fh, "# height %u \n", gif->height);
+ fprintf(fh, "# frame_count %u \n", gif->frame_count);
+ fprintf(fh, "# frame_count_partial %u \n", gif->frame_count_partial);
+ fprintf(fh, "# loop_count %u \n", gif->loop_count);
+ fprintf(fh, "%u %u 256\n", gif->width, gif->height * gif->frame_count);
+
+ /* decode the frames */
+ for (i = 0; i != gif->frame_count; i++) {
+ unsigned int row, col;
+ unsigned char *image;
+
+ code = gif_decode_frame(gif, i);
+ if (code != GIF_OK)
+ warning("gif_decode_frame", code);
+
+ printf("# frame %u:\n", i);
+ image = (unsigned char *) gif->frame_image;
+ for (row = 0; row != gif->height; row++) {
+ for (col = 0; col != gif->width; col++) {
+ size_t z = (row * gif->width + col) * 4;
+ fprintf(fh, "%u %u %u ",
+ (unsigned char) image[z],
+ (unsigned char) image[z + 1],
+ (unsigned char) image[z + 2]);
+ }
+ fprintf(fh, "\n");
+ }
+ }
+
}
+int main(int argc, char *argv[])
+{
+ gif_bitmap_callback_vt bitmap_callbacks = {
+ bitmap_create,
+ bitmap_destroy,
+ bitmap_get_buffer,
+ bitmap_set_opaque,
+ bitmap_test_opaque,
+ bitmap_modified
+ };
+ gif_animation gif;
+ size_t size;
+ gif_result code;
+ unsigned char *data;
+ FILE *outf = stdout;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s image.gif [out]\n", argv[0]);
+ return 1;
+ }
+
+ if (argc > 2) {
+ outf = fopen(argv[2], "w+");
+ if (outf == NULL) {
+ fprintf(stderr, "Unable to open %s for writing\n", argv[2]);
+ return 2;
+ }
+ }
+
+ /* create our gif animation */
+ gif_create(&gif, &bitmap_callbacks);
+
+ /* load file into memory */
+ data = load_file(argv[1], &size);
+
+ /* begin decoding */
+ do {
+ code = gif_initialise(&gif, size, data);
+ if (code != GIF_OK && code != GIF_WORKING) {
+ warning("gif_initialise", code);
+ return 1;
+ }
+ } while (code != GIF_OK);
+
+ write_ppm(outf, argv[1], &gif);
+
+ if (argc > 2) {
+ fclose(outf);
+ }
+
+ /* clean up */
+ gif_finalise(&gif);
+ free(data);
+
+ return 0;
+}