From 417ac3938cf0d3d93598f3b55d89f7922e8694a9 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 19:53:36 +0500 Subject: [PATCH 01/14] Update to edition 2021 (latest at this time) --- Cargo.toml | 1 + src/kaitai_stream.rs | 2 +- src/kaitai_struct.rs | 16 ++++++++-------- src/lib.rs | 10 +++------- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a8bffb..65614e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT" readme = "README.md" documentation = "https://github.com/kaitai-io/kaitai_struct/wiki" description = "Rust runtime for Kaitai Struct" +edition = "2021" [dependencies] byteorder = "0.5" diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index 07cc5a2..ba22135 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -8,7 +8,7 @@ use encoding::label::encoding_from_whatwg_label; macro_rules! read_endian { ($this:ident, $size:expr, $end:ident, $method:ident) => {{ let mut buf = [0; $size]; - try!($this.read_exact(&mut buf)); + $this.read_exact(&mut buf)?; Ok($end::$method(&buf)) }} } diff --git a/src/kaitai_struct.rs b/src/kaitai_struct.rs index 1e8ef2a..005df46 100644 --- a/src/kaitai_struct.rs +++ b/src/kaitai_struct.rs @@ -1,25 +1,25 @@ use std; -use kaitai_stream::KaitaiStream; +use crate::kaitai_stream::KaitaiStream; pub trait KaitaiStruct { fn from_file(path: &str) -> std::io::Result where Self : Sized { let mut f = std::fs::File::open(path)?; Self::new(&mut f, &None, &None) } - + fn from_bytes(bytes: Vec) -> std::io::Result where Self : Sized { let mut b = std::io::Cursor::new(bytes); Self::new(&mut b, &None, &None) } - + fn new(stream: &mut S, - parent: &Option>, - root: &Option>) + parent: &Option>, + root: &Option>) -> std::io::Result where Self : Sized; - + fn read(&mut self, stream: &mut S, - parent: &Option>, - root: &Option>) -> std::io::Result<()> where Self : Sized; + parent: &Option>, + root: &Option>) -> std::io::Result<()> where Self : Sized; } diff --git a/src/lib.rs b/src/lib.rs index 41b5e4d..e6739f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,17 +1,13 @@ -extern crate byteorder; -extern crate encoding; -extern crate flate2; - mod kaitai_stream; mod kaitai_struct; -pub use kaitai_stream::KaitaiStream; -pub use kaitai_struct::KaitaiStruct; +pub use crate::kaitai_stream::KaitaiStream; +pub use crate::kaitai_struct::KaitaiStruct; #[cfg(test)] mod tests { use std::io::Cursor; - use KaitaiStream; + use crate::KaitaiStream; #[test] fn test_seek() { From 52a54a9191796ba56470a74a93138d037a3d73cb Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 19:56:42 +0500 Subject: [PATCH 02/14] Run `cargo fmt` --- src/kaitai_stream.rs | 23 +++++++++--------- src/kaitai_struct.rs | 36 ++++++++++++++++++--------- src/lib.rs | 58 +++++++++++++++++++++++++++----------------- 3 files changed, 72 insertions(+), 45 deletions(-) diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index ba22135..1e846da 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -1,16 +1,16 @@ -use std::io::{Cursor, Seek, SeekFrom, Read, Result}; use flate2::read::ZlibDecoder; +use std::io::{Cursor, Read, Result, Seek, SeekFrom}; use byteorder::{BigEndian, ByteOrder, LittleEndian}; -use encoding::DecoderTrap; use encoding::label::encoding_from_whatwg_label; +use encoding::DecoderTrap; macro_rules! read_endian { ($this:ident, $size:expr, $end:ident, $method:ident) => {{ let mut buf = [0; $size]; $this.read_exact(&mut buf)?; Ok($end::$method(&buf)) - }} + }}; } pub trait KaitaiStream: Read + Seek { @@ -210,13 +210,14 @@ pub trait KaitaiStream: Read + Seek { } } - fn read_strz(&mut self, - encoding: &str, - terminator: u8, - include_terminator: bool, - consume_terminator: bool, - eos_error: bool) - -> Result { + fn read_strz( + &mut self, + encoding: &str, + terminator: u8, + include_terminator: bool, + consume_terminator: bool, + eos_error: bool, + ) -> Result { let enc = match encoding_from_whatwg_label(encoding) { Some(enc) => enc, None => panic!("Unknown encoding: {}", encoding), @@ -305,4 +306,4 @@ pub trait KaitaiStream: Read + Seek { } } -impl KaitaiStream for T {} \ No newline at end of file +impl KaitaiStream for T {} diff --git a/src/kaitai_struct.rs b/src/kaitai_struct.rs index 005df46..f9cc51a 100644 --- a/src/kaitai_struct.rs +++ b/src/kaitai_struct.rs @@ -1,25 +1,37 @@ -use std; use crate::kaitai_stream::KaitaiStream; +use std; pub trait KaitaiStruct { - fn from_file(path: &str) -> std::io::Result where Self : Sized { + fn from_file(path: &str) -> std::io::Result + where + Self: Sized, + { let mut f = std::fs::File::open(path)?; Self::new(&mut f, &None, &None) } - fn from_bytes(bytes: Vec) -> std::io::Result where Self : Sized { + fn from_bytes(bytes: Vec) -> std::io::Result + where + Self: Sized, + { let mut b = std::io::Cursor::new(bytes); Self::new(&mut b, &None, &None) } - fn new(stream: &mut S, - parent: &Option>, - root: &Option>) - -> std::io::Result - where Self : Sized; + fn new( + stream: &mut S, + parent: &Option>, + root: &Option>, + ) -> std::io::Result + where + Self: Sized; - fn read(&mut self, - stream: &mut S, - parent: &Option>, - root: &Option>) -> std::io::Result<()> where Self : Sized; + fn read( + &mut self, + stream: &mut S, + parent: &Option>, + root: &Option>, + ) -> std::io::Result<()> + where + Self: Sized; } diff --git a/src/lib.rs b/src/lib.rs index e6739f2..89c2853 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,8 @@ pub use crate::kaitai_struct::KaitaiStruct; #[cfg(test)] mod tests { - use std::io::Cursor; use crate::KaitaiStream; + use std::io::Cursor; #[test] fn test_seek() { @@ -50,13 +50,13 @@ mod tests { } macro_rules! test_read_integer { - ($name:ident, $value:expr) => ( + ($name:ident, $value:expr) => { #[test] fn $name() { let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!(buf.$name().unwrap(), $value); } - ); + }; } test_read_integer!(read_u1, 1); @@ -116,16 +116,20 @@ mod tests { #[test] fn ensure_fixed_contents() { let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(buf.ensure_fixed_contents(4, vec![1, 2, 3, 4]).unwrap(), - vec![1, 2, 3, 4]); + assert_eq!( + buf.ensure_fixed_contents(4, vec![1, 2, 3, 4]).unwrap(), + vec![1, 2, 3, 4] + ); } #[test] #[should_panic] fn ensure_fixed_contents_panic() { let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(buf.ensure_fixed_contents(4, vec![5, 6, 7, 8]).unwrap(), - vec![1, 2, 3, 4]); + assert_eq!( + buf.ensure_fixed_contents(4, vec![5, 6, 7, 8]).unwrap(), + vec![1, 2, 3, 4] + ); } #[test] @@ -135,8 +139,7 @@ mod tests { 147, 250, 150, 123, 140, 234, // shift_jis ]); assert_eq!(buf.read_str_byte_limit(9, "utf-8").unwrap(), "日本語"); - assert_eq!(buf.read_str_byte_limit(6, "shift_jis").unwrap(), - "日本語"); + assert_eq!(buf.read_str_byte_limit(6, "shift_jis").unwrap(), "日本語"); } #[test] @@ -152,10 +155,14 @@ mod tests { 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // utf-8 147, 250, 150, 123, 140, 234, 0, // shift_jis ]); - assert_eq!(buf.read_strz("utf-8", 0, false, true, false).unwrap(), - "日本語"); - assert_eq!(buf.read_strz("shift_jis", 0, false, true, false).unwrap(), - "日本語"); + assert_eq!( + buf.read_strz("utf-8", 0, false, true, false).unwrap(), + "日本語" + ); + assert_eq!( + buf.read_strz("shift_jis", 0, false, true, false).unwrap(), + "日本語" + ); } #[test] @@ -174,25 +181,32 @@ mod tests { #[test] fn process_xor_one_many() { let mut buf = Cursor::new(vec![]); - assert_eq!(buf.process_xor_many(vec![0, 0, 0, 0], vec![1, 2, 3, 4]), - vec![1, 2, 3, 4]); + assert_eq!( + buf.process_xor_many(vec![0, 0, 0, 0], vec![1, 2, 3, 4]), + vec![1, 2, 3, 4] + ); } #[test] fn process_rotate_left() { let mut buf = Cursor::new(vec![]); - assert_eq!(buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], 2, 1), - vec![0b1100_0011, 0b1001_1001]); - assert_eq!(buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], -6, 1), - vec![0b1100_0011, 0b1001_1001]); + assert_eq!( + buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], 2, 1), + vec![0b1100_0011, 0b1001_1001] + ); + assert_eq!( + buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], -6, 1), + vec![0b1100_0011, 0b1001_1001] + ); } #[test] fn process_zlib() { let mut buf = Cursor::new(vec![]); - let arr = vec![120, 156, 75, 84, 40, 44, 205, 76, 206, 86, 72, 42, 202, 47, 207, 83, 72, - 203, 175, 80, 200, 42, 205, 45, 40, 86, 200, 47, 75, 45, 2, 0, 148, 189, - 10, 127]; + let arr = vec![ + 120, 156, 75, 84, 40, 44, 205, 76, 206, 86, 72, 42, 202, 47, 207, 83, 72, 203, 175, 80, + 200, 42, 205, 45, 40, 86, 200, 47, 75, 45, 2, 0, 148, 189, 10, 127, + ]; let deflate = buf.process_zlib(arr).unwrap(); assert_eq!(deflate, "a quick brown fox jumps over".as_bytes()) } From e6e30078f9ff676ff2562a56fcb3d836f9ecc610 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 19:59:42 +0500 Subject: [PATCH 03/14] Update dependencies to the latest versions - byteorder: 0.5 -> 1.x - flate2: 0.2 -> 1.x --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 65614e6..8a1c023 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,6 @@ description = "Rust runtime for Kaitai Struct" edition = "2021" [dependencies] -byteorder = "0.5" +byteorder = "1.0" encoding = "0.2" -flate2 = "0.2" +flate2 = "1.0" From c347ac6968fc7e181180a6cd83621ef61dced5ce Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 21:16:46 +0500 Subject: [PATCH 04/14] Use pretty_assertions for colored diffs --- Cargo.toml | 3 +++ src/lib.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 8a1c023..ad2b552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,6 @@ edition = "2021" byteorder = "1.0" encoding = "0.2" flate2 = "1.0" + +[dev-dependencies] +pretty_assertions = "1.4" diff --git a/src/lib.rs b/src/lib.rs index 89c2853..4b061bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub use crate::kaitai_struct::KaitaiStruct; #[cfg(test)] mod tests { use crate::KaitaiStream; + use pretty_assertions::assert_eq; use std::io::Cursor; #[test] From fa8c0d65c854a33d4ffd29404dfc3dd4f6c47237 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 21:57:13 +0500 Subject: [PATCH 05/14] Import things instead of use full-qualified names --- src/kaitai_struct.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/kaitai_struct.rs b/src/kaitai_struct.rs index f9cc51a..078b581 100644 --- a/src/kaitai_struct.rs +++ b/src/kaitai_struct.rs @@ -1,20 +1,21 @@ use crate::kaitai_stream::KaitaiStream; -use std; +use std::fs::File; +use std::io::{Cursor, Result}; pub trait KaitaiStruct { - fn from_file(path: &str) -> std::io::Result + fn from_file(path: &str) -> Result where Self: Sized, { - let mut f = std::fs::File::open(path)?; + let mut f = File::open(path)?; Self::new(&mut f, &None, &None) } - fn from_bytes(bytes: Vec) -> std::io::Result + fn from_bytes(bytes: Vec) -> Result where Self: Sized, { - let mut b = std::io::Cursor::new(bytes); + let mut b = Cursor::new(bytes); Self::new(&mut b, &None, &None) } @@ -22,7 +23,7 @@ pub trait KaitaiStruct { stream: &mut S, parent: &Option>, root: &Option>, - ) -> std::io::Result + ) -> Result where Self: Sized; @@ -31,7 +32,7 @@ pub trait KaitaiStruct { stream: &mut S, parent: &Option>, root: &Option>, - ) -> std::io::Result<()> + ) -> Result<()> where Self: Sized; } From 6ecdcde23499b49ea6a04176f0ebd68a305c38ff Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 22:38:21 +0500 Subject: [PATCH 06/14] Replace `panic!` with `unimplemented!` when it is used for unimplemented things --- src/kaitai_stream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index 1e846da..76e3044 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -291,7 +291,7 @@ pub trait KaitaiStream: Read + Seek { result[i] = data[i].rotate_left(rot_amount as u32); } } - _ => panic!("Unable to rotate a group of {} bytes yet", group_size), + _ => unimplemented!("Unable to rotate a group of {} bytes yet", group_size), } return result; } From e862bebb0b38f41e986c052b46f1ab9c63322e59 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 30 Mar 2024 00:59:54 +0500 Subject: [PATCH 07/14] Do not make unnecessary dynamic allocations in tests --- src/lib.rs | 60 +++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4b061bc..686b3da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,14 +12,14 @@ mod tests { #[test] fn test_seek() { - let mut buf = Cursor::new(vec![0, 0, 0, 0, 64, 226, 1, 0]); + let mut buf = Cursor::new([0, 0, 0, 0, 64, 226, 1, 0]); let _ = buf.seek(4); assert_eq!(buf.read_s4le().unwrap(), 123456); } #[test] fn test_pos() { - let mut buf = Cursor::new(vec![0, 0, 0, 0, 64, 226, 1, 0]); + let mut buf = Cursor::new([0, 0, 0, 0, 64, 226, 1, 0]); assert_eq!(buf.pos().unwrap(), 0); let _ = buf.seek(4); assert_eq!(buf.pos().unwrap(), 4); @@ -27,7 +27,7 @@ mod tests { #[test] fn test_multiple_reads() { - let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); + let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); for x in 0..8 { assert_eq!(buf.pos().unwrap(), x as u64); assert_eq!(buf.read_s1().unwrap(), (x + 1) as i8); @@ -36,13 +36,13 @@ mod tests { #[test] fn test_size() { - let mut buf = Cursor::new(vec![0, 0, 0, 0, 64, 226, 1, 0]); + let mut buf = Cursor::new([0, 0, 0, 0, 64, 226, 1, 0]); assert_eq!(buf.size().unwrap(), 8); } #[test] fn test_is_eof() { - let mut buf = Cursor::new(vec![0, 0, 0, 0]); + let mut buf = Cursor::new([0, 0, 0, 0]); assert_eq!(buf.is_eof().unwrap(), false); let _ = buf.read_s2le(); assert_eq!(buf.is_eof().unwrap(), false); @@ -54,7 +54,7 @@ mod tests { ($name:ident, $value:expr) => { #[test] fn $name() { - let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); + let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!(buf.$name().unwrap(), $value); } }; @@ -80,62 +80,62 @@ mod tests { #[test] fn read_f4le() { - let mut buf = Cursor::new(vec![0, 0, 128, 62]); + let mut buf = Cursor::new([0, 0, 128, 62]); assert_eq!(buf.read_f4le().unwrap(), 0.25); } #[test] fn read_f4be() { - let mut buf = Cursor::new(vec![62, 128, 0, 0]); + let mut buf = Cursor::new([62, 128, 0, 0]); assert_eq!(buf.read_f4be().unwrap(), 0.25); } #[test] fn read_f8le() { - let mut buf = Cursor::new(vec![0, 0, 0, 0, 0, 0, 208, 63]); + let mut buf = Cursor::new([0, 0, 0, 0, 0, 0, 208, 63]); assert_eq!(buf.read_f8le().unwrap(), 0.25); } #[test] fn read_f8be() { - let mut buf = Cursor::new(vec![63, 208, 0, 0, 0, 0, 0, 0]); + let mut buf = Cursor::new([63, 208, 0, 0, 0, 0, 0, 0]); assert_eq!(buf.read_f8be().unwrap(), 0.25); } #[test] fn read_bytes() { - let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(buf.read_bytes(4).unwrap(), vec![1, 2, 3, 4]); + let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(buf.read_bytes(4).unwrap(), [1, 2, 3, 4]); } #[test] fn read_bytes_full() { - let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(buf.read_bytes_full().unwrap(), vec![1, 2, 3, 4, 5, 6, 7, 8]); + let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(buf.read_bytes_full().unwrap(), [1, 2, 3, 4, 5, 6, 7, 8]); } #[test] fn ensure_fixed_contents() { - let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); + let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!( buf.ensure_fixed_contents(4, vec![1, 2, 3, 4]).unwrap(), - vec![1, 2, 3, 4] + [1, 2, 3, 4] ); } #[test] #[should_panic] fn ensure_fixed_contents_panic() { - let mut buf = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); + let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!( buf.ensure_fixed_contents(4, vec![5, 6, 7, 8]).unwrap(), - vec![1, 2, 3, 4] + [1, 2, 3, 4] ); } #[test] fn read_str_byte_limit() { - let mut buf = Cursor::new(vec![ + let mut buf = Cursor::new([ 230, 151, 165, 230, 156, 172, 232, 170, 158, // utf-8 147, 250, 150, 123, 140, 234, // shift_jis ]); @@ -145,14 +145,14 @@ mod tests { #[test] fn read_str_eos() { - let mut buf = Cursor::new(vec![49, 50, 51]); + let mut buf = Cursor::new([49, 50, 51]); assert_eq!(buf.read_str_eos("ascii").unwrap(), "123"); assert_eq!(buf.pos().unwrap(), 3); } #[test] fn read_strz() { - let mut buf = Cursor::new(vec![ + let mut buf = Cursor::new([ 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // utf-8 147, 250, 150, 123, 140, 234, 0, // shift_jis ]); @@ -169,41 +169,41 @@ mod tests { #[test] #[should_panic] fn read_strz_panic() { - let mut buf = Cursor::new(vec![49, 50, 51]); // no terminator + let mut buf = Cursor::new([49, 50, 51]); // no terminator assert_eq!(buf.read_strz("utf-8", 0, false, true, true).unwrap(), "123"); } #[test] fn process_xor_one() { - let mut buf = Cursor::new(vec![]); - assert_eq!(buf.process_xor_one(vec![0, 0, 0, 0], 1), vec![1, 1, 1, 1]); + let mut buf = Cursor::new([]); + assert_eq!(buf.process_xor_one(vec![0, 0, 0, 0], 1), [1, 1, 1, 1]); } #[test] fn process_xor_one_many() { - let mut buf = Cursor::new(vec![]); + let mut buf = Cursor::new([]); assert_eq!( buf.process_xor_many(vec![0, 0, 0, 0], vec![1, 2, 3, 4]), - vec![1, 2, 3, 4] + [1, 2, 3, 4] ); } #[test] fn process_rotate_left() { - let mut buf = Cursor::new(vec![]); + let mut buf = Cursor::new([]); assert_eq!( buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], 2, 1), - vec![0b1100_0011, 0b1001_1001] + [0b1100_0011, 0b1001_1001] ); assert_eq!( buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], -6, 1), - vec![0b1100_0011, 0b1001_1001] + [0b1100_0011, 0b1001_1001] ); } #[test] fn process_zlib() { - let mut buf = Cursor::new(vec![]); + let mut buf = Cursor::new([]); let arr = vec![ 120, 156, 75, 84, 40, 44, 205, 76, 206, 86, 72, 42, 202, 47, 207, 83, 72, 203, 175, 80, 200, 42, 205, 45, 40, 86, 200, 47, 75, 45, 2, 0, 148, 189, 10, 127, From 1cab55b5d9c7e37ad642ee60659d169f1e6153df Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 22:14:20 +0500 Subject: [PATCH 08/14] Remove deprecated and unused `ensure_fixed_contents`. Validators should be used instead Removed in https://github.com/kaitai-io/kaitai_struct_compiler/commit/3fcc700017d4add59724338230604977952dbaec --- src/kaitai_stream.rs | 11 ----------- src/lib.rs | 19 ------------------- 2 files changed, 30 deletions(-) diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index 76e3044..d664534 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -169,17 +169,6 @@ pub trait KaitaiStream: Read + Seek { } } - fn ensure_fixed_contents(&mut self, count: usize, expected: Vec) -> Result> { - let mut buffer = vec![0; count]; - match self.read_exact(&mut buffer[..]) { - Ok(_) => { - assert_eq!(buffer, expected); - Ok(buffer) - } - Err(e) => Err(e), - } - } - // ------- // // Strings // // ------- // diff --git a/src/lib.rs b/src/lib.rs index 686b3da..74a47ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,25 +114,6 @@ mod tests { assert_eq!(buf.read_bytes_full().unwrap(), [1, 2, 3, 4, 5, 6, 7, 8]); } - #[test] - fn ensure_fixed_contents() { - let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!( - buf.ensure_fixed_contents(4, vec![1, 2, 3, 4]).unwrap(), - [1, 2, 3, 4] - ); - } - - #[test] - #[should_panic] - fn ensure_fixed_contents_panic() { - let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!( - buf.ensure_fixed_contents(4, vec![5, 6, 7, 8]).unwrap(), - [1, 2, 3, 4] - ); - } - #[test] fn read_str_byte_limit() { let mut buf = Cursor::new([ From 4d3907acf596f95737e3e26f3760f296090351e5 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 23:09:29 +0500 Subject: [PATCH 09/14] Convert built-in processors to free functions --- src/kaitai_stream.rs | 56 +------------------------------------------- src/lib.rs | 20 +++++++--------- src/processors.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 66 deletions(-) create mode 100644 src/processors.rs diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index d664534..2c611fb 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -1,5 +1,4 @@ -use flate2::read::ZlibDecoder; -use std::io::{Cursor, Read, Result, Seek, SeekFrom}; +use std::io::{Read, Result, Seek, SeekFrom}; use byteorder::{BigEndian, ByteOrder, LittleEndian}; use encoding::label::encoding_from_whatwg_label; @@ -240,59 +239,6 @@ pub trait KaitaiStream: Read + Seek { Err(e) => panic!("Error decoding string: {}", e), } } - - // --------------------- // - // Byte array processing // - // --------------------- // - - fn process_xor_one(&mut self, value: Vec, key: u8) -> Vec { - let mut result = vec![0; value.len()]; - for i in 0..value.len() { - result[i] = (value[i] ^ key) as u8; - } - return result; - } - - fn process_xor_many(&mut self, value: Vec, key: Vec) -> Vec { - let mut result = vec![0; value.len()]; - let mut j = 0; - for i in 0..value.len() { - result[i] = (value[i] ^ key[j]) as u8; - j = (j + 1) % key.len(); - } - return result; - } - - fn process_rotate_left(&mut self, data: Vec, amount: i32, group_size: i32) -> Vec { - if amount < -7 || amount > 7 { - panic!("Rotation of more than 7 cannot be performed."); - } - - let mut rot_amount = amount; - if rot_amount < 0 { - rot_amount += 8; - } - - let mut result = vec![0; data.len()]; - match group_size { - 1 => { - for i in 0..data.len() { - result[i] = data[i].rotate_left(rot_amount as u32); - } - } - _ => unimplemented!("Unable to rotate a group of {} bytes yet", group_size), - } - return result; - } - - fn process_zlib(&mut self, data: Vec) -> Result> { - let mut decoder = ZlibDecoder::new(Cursor::new(data)); - let mut result = Vec::new(); - match decoder.read_to_end(&mut result) { - Ok(_) => Ok(result), - Err(e) => Err(e), - } - } } impl KaitaiStream for T {} diff --git a/src/lib.rs b/src/lib.rs index 74a47ac..edf8ceb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,10 @@ mod kaitai_stream; mod kaitai_struct; +mod processors; pub use crate::kaitai_stream::KaitaiStream; pub use crate::kaitai_struct::KaitaiStruct; +pub use crate::processors::*; #[cfg(test)] mod tests { @@ -156,40 +158,36 @@ mod tests { #[test] fn process_xor_one() { - let mut buf = Cursor::new([]); - assert_eq!(buf.process_xor_one(vec![0, 0, 0, 0], 1), [1, 1, 1, 1]); + assert_eq!(crate::process_xor_one(&[0, 0, 0, 0], 1), [1, 1, 1, 1]); } #[test] - fn process_xor_one_many() { - let mut buf = Cursor::new([]); + fn process_xor_many() { assert_eq!( - buf.process_xor_many(vec![0, 0, 0, 0], vec![1, 2, 3, 4]), + crate::process_xor_many(&[0, 0, 0, 0], &[1, 2, 3, 4]), [1, 2, 3, 4] ); } #[test] fn process_rotate_left() { - let mut buf = Cursor::new([]); assert_eq!( - buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], 2, 1), + crate::process_rotate_left(&[0b1111_0000, 0b0110_0110], 2, 1), [0b1100_0011, 0b1001_1001] ); assert_eq!( - buf.process_rotate_left(vec![0b1111_0000, 0b0110_0110], -6, 1), + crate::process_rotate_left(&[0b1111_0000, 0b0110_0110], -6, 1), [0b1100_0011, 0b1001_1001] ); } #[test] fn process_zlib() { - let mut buf = Cursor::new([]); - let arr = vec![ + let arr = [ 120, 156, 75, 84, 40, 44, 205, 76, 206, 86, 72, 42, 202, 47, 207, 83, 72, 203, 175, 80, 200, 42, 205, 45, 40, 86, 200, 47, 75, 45, 2, 0, 148, 189, 10, 127, ]; - let deflate = buf.process_zlib(arr).unwrap(); + let deflate = crate::process_zlib(&arr).unwrap(); assert_eq!(deflate, "a quick brown fox jumps over".as_bytes()) } } diff --git a/src/processors.rs b/src/processors.rs new file mode 100644 index 0000000..df911d3 --- /dev/null +++ b/src/processors.rs @@ -0,0 +1,56 @@ +//! Module with built-in routines for `process` key. + +use flate2::read::ZlibDecoder; +use std::io::{Cursor, Read, Result}; + +// TODO: inplace processing +pub fn process_xor_one(value: &[u8], key: u8) -> Vec { + let mut result = vec![0; value.len()]; + for i in 0..value.len() { + result[i] = (value[i] ^ key) as u8; + } + return result; +} + +// TODO: inplace processing +pub fn process_xor_many(value: &[u8], key: &[u8]) -> Vec { + let mut result = vec![0; value.len()]; + let mut j = 0; + for i in 0..value.len() { + result[i] = (value[i] ^ key[j]) as u8; + j = (j + 1) % key.len(); + } + return result; +} + +// TODO: inplace processing +pub fn process_rotate_left(data: &[u8], amount: i32, group_size: i32) -> Vec { + if amount < -7 || amount > 7 { + panic!("Rotation of more than 7 cannot be performed."); + } + + let mut rot_amount = amount; + if rot_amount < 0 { + rot_amount += 8; + } + + let mut result = vec![0; data.len()]; + match group_size { + 1 => { + for i in 0..data.len() { + result[i] = data[i].rotate_left(rot_amount as u32); + } + } + _ => unimplemented!("Unable to rotate a group of {} bytes yet", group_size), + } + return result; +} + +pub fn process_zlib(data: &[u8]) -> Result> { + let mut decoder = ZlibDecoder::new(Cursor::new(data)); + let mut result = Vec::new(); + match decoder.read_to_end(&mut result) { + Ok(_) => Ok(result), + Err(e) => Err(e), + } +} From e6d43cb0e2b876fe2b47b7444d71fd7569b78618 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 30 Mar 2024 00:27:37 +0500 Subject: [PATCH 10/14] Remove never used and not planned to use methods of string reading String reading reworked in https://github.com/kaitai-io/kaitai_struct_compiler/commit/f0bd143b382e0a36f96fd4644a5345c0156d3d1a so those methods not needed anymore --- src/kaitai_stream.rs | 30 ------------------------------ src/lib.rs | 17 ----------------- 2 files changed, 47 deletions(-) diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index 2c611fb..6be5a45 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -168,36 +168,6 @@ pub trait KaitaiStream: Read + Seek { } } - // ------- // - // Strings // - // ------- // - - fn read_str_eos(&mut self, encoding: &str) -> Result { - match encoding_from_whatwg_label(encoding) { - Some(enc) => { - let buffer = self.read_bytes_full()?; - match enc.decode(&buffer, DecoderTrap::Strict) { - Ok(s) => Ok(s), - Err(e) => panic!("Error decoding string: {}", e), - } - } - None => panic!("Unknown encoding: {}", encoding), - } - } - - fn read_str_byte_limit(&mut self, length: usize, encoding: &str) -> Result { - match encoding_from_whatwg_label(encoding) { - Some(enc) => { - let buffer = self.read_bytes(length)?; - match enc.decode(&buffer, DecoderTrap::Strict) { - Ok(s) => Ok(s), - Err(e) => panic!("Error decoding string: {}", e), - } - } - None => panic!("Unknown encoding: {}", encoding), - } - } - fn read_strz( &mut self, encoding: &str, diff --git a/src/lib.rs b/src/lib.rs index edf8ceb..9564f42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,23 +116,6 @@ mod tests { assert_eq!(buf.read_bytes_full().unwrap(), [1, 2, 3, 4, 5, 6, 7, 8]); } - #[test] - fn read_str_byte_limit() { - let mut buf = Cursor::new([ - 230, 151, 165, 230, 156, 172, 232, 170, 158, // utf-8 - 147, 250, 150, 123, 140, 234, // shift_jis - ]); - assert_eq!(buf.read_str_byte_limit(9, "utf-8").unwrap(), "日本語"); - assert_eq!(buf.read_str_byte_limit(6, "shift_jis").unwrap(), "日本語"); - } - - #[test] - fn read_str_eos() { - let mut buf = Cursor::new([49, 50, 51]); - assert_eq!(buf.read_str_eos("ascii").unwrap(), "123"); - assert_eq!(buf.pos().unwrap(), 3); - } - #[test] fn read_strz() { let mut buf = Cursor::new([ From 9165d8bc87c0568618951bdd0702ddea9dae508b Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 30 Mar 2024 00:41:21 +0500 Subject: [PATCH 11/14] Implement `read_bytes_term` method instead of `read_strz` --- src/kaitai_stream.rs | 19 +++++-------------- src/lib.rs | 17 ++++++++++------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index 6be5a45..5dcbda6 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -1,8 +1,6 @@ use std::io::{Read, Result, Seek, SeekFrom}; use byteorder::{BigEndian, ByteOrder, LittleEndian}; -use encoding::label::encoding_from_whatwg_label; -use encoding::DecoderTrap; macro_rules! read_endian { ($this:ident, $size:expr, $end:ident, $method:ident) => {{ @@ -168,21 +166,17 @@ pub trait KaitaiStream: Read + Seek { } } - fn read_strz( + fn read_bytes_term( &mut self, - encoding: &str, terminator: u8, include_terminator: bool, consume_terminator: bool, eos_error: bool, - ) -> Result { - let enc = match encoding_from_whatwg_label(encoding) { - Some(enc) => enc, - None => panic!("Unknown encoding: {}", encoding), - }; + ) -> Result> { let mut buffer = vec![]; - let mut c = vec![0; 1]; + let mut c = [0; 1]; loop { + // TODO: Very non-optimal, optimize! match self.read_exact(&mut c[..]) { Ok(_) => {} Err(e) => { @@ -204,10 +198,7 @@ pub trait KaitaiStream: Read + Seek { } buffer.push(c[0]) } - match enc.decode(&buffer, DecoderTrap::Strict) { - Ok(s) => Ok(s), - Err(e) => panic!("Error decoding string: {}", e), - } + Ok(buffer) } } diff --git a/src/lib.rs b/src/lib.rs index 9564f42..53f29c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,26 +117,29 @@ mod tests { } #[test] - fn read_strz() { + fn read_bytes_term() { let mut buf = Cursor::new([ 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // utf-8 147, 250, 150, 123, 140, 234, 0, // shift_jis ]); assert_eq!( - buf.read_strz("utf-8", 0, false, true, false).unwrap(), - "日本語" + buf.read_bytes_term(0, false, true, false).unwrap(), + [230, 151, 165, 230, 156, 172, 232, 170, 158] ); assert_eq!( - buf.read_strz("shift_jis", 0, false, true, false).unwrap(), - "日本語" + buf.read_bytes_term(0, false, true, false).unwrap(), + [147, 250, 150, 123, 140, 234] ); } #[test] #[should_panic] - fn read_strz_panic() { + fn read_bytes_term_panic() { let mut buf = Cursor::new([49, 50, 51]); // no terminator - assert_eq!(buf.read_strz("utf-8", 0, false, true, true).unwrap(), "123"); + assert_eq!( + buf.read_bytes_term(0, false, true, true).unwrap(), + [49, 50, 51] + ); } #[test] From b35c40f8505cd58b3bfc4f65a5c4fe052dd6b10d Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 30 Mar 2024 01:25:55 +0500 Subject: [PATCH 12/14] Rewrite tests for `read_bytes_term` to ensure full coverage --- src/lib.rs | 123 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 53f29c6..aa7f698 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,30 +116,107 @@ mod tests { assert_eq!(buf.read_bytes_full().unwrap(), [1, 2, 3, 4, 5, 6, 7, 8]); } - #[test] - fn read_bytes_term() { - let mut buf = Cursor::new([ - 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // utf-8 - 147, 250, 150, 123, 140, 234, 0, // shift_jis - ]); - assert_eq!( - buf.read_bytes_term(0, false, true, false).unwrap(), - [230, 151, 165, 230, 156, 172, 232, 170, 158] - ); - assert_eq!( - buf.read_bytes_term(0, false, true, false).unwrap(), - [147, 250, 150, 123, 140, 234] - ); - } + mod read_bytes_term { + use super::*; - #[test] - #[should_panic] - fn read_bytes_term_panic() { - let mut buf = Cursor::new([49, 50, 51]); // no terminator - assert_eq!( - buf.read_bytes_term(0, false, true, true).unwrap(), - [49, 50, 51] - ); + mod without_error { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn with_terminator() { + let mut buf = Cursor::new([ + 1, 2, 3, 4, 0, // first chunk + 5, 6, 0, // second chunk + ]); + // Read to 0, but not consume it and not include in the result + assert_eq!( + buf.read_bytes_term(0, false, false, false).unwrap(), + [1, 2, 3, 4] + ); + // Read to 0 and consume it, but do not include in the result. + // Because we already at 0, an empty array is returned + assert_eq!(buf.read_bytes_term(0, false, true, false).unwrap(), []); + // Read to second 0, include it to the result, but not consume + assert_eq!( + buf.read_bytes_term(0, true, false, false).unwrap(), + [5, 6, 0] + ); + // Read to second 0 and consume it, and include in the result. + // Because we already at second 0, only it is returned + assert_eq!(buf.read_bytes_term(0, true, true, false).unwrap(), [0]); + } + + #[test] + fn without_terminator() { + let mut buf = Cursor::new([1, 2, 3, 4]); + // Read to missing 0, do not try consume it or include it in the result + assert_eq!( + buf.read_bytes_term(0, false, false, false).unwrap(), + [1, 2, 3, 4] + ); + // Read to missing 0, try to consume it but do not try to include it in the result + // Because we already at the end, an empty array is returned + assert_eq!(buf.read_bytes_term(0, false, true, false).unwrap(), []); + + let mut buf = Cursor::new([5, 6]); + // Read to missing 0, do not try to consume, but try to include it in the result + assert_eq!(buf.read_bytes_term(0, true, false, false).unwrap(), [5, 6]); + // Read to missing 0, try to consume and include it in the result + // Because we already at the end, an empty array is returned + assert_eq!(buf.read_bytes_term(0, true, true, false).unwrap(), []); + } + } + + mod with_eos_error { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn with_terminator() { + let mut buf = Cursor::new([ + 1, 2, 3, 4, 0, // first chunk + 5, 6, 0, // second chunk + ]); + // Read to 0, but not consume it and not include in the result + assert_eq!( + buf.read_bytes_term(0, false, false, true).unwrap(), + [1, 2, 3, 4] + ); + // Read to 0 and consume it, but do not include in the result. + // Because we already at 0, an empty array is returned + assert_eq!(buf.read_bytes_term(0, false, true, true).unwrap(), []); + // Read to second 0, include it to the result, but not consume + assert_eq!( + buf.read_bytes_term(0, true, false, true).unwrap(), + [5, 6, 0] + ); + // Read to second 0 and consume it, and include in the result. + // Because we already at second 0, only it is returned + assert_eq!(buf.read_bytes_term(0, true, true, true).unwrap(), [0]); + } + + #[test] + fn without_terminator() { + // Read to missing 0 lead to error + assert!(matches!( + Cursor::new([1, 2]).read_bytes_term(0, false, false, true), + Err(_) + )); + assert!(matches!( + Cursor::new([3, 4]).read_bytes_term(0, false, true, true), + Err(_) + )); + assert!(matches!( + Cursor::new([5, 6]).read_bytes_term(0, true, false, true), + Err(_) + )); + assert!(matches!( + Cursor::new([7, 8]).read_bytes_term(0, true, true, true), + Err(_) + )); + } + } } #[test] From 01d794d52a3a8c27d87079718bc6b2254e2ccde4 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 30 Mar 2024 01:50:49 +0500 Subject: [PATCH 13/14] Document the crate and deny any missing documentation or unsafe code --- src/kaitai_stream.rs | 53 +++++++++++++++++++++++++++++++++++++++++++ src/kaitai_struct.rs | 2 ++ src/lib.rs | 12 ++++++++++ src/processors.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) diff --git a/src/kaitai_stream.rs b/src/kaitai_stream.rs index 5dcbda6..9af0029 100644 --- a/src/kaitai_stream.rs +++ b/src/kaitai_stream.rs @@ -10,11 +10,32 @@ macro_rules! read_endian { }}; } +/// `KaitaiStream` trait provides implementation of [Kaitai Stream API] for Rust. +/// +/// It provides a wide variety of simple methods to read (parse) binary +/// representations of primitive types, such as integer and floating +/// point numbers, byte arrays and strings, and also provides stream +/// positioning / navigation methods with unified cross-language and +/// cross-toolkit semantics. +/// +/// Methods of this trait are called from the generated code to parse bynary stream +/// into generated structures. +/// +/// This trait is automatically implemented for all sources that is `Read + Seek`. +/// +/// Typically, end users won't access any of these Kaitai Stream methods +/// manually, but would describe a binary structure format using .ksy language +/// and then would use Kaitai Struct compiler to generate source code in +/// desired target language. That code, in turn, would use this trait +/// and API to do the actual parsing job. +/// +/// [Kaitai Stream API]: https://doc.kaitai.io/stream_api.html pub trait KaitaiStream: Read + Seek { // ------------------ // // Stream positioning // // ------------------ // + /// Check if stream pointer is at the end of stream. fn is_eof(&mut self) -> Result { // TODO: I'm positive there's a better way to do this! // See also the `size` implementation @@ -24,6 +45,7 @@ pub trait KaitaiStream: Read + Seek { return Ok(pos >= size); } + /// Set stream pointer to designated position in bytes from the beginning of the stream. fn seek(&mut self, position: u64) -> Result<()> { match Seek::seek(self, SeekFrom::Start(position)) { Ok(_) => Ok(()), @@ -31,6 +53,7 @@ pub trait KaitaiStream: Read + Seek { } } + /// Get current position of a stream pointer in number of bytes from the beginning of the stream. fn pos(&mut self) -> Result { match Seek::seek(self, SeekFrom::Current(0)) { Ok(i) => Ok(i as u64), @@ -38,6 +61,7 @@ pub trait KaitaiStream: Read + Seek { } } + /// Get total size of the stream in bytes. fn size(&mut self) -> Result { // TODO: I'm positive there's a better way to do this! let pos = self.pos()?; @@ -50,6 +74,7 @@ pub trait KaitaiStream: Read + Seek { // Integer types - signed // // ---------------------- // + /// Reads one signed 1-byte integer, used to parse `s1` Kaitai type. fn read_s1(&mut self) -> Result { let mut buf = [0; 1]; self.read_exact(&mut buf)?; @@ -58,28 +83,34 @@ pub trait KaitaiStream: Read + Seek { // Big endian + /// Reads one signed 2-byte integer, used to parse `s2` Kaitai type in Big Endian. fn read_s2be(&mut self) -> Result { read_endian!(self, 2, BigEndian, read_i16) } + /// Reads one signed 4-byte integer, used to parse `s4` Kaitai type in Big Endian. fn read_s4be(&mut self) -> Result { read_endian!(self, 4, BigEndian, read_i32) } + /// Reads one signed 8-byte integer, used to parse `s8` Kaitai type in Big Endian. fn read_s8be(&mut self) -> Result { read_endian!(self, 8, BigEndian, read_i64) } // Little endian + /// Reads one signed 2-byte integer, used to parse `s2` Kaitai type in Little Endian. fn read_s2le(&mut self) -> Result { read_endian!(self, 2, LittleEndian, read_i16) } + /// Reads one signed 4-byte integer, used to parse `s4` Kaitai type in Little Endian. fn read_s4le(&mut self) -> Result { read_endian!(self, 4, LittleEndian, read_i32) } + /// Reads one signed 8-byte integer, used to parse `s8` Kaitai type in Little Endian. fn read_s8le(&mut self) -> Result { read_endian!(self, 8, LittleEndian, read_i64) } @@ -88,6 +119,7 @@ pub trait KaitaiStream: Read + Seek { // Integer types - unsigned // // ------------------------ // + /// Reads one unsigned 1-byte integer, used to parse `u1` Kaitai type. fn read_u1(&mut self) -> Result { let mut buf = [0; 1]; self.read_exact(&mut buf)?; @@ -96,28 +128,34 @@ pub trait KaitaiStream: Read + Seek { // Big endian + /// Reads one unsigned 2-byte integer, used to parse `u2` Kaitai type in Big Endian. fn read_u2be(&mut self) -> Result { read_endian!(self, 2, BigEndian, read_u16) } + /// Reads one unsigned 4-byte integer, used to parse `u4` Kaitai type in Big Endian. fn read_u4be(&mut self) -> Result { read_endian!(self, 4, BigEndian, read_u32) } + /// Reads one unsigned 8-byte integer, used to parse `u8` Kaitai type in Big Endian. fn read_u8be(&mut self) -> Result { read_endian!(self, 8, BigEndian, read_u64) } // Little endian + /// Reads one unsigned 2-byte integer, used to parse `u2` Kaitai type in Little Endian. fn read_u2le(&mut self) -> Result { read_endian!(self, 2, LittleEndian, read_u16) } + /// Reads one unsigned 4-byte integer, used to parse `u4` Kaitai type in Little Endian. fn read_u4le(&mut self) -> Result { read_endian!(self, 4, LittleEndian, read_u32) } + /// Reads one unsigned 8-byte integer, used to parse `u8` Kaitai type in Little Endian. fn read_u8le(&mut self) -> Result { read_endian!(self, 8, LittleEndian, read_u64) } @@ -128,20 +166,24 @@ pub trait KaitaiStream: Read + Seek { // Big endian + /// Reads one floating point number with single precision, used to parse `f4` Kaitai type in Big Endian. fn read_f4be(&mut self) -> Result { read_endian!(self, 4, BigEndian, read_f32) } + /// Reads one floating point number with double precision, used to parse `f8` Kaitai type in Big Endian. fn read_f8be(&mut self) -> Result { read_endian!(self, 8, BigEndian, read_f64) } // Little endian + /// Reads one floating point number with single precision, used to parse `f4` Kaitai type in Little Endian. fn read_f4le(&mut self) -> Result { read_endian!(self, 4, LittleEndian, read_f32) } + /// Reads one floating point number with double precision, used to parse `f8` Kaitai type in Little Endian. fn read_f8le(&mut self) -> Result { read_endian!(self, 8, LittleEndian, read_f64) } @@ -150,6 +192,7 @@ pub trait KaitaiStream: Read + Seek { // Byte arrays // // ----------- // + /// Reads designated number of bytes from the stream and returns them in a newly allocated buffer. fn read_bytes(&mut self, count: usize) -> Result> { let mut buffer = vec![0; count]; match self.read_exact(&mut buffer[..]) { @@ -158,6 +201,7 @@ pub trait KaitaiStream: Read + Seek { } } + /// Reads all the remaining bytes in a stream and returns them in a newly allocated buffer. fn read_bytes_full(&mut self) -> Result> { let mut buffer = vec![0; 0]; match self.read_to_end(&mut buffer) { @@ -166,6 +210,15 @@ pub trait KaitaiStream: Read + Seek { } } + /// Reads bytes until the `terminator` byte is reached. + /// + /// # Parameters + /// - `terminator`: the byte that terminates search + /// - `include_terminator`: `true` to include the terminator in the returned array. + /// If `eos_error` is `false` and no terminator found, does nothing + /// - `consume_terminator`: `true` to consume the terminator byte before returning + /// - `eos_error`: `true` to return an error when the EOS was reached before the terminator, + /// otherwise EOF is treated as a terminator fn read_bytes_term( &mut self, terminator: u8, diff --git a/src/kaitai_struct.rs b/src/kaitai_struct.rs index 078b581..456bd35 100644 --- a/src/kaitai_struct.rs +++ b/src/kaitai_struct.rs @@ -2,6 +2,8 @@ use crate::kaitai_stream::KaitaiStream; use std::fs::File; use std::io::{Cursor, Result}; +/// A trait that is implemented by all structures generated by Kaitai Struct. +#[allow(missing_docs)] // TODO: It is unclear yet should we keep this interface or not pub trait KaitaiStruct { fn from_file(path: &str) -> Result where diff --git a/src/lib.rs b/src/lib.rs index aa7f698..31c86d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,15 @@ +//! # Kaitai Struct: runtime library for Rust +//! +//! This library implements Kaitai Struct API for Rust. +//! +//! [Kaitai Struct] is a declarative language used for describe various binary +//! data structures, laid out in files or in memory: i.e. binary file +//! formats, network stream packet formats, etc. +//! +//! [Kaitai Struct]: https://github.com/kaitai-io/kaitai_struct/ +#![deny(missing_docs)] +#![deny(unsafe_code)] + mod kaitai_stream; mod kaitai_struct; mod processors; diff --git a/src/processors.rs b/src/processors.rs index df911d3..1db473a 100644 --- a/src/processors.rs +++ b/src/processors.rs @@ -3,6 +3,23 @@ use flate2::read::ZlibDecoder; use std::io::{Cursor, Read, Result}; +/// Performs a XOR processing with given data, XORing every byte of input with a single given value. +/// Returns processed data +/// +/// # Examples +/// +/// ``` +/// # use kaitai_struct::process_xor_one; +/// # use pretty_assertions::assert_eq; +/// assert_eq!( +/// process_xor_one(b"Hello world", 0x10), +/// &[88, 117, 124, 124, 127, 48, 103, 127, 98, 124, 116] +/// ); +/// ``` +/// +/// # Parameters +/// - `data`: data to process +/// - `key`: value to XOR with // TODO: inplace processing pub fn process_xor_one(value: &[u8], key: u8) -> Vec { let mut result = vec![0; value.len()]; @@ -12,6 +29,24 @@ pub fn process_xor_one(value: &[u8], key: u8) -> Vec { return result; } +/// Performs a XOR processing with given data, XORing every byte of input with a key +/// array, repeating key array many times, if necessary (i.e. if data array is longer +/// than key array). +/// +/// # Examples +/// +/// ``` +/// # use kaitai_struct::process_xor_many; +/// # use pretty_assertions::assert_eq; +/// assert_eq!( +/// process_xor_many(b"Hello world", b"secret"), +/// &[59, 0, 15, 30, 10, 84, 4, 10, 17, 30, 1] +/// ); +/// ``` +/// +/// # Parameters +/// - `data`: data to process +/// - `key`: array of bytes to XOR with // TODO: inplace processing pub fn process_xor_many(value: &[u8], key: &[u8]) -> Vec { let mut result = vec![0; value.len()]; @@ -23,6 +58,21 @@ pub fn process_xor_many(value: &[u8], key: &[u8]) -> Vec { return result; } +/// Performs a circular left rotation shift for a given buffer by a given amount of bits, +/// using groups of `group_size` bytes each time. Right circular rotation should be performed +/// using this procedure with corrected amount. +/// +/// Returns copy of source array with requested shift applied. +/// +/// # Panics +/// If `abs(amount) > 7` then a panic is generated. +/// +/// NOTE: also panic is generated when `group_size` is not 1, because it is not implemented yet. +/// +/// # Parameters +/// - `data`: source data to process +/// - `amount`: number of bits to shift by +/// - `group_size`: number of bytes per group to shift // TODO: inplace processing pub fn process_rotate_left(data: &[u8], amount: i32, group_size: i32) -> Vec { if amount < -7 || amount > 7 { @@ -46,6 +96,10 @@ pub fn process_rotate_left(data: &[u8], amount: i32, group_size: i32) -> Vec return result; } +/// Performs an unpacking ("inflation") of zlib-compressed data with usual zlib headers. +/// +/// # Parameters +/// - `data`: compressed data pub fn process_zlib(data: &[u8]) -> Result> { let mut decoder = ZlibDecoder::new(Cursor::new(data)); let mut result = Vec::new(); From e83f65f8eb30bb436f84ca4153005db748628d58 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 29 Mar 2024 19:00:01 +0500 Subject: [PATCH 14/14] Add trait FromStrRadix for generic conversion from string in a given base --- src/lib.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 31c86d0..04d9d70 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,8 @@ #![deny(missing_docs)] #![deny(unsafe_code)] +use std::num::ParseIntError; + mod kaitai_stream; mod kaitai_struct; mod processors; @@ -18,6 +20,60 @@ pub use crate::kaitai_stream::KaitaiStream; pub use crate::kaitai_struct::KaitaiStruct; pub use crate::processors::*; +/// Parse a value from a string in a given base to an integer. +/// +/// This trait allows type deduction based on the returned value, in the same way, +/// as [FromStr] did. It is implemented for all integer types and delegates +/// conversion to their [`{integer}::from_str_radix`][m] methods. +/// +/// # Examples +/// Basic usage: +/// ``` +/// # use kaitai_struct::FromStrRadix; +/// # use pretty_assertions::assert_eq; +/// // Unlike direct call to `usize::from_str_radix`, the resulting type here +/// // dictated by the left side of assignment +/// let n: Result = FromStrRadix::from_str_radix("A", 16); +/// assert_eq!(n, Ok(10)); +/// ``` +/// +/// [FromStr]: std::str::FromStr +/// [m]: usize::from_str_radix +pub trait FromStrRadix: Sized { + /// Converts a string slice in a given base to an integer. + /// + /// The string is expected to be an optional `+` or `-` sign followed by digits. + /// Leading and trailing whitespace represent an error. + /// Digits are a subset of these characters, depending on radix: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36. + fn from_str_radix(src: &str, radix: u32) -> Result; +} + +macro_rules! impl_conversion { + ($($ty:ty)+) => { + $( + impl FromStrRadix for $ty { + #[inline(always)] + fn from_str_radix(src: &str, radix: u32) -> Result { + Self::from_str_radix(src, radix) + } + } + )* + }; +} + +impl_conversion!( + u8 u16 u32 u64 u128 usize + i8 i16 i32 i64 i128 isize +); + #[cfg(test)] mod tests { use crate::KaitaiStream;