mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-09 11:48:16 +00:00
Added a write_maybe_null_ascii_string to game::util.
Finished `Bytes` implementation for `game::deck::table::Table`.
This commit is contained in:
@@ -18,6 +18,9 @@ pub struct Deck {
|
||||
|
||||
/// All of the card ids that make up this deck
|
||||
pub cards: [u16; 30],
|
||||
|
||||
// Unknown
|
||||
unknown: [u8; 0xc],
|
||||
}
|
||||
|
||||
/// Error type for [`Bytes::from_bytes`]
|
||||
@@ -37,11 +40,11 @@ pub enum FromBytesError {
|
||||
pub enum ToBytesError {
|
||||
/// Unable to write the deck name
|
||||
#[display(fmt = "Unable to write the deck name")]
|
||||
Name(#[error(source)] util::WriteNullAsciiStringError),
|
||||
Name(#[error(source)] util::WriteMaybeNullAsciiStringError),
|
||||
|
||||
/// Unable to write the deck owner
|
||||
#[display(fmt = "Unable to write the deck owner")]
|
||||
Owner(#[error(source)] util::WriteNullAsciiStringError),
|
||||
Owner(#[error(source)] util::WriteMaybeNullAsciiStringError),
|
||||
}
|
||||
|
||||
impl Bytes for Deck {
|
||||
@@ -51,12 +54,11 @@ impl Bytes for Deck {
|
||||
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
// Split the bytes
|
||||
let bytes = util::array_split!(&bytes,
|
||||
deck : [0x3c],
|
||||
name : [0x13],
|
||||
owner: [0x13],
|
||||
|
||||
_unknown: [0xc],
|
||||
let bytes = util::array_split!(bytes,
|
||||
deck : [0x3c],
|
||||
name : [0x13],
|
||||
owner : [0x13],
|
||||
unknown: [0xc],
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
@@ -77,10 +79,33 @@ impl Bytes for Deck {
|
||||
|
||||
cards_buf
|
||||
},
|
||||
|
||||
unknown: *bytes.unknown,
|
||||
})
|
||||
}
|
||||
|
||||
fn to_bytes(&self, _bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
todo!();
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
// Split the bytes
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
deck : [0x3c],
|
||||
name : [0x13],
|
||||
owner : [0x13],
|
||||
unknown: [0xc],
|
||||
);
|
||||
|
||||
// Nanme / Owner
|
||||
util::write_maybe_null_ascii_string(&self.name, bytes.name).map_err(ToBytesError::Name)?;
|
||||
util::write_maybe_null_ascii_string(&self.owner, bytes.owner).map_err(ToBytesError::Owner)?;
|
||||
|
||||
// Deck
|
||||
for (card_id, card) in self.cards.iter().enumerate() {
|
||||
LittleEndian::write_u16(&mut bytes.deck[0x0 + card_id * 2..0x2 + card_id * 2], *card);
|
||||
}
|
||||
|
||||
// Unknown
|
||||
*bytes.unknown = self.unknown;
|
||||
|
||||
// And return Ok
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,19 +47,48 @@ pub enum DeserializeError {
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
/// Could not parse a deck entry
|
||||
#[display(fmt = "Unable to parse deck entry with id {}", "id")]
|
||||
ParseDeck {
|
||||
/// Could not deserialize a deck entry
|
||||
#[display(fmt = "Unable to serialize deck entry with id {}", "id")]
|
||||
DeserializeDeck {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: deck::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
/// Error type for [`Table::serialize`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum SerializeError {
|
||||
/// Unable to seek game file
|
||||
#[display(fmt = "Unable to seek game file to card table")]
|
||||
Seek(#[error(source)] std::io::Error),
|
||||
|
||||
/// Unable to read table header
|
||||
#[display(fmt = "Unable to read table header")]
|
||||
WriteHeader(#[error(source)] std::io::Error),
|
||||
|
||||
/// Could not deserialize a deck entry
|
||||
#[display(fmt = "Unable to deserialize deck entry with id {}", "id")]
|
||||
SerializeDeck {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: deck::ToBytesError,
|
||||
},
|
||||
|
||||
/// Could not write a deck entry
|
||||
#[display(fmt = "Unable to read deck entry with id {}", "id")]
|
||||
WriteDeck {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl Table {
|
||||
pub fn deserialize<F>(game_file: &mut GameFile<F>) -> Result<Self, DeserializeError>
|
||||
pub fn deserialize<R>(game_file: &mut GameFile<R>) -> Result<Self, DeserializeError>
|
||||
where
|
||||
F: Read + Write + Seek,
|
||||
R: Read + Write + Seek,
|
||||
{
|
||||
// The deck array
|
||||
let mut decks = vec![];
|
||||
@@ -76,7 +105,7 @@ impl Table {
|
||||
game_file.read_exact(&mut bytes).map_err(|err| DeserializeError::ReadDeck { id, err })?;
|
||||
|
||||
// And try to serialize the deck
|
||||
let deck = Deck::from_bytes(&bytes).map_err(|err| DeserializeError::ParseDeck { id, err })?;
|
||||
let deck = Deck::from_bytes(&bytes).map_err(|err| DeserializeError::DeserializeDeck { id, err })?;
|
||||
|
||||
// And add it
|
||||
decks.push(deck);
|
||||
@@ -85,4 +114,27 @@ impl Table {
|
||||
// And return the table
|
||||
Ok(Self { decks })
|
||||
}
|
||||
|
||||
pub fn serialize<R>(&self, game_file: &mut GameFile<R>) -> Result<(), SerializeError>
|
||||
where
|
||||
R: Read + Write + Seek,
|
||||
{
|
||||
// Seek to the beginning of the deck table
|
||||
game_file
|
||||
.seek(std::io::SeekFrom::Start(u64::from(Self::DECK_TABLE_START_ADDRESS)))
|
||||
.map_err(SerializeError::Seek)?;
|
||||
|
||||
// Then get each deck
|
||||
for (id, deck) in self.decks.iter().enumerate() {
|
||||
// Parse each deck into bytes
|
||||
let mut bytes = [0; 0x6e];
|
||||
deck.to_bytes(&mut bytes).map_err(|err| SerializeError::SerializeDeck { id, err })?;
|
||||
|
||||
// And write them to file
|
||||
game_file.write(&bytes).map_err(|err| SerializeError::WriteDeck { id, err })?;
|
||||
}
|
||||
|
||||
// And return Ok
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,3 +183,35 @@ pub fn write_null_ascii_string<'a>(input: &ascii::AsciiStr, buf: &'a mut [u8]) -
|
||||
// And return Ok with the buffer
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Error type for [`write_maybe_null_ascii_string`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum WriteMaybeNullAsciiStringError {
|
||||
/// The input string was too large
|
||||
#[display(fmt = "Input string was too large for buffer. ({} / {})", "input_len", "buffer_len")]
|
||||
TooLarge { input_len: usize, buffer_len: usize },
|
||||
}
|
||||
|
||||
/// Writes a possibly null-terminated ascii string to a buffer and returns it
|
||||
pub fn write_maybe_null_ascii_string<'a>(input: &ascii::AsciiStr, buf: &'a mut [u8]) -> Result<&'a mut [u8], WriteMaybeNullAsciiStringError> {
|
||||
// If the input string doesn't fit into the buffer, return Err
|
||||
if input.len() > buf.len() {
|
||||
return Err(WriteMaybeNullAsciiStringError::TooLarge {
|
||||
input_len: input.len(),
|
||||
buffer_len: buf.len(),
|
||||
});
|
||||
}
|
||||
|
||||
// Copy everything over to the slice
|
||||
// Note: We leave all other bytes as they are, no need to set them to 0
|
||||
buf[0..input.len()].copy_from_slice(input.as_bytes());
|
||||
|
||||
// If there's a character left, write it to null
|
||||
if let Some(null_byte) = buf.get_mut(input.len()) {
|
||||
*null_byte = 0;
|
||||
}
|
||||
|
||||
// And return Ok with the buffer
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user