DirEntry now implements Bytes.

This commit is contained in:
Filipe Rodrigues 2021-06-04 19:06:35 +01:00
parent cd31c9d8ca
commit 982393bd64
3 changed files with 44 additions and 27 deletions

View File

@ -11,6 +11,7 @@ pub use error::DeserializeBytesError;
use super::ptr::{DirPtr, FilePtr};
use byteorder::{ByteOrder, LittleEndian};
use chrono::NaiveDateTime;
use dcb_bytes::Bytes;
use dcb_util::{ascii_str_arr::AsciiChar, AsciiStrArr};
use std::convert::TryInto;
@ -78,9 +79,12 @@ pub struct DirEntry {
pub kind: DirEntryKind,
}
impl DirEntry {
/// Reads a directory entry reader from bytes
pub fn deserialize_bytes(bytes: &[u8; 0x20]) -> Result<Option<Self>, DeserializeBytesError> {
impl Bytes for DirEntry {
type ByteArray = [u8; 0x20];
type DeserializeError = DeserializeBytesError;
type SerializeError = !;
fn deserialize_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::DeserializeError> {
let bytes = dcb_util::array_split!(bytes,
kind : 0x1,
extension : [0x3],
@ -90,19 +94,6 @@ impl DirEntry {
name : [0x10],
);
// Special case some files which cause problems and return early, as if we encountered the final entry.
#[allow(clippy::single_match)] // We might add more matches in the future
match bytes.name {
[0x83, 0x52, 0x83, 0x53, 0x81, 0x5B, 0x20, 0x81, 0x60, 0x20, 0x43, 0x41, 0x52, 0x44, 0x32, 0x00] => {
log::warn!(
"Ignoring special directory entry: {:?}",
String::from_utf8_lossy(bytes.name)
);
return Ok(None);
},
_ => (),
}
// Then get the name and extension
let mut name = AsciiStrArr::from_bytes(bytes.name).map_err(DeserializeBytesError::Name)?;
name.trim_end(AsciiChar::Null);
@ -116,7 +107,6 @@ impl DirEntry {
// Check kind
let kind = match bytes.kind {
0x0 => return Ok(None),
0x1 => DirEntryKind::File {
extension,
ptr: FilePtr { sector_pos, size },
@ -131,11 +121,10 @@ impl DirEntry {
&kind => return Err(DeserializeBytesError::InvalidKind(kind)),
};
Ok(Some(Self { name, date, kind }))
Ok(Self { name, date, kind })
}
/// Writes this entry to bytes.
pub fn serialize_bytes(&self, bytes: &mut [u8; 0x20]) {
fn serialize_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::SerializeError> {
let bytes = dcb_util::array_split_mut!(bytes,
kind : 0x1,
extension : [0x3],
@ -174,5 +163,7 @@ impl DirEntry {
.try_into()
.expect("Seconds didn't fit into date");
LittleEndian::write_u32(bytes.date, date);
Ok(())
}
}

View File

@ -1,6 +1,15 @@
#![doc(include = "lib.md")]
// Features
#![feature(external_doc, seek_stream_len, try_blocks, associated_type_bounds)]
#![feature(
external_doc,
seek_stream_len,
try_blocks,
associated_type_bounds,
never_type,
unwrap_infallible,
format_args_capture,
str_internals
)]
// Lints
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]
// We'll disable the ones we don't need

View File

@ -12,6 +12,8 @@ pub use error::{
use super::DirEntry;
use crate::DirEntryKind;
use ascii::AsciiStr;
use core::str::lossy::Utf8Lossy;
use dcb_bytes::Bytes;
use dcb_util::IoCursor;
use std::io::{self, SeekFrom};
@ -93,11 +95,26 @@ impl DirPtr {
let iter = std::iter::from_fn(move || {
let entry: Result<_, _> = try {
// Read the bytes
let mut entry_bytes = [0; 0x20];
reader.read_exact(&mut entry_bytes).map_err(ReadEntryError::ReadEntry)?;
let mut bytes = [0; 0x20];
reader.read_exact(&mut bytes).map_err(ReadEntryError::ReadEntry)?;
// And parse it
DirEntry::deserialize_bytes(&entry_bytes).map_err(ReadEntryError::ParseEntry)?
// If all bytes are null, we're finished
if bytes == [0; 0x20] {
return None;
}
// Special case some entries which cause problems
#[allow(clippy::single_match)] // We might add more matches in the future
match &bytes {
b"\x01CDD\xd5/\x00\x00\xf0?\x01\x00\xe6u\xad:\x83R\x83S\x81[ \x81` CARD2\x00" => {
log::warn!("Ignoring special directory entry: {:?}", Utf8Lossy::from_bytes(&bytes));
return None;
},
_ => (),
}
// Else parse it
Some(DirEntry::deserialize_bytes(&bytes).map_err(ReadEntryError::ParseEntry)?)
};
entry.transpose()
@ -150,7 +167,7 @@ impl DirPtr {
for entry in entries {
// Put the entry into bytes
let mut entry_bytes = [0; 0x20];
entry.serialize_bytes(&mut entry_bytes);
entry.serialize_bytes(&mut entry_bytes).into_ok();
// Then write it
writer.write_all(&entry_bytes).map_err(WriteEntriesError::WriteEntry)?;
@ -191,7 +208,7 @@ impl DirEntryPtr {
// Then write the entry
let mut entry_bytes = [0; 0x20];
entry.serialize_bytes(&mut entry_bytes);
entry.serialize_bytes(&mut entry_bytes).into_ok();
// Then write it
writer.write_all(&entry_bytes).map_err(WriteEntryError::WriteEntry)