Skip to content

Instantly share code, notes, and snippets.

@gabonator
Created February 14, 2023 10:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gabonator/3336f2efa85dc98a18e58d9614693fd6 to your computer and use it in GitHub Desktop.
Save gabonator/3336f2efa85dc98a18e58d9614693fd6 to your computer and use it in GitHub Desktop.
run length encoder/decoder
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "testrle.h"
typedef uint8_t UINT8;
typedef int INTN;
typedef void VOID;
#define ASSERT assert
INTN header(UINT8* rle)
{
ASSERT(*rle++ == 'R');
INTN len = 0;
do {
len <<= 7;
len |= *rle & 127;
} while (*rle++ & 0x80);
return len;
}
VOID unpack(UINT8* rle, UINT8* end, UINT8* ptr)
{
ASSERT(*rle++ == 'R');
INTN len = 0;
do {
len <<= 7;
len |= *rle & 127;
} while (*rle++ & 0x80);
while (rle < end)
{
ASSERT(*rle++ == 'G');
int vlc0 = 0;
do {
vlc0 <<= 7;
vlc0 |= *rle & 127;
} while (*rle++ & 0x80);
// copy
len -= vlc0;
while (vlc0--)
*ptr++ = *rle++;
if (rle >= end)
break;
ASSERT(*rle++ == 'V');
int vlc1 = 0;
do {
vlc1 <<= 7;
vlc1 |= *rle & 127;
} while (*rle++ & 0x80);
// fill
len -= vlc1;
while (vlc1--)
*ptr++ = *rle;
rle++;
}
ASSERT(len == 0);
}
int main(void)
{
int len = header(test_rle);
uint8_t* ptr = malloc(len);
unpack(test_rle, test_rle + test_rle_len, ptr);
FILE *f = fopen("test.bin", "wb");
fwrite(ptr, 1, len, f);
fclose(f);
free(ptr);
}
if (process.argv.length != 5)
throw "no args";
if (process.argv[2] == "encode")
{
// encode
var fs = require("fs");
var f = fs.openSync(process.argv[3]);
var total = fs.fstatSync(f).size;
var fo = fs.openSync(process.argv[4], "w");
var last = 0;
var buf = Buffer.alloc(1024)
var i = 0;
var accum = [];
var phase = 0;
writeLength(total);
phase = 1;
var acclen = 0;
var sum = 0;
while (fs.readSync(f, buf))
{
for (var j=0; j<buf.length; j++)
{
if (phase == 1)
{
accum.push(buf[j]);
var l = accum.length;
if (accum.length > 4 && accum[l-1] == accum[l-2] && accum[l-1] == accum[l-3] && accum[l-1] == accum[l-4])
{
writeLength(l-4);
for (var i=0; i<l-4; i++)
writeByte(accum[i]);
phase = 2;
accum = [accum[l-1]];
acclen = 3;
}
}
if (phase == 2)
{
if (buf[j] == accum[0])
acclen++;
else
{
writeLength(acclen);
writeByte(accum[0]);
accum = [buf[j]];
phase = 1;
}
}
}
}
if (phase == 1)
{
writeLength(accum.length);
for (var i=0; i<l; l++)
writeByte(accum[i]);
}
if (phase == 2)
{
writeLength(acclen);
writeByte(accum[0])
}
function writeByte(b)
{
fs.writeSync(fo, Buffer.from([b]));
}
function writeLength(l)
{
sum += l;
writeByte("RGV".charCodeAt(phase));
var bytes = [];
if (l==0) throw "Error"
while (l > 0)
{
bytes.push(l & 127);
l >>= 7;
}
bytes.reverse();
for (var i=0; i<bytes.length-1; i++)
writeByte(bytes[i] | 128)
writeByte(bytes[bytes.length-1]);
}
fs.closeSync(fo);
if (sum != total)
throw "error!";
}
if (process.argv[2] == "decode")
{
// decode
var fs = require("fs");
var f = fs.openSync(process.argv[3]);
var fo = fs.openSync(process.argv[4], "w");
var buf = Buffer.alloc(1);
var phase = 1;
var eof = false;
var zero = Buffer.alloc(1024);
var sum = 0;
var total = readVlc(0);
sum = 0;
while (!eof)
{
var l = readVlc(1);
if (!l)
break;
var b = Buffer.alloc(l);
fs.readSync(f, b);
fs.writeSync(fo, b);
var l = readVlc(2);
if (!l)
break;
fs.readSync(f, buf);
for (var i=0; i<1024; i++)
zero[i] = buf[i];
while (l >= 1024)
{
fs.writeSync(fo, zero);
l -= 1024;
}
for (var i=0; i<l; i++)
fs.writeSync(fo, buf);
}
function readVlc(phase)
{
if (!fs.readSync(f, buf))
return 0;
if (buf[0] != "RGV".charCodeAt(phase))
throw " problem"
var l = 0;
do {
l <<= 7;
if (!fs.readSync(f, buf))
throw "problem"
l |= buf[0] & 127;
} while (buf[0] & 0x80)
sum += l;
return l;
}
fs.closeSync(fo);
if (sum != total)
throw "error"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment