From c340f304934836713a910bd19bd6e8e482d3110b Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Mon, 5 Dec 2016 14:51:57 -0500 Subject: [PATCH] Handle DAOX chunk --- src/lib.rs | 207 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 195 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index afb58ca..db8214a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ pub struct NrgMetadata { pub nrg_version: u8, pub chunk_offset: u64, pub cuex_chunk: Option, + pub daox_chunk: Option, } impl NrgMetadata { @@ -66,13 +67,14 @@ impl NrgMetadata { nrg_version: 0, chunk_offset: 0, cuex_chunk: None, + daox_chunk: None, } } } impl fmt::Display for NrgMetadata { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Image size: {}\n\ + try!(write!(f, "Image size: {} Bytes\n\ NRG format version: {}\n\ First chunk offset: {}", self.file_size, @@ -81,7 +83,12 @@ impl fmt::Display for NrgMetadata { )); match self.cuex_chunk { None => {}, - Some(ref chunk) => try!(write!(f, "\n\ + Some(ref chunk) => try!(write!(f, "\n\n\ + {}", chunk)), + } + match self.daox_chunk { + None => {}, + Some(ref chunk) => try!(write!(f, "\n\n\ {}", chunk)), } Ok(()) @@ -108,7 +115,7 @@ impl fmt::Display for NrgCuex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "Chunk ID: CUEX\n\ Chunk description: Cue Sheet\n\ - Chunk size: {}", self.size)); + Chunk size: {} Bytes", self.size)); if self.tracks.is_empty() { try!(write!(f, "\nNo CUEX tracks!")); } else { @@ -172,6 +179,123 @@ impl fmt::Display for NrgCuexTrack { } +#[derive(Debug)] +pub struct NrgDaox { + pub size: u32, + pub size2: u32, + pub upc: String, + pub padding: u8, + pub toc_type: u16, + pub first_track: u8, + pub last_track: u8, + pub tracks: Vec, +} + +impl NrgDaox { + fn new() -> NrgDaox { + NrgDaox { + size: 0, + size2: 0, + upc: String::new(), + padding: 0, + toc_type: 0, + first_track: 0, + last_track: 0, + tracks: Vec::new(), + } + } +} + +impl fmt::Display for NrgDaox { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(writeln!(f, "Chunk ID: DAOX\n\ + Chunk description: DAO (Disc At Once) Information\n\ + Chunk size: {} Bytes\n\ + Chunk size 2: {}\n\ + UPC: \"{}\"", + self.size, + self.size2, + self.upc)); + + if self.padding != 0 { + try!(writeln!(f, "Padding: {} (Warning: should be 0!)", + self.padding)); + } + + try!(write!(f, "TOC type: 0x{:04X}\n\ + First track in the session: {}\n\ + Last track in the session: {}", + self.toc_type, + self.first_track, + self.last_track)); + + if self.tracks.is_empty() { + try!(write!(f, "\nNo DAOX tracks!")); + } else { + let mut i = 1; + for track in &self.tracks { + try!(write!(f, "\n\ + Track {:02}:\n\ + {}", i, track)); + i += 1; + } + } + + Ok(()) + } +} + + +#[derive(Debug)] +pub struct NrgDaoxTrack { + isrc: String, + sector_size: u16, + data_mode: u16, + unknown: u16, + index0: u64, + index1: u64, + track_end: u64, +} + +impl NrgDaoxTrack { + fn new() -> NrgDaoxTrack { + NrgDaoxTrack { + isrc: String::new(), + sector_size: 0, + data_mode: 0, + unknown: 0, + index0: 0, + index1: 0, + track_end: 0, + } + } +} + +impl fmt::Display for NrgDaoxTrack { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(writeln!(f, "\tISRC: \"{}\"\n\ + \tSector size in the image file: {} Bytes\n\ + \tMode of the data in the image file: 0x{:04X}", + self.isrc, + self.sector_size, + self.data_mode)); + + if self.unknown != 0x0001 { + try!(writeln!(f, "\tUnknown field: 0x{:04X} \ + (Warning: should be 0x0001!)", + self.unknown)); + } + + write!(f, "\tIndex0 (Pre-gap): {} Bytes\n\ + \tIndex1 (Start of track): {} Bytes\n\ + \tEnd of track + 1: {} Bytes", + self.index0, + self.index1, + self.track_end) + } +} + + pub fn parse_nrg_metadata(img_name: String) -> Result { let mut nm = NrgMetadata::new(); @@ -200,7 +324,7 @@ pub fn parse_nrg_metadata(img_name: String) -> Result { /// Determines the NRG format of an open NRG image `fd` of file `file_size`. -/// +/// /// The offset is left after the main chunk ID, therefore the calling function /// can read the first data chunk's offset (32 bits for NRG v1 or 64 bits for /// NRG v2) directly without seeking. @@ -240,8 +364,7 @@ fn read_nrg_chunks(fd: &mut File, nm: &mut NrgMetadata) -> Result match chunk_id.as_ref() { "END!" => break, "CUEX" => { nm.cuex_chunk = Some(try!(read_nrg_cuex(fd))); }, - "DAOX" => { try!(skip_unhandled_chunk(fd, &chunk_id)); }, - //"DAOX" => { try!(read_nrg_daox(fd)); }, + "DAOX" => { nm.daox_chunk = Some(try!(read_nrg_daox(fd))); }, "CDTX" => { try!(skip_unhandled_chunk(fd, &chunk_id)); }, "ETN2" => { try!(skip_unhandled_chunk(fd, &chunk_id)); }, "SINF" => { try!(skip_unhandled_chunk(fd, &chunk_id)); }, @@ -299,7 +422,6 @@ fn read_u32(fd: &mut File) -> Result { /// Reads a 16-bit unsigned integer from `fd`. -#[cfg(dead_code)] fn read_u16(fd: &mut File) -> Result { let mut buf = [0u8; 2]; try!(fd.read_exact(&mut buf)); @@ -332,8 +454,8 @@ fn skip_unhandled_chunk(fd: &mut File, chunk_id: &str) -> Result<(), NrgError> { /// /// The CUEX is constituted of the following data: /// -/// - 4 B: Chunk size (bytes): size to be read *after* this (should be a -/// multiple of 8) +/// - 4 B: Chunk size (in bytes): size to be read *after* this chunk size +/// (should be a multiple of 8) /// /// - one or more pairs of 8-byte blocks composed of: /// + 1 B: Mode (values found: 0x01 for audio; 0x21 for non @@ -373,9 +495,70 @@ fn read_nrg_cuex_track(fd: &mut File) -> Result { } -#[cfg(dead_code)] -fn read_nrg_daox(fd: &mut File) -> Result { - unimplemented!(); +/// Reads the NRG Disc-At-Once Information chunk (DAOX). +/// +/// The DAOX is constituted of the following data: +/// +/// - 4 B: Chunk size (in bytes) +/// - 4 B: Chunk size again, sometimes little endian +/// - 13 B: UPC (text) or null bytes +/// - 1 B: Unknown (padding?), always 0 +/// - 2 B: TOC type +/// - 1 B: First track in the session +/// - 1 B: Last track in the session +/// +/// Followed by one or more groups of 42-byte blocks composed of: +/// - 12 B: ISRC (text) or null bytes +/// - 2 B: Sector size in the image file (bytes) +/// - 2 B: Mode of the data in the image file +/// - 2 B: Unknown (should always be 0x0001) +/// - 8 B: Index0 (Pre-gap) (bytes) +/// - 8 B: Index1 (Start of track) (bytes) +/// - 8 B: End of track + 1 (bytes) +fn read_nrg_daox(fd: &mut File) -> Result { + let mut chunk = NrgDaox::new(); + chunk.size = try!(read_u32(fd)); + let mut bytes_read = 0; + + chunk.size2 = try!(read_u32(fd)); + bytes_read += 4; // 32 bits + + chunk.upc = try!(read_sized_string(fd, 13)); + bytes_read += 13; + + chunk.padding = try!(read_u8(fd)); + bytes_read += 1; + + chunk.toc_type = try!(read_u16(fd)); + bytes_read += 2; + + chunk.first_track = try!(read_u8(fd)); + chunk.last_track = try!(read_u8(fd)); + bytes_read += 2; + + // Read all the 42-byte track info + while bytes_read < chunk.size { + chunk.tracks.push(try!(read_nrg_daox_track(fd))); + bytes_read += 42; + } + + assert_eq!(bytes_read, chunk.size); + + Ok(chunk) +} + + +/// Reads a track from the NRG DAO Information. +fn read_nrg_daox_track(fd: &mut File) -> Result { + let mut track = NrgDaoxTrack::new(); + track.isrc = try!(read_sized_string(fd, 12)); + track.sector_size = try!(read_u16(fd)); + track.data_mode = try!(read_u16(fd)); + track.unknown = try!(read_u16(fd)); + track.index0 = try!(read_u64(fd)); + track.index1 = try!(read_u64(fd)); + track.track_end = try!(read_u64(fd)); + Ok(track) }