1use std::fs;
2
3#[cfg(feature = "lzma")]
4use std::io::Read;
5
6use super::error::ReplayError;
7use super::mode::Gamemode;
8use super::read::{read_byte, read_int, read_string};
9
10#[derive(Debug)]
11pub struct Replay {
12 pub gamemode: Gamemode,
13 pub version: u32,
14 pub beatmap_md5: Option<String>,
15 pub username: Option<String>,
16 pub replay_md5: Option<String>,
17 pub n300: u16,
18 pub n100: u16,
19 pub n50: u16,
20 pub geki: u16,
21 pub katu: u16,
22 pub misses: u16,
23 pub score: u32,
24 pub combo: u16,
25 pub perfect: u8,
26 pub mods: u32,
27 pub life_bar: Option<String>,
28 pub time_stamp: usize,
29 pub replay_length: u32,
30 pub replay_data: Vec<u8>,
31 pub score_id: usize,
32 pub mod_info: Option<f64>,
33}
34
35impl Replay {
36 pub fn read(path: &str) -> Result<Self, ReplayError> {
37 let mut content = fs::read(path)?;
38 let mut p = 0;
39
40 let mut _replay_length = 0;
41
42 Ok(Self {
43 gamemode : Gamemode::from(read_byte(&mut p, &content)),
44 version : read_int!(u32, &mut p, &content),
45 beatmap_md5 : read_string(&mut p, &mut content).ok(),
46 username : read_string(&mut p, &mut content).ok(),
47 replay_md5 : read_string(&mut p, &mut content).ok(),
48 n300 : read_int!(u16, &mut p, &content),
49 n100 : read_int!(u16, &mut p, &content),
50 n50 : read_int!(u16, &mut p, &content),
51 geki : read_int!(u16, &mut p, &content),
52 katu : read_int!(u16, &mut p, &content),
53 misses : read_int!(u16, &mut p, &content),
54 score : read_int!(u32, &mut p, &content),
55 combo : read_int!(u16, &mut p, &content),
56 perfect : read_byte(&mut p, &content),
57 mods : read_int!(u32, &mut p, &content),
58 life_bar : read_string(&mut p, &mut content).ok(),
59 time_stamp : read_int!(usize, &mut p, &content),
60 replay_length: {
61 _replay_length = read_int!(u32, &mut p, &content);
62 _replay_length
63 },
64 replay_data: {
65 let start = *&mut p;
66 *&mut p = _replay_length as usize;
67
68 content[start..(_replay_length as usize)].to_vec()
69 },
70 score_id: read_int!(usize, &mut p, &content),
71 mod_info: {
72 if *&mut p != content.len() {
73 Some(read_int!(usize, &mut p, &content) as f64)
74 } else {
75 None
76 }
77 }
78 })
79 }
80
81 #[cfg(feature = "lzma")]
82 pub fn parse_lzma(&mut self) -> Result<String, ReplayError> {
83 let mut reader = lzma::Reader::from(&*self.replay_data)?;
84 let mut stream = String::with_capacity(4096);
85
86 reader.read_to_string(&mut stream)?;
87 Ok(stream)
88 }
89}