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.
This commit is contained in:
parent
544a996361
commit
d94fb966a2
@ -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 $@
|
||||
|
||||
2
tools/test_iff/.gitignore
vendored
Normal file
2
tools/test_iff/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.o
|
||||
parseiff
|
||||
10
tools/test_iff/Makefile
Normal file
10
tools/test_iff/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
CFLAGS = -Wall
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: parseiff
|
||||
|
||||
clean:
|
||||
$(RM) *.o parseiff
|
||||
|
||||
parseiff: parseiff.o
|
||||
28
tools/test_iff/checkiff.sh
Executable file
28
tools/test_iff/checkiff.sh
Executable file
@ -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 <file|directory>"
|
||||
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
|
||||
210
tools/test_iff/parseiff.c
Normal file
210
tools/test_iff/parseiff.c
Normal file
@ -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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <file.iff>\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;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user