/ crates / exparser / src / rpk.rs
rpk.rs
  1  use std::io;
  2  
  3  use deku::{prelude::*, reader::ReaderRet};
  4  use log::*;
  5  use serde::{Deserialize, Serialize};
  6  
  7  #[cfg(feature = "python")]
  8  use pyo3::prelude::*;
  9  
 10  use crate::VecReader;
 11  
 12  pub const MAGIC: u32 = 0xAFBF0C01;
 13  
 14  #[derive(Debug, Clone, Default)]
 15  pub struct Context {
 16  	/// Whether to skip the `Rpk` data field or not.
 17  	///
 18  	/// By default, the data field will be read by the reader. If you want to save memory and have
 19  	/// better performance, and the data field is not needed such as when simply viewing a list of
 20  	/// entries, setting this to `true` may be desired.
 21  	pub entries_only: bool,
 22  	/// Filter the `Rpk` data field by a desired `Vec<Entry>`.
 23  	///
 24  	/// By default, no filter is applied thus all of the data is read by the reader. If only data
 25  	/// from certain entries is desired, provide this field with your desired entries.
 26  	pub entries: Option<Vec<Entry>>,
 27  }
 28  
 29  #[cfg(feature = "python")]
 30  /// Rayform Package
 31  #[pyclass]
 32  #[deku_derive(DekuRead, DekuWrite)]
 33  #[derive(Clone, Debug, Deserialize, Serialize)]
 34  #[deku(ctx = "ctx: Context", ctx_default = "Context::default()")]
 35  pub struct Rpk {
 36  	#[deku(temp, temp_value = "(entries.len() * 32) as u32")]
 37  	pub size_of_entries: u32,
 38  	#[pyo3(get)]
 39  	#[deku(count = "size_of_entries / 32")]
 40  	pub entries: Vec<Entry>,
 41  	#[pyo3(get)]
 42  	#[deku(
 43  		cond = "!ctx.entries_only",
 44  		reader = "Rpk::read(ctx, deku::reader, entries)",
 45  		writer = "VecReader::write_nested(deku::writer, &self.data)"
 46  	)]
 47  	pub data: Vec<Vec<u8>>,
 48  }
 49  
 50  #[cfg(not(feature = "python"))]
 51  /// Rayform Package
 52  #[deku_derive(DekuRead, DekuWrite)]
 53  #[derive(Clone, Debug, Deserialize, Serialize)]
 54  #[deku(ctx = "ctx: Context", ctx_default = "Context::default()")]
 55  pub struct Rpk {
 56  	#[deku(temp, temp_value = "(entries.len() * 32) as u32")]
 57  	pub size_of_entries: u32,
 58  	#[deku(count = "size_of_entries / 32")]
 59  	pub entries: Vec<Entry>,
 60  	#[deku(
 61  		cond = "!ctx.entries_only",
 62  		reader = "Rpk::read(ctx, deku::reader, entries)",
 63  		writer = "VecReader::write_nested(deku::writer, &self.data)"
 64  	)]
 65  	pub data: Vec<Vec<u8>>,
 66  }
 67  
 68  impl Rpk {
 69  	fn read<R: io::Read + io::Seek>(
 70  		ctx: Context,
 71  		reader: &mut Reader<R>,
 72  		entries: &[Entry],
 73  	) -> Result<Vec<Vec<u8>>, DekuError> {
 74  		// Sort the entries by offset so we can read them in order.
 75  		let mut entries = match ctx.entries {
 76  			Some(entries) => entries,
 77  			None => entries.to_vec(),
 78  		};
 79  		entries.sort_by(|a, b| a.offset.cmp(&b.offset));
 80  
 81  		let mut formats: Vec<Vec<u8>> = Vec::with_capacity(entries.len());
 82  
 83  		for entry in entries {
 84  			let mut buf = vec![0; entry.size as usize];
 85  
 86  			// deku is slow at reading Vec<u8> so we read the bytes into a buffer ourselves.
 87  			let format = match reader.read_bytes(entry.size as usize, &mut buf) {
 88  				Ok(ReaderRet::Bytes) => Ok(buf),
 89  				Ok(ReaderRet::Bits(_)) => {
 90  					Err(DekuError::InvalidParam("Expected bytes, got bits".into()))
 91  				}
 92  				Err(err) => Err(err),
 93  			}?;
 94  
 95  			formats.push(format);
 96  		}
 97  		Ok(formats)
 98  	}
 99  }
100  
101  #[cfg_attr(feature = "python", pyclass(get_all))]
102  #[derive(Debug, DekuRead, DekuWrite, Deserialize, Serialize, Clone)]
103  pub struct Entry {
104  	#[deku(
105  		reader = "Entry::read(deku::reader)",
106  		writer = "Entry::write(deku::writer, &self.name)"
107  	)]
108  	pub name: String,
109  	pub offset: u32,
110  	#[deku(pad_bytes_after = "8")]
111  	pub size: u32,
112  }
113  
114  impl Entry {
115  	fn read<R: io::Read + io::Seek>(reader: &mut Reader<R>) -> Result<String, DekuError> {
116  		let mut buf: Vec<u8> = vec![0; 16];
117  		match reader.read_bytes(16, &mut buf) {
118  			Ok(ReaderRet::Bytes) => {
119  				let mut s = String::new();
120  				for b in buf {
121  					match b {
122  						0 => break,
123  						v => s.push(v as char),
124  					}
125  				}
126  				Ok(s)
127  			}
128  			Ok(ReaderRet::Bits(_)) => {
129  				Err(DekuError::InvalidParam("Expected bytes, got bits".into()))
130  			}
131  			Err(err) => Err(err),
132  		}
133  	}
134  
135  	fn write<W: io::Write + io::Seek>(
136  		writer: &mut Writer<W>,
137  		value: &str,
138  	) -> Result<(), DekuError> {
139  		let mut buf = vec![0; 16];
140  		for (i, c) in value.chars().enumerate() {
141  			if i >= 16 {
142  				warn!(
143  					r#"entry name "{}" has been truncated due to being longer than 16 characters."#,
144  					value
145  				);
146  				break;
147  			}
148  			buf[i] = c as u8;
149  		}
150  		writer.write_bytes(&buf)
151  	}
152  }