mirror of
https://github.com/NinjaCheetah/rustii.git
synced 2026-03-03 03:15:28 -05:00
Implement thiserror for library errors
This commit is contained in:
@@ -3,33 +3,24 @@
|
||||
//
|
||||
// Implements content parsing and editing.
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||
use sha1::{Sha1, Digest};
|
||||
use thiserror::Error;
|
||||
use crate::title::tmd::ContentRecord;
|
||||
use crate::title::crypto;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ContentError {
|
||||
IndexNotFound,
|
||||
CIDNotFound,
|
||||
BadHash,
|
||||
#[error("requested index {index} is out of range (must not exceed {max})")]
|
||||
IndexOutOfRange { index: usize, max: usize },
|
||||
#[error("content with requested Content ID {0} could not be found")]
|
||||
CIDNotFound(u32),
|
||||
#[error("content's hash did not match the expected value (was {hash}, expected {expected})")]
|
||||
BadHash { hash: String, expected: String },
|
||||
#[error("content data is not in a valid format")]
|
||||
IO(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for ContentError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let description = match *self {
|
||||
ContentError::IndexNotFound => "The specified content index does not exist.",
|
||||
ContentError::CIDNotFound => "The specified Content ID does not exist.",
|
||||
ContentError::BadHash => "The content hash does not match the expected hash.",
|
||||
};
|
||||
f.write_str(description)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ContentError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A structure that represents the block of data containing the content of a digital Wii title.
|
||||
pub struct ContentRegion {
|
||||
@@ -43,7 +34,7 @@ pub struct ContentRegion {
|
||||
impl ContentRegion {
|
||||
/// Creates a ContentRegion instance that can be used to parse and edit content stored in a
|
||||
/// digital Wii title from the content area of a WAD and the ContentRecords from a TMD.
|
||||
pub fn from_bytes(data: &[u8], content_records: Vec<ContentRecord>) -> Result<Self, std::io::Error> {
|
||||
pub fn from_bytes(data: &[u8], content_records: Vec<ContentRecord>) -> Result<Self, ContentError> {
|
||||
let content_region_size = data.len() as u32;
|
||||
let num_contents = content_records.len() as u16;
|
||||
// Calculate the starting offsets of each content.
|
||||
@@ -112,7 +103,7 @@ impl ContentRegion {
|
||||
|
||||
/// Gets the encrypted content file from the ContentRegion at the specified index.
|
||||
pub fn get_enc_content_by_index(&self, index: usize) -> Result<Vec<u8>, ContentError> {
|
||||
let content = self.contents.get(index).ok_or(ContentError::IndexNotFound)?;
|
||||
let content = self.contents.get(index).ok_or(ContentError::IndexOutOfRange { index, max: self.content_records.len() - 1 })?;
|
||||
Ok(content.clone())
|
||||
}
|
||||
|
||||
@@ -126,7 +117,7 @@ impl ContentRegion {
|
||||
hasher.update(content_dec.clone());
|
||||
let result = hasher.finalize();
|
||||
if result[..] != self.content_records[index].content_hash {
|
||||
return Err(ContentError::BadHash);
|
||||
return Err(ContentError::BadHash { hash: hex::encode(result), expected: hex::encode(self.content_records[index].content_hash) });
|
||||
}
|
||||
Ok(content_dec)
|
||||
}
|
||||
@@ -135,10 +126,10 @@ impl ContentRegion {
|
||||
pub fn get_enc_content_by_cid(&self, cid: u32) -> Result<Vec<u8>, ContentError> {
|
||||
let index = self.content_records.iter().position(|x| x.content_id == cid);
|
||||
if let Some(index) = index {
|
||||
let content = self.get_enc_content_by_index(index).map_err(|_| ContentError::CIDNotFound)?;
|
||||
let content = self.get_enc_content_by_index(index).map_err(|_| ContentError::CIDNotFound(cid))?;
|
||||
Ok(content)
|
||||
} else {
|
||||
Err(ContentError::CIDNotFound)
|
||||
Err(ContentError::CIDNotFound(cid))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +140,7 @@ impl ContentRegion {
|
||||
let content_dec = self.get_content_by_index(index, title_key)?;
|
||||
Ok(content_dec)
|
||||
} else {
|
||||
Err(ContentError::CIDNotFound)
|
||||
Err(ContentError::CIDNotFound(cid))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +149,7 @@ impl ContentRegion {
|
||||
/// index.
|
||||
pub fn load_content(&mut self, content: &[u8], index: usize, title_key: [u8; 16]) -> Result<(), ContentError> {
|
||||
if index >= self.content_records.len() {
|
||||
return Err(ContentError::IndexNotFound);
|
||||
return Err(ContentError::IndexOutOfRange { index, max: self.content_records.len() - 1 });
|
||||
}
|
||||
// Hash the content we're trying to load to ensure it matches the hash expected in the
|
||||
// matching record.
|
||||
@@ -166,7 +157,7 @@ impl ContentRegion {
|
||||
hasher.update(content);
|
||||
let result = hasher.finalize();
|
||||
if result[..] != self.content_records[index].content_hash {
|
||||
return Err(ContentError::BadHash);
|
||||
return Err(ContentError::BadHash { hash: hex::encode(result), expected: hex::encode(self.content_records[index].content_hash) });
|
||||
}
|
||||
let content_enc = crypto::encrypt_content(content, title_key, self.content_records[index].index, self.content_records[index].content_size);
|
||||
self.contents[index] = content_enc;
|
||||
|
||||
Reference in New Issue
Block a user