parent
8652b455be
commit
1a029d44a4
@ -0,0 +1,84 @@
|
||||
use std::fmt;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NrgCuex {
|
||||
pub size: u32,
|
||||
pub tracks: Vec<NrgCuexTrack>,
|
||||
}
|
||||
|
||||
impl NrgCuex {
|
||||
pub fn new() -> NrgCuex {
|
||||
NrgCuex {
|
||||
size: 0,
|
||||
tracks: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: {} Bytes", self.size));
|
||||
if self.tracks.is_empty() {
|
||||
try!(write!(f, "\nNo CUEX tracks!"));
|
||||
} else {
|
||||
for track in &self.tracks {
|
||||
try!(write!(f, "\n\
|
||||
Track:\n\
|
||||
{}", track));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NrgCuexTrack {
|
||||
pub mode: u8,
|
||||
pub track_number: u8,
|
||||
pub index_number: u8,
|
||||
pub padding: u8,
|
||||
pub position_sectors: i32,
|
||||
}
|
||||
|
||||
impl NrgCuexTrack {
|
||||
pub fn new() -> NrgCuexTrack {
|
||||
NrgCuexTrack {
|
||||
mode: 0,
|
||||
track_number: 0,
|
||||
index_number: 0,
|
||||
padding: 0,
|
||||
position_sectors: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NrgCuexTrack {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(writeln!(f, "\tMode: 0x{:02X}", self.mode));
|
||||
|
||||
try!(write!(f, "\tTrack number: "));
|
||||
if self.track_number == 0 {
|
||||
try!(writeln!(f, "0 (lead-in area)"));
|
||||
} else if self.track_number == 0xAA {
|
||||
try!(writeln!(f, "0xAA (lead-out area)"));
|
||||
} else {
|
||||
try!(writeln!(f, "{}", self.track_number));
|
||||
}
|
||||
|
||||
try!(writeln!(f, "\tIndex number: {}", self.index_number));
|
||||
|
||||
if self.padding != 0 {
|
||||
try!(writeln!(f, "\tPadding: {} (Warning: should be 0!)",
|
||||
self.padding));
|
||||
}
|
||||
|
||||
// Audio CDs are played at a 75 sectors per second rate:
|
||||
let position_seconds: f64 = (self.position_sectors as f64) / 75.0;
|
||||
write!(f, "\tPosition: {} sectors ({:.2} seconds)",
|
||||
self.position_sectors, position_seconds)
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
use std::fmt;
|
||||
|
||||
|
||||
#[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<NrgDaoxTrack>,
|
||||
}
|
||||
|
||||
impl NrgDaox {
|
||||
pub 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 {
|
||||
pub isrc: String,
|
||||
pub sector_size: u16,
|
||||
pub data_mode: u16,
|
||||
pub unknown: u16,
|
||||
pub index0: u64,
|
||||
pub index1: u64,
|
||||
pub track_end: u64,
|
||||
}
|
||||
|
||||
impl NrgDaoxTrack {
|
||||
pub 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)
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NrgError {
|
||||
Io(io::Error),
|
||||
NrgFormat,
|
||||
NrgFormatV1,
|
||||
NrgChunkId,
|
||||
}
|
||||
|
||||
impl fmt::Display for NrgError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
NrgError::Io(ref err) => err.fmt(f),
|
||||
NrgError::NrgFormat => write!(f, "NRG format unknown."),
|
||||
NrgError::NrgFormatV1 => write!(f, "NRG v1 format is not handled."),
|
||||
NrgError::NrgChunkId => write!(f, "NRG chunk ID unknown."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for NrgError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
NrgError::Io(ref err) => err.description(),
|
||||
NrgError::NrgFormat => "NRG format",
|
||||
NrgError::NrgFormatV1 => "NRG format v1",
|
||||
NrgError::NrgChunkId => "NRG chunk ID",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&Error> {
|
||||
match *self {
|
||||
NrgError::Io(ref err) => Some(err),
|
||||
NrgError::NrgFormat => None,
|
||||
NrgError::NrgFormatV1 => None,
|
||||
NrgError::NrgChunkId => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for NrgError {
|
||||
fn from(err: io::Error) -> NrgError {
|
||||
NrgError::Io(err)
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
use std::fmt;
|
||||
|
||||
use cuex::NrgCuex;
|
||||
use daox::NrgDaox;
|
||||
use sinf::NrgSinf;
|
||||
use mtyp::NrgMtyp;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NrgMetadata {
|
||||
pub file_size: u64,
|
||||
pub nrg_version: u8,
|
||||
pub chunk_offset: u64,
|
||||
pub cuex_chunk: Option<NrgCuex>,
|
||||
pub daox_chunk: Option<NrgDaox>,
|
||||
pub sinf_chunk: Option<NrgSinf>,
|
||||
pub mtyp_chunk: Option<NrgMtyp>,
|
||||
}
|
||||
|
||||
impl NrgMetadata {
|
||||
pub fn new() -> NrgMetadata {
|
||||
NrgMetadata {
|
||||
file_size: 0,
|
||||
nrg_version: 0,
|
||||
chunk_offset: 0,
|
||||
cuex_chunk: None,
|
||||
daox_chunk: None,
|
||||
sinf_chunk: None,
|
||||
mtyp_chunk: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NrgMetadata {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "Image size: {} Bytes\n\
|
||||
NRG format version: {}\n\
|
||||
First chunk offset: {}",
|
||||
self.file_size,
|
||||
self.nrg_version,
|
||||
self.chunk_offset,
|
||||
));
|
||||
match self.cuex_chunk {
|
||||
None => {},
|
||||
Some(ref chunk) => try!(write!(f, "\n\n\
|
||||
{}", chunk)),
|
||||
}
|
||||
match self.daox_chunk {
|
||||
None => {},
|
||||
Some(ref chunk) => try!(write!(f, "\n\n\
|
||||
{}", chunk)),
|
||||
}
|
||||
match self.sinf_chunk {
|
||||
None => {},
|
||||
Some(ref chunk) => try!(write!(f, "\n\n\
|
||||
{}", chunk)),
|
||||
}
|
||||
match self.mtyp_chunk {
|
||||
None => {},
|
||||
Some(ref chunk) => try!(write!(f, "\n\n\
|
||||
{}", chunk)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
use std::fmt;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NrgMtyp {
|
||||
pub size: u32,
|
||||
pub unknown: u32,
|
||||
}
|
||||
|
||||
impl NrgMtyp {
|
||||
pub fn new() -> NrgMtyp {
|
||||
NrgMtyp {
|
||||
size: 0,
|
||||
unknown: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NrgMtyp {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Chunk ID: MTYP\n\
|
||||
Chunk description: Media Type (?)\n\
|
||||
Chunk size: {} Bytes\n\
|
||||
Unknown field: 0x{:04X}",
|
||||
self.size,
|
||||
self.unknown)
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
|
||||
use error::NrgError;
|
||||
|
||||
|
||||
/// Reads a String of size `size` from `fd`.
|
||||
pub fn read_sized_string(fd: &File, size: u64) -> Result<String, NrgError> {
|
||||
let mut handle = fd.take(size);
|
||||
let mut string = String::new();
|
||||
try!(handle.read_to_string(&mut string));
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
|
||||
/// Reads a 64-bit unsigned integer from `fd`.
|
||||
pub fn read_u64(fd: &mut File) -> Result<u64, NrgError> {
|
||||
let mut buf = [0u8; 8];
|
||||
try!(fd.read_exact(&mut buf));
|
||||
let i: u64;
|
||||
unsafe {
|
||||
i = mem::transmute(buf);
|
||||
}
|
||||
Ok(u64::from_be(i))
|
||||
}
|
||||
|
||||
|
||||
/// Reads a 32-bit unsigned integer from `fd`.
|
||||
pub fn read_u32(fd: &mut File) -> Result<u32, NrgError> {
|
||||
let mut buf = [0u8; 4];
|
||||
try!(fd.read_exact(&mut buf));
|
||||
let i: u32;
|
||||
unsafe {
|
||||
i = mem::transmute(buf);
|
||||
}
|
||||
Ok(u32::from_be(i))
|
||||
}
|
||||
|
||||
|
||||
/// Reads a 16-bit unsigned integer from `fd`.
|
||||
pub fn read_u16(fd: &mut File) -> Result<u16, NrgError> {
|
||||
let mut buf = [0u8; 2];
|
||||
try!(fd.read_exact(&mut buf));
|
||||
let i: u16;
|
||||
unsafe {
|
||||
i = mem::transmute(buf);
|
||||
}
|
||||
Ok(u16::from_be(i))
|
||||
}
|
||||
|
||||
|
||||
/// Reads an unsigned byte from `fd`.
|
||||
pub fn read_u8(fd: &mut File) -> Result<u8, NrgError> {
|
||||
let mut buf = [0u8; 1];
|
||||
try!(fd.read_exact(&mut buf));
|
||||
Ok(buf[0])
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
use std::fmt;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NrgSinf {
|
||||
pub size: u32,
|
||||
pub nb_tracks: u32,
|
||||
}
|
||||
|
||||
impl NrgSinf {
|
||||
pub fn new() -> NrgSinf {
|
||||
NrgSinf {
|
||||
size: 0,
|
||||
nb_tracks: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NrgSinf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Chunk ID: SINF\n\
|
||||
Chunk description: Session Information\n\
|
||||
Chunk size: {} Bytes\n\
|
||||
Number of tracks in the session: {}",
|
||||
self.size,
|
||||
self.nb_tracks)
|
||||
}
|
||||
}
|
Loading…
Reference in new issue