Created
April 16, 2011 23:33
-
-
Save kovrov/923617 to your computer and use it in GitHub Desktop.
Delphine's unpacking routines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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