diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbff58a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +xrle diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..30119e2 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +CFLAGS := -Wall -Wextra -std=c99 -pedantic -Og -g3 + +all: xrle +xrle: xrle.o main.o + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) diff --git a/main.c b/main.c new file mode 100644 index 0000000..64755da --- /dev/null +++ b/main.c @@ -0,0 +1,95 @@ +#include +#include +#include "xrle.h" + +void *read_file(const char *file, size_t *sz) +{ + FILE *f; + void *ret = NULL; + + f = fopen(file, "rb"); + if(f == NULL) + goto out; + + fseek(f, 0, SEEK_END); + *sz = ftell(f); + fseek(f, 0, SEEK_SET); + + ret = malloc(*sz); + if(ret != NULL) + fread(ret, 1, *sz, f); + + fclose(f); + +out: + return ret; +} + + +int main(int argc, char *argv[]) +{ + const char *file; + char *in, *out; + size_t insz, outsz; + + if(argc != 3 || argv[1][0] != '-') + { + fprintf(stderr, "Usage: xrle [-c|-d] file > out\n"); + return 1; + } + + if(argv[1][1] != 'c' && argv[1][1] != 'd') + { + fprintf(stderr, "Unknown option '%s'\n", argv[1]); + return 1; + } + + file = argv[2]; + in = read_file(file, &insz); + if(in == NULL) + { + fprintf(stderr, "An error occured\n"); + return 1; + } + + if(argv[1][1] == 'c') + { + out = malloc(xrle_max_out(insz)); + if(out == NULL) + { + fprintf(stderr, "Unable to allocate memory\n"); + return 1; + } + + outsz = xrle_compress(out, in, insz); + for(size_t i = 0; i < outsz; i++) + putc(out[i], stdout); + + fflush(stdout); + free(out); + + } + else + { + outsz = xrle_getsz(in); + out = malloc(outsz + 8); + if(out == NULL) + { + fprintf(stderr, "Unable to allocate %lu bytes of memory\n", outsz); + return 1; + } + + outsz = xrle_decompress(out, in, insz); + for(size_t i = 0; i < outsz; i++) + putc(out[i], stdout); + + fflush(stdout); + free(out); + + } + + fprintf(stderr, "%lu --> %lu, %f%%\n", insz, outsz, ((float)outsz/(float)insz)*100.0f); + free(in); + + return 0; +} diff --git a/xrle.c b/xrle.c index 19329b7..5b3d01c 100644 --- a/xrle.c +++ b/xrle.c @@ -25,6 +25,14 @@ */ /* + * Files created with this tool are not endian agnostic. + * + * Header: + * 32 bits + * +--------------+ + * | size of file | + * +--------------+ + * * Format: * 32 bits 32 bits 64 bits * +----------------+---------------+----------+----------------+ @@ -36,8 +44,8 @@ #include #include -#define U64 uint64_t -#define U32 uint32_t +typedef uint64_t U64; +typedef uint32_t U32; size_t xrle_compress(void * out,const void * in,size_t in_size) { @@ -45,6 +53,9 @@ size_t xrle_compress(void * out,const void * in,size_t in_size) U32 tail = in_size & 7,*descr,repeat; U64 *in_limit = (U64 *)((char *)in + in_size - tail),previous,next; + *out_pos = in_size; + out_pos++; + if(in_size < 16){ memcpy(out,in,in_size); return in_size; @@ -85,6 +96,13 @@ size_t xrle_compress(void * out,const void * in,size_t in_size) return (char *)out_pos - (char *)out + tail; } +U32 xrle_getsz(const void * in) +{ + U32 expected; + memcpy(&expected, in, sizeof(expected)); + return expected; +} + size_t xrle_decompress(void * out,const void * in,size_t in_size) { @@ -92,6 +110,8 @@ size_t xrle_decompress(void * out,const void * in,size_t in_size) U32 tail = in_size & 7,lit_len,repeat,i; U64 *in_limit = (U64 *)((char *)in + in_size - tail); + in_pos++; + if(in_size < 16){ memcpy(out,in,in_size); return in_size; diff --git a/xrle.h b/xrle.h index 24b3dd3..68edfc9 100644 --- a/xrle.h +++ b/xrle.h @@ -39,6 +39,8 @@ */ size_t xrle_compress(void * out,const void * in,size_t in_size); +size_t xrle_getsz(const void * in); + /* * in: buffer to decompress * out: buffer to store decompressed data @@ -53,4 +55,4 @@ size_t xrle_compress(void * out,const void * in,size_t in_size); size_t xrle_decompress(void * out,const void * in,size_t in_size); /* This macro returns the maximum size of compressed data in bytes */ -#define xrle_max_out(A) ((A) + 8) +#define xrle_max_out(A) ((A) + 8 + 4)