1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use jomini::{BinaryDeserializer, FailedResolveStrategy, TextDeserializer, TextTape};
use crate::{Hoi4Error, flavor::Hoi4Flavor, models::Hoi4Save, tokens::TokenLookup};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Encoding {
Binary,
Plaintext,
}
#[derive(Debug, Clone)]
pub struct Hoi4ExtractorBuilder {
on_failed_resolve: FailedResolveStrategy,
}
impl Default for Hoi4ExtractorBuilder {
fn default() -> Self {
Hoi4ExtractorBuilder::new()
}
}
impl Hoi4ExtractorBuilder {
pub fn new() -> Self {
Hoi4ExtractorBuilder {
on_failed_resolve: FailedResolveStrategy::Ignore,
}
}
pub fn with_on_failed_resolve(mut self, strategy: FailedResolveStrategy) -> Self {
self.on_failed_resolve = strategy;
self
}
pub fn extract_save(&self, data: &[u8]) -> Result<(Hoi4Save, Encoding), Hoi4Error> {
self.extract_save_as(data)
}
fn extract_save_as(&self, data: &[u8]) -> Result<(Hoi4Save, Encoding), Hoi4Error> {
let text_header = b"HOI4txt";
let binary_header = b"HOI4bin";
match data.get(..text_header.len()) {
Some(x) if x == text_header => {
let save_data = &data[text_header.len()..];
let tape = TextTape::from_slice(save_data)?;
let save = TextDeserializer::from_utf8_tape(&tape)?;
Ok((save, Encoding::Plaintext))
},
Some(x) if x == binary_header => {
let save_data = &data[binary_header.len()..];
let save = BinaryDeserializer::builder_flavor(Hoi4Flavor).from_slice(save_data, &TokenLookup)?;
Ok((save, Encoding::Binary))
}
_ => {
return Err(Hoi4Error::new(crate::Hoi4ErrorKind::UnknownHeader))
}
}
}
}
#[derive(Debug, Clone)]
pub struct Hoi4Extractor {}
impl Hoi4Extractor {
pub fn builder() -> Hoi4ExtractorBuilder {
Hoi4ExtractorBuilder::new()
}
pub fn extract_save(&self, data: &[u8]) -> Result<(Hoi4Save, Encoding), Hoi4Error> {
Self::builder().extract_save(data)
}
}