use crate::error::Error;
use crate::ncsd::NCCHPartitionEntry;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use byteorder::LittleEndian;
use byteorder::ReadBytesExt;
#[derive(Debug)]
pub struct NCCH {
pub signature: [u8; 0x100],
pub magic: [u8; 4],
pub size: u32,
pub partition_title_id: u64,
pub maker_code: u16,
pub version: u16,
pub sha256_check: u32,
pub program_id: u64,
pub logo_sha256: Option<[u8; 0x20]>,
pub product_code: [u8; 16],
pub extended_header_sha256: [u8; 0x20],
pub extended_header_size: u32,
pub flags: u64,
pub plain_region_offset: u32, pub plain_region_size: u32, pub logo_region_offset: Option<u32>, pub logo_region_size: Option<u32>, pub exefs_offset: u32, pub exefs_size: u32, pub exefs_hash_region_size: u32, pub romfs_offset: u32, pub romfs_size: u32, pub romfs_hash_region_size: u32,
pub exefs_sha256: [u8; 0x20],
pub romfs_sha256: [u8; 0x20],
pub partition_entry: NCCHPartitionEntry,
}
pub trait NCCHRead {
fn read_ncch(&mut self, partition: NCCHPartitionEntry) -> Result<Option<NCCH>, Error>;
}
impl<T: Read + Seek> NCCHRead for T {
fn read_ncch(&mut self, partition: NCCHPartitionEntry) -> Result<Option<NCCH>, Error> {
if partition.size == 0 {
return Ok(None);
}
let offset = partition.offset;
let offset = u64::from(offset) * 0x200u64;
self.seek(SeekFrom::Start(offset))?;
let mut signature = [0u8; 0x100];
self.read_exact(&mut signature)?;
let mut magic = [0u8; 4];
self.read_exact(&mut magic)?;
let size = self.read_u32::<LittleEndian>()?;
let partition_title_id = self.read_u64::<LittleEndian>()?;
let maker_code = self.read_u16::<LittleEndian>()?;
let version = self.read_u16::<LittleEndian>()?;
let sha256_check = self.read_u32::<LittleEndian>()?;
let program_id = self.read_u64::<LittleEndian>()?;
self.seek(SeekFrom::Current(0x10))?;
let mut logo_sha256 = [0u8; 0x20];
self.read_exact(&mut logo_sha256)?;
let mut product_code = [0u8; 0x10];
self.read_exact(&mut product_code)?;
let mut extended_header_sha256 = [0u8; 0x20];
self.read_exact(&mut extended_header_sha256)?;
let extended_header_size = self.read_u32::<LittleEndian>()?;
self.seek(SeekFrom::Current(0x4))?;
let flags = self.read_u64::<LittleEndian>()?;
let plain_region_offset = self.read_u32::<LittleEndian>()?;
let plain_region_size = self.read_u32::<LittleEndian>()?;
let logo_region_offset = self.read_u32::<LittleEndian>()?;
let logo_region_size = self.read_u32::<LittleEndian>()?;
let (logo_sha256, logo_region_offset, logo_region_size) = if logo_region_size == 0 {
(None, None, None)
} else {
(
Some(logo_sha256),
Some(logo_region_offset),
Some(logo_region_size),
)
};
let exefs_offset = self.read_u32::<LittleEndian>()?;
let exefs_size = self.read_u32::<LittleEndian>()?;
let exefs_hash_region_size = self.read_u32::<LittleEndian>()?;
self.seek(SeekFrom::Current(0x4))?;
let romfs_offset = self.read_u32::<LittleEndian>()?;
let romfs_size = self.read_u32::<LittleEndian>()?;
let romfs_hash_region_size = self.read_u32::<LittleEndian>()?;
self.seek(SeekFrom::Current(0x4))?;
let mut exefs_sha256 = [0u8; 0x20];
self.read_exact(&mut exefs_sha256)?;
let mut romfs_sha256 = [0u8; 0x20];
self.read_exact(&mut romfs_sha256)?;
Ok(Some(NCCH {
signature,
magic,
size,
partition_title_id,
maker_code,
version,
sha256_check,
program_id,
logo_sha256,
product_code,
extended_header_sha256,
extended_header_size,
flags,
plain_region_offset,
plain_region_size,
logo_region_offset,
logo_region_size,
exefs_offset,
exefs_size,
exefs_hash_region_size,
romfs_offset,
romfs_size,
romfs_hash_region_size,
exefs_sha256,
romfs_sha256,
partition_entry: partition,
}))
}
}