Brainf*ck simple RLE library in ANSI C/C++

bzt 0a410f1ee9 Initial commit 4 lat temu
LICENSE 0a410f1ee9 Initial commit 4 lat temu
README.md 0a410f1ee9 Initial commit 4 lat temu
rle_libc.h 0a410f1ee9 Initial commit 4 lat temu
rle_opt.h 0a410f1ee9 Initial commit 4 lat temu
test.c 0a410f1ee9 Initial commit 4 lat temu

README.md

Run-Length Encoding Library

Well, there's nothing interesting here. I was looking for a simple to use RLE lib, but I couldn't find any, so I quickly wrote one in ANSI C89 / C++.

All that I could find was ridiculously overengineered (hundreds of SLoC!!!), used unnecessary temporary buffers with unnecessary copying of memory, or read packets by byte from a file which made them incredibly slow. But worst of all, their format was incompatible with the one we need (and I haven't talked about that monstrocity binvox files have... seriously, the coordinate with the farest offset in memory runs the fastest? WTF?)

This library uses the simplest implementation possible. No temporary buffers at all, requires only 5 variables on stack tops. The source can be compiled on little-endian and big-endian machines as well.

The format these routines use is the same as Targa RLE's encoding: one byte header, followed by data in each packet. The data can be 8 (palette), 16 (hicolor), 24 (RGB) or 32 bits (RGBA) wide. There are two kinds of header, depending if the header byte's bit 7 is set: unset means (header + 1) data follows, set means one data follows which must be repeated ((header & 127) + 1) times. That simple.

API Usage

Dependency-free

You probably don't want to include the rle_opt.h ANSI C header as-is, instead you should copy'n'paste the required implementation into your code. Each function is about 20 SLoC or less.

These are specific functions to encode and decode bytes, shorts, triplets and integers. These are absolutely and totally dependency-free. They have only one restriction in lack of malloc, you must provide a sufficiently large output buffer for them.

void rle_enc8(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);
void rle_enc16(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);
void rle_enc24(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);
void rle_enc32(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);

These are the encoders.

void rle_dec8(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);
void rle_dec16(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);
void rle_dec24(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);
void rle_dec32(unsigned char *inbuff, int inlen, unsigned char *outbuff, int *outlen);

The decoder counterparts.

Libc version

There's also a libc dependent universal solution rle_libc.h, which accepts the size of members as an argument, and depends on realloc, memcmp and memcpy. Only these three, nothing else. If you don't provide a buffer for them then they will allocate and return one. Less than 40 SLoC alltogether.

unsigned char *rle_enc((unsigned char *inbuff, int inlen, int membsize, unsigned char *outbuff, int *outlen);
unsigned char *rle_dec((unsigned char *inbuff, int inlen, int membsize, unsigned char *outbuff, int *outlen);

That's all, why on earth would someone overcomplicate something that's brainfuck simple? K.I.S.S.!

bzt