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 crate::darksiders1::{gfc, unit4};
use failure::Error;
use std::io;
pub fn read(sav: &[u8], slot: i32) -> Result<gfc::Object, Error> {
validate_slot(slot)?;
let manager = create_keen_save_game_manager(sav);
let buffer = manager.read_save(slot);
gfc::DSSaveGameManager::read_save(io::Cursor::new(buffer))
}
pub fn write(sav: &mut [u8], slot: i32, data: &gfc::Object) -> Result<(), Error> {
validate_slot(slot)?;
let mut out = Vec::with_capacity(0x19200);
gfc::DSSaveGameManager::write_save(io::Cursor::new(&mut out), data)?;
let mut manager = create_keen_save_game_manager(sav);
manager.write_save(slot, &out);
Ok(())
}
fn create_keen_save_game_manager<B: AsRef<[u8]>>(
buffer: B,
) -> gfc::KeenSaveGameManager<B> {
gfc::KeenSaveGameManager::new(gfc::SaveGameManagerParams {
game_session: unit4::LocalGameSession::create(buffer),
game_name: "Darksiders Warfinitive Edition - All your save game are belong to \
us!",
save_game_version: 0x0100_0000,
})
}
fn validate_slot(slot: i32) -> Result<(), Error> {
if slot < -1 || slot > 9 {
Err(failure::err_msg("invalid slot"))
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::sav;
use failure::Error;
use std::{fs, io};
const SLOT: i32 = -1;
#[test]
fn read_empty() -> Result<(), Error> {
let sav = read_fixture("keen_savegame_0_0_empty.sav")?;
assert!(sav::read(&sav, -1).is_err());
Ok(())
}
#[test]
fn read_new_game() -> Result<(), Error> {
let sav = read_fixture("keen_savegame_0_0_new_game.sav")?;
sav::read(&sav, -1)?;
Ok(())
}
#[test]
fn round_trip_new_game() -> Result<(), Error> {
let mut sav = read_fixture("keen_savegame_0_0_new_game.sav")?;
let object1 = sav::read(&sav, SLOT)?;
sav::write(&mut sav, SLOT, &object1)?;
let object2 = sav::read(&sav, SLOT)?;
assert_eq!(format!("{:#?}", object1), format!("{:#?}", object2));
Ok(())
}
#[test]
fn validate_slot() -> Result<(), Error> {
let err = sav::read(&[], 15).unwrap_err();
assert!(format!("{}", err) == "invalid slot");
Ok(())
}
fn read_fixture(name: &str) -> io::Result<Vec<u8>> {
let root = env!("CARGO_MANIFEST_DIR");
let path = format!("{}/src/sav/fixtures/{}", root, name);
fs::read(&path)
}
}