about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2023-06-09 01:38:51 -0500
committergennyble <gen@nyble.dev>2023-06-09 01:38:51 -0500
commitb08ac436beed955053b672d65715811535a46096 (patch)
tree3b7adedf8a0930b875ad9ea3f1c07c1c10b10389
parent1e2224b6273e2b57ebf7dc90e2439c1d6075ef39 (diff)
downloadlri-rs-b08ac436beed955053b672d65715811535a46096.tar.gz
lri-rs-b08ac436beed955053b672d65715811535a46096.zip
unpacker
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock331
-rw-r--r--Cargo.toml5
-rw-r--r--src/main.rs93
-rw-r--r--unpacker/Cargo.lock7
-rw-r--r--unpacker/Cargo.toml8
-rw-r--r--unpacker/src/lib.rs44
-rw-r--r--unpacker/src/main.rs24
8 files changed, 467 insertions, 47 deletions
diff --git a/.gitignore b/.gitignore
index ed84e91..37ee4b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-/target
+**/target
 *.png
 *.lri_part
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 791e29d..0784b30 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -21,6 +21,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
 
 [[package]]
+name = "approx"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -33,18 +42,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
-name = "bitvec"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
-dependencies = [
- "funty",
- "radium",
- "tap",
- "wyz",
-]
-
-[[package]]
 name = "bytemuck"
 version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -143,6 +140,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
 
 [[package]]
+name = "enumn"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.18",
+]
+
+[[package]]
 name = "fdeflate"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -162,10 +170,15 @@ dependencies = [
 ]
 
 [[package]]
-name = "funty"
-version = "2.0.0"
+name = "getrandom"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
 
 [[package]]
 name = "gif"
@@ -178,6 +191,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
 name = "hermit-abi"
 version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -198,7 +217,7 @@ dependencies = [
  "gif",
  "jpeg-decoder",
  "num-iter",
- "num-rational",
+ "num-rational 0.3.2",
  "num-traits",
  "png 0.16.8",
  "scoped_threadpool",
@@ -218,12 +237,21 @@ dependencies = [
 name = "l16-lri"
 version = "0.1.0"
 dependencies = [
- "bitvec",
  "lri-rs",
+ "nalgebra",
  "png 0.17.8",
+ "rawloader",
+ "rawproc",
+ "unpacker",
 ]
 
 [[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
 name = "libc"
 version = "0.2.146"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -241,6 +269,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "matrixmultiply"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77"
+dependencies = [
+ "autocfg",
+ "rawpointer",
+]
+
+[[package]]
 name = "memoffset"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -279,6 +317,42 @@ dependencies = [
 ]
 
 [[package]]
+name = "nalgebra"
+version = "0.31.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20bd243ab3dbb395b39ee730402d2e5405e448c75133ec49cc977762c4cba3d1"
+dependencies = [
+ "approx",
+ "matrixmultiply",
+ "nalgebra-macros",
+ "num-complex",
+ "num-rational 0.4.1",
+ "num-traits",
+ "simba",
+ "typenum",
+]
+
+[[package]]
+name = "nalgebra-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
 name = "num-integer"
 version = "0.1.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -311,6 +385,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "num-rational"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
 name = "num-traits"
 version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -330,6 +415,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "paste"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+
+[[package]]
 name = "png"
 version = "0.16.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -355,6 +446,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
 name = "protobuf"
 version = "2.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -383,10 +489,76 @@ dependencies = [
 ]
 
 [[package]]
-name = "radium"
-version = "0.7.0"
+name = "quote"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rawloader"
+version = "0.37.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d8c6f168c492ffd326537b3aa5a8d5fe07f0d8a3970c5957f286bcd13f888aa"
+dependencies = [
+ "byteorder",
+ "enumn",
+ "glob",
+ "lazy_static",
+ "rayon",
+ "rustc_version",
+ "toml",
+]
+
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
+[[package]]
+name = "rawproc"
+version = "0.1.0"
+source = "git+https://github.com/eclecticnybles/gaze#47dbf3f29edd932bb8e363146e7a5d1505d90c22"
+dependencies = [
+ "nalgebra",
+ "num-traits",
+ "rand",
+ "rawloader",
+ "thiserror",
+]
 
 [[package]]
 name = "rayon"
@@ -411,6 +583,24 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "safe_arch"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62a7484307bd40f8f7ccbacccac730108f2cae119a3b11c74485b48aa9ea650f"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
 name = "scoped_threadpool"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -423,22 +613,77 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+
+[[package]]
 name = "serde"
 version = "1.0.163"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
 
 [[package]]
+name = "simba"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176"
+dependencies = [
+ "approx",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "wide",
+]
+
+[[package]]
 name = "simd-adler32"
 version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
 
 [[package]]
-name = "tap"
-version = "1.0.1"
+name = "syn"
+version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.18",
+]
 
 [[package]]
 name = "tiff"
@@ -452,16 +697,48 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "typenum"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+
+[[package]]
+name = "unpacker"
+version = "0.1.0"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
 name = "weezl"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
 
 [[package]]
-name = "wyz"
-version = "0.5.1"
+name = "wide"
+version = "0.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+checksum = "40018623e2dba2602a9790faba8d33f2ebdebf4b86561b83928db735f8784728"
 dependencies = [
- "tap",
+ "bytemuck",
+ "safe_arch",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 050859b..42afe6a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,4 +8,7 @@ edition = "2021"
 [dependencies]
 png = "0.17.8"
 lri-rs = { path = "../lri-rs" }
-bitvec = "1.0.1"
+unpacker = { path = "unpacker" }
+rawproc = { git = "https://github.com/eclecticnybles/gaze" }
+rawloader = "0.37.1"
+nalgebra = "0.31.4"
diff --git a/src/main.rs b/src/main.rs
index 8503a98..c9058ac 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,14 @@
 use std::{fs::File, io::Write, os::unix::prelude::FileExt, path::Path};
 
 use lri_rs::{proto::camera_module::CameraModule, Message};
+use nalgebra::Matrix3;
 use png::{BitDepth, ColorType};
+use rawloader::CFA;
+use rawproc::{
+	colorspace::BayerRgb,
+	image::{Image, RawMetadata},
+};
+use unpacker::Unpacker;
 
 // This code is going to be rough. Just trying to parse this using the technique
 // I know: just play with the raw data
@@ -103,7 +110,7 @@ fn main() {
 			let mut file = File::create(&name).unwrap();
 			file.write_all(&data[head.start..head.end]).unwrap();
 			println!(
-				"Wrote {:.2}MB to disk as {name}",
+				"\nWrote {:.2}MB to disk as {name}",
 				head.header.combined_length as f32 / (1024.0 * 1024.0)
 			);
 			head.header.print_info();
@@ -127,19 +134,58 @@ fn main() {
 		println!("Found stamp in {idx}");
 	}
 
-	println!("\nAttemtping to parse data after first image in 2");
-	let head = &heads[2];
-	let start = head.start + (ar1335_crop as f32 * 2.5).ceil() as usize;
-	let after_image = &data[start..start + 4352];
-	let proto = match lri_rs::proto::lightheader::LightHeader::parse_from_bytes(after_image) {
-		Ok(_) => println!("Success?!?!?!"),
-		Err(e) => println!("Failed {e}"),
-	};
+	println!("\nAttemtping to unpack image in idx2");
+	let msg = body(&heads[2], &data);
+	let mut up = Unpacker::new();
+	for idx in 0..16224000 {
+		up.push(msg[idx]);
+	}
+	up.finish();
+
+	let mut imgdata = vec![];
+	for chnk in up.out.chunks(2) {
+		let sixteen = ((u16::from_le_bytes([chnk[0], chnk[1]]) as f32 / 1024.0) * 255.0) as u8;
+		imgdata.push(sixteen.min(255));
+	}
+
+	let rawimg: Image<u8, BayerRgb> = Image::from_raw_parts(
+		4160,
+		3120,
+		RawMetadata {
+			whitebalance: [1.0, 1.0, 1.0],
+			whitelevels: [1024, 1024, 1024],
+			crop: None,
+			cfa: CFA::new("BGGR"),
+			cam_to_xyz: Matrix3::new(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
+		},
+		imgdata,
+	);
+	let img = rawimg.debayer();
+
+	make_png(
+		"image.png",
+		4160,
+		3120,
+		ColorType::Rgb,
+		BitDepth::Eight,
+		&img.data,
+	);
+
+	let msg = &msg[16224000..];
+	dump(msg, "afterimg2");
+	let question = &msg[..4352];
+	let next = &msg[4352..];
 
-	println!("Eight before: {:?}", &data[start - 8..start]);
-	println!("Eight in: {:?}", &data[start..start + 8]);
+	println!(
+		"Up out is {} bytes. Expecte {}. Difference {} [work: {:0b} - idx {}]",
+		up.out.len(),
+		ar1335_crop * 2,
+		up.out.len() as isize - (ar1335_crop * 2) as isize,
+		up.work,
+		up.work_idx
+	);
 
-	println!("\nDumping the Message of idx 1");
+	println!("\nDumping the Message of idx 4");
 	dump_body(&heads[4], &data, "msg4.lri_part");
 
 	let mut modules = vec![];
@@ -197,14 +243,25 @@ fn main() {
 
 fn dump_body(head: &HeaderAndOffset, data: &[u8], path: &str) {
 	let msg = body(head, data);
+	dump(msg, path)
+}
+
+fn dump(data: &[u8], path: &str) {
 	let mut file = File::create(&path).unwrap();
-	file.write_all(msg).unwrap();
-	println!("Wrote {:.2}KB to disk as {path}", msg.len() as f32 / 1024.0);
+	file.write_all(data).unwrap();
+	println!(
+		"Wrote {:.2}KB to disk as {path}",
+		data.len() as f32 / 1024.0
+	);
 }
 
 fn body<'a>(head: &HeaderAndOffset, data: &'a [u8]) -> &'a [u8] {
-	&data[head.start + head.header.header_length as usize
-		..head.start + head.header.header_length as usize + head.header.message_length as usize]
+	if head.header.header_length == 32 {
+		&data[head.start + head.header.header_length as usize
+			..head.start + head.header.header_length as usize + head.header.message_length as usize]
+	} else {
+		&data[head.start + 32..head.end]
+	}
 }
 
 fn find_pattern<'a>(
@@ -243,7 +300,7 @@ fn make_png<P: AsRef<Path>>(
 
 	let pix = width * height;
 
-	let file = File::create("ahh.png").unwrap();
+	let file = File::create(path).unwrap();
 	let mut enc = png::Encoder::new(file, width as u32, height as u32);
 	enc.set_color(color);
 	enc.set_depth(depth);
@@ -309,7 +366,7 @@ impl LightHeader {
 			reserved,
 		} = self;
 
-		println!("\nMagic: {magic_number}\nCombined Length: {combined_length}\nHeader Length: {header_length}\nMessage Length: {message_length}\nKind: {kind}\nReserved: {reserved:?}");
+		println!("Magic: {magic_number}\nCombined Length: {combined_length}\nHeader Length: {header_length}\nMessage Length: {message_length}\nKind: {kind}\nReserved: {reserved:?}");
 	}
 
 	pub fn nice_info(&self) {
diff --git a/unpacker/Cargo.lock b/unpacker/Cargo.lock
new file mode 100644
index 0000000..44d0a0f
--- /dev/null
+++ b/unpacker/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "unpacker"
+version = "0.1.0"
diff --git a/unpacker/Cargo.toml b/unpacker/Cargo.toml
new file mode 100644
index 0000000..147529a
--- /dev/null
+++ b/unpacker/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "unpacker"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/unpacker/src/lib.rs b/unpacker/src/lib.rs
new file mode 100644
index 0000000..f649581
--- /dev/null
+++ b/unpacker/src/lib.rs
@@ -0,0 +1,44 @@
+#[derive(Debug)]
+pub struct Unpacker {
+	pub out: Vec<u8>,
+	pub work: u16,
+	pub work_idx: usize,
+}
+
+impl Unpacker {
+	pub fn new() -> Self {
+		Self {
+			out: vec![],
+			work: 0,
+			work_idx: 0,
+		}
+	}
+
+	pub fn push(&mut self, byte: u8) {
+		self.work = self.work << 8;
+		self.work |= byte as u16;
+		self.work_idx += 8;
+
+		//println!("[{work_idx}]");
+
+		if self.work_idx >= 10 {
+			let to_front = self.work_idx - 10;
+			let fronted = self.work >> to_front;
+			let masked = fronted & 0b000_000_111_11_111_11;
+
+			let fixwork = fronted << to_front;
+
+			self.out.extend(masked.to_le_bytes());
+			self.work_idx -= 10;
+			self.work ^= fixwork;
+		}
+	}
+
+	pub fn finish(&mut self) {
+		if self.work_idx > 0 {
+			let remain = 10 - self.work_idx;
+			let out = self.work << remain;
+			self.out.extend(out.to_le_bytes())
+		}
+	}
+}
diff --git a/unpacker/src/main.rs b/unpacker/src/main.rs
new file mode 100644
index 0000000..047b4c5
--- /dev/null
+++ b/unpacker/src/main.rs
@@ -0,0 +1,24 @@
+use unpacker::Unpacker;
+
+fn main() {
+	// Four bits padding at the end.
+	let testdata = vec![
+		0b10000000, 0b00010000, 0b00000010, 0b00000000, 0b01000000, 0b00001000, 0b00000001,
+		0b00000000, 0b00100000, 0b00000100, 0b00000000, 0b10000000, 0b00010000,
+	];
+
+	let mut up = Unpacker {
+		out: vec![],
+		work: 0,
+		work_idx: 0,
+	};
+
+	for byte in testdata {
+		up.push(byte);
+	}
+	up.finish();
+
+	for chnk in up.out.chunks(2) {
+		println!("{:08b} {:08b}", chnk[0], chnk[1]);
+	}
+}