use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq)]
pub struct Datafile {
pub header: Header,
pub game: Vec<Game>,
}
#[derive(Serialize, Deserialize, PartialEq)]
pub struct Header {
pub id: u32,
pub name: String,
pub version: String,
}
#[derive(Serialize, Deserialize, PartialEq)]
pub struct Game {
#[serde(rename = "@name")]
pub name: String,
#[serde(rename = "@id")]
pub id: String,
pub rom: Rom,
}
#[derive(Serialize, Deserialize, PartialEq)]
pub struct Rom {
#[serde(rename = "@name")]
pub name: String,
#[serde(rename = "@size")]
pub size: u32,
#[serde(rename = "@crc")]
pub crc: String,
#[serde(rename = "@md5")]
pub md5: String,
#[serde(rename = "@sha1")]
pub sha1: String,
#[serde(rename = "@sha256")]
pub sha256: String,
#[serde(rename = "@status")]
pub status: Option<String>,
}
pub fn load_from_string(xml: String) -> Result<Datafile, String> {
serde_xml_rs::from_str(&xml).map_err(|e| format!("Failed to parse XML dat file: {}", e))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_single_game() {
let xml = r#"<?xml version="1.0"?>
<datafile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://datomatic.no-intro.org/stuff https://datomatic.no-intro.org/stuff/schema_nointro_datfile_v3.xsd">
<header>
<id>1</id>
<name>Test System</name>
<version>000000</version>
</header>
<game name="Test Game" id="0001">
<rom name="Test Game.ext" size="40976" crc="393a432f" md5="f94bb9bb55f325d9af8a0fff80b9376d" sha1="33d23c2f2cfa4c9efec87f7bc1321ce3ce6c89bd" sha256="0b3d9e1f01ed1668205bab34d6c82b0e281456e137352e4f36a9b2cfa3b66dea" status="verified" header="4E 45 53 1A 02 01 01 08 00 00 00 00 02 00 00 01"/>
</game>
</datafile>
"#;
let dat = load_from_string(xml.to_string()).unwrap();
assert_eq!(dat.header.id, 1);
assert_eq!(dat.header.name, "Test System");
assert_eq!(dat.header.version, "000000");
assert_eq!(dat.game.len(), 1);
let game = &dat.game[0];
assert_eq!(game.name, "Test Game");
assert_eq!(game.id, "0001");
assert_eq!(game.rom.name, "Test Game.ext");
assert_eq!(game.rom.size, 40976);
assert_eq!(game.rom.crc, "393a432f");
assert_eq!(game.rom.md5, "f94bb9bb55f325d9af8a0fff80b9376d");
assert_eq!(game.rom.sha1, "33d23c2f2cfa4c9efec87f7bc1321ce3ce6c89bd");
assert_eq!(
game.rom.sha256,
"0b3d9e1f01ed1668205bab34d6c82b0e281456e137352e4f36a9b2cfa3b66dea"
);
}
#[test]
fn parse_two_games() {
let xml = r#"<?xml version="1.0"?>
<datafile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://datomatic.no-intro.org/stuff https://datomatic.no-intro.org/stuff/schema_nointro_datfile_v3.xsd">
<header>
<id>1</id>
<name>Test System</name>
<version>000000</version>
</header>
<game name="Test Game" id="0001">
<rom name="Test Game.ext" size="40976" crc="393a432f" md5="f94bb9bb55f325d9af8a0fff80b9376d" sha1="33d23c2f2cfa4c9efec87f7bc1321ce3ce6c89bd" sha256="0b3d9e1f01ed1668205bab34d6c82b0e281456e137352e4f36a9b2cfa3b66dea" status="verified" header="4E 45 53 1A 02 01 01 08 00 00 00 00 02 00 00 01"/>
</game>
<game name="Test Game 2" id="0002">
<rom name="Test Game 2.ext" size="262160" crc="43507232" md5="55f7030dc6173f2a0145a97f369f49f4" sha1="d3f8cfd7822c1cf634c2132009f877b44244850f" sha256="41300bc4942a8a4f9b53148b404dd5cae3dd708ebdd9b617888d290a51a83e43" status="verified" header="4E 45 53 1A 08 10 40 08 00 00 07 00 00 00 00 01"/>
</game>
</datafile>
"#;
let dat = load_from_string(xml.to_string()).unwrap();
assert_eq!(dat.header.id, 1);
assert_eq!(dat.header.name, "Test System");
assert_eq!(dat.header.version, "000000");
assert_eq!(dat.game.len(), 2);
let game1 = &dat.game[0];
assert_eq!(game1.name, "Test Game");
assert_eq!(game1.rom.name, "Test Game.ext");
let game2 = &dat.game[1];
assert_eq!(game2.name, "Test Game 2");
assert_eq!(game2.id, "0002");
assert_eq!(game2.rom.name, "Test Game 2.ext");
assert_eq!(game2.rom.size, 262160);
assert_eq!(game2.rom.crc, "43507232");
assert_eq!(game2.rom.md5, "55f7030dc6173f2a0145a97f369f49f4");
assert_eq!(game2.rom.sha1, "d3f8cfd7822c1cf634c2132009f877b44244850f");
assert_eq!(
game2.rom.sha256,
"41300bc4942a8a4f9b53148b404dd5cae3dd708ebdd9b617888d290a51a83e43"
);
}
}