Skip to content

Instantly share code, notes, and snippets.

@kovrov
Created April 16, 2011 23:33
Show Gist options
  • Select an option

  • Save kovrov/923617 to your computer and use it in GitHub Desktop.

Select an option

Save kovrov/923617 to your computer and use it in GitHub Desktop.
Delphine's unpacking routines
import std.intrinsic;
pure uint pop(ref const(uint)[] stream)
{
auto res = bswap(stream[$-1]);
stream.length -= 1;
return res;
}
struct UnpackCtx
{
uint crc;
uint chunk;
const(uint)[] src;
ubyte[] dst;
size_t dst_idx;
pure:
this(const uint[] src)
{
this.src = src;
this.dst.length = this.src.pop(); // unpacked length
this.dst_idx = this.dst.length - 1;
this.crc = this.src.pop();
this.chunk = this.src.pop();
this.crc ^= this.chunk;
}
uint read_bit_from_src()
{
// pop least significant bit out of chunk
uint CF = this.chunk & 0b1;
this.chunk >>= 1;
// chunk becomes zero means sentinel bit is gone
if (this.chunk == 0)
{
this.chunk = this.src.pop();
this.crc ^= this.chunk;
// pop least significant bit and set sentinel bit (most significant)
CF = this.chunk & 0b1;
this.chunk = (this.chunk >> 1) | (0b1 << 31);
}
return CF;
}
uint read_bits_from_src(uint bit_count)
{
assert (bit_count <= uint.sizeof * 8);
uint c = 0;
while (bit_count--)
{
c <<= 1;
c |= this.read_bit_from_src();
}
return c;
}
void copy_bytes_from_src(int num_bytes)
{
while (num_bytes--)
this.dst[this.dst_idx--] = cast(ubyte)this.read_bits_from_src(8);
}
void copy_bytes_from_window(int num_bytes, uint offset)
{
while (num_bytes--)
{
this.dst[this.dst_idx] = this.dst[this.dst_idx + offset];
this.dst_idx--;
}
}
}
pure ubyte[] delphine_unpack(const uint[] src)
{
auto ctx = UnpackCtx(src);
while (ctx.dst_idx >= 0 && ctx.dst_idx < ctx.dst.length) // dst_idx is unsigned
{
if (0b0 == ctx.read_bit_from_src())
{
if (0b0 == ctx.read_bit_from_src())
{
int num_bytes = ctx.read_bits_from_src(3) + 1;
ctx.copy_bytes_from_src(num_bytes);
}
else
{
int num_bytes = 2;
uint offset = ctx.read_bits_from_src(8);
ctx.copy_bytes_from_window(num_bytes, offset);
}
}
else
{
uint c = ctx.read_bits_from_src(2);
switch (c)
{
case 0b11:
int num_bytes = ctx.read_bits_from_src(8) + 9;
ctx.copy_bytes_from_src(num_bytes);
break;
case 0b10:
int num_bytes = ctx.read_bits_from_src(8) + 1;
uint offset = ctx.read_bits_from_src(12);
ctx.copy_bytes_from_window(num_bytes, offset);
break;
default: // 0b00, 0b01
int num_bytes = c + 3;
uint offset = ctx.read_bits_from_src(c + 9);
ctx.copy_bytes_from_window(num_bytes, offset);
break;
}
}
}
assert (ctx.crc == 0);
return ctx.dst;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment