use std::{ffi::OsStr, fs::OpenOptions, io::Read, path::Path};
use types::{DeltaDecoderTable, Demo};
mod byte_writer;
mod delta;
mod nom_helper;
mod utils;
pub mod bit;
pub mod demo_parser;
pub mod demo_writer;
pub mod error;
pub mod netmsg_doer;
pub mod types;
pub use crate::bit::BitSliceCast;
use crate::{demo_parser::parse_demo, error::DemoError, types::MessageDataParseMode};
pub use utils::bitslice_to_string;
pub extern crate bitvec;
impl Demo {
pub fn parse_from_file(
path: impl AsRef<OsStr> + AsRef<Path>,
netmsg_parse_mode: MessageDataParseMode,
) -> Result<Self, DemoError> {
let mut file = OpenOptions::new().read(true).open(path)?;
let mut bytes: Vec<u8> = vec![];
file.read_to_end(&mut bytes)?;
Self::parse_from_bytes(bytes.as_slice(), netmsg_parse_mode)
}
pub fn parse_from_bytes(
demo_bytes: &[u8],
netmsg_parse_mode: MessageDataParseMode,
) -> Result<Self, DemoError> {
parse_demo(demo_bytes, netmsg_parse_mode)
.map_err(|_| DemoError::ParseError)
.map(|(_, x)| x)
}
}
pub fn open_demo(demo_path: impl AsRef<Path> + AsRef<OsStr>) -> Result<Demo, DemoError> {
Demo::parse_from_file(demo_path, types::MessageDataParseMode::Parse)
}
pub fn open_demo_from_bytes(demo_bytes: &[u8]) -> Result<Demo, DemoError> {
Demo::parse_from_bytes(demo_bytes, types::MessageDataParseMode::Parse)
}
#[macro_export]
macro_rules! nbit_num {
($num:expr, $bit:expr) => {{
use $crate::bit::BitWriter;
let mut writer = BitWriter::new();
writer.append_u32_range($num as u32, $bit);
writer.data
}};
}
#[macro_export]
macro_rules! nbit_str {
($name:expr) => {{
use $crate::bit::BitWriter;
let mut writer = BitWriter::new();
$name.as_bytes().iter().for_each(|s| writer.append_u8(*s));
writer.data
}};
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn open() {
open_demo("./src/tests/demotest.dem").unwrap();
}
#[test]
fn open_without_netmessage() {
Demo::parse_from_file(
"./src/tests/demotest.dem",
types::MessageDataParseMode::Parse,
)
.unwrap();
}
#[test]
fn write_read() {
let dem = open_demo("./src/tests/demotest.dem").unwrap();
let a = dem.write_to_bytes();
let _dem = open_demo_from_bytes(&a).unwrap();
}
#[test]
fn read_a_lot() {
let folder = "./src/tests/";
std::fs::read_dir(folder)
.map(|res| {
res.filter_map(|entry| entry.ok()).for_each(|entry| {
let path = entry.path();
if path.is_dir() {
return;
}
if path.extension().map(|ext| ext != "dem").unwrap_or(false) {
return;
}
assert!(
open_demo(path.as_path()).is_ok(),
"error opening {}",
path.display()
)
})
})
.unwrap_or_else(|_| assert!(false));
}
#[test]
fn read_write_read_a_lot() {
let folder = "./src/tests/";
if let Ok(read_dir_res) = std::fs::read_dir(folder) {
read_dir_res
.filter_map(|entry| entry.ok())
.for_each(|entry| {
let path = entry.path();
if path.is_dir() {
return;
}
if path.extension().map(|ext| ext != "dem").unwrap_or(false) {
return;
}
let a = open_demo(path.as_path());
assert!(a.is_ok(), "error opening {}", path.display());
let a = a.unwrap();
let a_bytes = a.write_to_bytes();
let a_again = open_demo_from_bytes(&a_bytes);
assert!(
a_again.is_ok(),
"error parse write parse {}",
path.display()
)
})
} else {
panic!("cannot read dir for read_write_read_a_lot");
}
}
}