Skip to content

Instantly share code, notes, and snippets.

@wareya
Created November 15, 2023 02:36
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 wareya/538c356fbb82909f2dfebdd26f3a6ed7 to your computer and use it in GitHub Desktop.
Save wareya/538c356fbb82909f2dfebdd26f3a6ed7 to your computer and use it in GitHub Desktop.
rle compressor/decompressor that supports word lengths up to 4 bytes
fn big_rle_compress(input : &[u8]) -> Vec<u8>
{
let mut ret = Vec::new();
let mut i = 0;
let mut mode = 0; // 0 - raw, 1 - rle
let mut mode_index = 0;
while i < input.len()
{
let c = input[i];
let mut j = i + 1;
while j < (i+64).min(input.len())
{
let b = input[j];
if b != c
{
break;
}
j += 1;
}
let mut n = j - i;
let mut rle_size = 1;
let mut j2 = i + 2;
while j2 + 1 < (i+128).min(input.len())
{
let c2 = input[i+1];
let b = input[j2];
let b2 = input[j2+1];
if b2 != c2 || b != c
{
break;
}
j2 += 2;
}
let n2 = (j2 - i) / 2;
if n2 * 2 > n
{
rle_size = 2;
n = n2;
j = j2;
}
let mut j3 = i + 3;
while j3 + 2 < (i+192).min(input.len())
{
let c2 = input[i+1];
let c3 = input[i+2];
let b = input[j3];
let b2 = input[j3+1];
let b3 = input[j3+2];
if b3 != c3 || b2 != c2 || b != c
{
break;
}
j3 += 3;
}
let n3 = (j3 - i) / 3;
if n3 * 3 > n
{
rle_size = 3;
n = n3;
j = j3;
}
let mut j4 = i + 4;
while j4 + 3 < (i+256).min(input.len())
{
let c2 = input[i+1];
let c3 = input[i+2];
let c4 = input[i+3];
let b = input[j4];
let b2 = input[j4+1];
let b3 = input[j4+2];
let b4 = input[j4+3];
if b4 != c4 || b3 != c3 || b2 != c2 || b != c
{
break;
}
j4 += 4;
}
let n4 = (j4 - i) / 4;
if n4 * 4 > n
{
rle_size = 4;
n = n4;
j = j4;
}
if mode == 0 && (n > 2 || ret.len() == 0)
{
mode = 1;
ret.push(0x00);
mode_index = ret.len() - 1;
}
else if mode == 1 && (n < 2 || ret.len() == 0)
{
mode = 0;
ret.push(0x80);
mode_index = ret.len() - 1;
}
if mode == 0
{
let mut mode_n = ret[mode_index] & 0x7F;
if mode_n == 0x7F
{
ret.push(0x80);
mode_index = ret.len() - 1;
mode_n = 0;
}
ret[mode_index] = 0x80 | (mode_n + 1);
ret.push(c);
i += 1;
}
else if mode == 1
{
let mut mode_n = ret[mode_index] & 0x7F;
if mode_n == 0x7F
{
ret.push(0x00);
mode_index = ret.len() - 1;
mode_n = 0;
}
ret[mode_index] = mode_n + 1;
let mut n = (n - 1) as u8;
n |= (rle_size - 1) << 6;
ret.push(n);
ret.push(c);
if rle_size > 1
{
ret.push(input[i + 1]);
}
if rle_size > 2
{
ret.push(input[i + 2]);
}
if rle_size > 3
{
ret.push(input[i + 3]);
}
i = j;
}
}
ret
}
fn big_rle_decompress(input : &[u8]) -> Vec<u8>
{
let mut ret = Vec::new();
let mut i = 0;
while i < input.len()
{
let m = input[i] as usize;
i += 1;
if m >= 0x80
{
for _ in 0..(m & 0x7F)
{
let c = input[i];
i += 1;
ret.push(c);
}
}
else
{
for _ in 0..(m & 0x7F)
{
let size = ((input[i] & 0xC0) >> 6) as usize + 1;
let n = (input[i] & 0x3F) as usize + 1;
i += 1;
if size == 1
{
let c = input[i];
i += 1;
for _ in 0..n
{
ret.push(c);
}
}
else if size == 2
{
let c = input[i];
i += 1;
let c2 = input[i];
i += 1;
for _ in 0..n
{
ret.push(c);
ret.push(c2);
}
}
else if size == 3
{
let c = input[i];
i += 1;
let c2 = input[i];
i += 1;
let c3 = input[i];
i += 1;
for _ in 0..n
{
ret.push(c);
ret.push(c2);
ret.push(c3);
}
}
else if size == 4
{
let c = input[i];
i += 1;
let c2 = input[i];
i += 1;
let c3 = input[i];
i += 1;
let c4 = input[i];
i += 1;
for _ in 0..n
{
ret.push(c);
ret.push(c2);
ret.push(c3);
ret.push(c4);
}
}
}
}
}
ret
}
fn rle_compress(input : &[u8]) -> Vec<u8>
{
let mut ret = Vec::new();
let mut i = 0;
let mut mode = 0; // 0 - raw, 1 - rle
let mut mode_index = 0;
while i < input.len()
{
let c = input[i];
let mut j = i + 1;
while j < (i+256).min(input.len())
{
let b = input[j];
if b != c
{
break;
}
j += 1;
}
let n = j - i;
if mode == 0 && (n > 2 || ret.len() == 0)
{
mode = 1;
ret.push(0x00);
mode_index = ret.len() - 1;
}
else if mode == 1 && (n < 2 || ret.len() == 0)
{
mode = 0;
ret.push(0x80);
mode_index = ret.len() - 1;
}
if mode == 0
{
let mut mode_n = ret[mode_index] & 0x7F;
if mode_n == 0x7F
{
ret.push(0x80);
mode_index = ret.len() - 1;
mode_n = 0;
}
ret[mode_index] = 0x80 | (mode_n + 1);
ret.push(c);
i += 1;
}
else if mode == 1
{
let mut mode_n = ret[mode_index] & 0x7F;
if mode_n == 0x7F
{
ret.push(0x00);
mode_index = ret.len() - 1;
mode_n = 0;
}
ret[mode_index] = mode_n + 1;
ret.push((n - 1) as u8);
ret.push(c);
i = j;
}
}
ret
}
fn rle_decompress(input : &[u8]) -> Vec<u8>
{
let mut ret = Vec::new();
let mut i = 0;
while i < input.len()
{
let m = input[i] as usize;
i += 1;
if m >= 0x80
{
for _ in 0..(m & 0x7F)
{
let c = input[i];
i += 1;
ret.push(c);
}
}
else
{
for _ in 0..(m & 0x7F)
{
let n = input[i] as usize + 1;
i += 1;
let c = input[i];
i += 1;
for _ in 0..n
{
ret.push(c);
}
}
}
}
ret
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment