diff --git a/src/Makefile b/src/Makefile index 8d8a25a6..dd2d6177 100644 --- a/src/Makefile +++ b/src/Makefile @@ -819,7 +819,7 @@ endif TESTSOBJS = $(patsubst %.c,%.o,$(wildcard tests/*.c)) \ miscfileformats.o fileformats.o oldies.o libraw2crtc.o \ - loadsavefuncs.o \ + loadsavefuncs.o packbits.o \ unicode.o \ io.o realpath.o version.o pversion.o \ gfx2surface.o \ diff --git a/src/packbits.c b/src/packbits.c new file mode 100644 index 00000000..9d7f8c40 --- /dev/null +++ b/src/packbits.c @@ -0,0 +1,69 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2018-2019 Thomas Bernard + Copyright 2008 Yves Rizoud + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + 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 +*/ + +///@file packbits.c +/// Packbits compression as used in IFF etc. +/// see http://fileformats.archiveteam.org/wiki/PackBits + +#include +#include +#include "struct.h" +#include "gfx2log.h" +#include "packbits.h" + +int PackBits_unpack_from_file(FILE * f, byte * dest, unsigned int count) +{ + unsigned int i = 0; + while (i < count) + { + byte cmd; + if (fread(&cmd, 1, 1, f) != 1) + return PACKBITS_UNPACK_READ_ERROR; + if (cmd > 128) + { + // cmd > 128 => repeat (257 - cmd) the next byte + byte v; + if (fread(&v, 1, 1, f) != 1) + return PACKBITS_UNPACK_READ_ERROR; + if (count < (i + 257 - cmd)) + return PACKBITS_UNPACK_OVERFLOW_ERROR; + memset(dest + i, v, (257 - cmd)); + i += (257 - cmd); + } + else if (cmd < 128) + { + // cmd < 128 => copy (cmd + 1) bytes + if (count < (i + cmd + 1)) + return PACKBITS_UNPACK_OVERFLOW_ERROR; + if (fread(dest + i, 1, (cmd + 1), f) != (unsigned)(cmd + 1)) + return PACKBITS_UNPACK_READ_ERROR; + i += (cmd + 1); + } + else + { + // 128 = NOP + GFX2_Log(GFX2_WARNING, "NOP in packbits stream\n"); + } + } + return PACKBITS_UNPACK_OK; +} diff --git a/src/packbits.h b/src/packbits.h new file mode 100644 index 00000000..8feb8093 --- /dev/null +++ b/src/packbits.h @@ -0,0 +1,41 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2018-2019 Thomas Bernard + Copyright 2008 Yves Rizoud + Copyright 2007 Adrien Destugues + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + 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 +*/ + +///@file packbits.h +/// Packbits compression as used in IFF etc. + +#ifndef PACKBITS_H_INCLUDED +#define PACKBITS_H_INCLUDED + +// error codes : + +#define PACKBITS_UNPACK_OK 0 +#define PACKBITS_UNPACK_READ_ERROR -1 +#define PACKBITS_UNPACK_OVERFLOW_ERROR -2 + +/** + * @return PACKBITS_UNPACK_OK or PACKBITS_UNPACK_READ_ERROR or PACKBITS_UNPACK_OVERFLOW_ERROR + */ +int PackBits_unpack_from_file(FILE * f, byte * dest, unsigned int count); + +#endif diff --git a/src/tests/tests.c b/src/tests/tests.c index d2b4dc01..fd696fdf 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -33,6 +33,7 @@ #include #include "../struct.h" #include "../oldies.h" +#include "../packbits.h" #include "../gfx2log.h" unsigned int MOTO_MAP_pack(byte * packed, const byte * unpacked, unsigned int unpacked_len); @@ -160,6 +161,7 @@ int Test_Packbits(void) NULL }; const long best_packed = 7 + 22 + 23; + byte buffer[1024]; snprintf(tempfilename, sizeof(tempfilename), "/tmp/gfx2test-packbits-%lx", random()); GFX2_Log(GFX2_DEBUG, "tempfile %s\n", tempfilename); @@ -190,13 +192,30 @@ int Test_Packbits(void) return 0; } - // TODO : test unpacking + // test unpacking f = fopen(tempfilename, "rb"); if (f == NULL) { GFX2_Log(GFX2_ERROR, "Failed to open %s for reading\n", tempfilename); return 0; } + for (i = 0; tests[i]; i++) + { + size_t len = strlen(tests[i]); + memset(buffer, 0x80, len); + if (PackBits_unpack_from_file(f, buffer, len) != PACKBITS_UNPACK_OK) + { + GFX2_Log(GFX2_ERROR, "PackBits_unpack_from_file() failed\n"); + return 0; + } + if (memcmp(buffer, tests[i], len) != 0) + { + GFX2_Log(GFX2_ERROR, "uncompressed stream mismatch !\n"); + GFX2_LogHexDump(GFX2_ERROR, "original ", (const byte *)tests[i], 0, len); + GFX2_LogHexDump(GFX2_ERROR, "unpacked ", buffer, 0, len); + return 0; + } + } fclose(f); unlink(tempfilename); return 1; // test OK