From d94fb966a272be7189fd5db0df4c4f8853fa9ea3 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 6 Feb 2018 11:38:40 +0100 Subject: [PATCH] test_iff: Add small tool to test for IFF file structures useful to see if an IFF file is malformed, but also to see how many frames there is in an animation, etc. --- tools/Makefile | 7 +- tools/test_iff/.gitignore | 2 + tools/test_iff/Makefile | 10 ++ tools/test_iff/checkiff.sh | 28 +++++ tools/test_iff/parseiff.c | 210 +++++++++++++++++++++++++++++++++++++ 5 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 tools/test_iff/.gitignore create mode 100644 tools/test_iff/Makefile create mode 100755 tools/test_iff/checkiff.sh create mode 100644 tools/test_iff/parseiff.c diff --git a/tools/Makefile b/tools/Makefile index 0ad4bb5a..e024c483 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,9 +1,12 @@ -.PHONY: all gifanalyzer sdl_image_test +.PHONY: all gifanalyzer sdl_image_test test_iff -all: gifanalyzer sdl_image_test +all: gifanalyzer sdl_image_test test_iff gifanalyzer: $(MAKE) -C $@ sdl_image_test: $(MAKE) -C $@ + +test_iff: + $(MAKE) -C $@ diff --git a/tools/test_iff/.gitignore b/tools/test_iff/.gitignore new file mode 100644 index 00000000..3effc978 --- /dev/null +++ b/tools/test_iff/.gitignore @@ -0,0 +1,2 @@ +*.o +parseiff diff --git a/tools/test_iff/Makefile b/tools/test_iff/Makefile new file mode 100644 index 00000000..d1ffc306 --- /dev/null +++ b/tools/test_iff/Makefile @@ -0,0 +1,10 @@ +CFLAGS = -Wall + +.PHONY: all clean + +all: parseiff + +clean: + $(RM) *.o parseiff + +parseiff: parseiff.o diff --git a/tools/test_iff/checkiff.sh b/tools/test_iff/checkiff.sh new file mode 100755 index 00000000..65e97e15 --- /dev/null +++ b/tools/test_iff/checkiff.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# set executable +PARSEIFF=./parseiff +if [ ! -x ${PARSEIFF} ] ; then + PARSEIFF="$(dirname $0)/parseiff" +fi + +if [ "$1" = "" ] ; then + echo "Usage: $0 " + echo "" + echo "Just run the parser on files. For directories, list files with parsing errors." + exit 1 +fi + +if [ -d "$1" ] ; then + find "$1" | + while IFS= read line; do + if [ -f "$line" ] && file "$line" | grep -q "IFF data" ; then + ${PARSEIFF} "$line" > /dev/null + #if ! ${PARSEIFF} "$line" > /dev/null ; then + # echo "error in $line" + #fi + fi + done +else + ${PARSEIFF} $1 +fi diff --git a/tools/test_iff/parseiff.c b/tools/test_iff/parseiff.c new file mode 100644 index 00000000..d9ab2a5a --- /dev/null +++ b/tools/test_iff/parseiff.c @@ -0,0 +1,210 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + * Gif Analyzer tool + + Copyright 2018 Thomas Bernard + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see +*/ + +#include +#include +#include +#include + +#define IFF_EOF -1 +#define IFF_FILE_TOO_LONG -2 +#define IFF_UNRECOGNIZED_CONTID -3 +#define IFF_SIZE_MISMATCH -4 + +const char * parseiff_errorstr(int err) +{ + switch (err) + { + case IFF_EOF: + return "prematurate End OF File"; + case IFF_FILE_TOO_LONG: + return "Extra bytes in file after end of IFF"; + case IFF_UNRECOGNIZED_CONTID: + return "Unrecognized IFF container ID (should probably be FORM)"; + case IFF_SIZE_MISMATCH: + return "Size Mismatch"; + default: + return "Unknown error"; + } +} + +static int read_long_be(FILE * f, uint32_t * l) +{ + int i, b; + for (i = 0; i < 4; i++) + { + b = getc(f); + if (b == EOF) + return IFF_EOF; + *l = (*l << 8) | b; + } + return 0; +} + +static const char * id_chunks[] = { + "LIST", "FORM", "PROP", "CAT ", " ", NULL +}; + +static int iscontainer(const char * chunkid) +{ + int i; + for (i = 0; id_chunks[i]; i++) + { + if (memcmp(id_chunks[i], chunkid, 4) == 0) + return 1; + } + return 0; +} + +static int parseiff_chunks(FILE * f, uint32_t size, int level) +{ + int i, index; + size_t n; + char section[4]; + uint32_t section_size; + + if (size&1) + { + fprintf(stderr, "WARNING: odd size of Container chunk, adjusting\n"); + size++; + } + index = 0; + while (size >= 8) + { + printf("%06lX: ", ftell(f)); + for (i = 0; i < level; i++) + printf(" "); + printf("#%02d ", index++); + n = fread(section, 1, 4, f); + if (n != 4) + return IFF_EOF; + if (read_long_be(f, §ion_size) < 0) + return IFF_EOF; + size -= 8; + if (iscontainer(section)) + { + int r; + char format[4]; + + n = fread(format, 1, 4, f); + if (n != 4) + return IFF_EOF; + printf("%.4s %u %.4s\n", section, section_size, format); + r = parseiff_chunks(f, section_size - 4, level+1); + if (r < 0) + return r; + } + else + { + printf("%.4s %u\n", section, section_size); + section_size = (section_size+1)&~1; // round to WORD boundary + fseek(f, section_size, SEEK_CUR); + } + if (section_size > size) + { + fprintf(stderr, "remaining size in chunk : %u, section size is %u\n", size, section_size); + return IFF_SIZE_MISMATCH; + } + size -= section_size; + } + if (size != 0) + { + fprintf(stderr, "level=%d size=%u\n", level, size); + return IFF_SIZE_MISMATCH; + } + return 0; +} + +static int parseiff_container(FILE * f, int level) +{ + int i; + size_t n; + char contid[4]; + char format[4]; + uint32_t size; + + printf("%06lX: ", ftell(f)); + for (i = 0; i < level; i++) + printf(" "); + n = fread(contid, 1, 4, f); + if (n != 4) + return IFF_EOF; + if (read_long_be(f, &size) < 0) + return IFF_EOF; + printf("%.4s %u ", contid, size); + if (iscontainer(contid)) + { + n = fread(format, 1, 4, f); + if (n != 4) + return IFF_EOF; + printf("%.4s\n", format); + return parseiff_chunks(f, size - 4, level+1); + } + printf("\n"); + return IFF_UNRECOGNIZED_CONTID; +} + +int parseiff(FILE * f) +{ + int r; + long offset, file_size; + r = parseiff_container(f, 0); + if (r < 0) + return r; + // check we are at end of file + offset = ftell(f); + fseek(f, 0, SEEK_END); + file_size = ftell(f); + if (offset != file_size) + { + fprintf(stderr, "parsed %ld bytes, but file is %ld bytes long.\n", offset, file_size); + return IFF_FILE_TOO_LONG; + } + return 0; +} + +int main(int argc, char * * argv) +{ + const char * filename; + FILE * f; + int r; + + printf("IFF file parser. Displays structure of IFF files.\n"); + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + return 1; + } + filename = argv[1]; + f = fopen(filename, "rb"); + if (f == NULL) + { + fprintf(stderr, "Can't open file %s for reading.\n", filename); + return 2; + } + r = parseiff(f); + if (r < 0) + { + putchar('\n'); + fprintf(stderr, "%s: ERROR %s (%d)\n", filename, parseiff_errorstr(r), r); + } + return r; +}