use std::collections::HashMap;
use crate::error::BioLibError;
pub struct ModuleInput;
impl ModuleInput {
pub fn serialize(
stdin: &[u8],
arguments: &[String],
files: &HashMap<String, Vec<u8>>,
) -> crate::Result<Vec<u8>> {
for path in files.keys() {
if path.contains("//") {
return Err(BioLibError::Validation(format!(
"File path '{path}' contains double slashes which are not allowed"
)));
}
}
let mut data = Vec::new();
data.push(1u8); data.push(1u8);
data.extend_from_slice(&(stdin.len() as u64).to_be_bytes());
let argument_len: usize = arguments.iter().map(|arg| arg.len() + 2).sum();
data.extend_from_slice(&(argument_len as u32).to_be_bytes());
let file_data_len: usize = files
.iter()
.map(|(path, file_data)| file_data.len() + path.len() + 12)
.sum();
data.extend_from_slice(&(file_data_len as u64).to_be_bytes());
data.extend_from_slice(stdin);
for argument in arguments {
let encoded = argument.as_bytes();
data.extend_from_slice(&(encoded.len() as u16).to_be_bytes());
data.extend_from_slice(encoded);
}
for (path, file_data) in files {
let encoded_path = path.as_bytes();
data.extend_from_slice(&(encoded_path.len() as u32).to_be_bytes());
data.extend_from_slice(&(file_data.len() as u64).to_be_bytes());
data.extend_from_slice(encoded_path);
data.extend_from_slice(file_data);
}
Ok(data)
}
pub fn deserialize(bbf: &[u8]) -> crate::Result<ModuleInputData> {
let mut pointer = 0usize;
let version = bbf[pointer];
pointer += 1;
let package_type = bbf[pointer];
pointer += 1;
if version != 1 {
return Err(BioLibError::BinaryFormat(format!(
"Unsupported version: {version}"
)));
}
if package_type != 1 {
return Err(BioLibError::BinaryFormat(format!(
"Unsupported package type: {package_type}"
)));
}
let stdin_len = read_u64_be(bbf, &mut pointer) as usize;
let argument_data_len = read_u32_be(bbf, &mut pointer) as usize;
let files_data_len = read_u64_be(bbf, &mut pointer) as usize;
let stdin = bbf[pointer..pointer + stdin_len].to_vec();
pointer += stdin_len;
let end_of_arguments = pointer + argument_data_len;
let mut arguments = Vec::new();
while pointer < end_of_arguments {
let arg_len = read_u16_be(bbf, &mut pointer) as usize;
let arg = String::from_utf8_lossy(&bbf[pointer..pointer + arg_len]).to_string();
pointer += arg_len;
arguments.push(arg);
}
let end_of_files = pointer + files_data_len;
let mut files = HashMap::new();
while pointer < end_of_files {
let path_len = read_u32_be(bbf, &mut pointer) as usize;
let data_len = read_u64_be(bbf, &mut pointer) as usize;
let path = String::from_utf8_lossy(&bbf[pointer..pointer + path_len]).to_string();
pointer += path_len;
let file_data = bbf[pointer..pointer + data_len].to_vec();
pointer += data_len;
files.insert(path, file_data);
}
Ok(ModuleInputData {
stdin,
arguments,
files,
})
}
}
#[derive(Debug)]
pub struct ModuleInputData {
pub stdin: Vec<u8>,
pub arguments: Vec<String>,
pub files: HashMap<String, Vec<u8>>,
}
fn read_u64_be(data: &[u8], pointer: &mut usize) -> u64 {
let value = u64::from_be_bytes(data[*pointer..*pointer + 8].try_into().unwrap());
*pointer += 8;
value
}
fn read_u32_be(data: &[u8], pointer: &mut usize) -> u32 {
let value = u32::from_be_bytes(data[*pointer..*pointer + 4].try_into().unwrap());
*pointer += 4;
value
}
fn read_u16_be(data: &[u8], pointer: &mut usize) -> u16 {
let value = u16::from_be_bytes(data[*pointer..*pointer + 2].try_into().unwrap());
*pointer += 2;
value
}