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
85
86
87
88
89
90
91
92
use std::io::{Read, Seek, Write, Error, ErrorKind, Result};
mod read;
mod write;
pub type CPXVersion = [u8; 4];
#[derive(Debug, Clone)]
pub(crate) struct CampaignHeader {
pub(crate) version: CPXVersion,
pub(crate) name: String,
pub(crate) num_scenarios: usize,
}
impl CampaignHeader {
pub(crate) fn new(name: &str) -> Self {
Self {
version: *b"1.00",
name: name.to_string(),
num_scenarios: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct ScenarioMeta {
pub size: usize,
pub(crate) offset: usize,
pub name: String,
pub filename: String,
}
pub use read::Campaign;
pub use write::CampaignWriter;
impl<R> Campaign<R>
where R: Read + Seek
{
pub fn write_to<W: Write>(&mut self, output: &mut W) -> Result<()> {
let mut writer = CampaignWriter::new(self.name(), output);
for i in 0..self.len() {
let bytes = self.by_index_raw(i)?;
match (self.get_name(i), self.get_filename(i)) {
(Some(name), Some(filename)) => {
writer.add_raw(name, filename, bytes);
},
_ => return Err(Error::new(ErrorKind::Other, "missing data for scenario"))
}
}
let _output = writer.flush()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use std::io::Cursor;
#[test]
fn rebuild_cpx() {
let instream = File::open("./test/campaigns/Armies at War A Combat Showcase.cpn").unwrap();
let mut outstream = vec![];
let mut incpx = Campaign::from(instream).unwrap();
incpx.write_to(&mut outstream).unwrap();
let mut written_cpx = Campaign::from(Cursor::new(outstream)).unwrap();
assert_eq!(written_cpx.name(), incpx.name());
assert_eq!(written_cpx.len(), incpx.len());
assert_eq!(written_cpx.by_index_raw(0).unwrap(), incpx.by_index_raw(0).unwrap());
}
}