From ab34bebcd55fb3e558516f99639ed9230aa10509 Mon Sep 17 00:00:00 2001 From: Marrub Date: Sun, 10 Feb 2019 05:31:57 -0500 Subject: [PATCH] better and more error handling --- src/durandal/bin.rs | 156 +++++++++++++++++++++++------------------ src/durandal/crc.rs | 4 +- src/durandal/err.rs | 50 +++++++++++-- src/durandal/image.rs | 8 +-- src/durandal/mod.rs | 6 +- src/durandal/text.rs | 17 ++--- src/main.rs | 32 +++++---- src/marathon/machdr.rs | 4 +- src/marathon/map.rs | 36 +++++----- src/marathon/pict.rs | 60 +++++++++------- src/marathon/term.rs | 11 +-- src/marathon/wad.rs | 20 +++--- 12 files changed, 231 insertions(+), 173 deletions(-) diff --git a/src/durandal/bin.rs b/src/durandal/bin.rs index 4b8c24f..8c1da99 100644 --- a/src/durandal/bin.rs +++ b/src/durandal/bin.rs @@ -2,115 +2,115 @@ use crate::durandal::err::*; use std::{fmt, - num::NonZeroU16}; + num::NonZeroU16, + slice::SliceIndex}; + +pub fn c_data(b: &[u8], i: I) -> ResultS<&>::Output> + where I: SliceIndex<[u8]> +{ + ok!(b.get(i), "not enough data") +} pub trait BinUtil { + /// Returns a byte from `self` at `i`. + fn c_byte(&self, i: usize) -> ResultS; + /// Returns a four-character-code identifier from `self` at `i`. - fn c_iden(&self, i: usize) -> ResultS; + fn c_iden(&self, i: usize) -> ResultS + { + ok!(self.o_iden(i), "not enough data") + } /// Returns a big-endian `u32` from `self` at `i`. - fn c_u32b(&self, i: usize) -> ResultS; + fn c_u32b(&self, i: usize) -> ResultS + { + ok!(self.o_u32b(i), "not enough data") + } /// Returns a big-endian `u16` from `self` at `i`. - fn c_u16b(&self, i: usize) -> ResultS; + fn c_u16b(&self, i: usize) -> ResultS + { + ok!(self.o_u16b(i), "not enough data") + } /// Returns a big-endian `i32` from `self` at `i`. fn c_i32b(&self, i: usize) -> ResultS { - match self.c_u32b(i) { - Ok(n) => Ok(n as i32), - Err(e) => Err(e), - } + ok!(self.o_i32b(i), "not enough data") } /// Returns a big-endian `i16` from `self` at `i`. fn c_i16b(&self, i: usize) -> ResultS { - match self.c_u16b(i) { - Ok(n) => Ok(n as i16), - Err(e) => Err(e), + ok!(self.o_i16b(i), "not enough data") + } + + /// Returns a four-character-code identifier from `self` at `i`. + fn o_iden(&self, i: usize) -> Option; + + /// Returns a big-endian `u32` from `self` at `i`. + fn o_u32b(&self, i: usize) -> Option; + + /// Returns a big-endian `u16` from `self` at `i`. + fn o_u16b(&self, i: usize) -> Option; + + /// Returns a big-endian `i32` from `self` at `i`. + fn o_i32b(&self, i: usize) -> Option + { + match self.o_u32b(i) { + Some(n) => Some(n as i32), + None => None, } } - /// The same as `c_iden`, but returns `Option`. - fn o_iden(&self, i: usize) -> Option - { - self.c_iden(i).ok() - } - - /// The same as `c_u32b`, but returns `Option`. - fn o_u32b(&self, i: usize) -> Option - { - self.c_u32b(i).ok() - } - - /// The same as `c_u16b`, but returns `Option`. - fn o_u16b(&self, i: usize) -> Option - { - self.c_u16b(i).ok() - } - - /// The same as `c_i32b`, but returns `Option`. - fn o_i32b(&self, i: usize) -> Option - { - self.c_i32b(i).ok() - } - - /// The same as `c_i16b`, but returns `Option`. + /// Returns a big-endian `i16` from `self` at `i`. fn o_i16b(&self, i: usize) -> Option { - self.c_i16b(i).ok() + match self.o_u16b(i) { + Some(n) => Some(n as i16), + None => None, + } } } impl BinUtil for [u8] { - fn c_iden(&self, i: usize) -> ResultS + fn c_byte(&self, i: usize) -> ResultS { - if i + 3 < self.len() { - Ok([self[i], self[i + 1], self[i + 2], self[i + 3]]) - } else { - Err(err_msg("not enough data")) + match self.get(i) { + Some(&v) => Ok(v), + None => Err(err_msg("not enough data")), } } - fn c_u32b(&self, i: usize) -> ResultS + fn o_iden(&self, i: usize) -> Option { if i + 3 < self.len() { - Ok(u32::from_be_bytes([self[i], - self[i + 1], - self[i + 2], - self[i + 3]])) + Some([self[i], self[i + 1], self[i + 2], self[i + 3]]) } else { - Err(err_msg("not enough data")) + None } } - fn c_u16b(&self, i: usize) -> ResultS + fn o_u32b(&self, i: usize) -> Option + { + if i + 3 < self.len() { + Some(u32::from_be_bytes([self[i], + self[i + 1], + self[i + 2], + self[i + 3]])) + } else { + None + } + } + + fn o_u16b(&self, i: usize) -> Option { if i + 1 < self.len() { - Ok(u16::from_be_bytes([self[i], self[i + 1]])) + Some(u16::from_be_bytes([self[i], self[i + 1]])) } else { - Err(err_msg("not enough data")) - } - } -} - -/// A four-character-code identifier. -pub type Ident = [u8; 4]; - -/// An object identified by a `u16` which may be `u16::max_value()` to -/// represent None. -pub struct ObjID(Option); - -impl fmt::Debug for ObjID -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result - { - match self.0 { - None => write!(f, "ObjID(None)"), - Some(n) => write!(f, "ObjID({})", n.get()), + None } } } @@ -146,4 +146,22 @@ impl ObjID } } +impl fmt::Debug for ObjID +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + match self.0 { + None => write!(f, "ObjID(None)"), + Some(n) => write!(f, "ObjID({})", n.get()), + } + } +} + +/// A four-character-code identifier. +pub type Ident = [u8; 4]; + +/// An object identified by a `u16` which may be `u16::max_value()` to +/// represent None. +pub struct ObjID(Option); + // EOF diff --git a/src/durandal/crc.rs b/src/durandal/crc.rs index 2aebe7d..12ae654 100644 --- a/src/durandal/crc.rs +++ b/src/durandal/crc.rs @@ -1,6 +1,6 @@ //! Cyclic redundancy check function. -fn crc_accum(a: u32) -> u32 +fn crc_accum(a: u32, _: u32) -> u32 { if a & 1 == 1 { 0xedb88320 ^ a >> 1 @@ -13,7 +13,7 @@ fn crc_init() -> [u32; 256] { let mut t = [0; 256]; for n in 0..256 { - t[n] = (0..8).fold(n as u32, |a, _| crc_accum(a)); + t[n] = (0..8).fold(n as u32, crc_accum); } t } diff --git a/src/durandal/err.rs b/src/durandal/err.rs index 82a9ec5..4467ffe 100644 --- a/src/durandal/err.rs +++ b/src/durandal/err.rs @@ -1,14 +1,34 @@ //! Error handling. -pub use failure::{err_msg, Error, Fail}; +pub use failure::{Error, Fail}; use crate::durandal::traits::PrimInt; use std::fmt; -#[derive(PartialEq)] -pub struct ReprError(pub T) where T: PrimInt; +macro_rules! ok +{ + ($v:expr, $msg:expr) => { + match $v { + Some(v) => Ok(v), + None => Err(err_msg($msg)), + } + } +} + +macro_rules! bail +{ + ($e:expr) => { + return Err(err_msg($e)) + } +} + +pub fn err_msg(msg: &'static str) -> Error +{ + Error::from(ErrMsg(msg)) +} impl Fail for ReprError where T: PrimInt {} +impl Fail for ErrMsg {} impl fmt::Display for ReprError where T: PrimInt { @@ -26,11 +46,27 @@ impl fmt::Debug for ReprError where T: PrimInt } } -pub type ResultS = Result; - -pub fn bad_flag() -> Error +impl fmt::Display for ErrMsg { - err_msg("bad flag") + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + f.write_str(self.0) + } } +impl fmt::Debug for ErrMsg +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + fmt::Display::fmt(self, f) + } +} + +#[derive(PartialEq)] +pub struct ReprError(pub T) where T: PrimInt; + +struct ErrMsg(&'static str); + +pub type ResultS = Result; + // EOF diff --git a/src/durandal/image.rs b/src/durandal/image.rs index 241af00..6e40680 100644 --- a/src/durandal/image.rs +++ b/src/durandal/image.rs @@ -36,7 +36,7 @@ pub fn write_ppm(out: &mut impl io::Write, im: &T) -> ResultS<()> for y in 0..im.h() { for x in 0..im.w() { - let cr = im.cr_at(x, y).ok_or_else(|| err_msg("no data in image"))?; + let cr = ok!(im.cr_at(x, y), "not enough data in image")?; write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?; } } @@ -56,7 +56,7 @@ pub trait Image pub trait Color { type Output: PrimInt; - const MAX: usize; + const MAX: u32; fn r(&self) -> Self::Output; fn g(&self) -> Self::Output; @@ -119,7 +119,7 @@ impl Color16 impl Color for Color16 { type Output = u16; - const MAX: usize = u16::max_value() as usize; + const MAX: u32 = u16::max_value() as u32; fn r(&self) -> u16 {self.0} fn g(&self) -> u16 {self.1} @@ -138,7 +138,7 @@ impl Color8 impl Color for Color8 { type Output = u8; - const MAX: usize = u8::max_value() as usize; + const MAX: u32 = u8::max_value() as u32; fn r(&self) -> u8 {self.0} fn g(&self) -> u8 {self.1} diff --git a/src/durandal/mod.rs b/src/durandal/mod.rs index da2ef0e..1a735e2 100644 --- a/src/durandal/mod.rs +++ b/src/durandal/mod.rs @@ -1,11 +1,13 @@ //! Library for various utilities. -pub mod bin; #[macro_use] pub mod cenum; +#[macro_use] +pub mod err; + +pub mod bin; pub mod chunk; pub mod crc; -pub mod err; pub mod fx32; pub mod image; pub mod text; diff --git a/src/durandal/text.rs b/src/durandal/text.rs index 98e9e66..d219ae6 100644 --- a/src/durandal/text.rs +++ b/src/durandal/text.rs @@ -1,7 +1,5 @@ //! Text conversion utilities. -use crate::durandal::err::*; - /// Dumps a slice of memory as text to stderr. pub fn dump_mem(b: &[u8]) { @@ -60,6 +58,7 @@ pub fn fuck_string(s: &[u8]) -> Vec v[p + 1] ^= 0xed; p += 2; } + for _ in 0..l % 4 { v[p] ^= 0xfe; p += 1; @@ -69,18 +68,10 @@ pub fn fuck_string(s: &[u8]) -> Vec } /// Reads a Pascal-style byte string with bounds checking. -pub fn pascal_str(b: &[u8]) -> ResultS<&[u8]> +pub fn pascal_str(b: &[u8]) -> Option<&[u8]> { - if b.len() < 1 { - Err(err_msg("not enough data for string")) - } else { - let s = b[0] as usize; - if s + 1 > b.len() { - Err(err_msg("not enough data in string")) - } else { - Ok(&b[1..1 + s]) - } - } + let s = *b.get(0)? as usize; + b.get(1..1 + s) } /// Converts input from Mac Roman to a Unicode string. diff --git a/src/main.rs b/src/main.rs index 2e902ce..a2b095d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,45 +3,51 @@ use maraiah::{durandal::{bin::*, chunk::*, err::*, image::*, text::*}, use std::{env, fs, io::{self, Write}}; +fn write_chunk(cid: &Ident, cnk: &[u8], eid: u16) -> ResultS<()> +{ + let fname = format!("out/{:04}{}.bin", eid, mac_roman_conv(cid)); + let out = fs::File::create(&fname)?; + let mut out = io::BufWriter::new(out); + out.write(cnk)?; + Ok(()) +} + fn read_chunk(cid: &Ident, cnk: &[u8], eid: u16) -> ResultS<()> { match cid { b"PICT" => { let im = pict::load_pict(cnk)?; - println!("entry {} has PICT {}x{}", eid, im.w(), im.h()); + eprintln!("entry {} has PICT {}x{}", eid, im.w(), im.h()); let out = fs::File::create(&format!("out/{}.ppm", eid))?; let mut out = io::BufWriter::new(out); write_ppm(&mut out, &im)?; } b"Minf" => { let minf = map::Minf::chunk(cnk)?; - println!("entry {} has {:#?}", eid, minf); + eprintln!("entry {} has {:#?}", eid, minf); } b"EPNT" => { let epnt = map::Endpoint::chunk(cnk)?; - println!("entry {} has EPNT {:#?}", eid, epnt); + eprintln!("entry {} has EPNT {:#?}", eid, epnt); } b"PNTS" => { let epnt = map::Point::chunk(cnk)?; - println!("entry {} has PNTS {:#?}", eid, epnt); + eprintln!("entry {} has PNTS {:#?}", eid, epnt); } b"LINS" => { let line = map::Line::chunk(cnk)?; - println!("entry {} has LINS {:#?}", eid, line); + eprintln!("entry {} has LINS {:#?}", eid, line); } b"SIDS" => { let line = map::Side::chunk(cnk)?; - println!("entry {} has SIDS {:#?}", eid, line); + eprintln!("entry {} has SIDS {:#?}", eid, line); } b"term" => { let term = term::Terminal::chunk(cnk)?; - println!("entry {} has term {:#?}", eid, term); + eprintln!("entry {} has term {:#?}", eid, term); } cid => { - let fname = format!("out/{:04}{}.bin", eid, mac_roman_conv(cid)); - let out = fs::File::create(&fname)?; - let mut out = io::BufWriter::new(out); - out.write(cnk)?; + write_chunk(cid, cnk, eid)?; } } @@ -52,7 +58,7 @@ fn process_wad(b: &[u8]) -> ResultS<()> { let wad = wad::Wad::new(b)?; - println!("{:#?}", wad); + eprintln!("{:#?}", wad); for (eid, ent) in wad.entries { for (cid, cnk) in ent.chunks { @@ -81,7 +87,7 @@ fn main() -> ResultS<()> let fp = fs::File::open(fna)?; let mm = unsafe {Mmap::map(&fp)?}; - let b = &mm[machdr::try_mac_header(&mm)..]; + let b = c_data(&mm, machdr::try_mac_header(&mm)..)?; match typ { "wad:" => process_wad(b), diff --git a/src/marathon/machdr.rs b/src/marathon/machdr.rs index 2a8dc1d..d769dea 100644 --- a/src/marathon/machdr.rs +++ b/src/marathon/machdr.rs @@ -6,7 +6,7 @@ use crate::durandal::bin::*; pub fn check_apple_single(b: &[u8]) -> Option { // check magic numbers - if b[0..8] != [0, 5, 22, 0, 0, 2, 0, 0] { + if *b.get(0..8)? != [0, 5, 22, 0, 0, 2, 0, 0] { return None; } @@ -31,7 +31,7 @@ pub fn check_apple_single(b: &[u8]) -> Option pub fn check_macbin(b: &[u8]) -> Option { // check legacy version, length, zero fill, and macbin2 version - if b[0] != 0 || b[1] > 63 || b[74] != 0 || b[123] > 129 { + if b.len() < 128 || b[0] != 0 || b[1] > 63 || b[74] != 0 || b[123] > 129 { return None; } diff --git a/src/marathon/map.rs b/src/marathon/map.rs index 13c19b8..743133d 100644 --- a/src/marathon/map.rs +++ b/src/marathon/map.rs @@ -23,9 +23,9 @@ impl Chunked for Endpoint let flags = b.c_u16b(0)?; let adj_hi = b.c_i16b(2)?; let adj_lo = b.c_i16b(4)?; - let pos = Point::read(&b[6..10])?; + let pos = Point::read(c_data(b, 6..10)?)?; let support = b.c_u16b(14)?; - let flags = EndpointFlags::from_bits(flags).ok_or_else(bad_flag)?; + let flags = ok!(EndpFlags::from_bits(flags), "bad EndpFlags")?; Ok(Endpoint{flags, adj_hi, adj_lo, pos, support}) } } @@ -46,7 +46,7 @@ impl Chunked for Line let side_b = b.c_u16b(14)?; let poly_f = b.c_u16b(16)?; let poly_b = b.c_u16b(18)?; - let flags = LineFlags::from_bits(flags).ok_or_else(bad_flag)?; + let flags = ok!(LineFlags::from_bits(flags), "bad LineFlags")?; Ok(Line{flags, length, adj_hi, adj_lo, epnt_f, epnt_b, side_f, side_b, poly_f, poly_b}) } @@ -56,7 +56,7 @@ impl SideTex { fn read(b: &[u8]) -> ResultS { - let offs = Point::read(&b[0..4])?; + let offs = Point::read(c_data(b, 0..4)?)?; let tex_id = b.c_u16b(4)?; let tex_id = ObjID::from_repr(tex_id); Ok(SideTex{offs, tex_id}) @@ -71,20 +71,20 @@ impl Chunked for Side { let stype = b.c_u16b(0)?; let flags = b.c_u16b(2)?; - let tex_pri = SideTex::read(&b[4..10])?; - let tex_sec = SideTex::read(&b[10..16])?; - let tex_tra = SideTex::read(&b[16..22])?; - let ex_tleft = Point::read(&b[22..26])?; - let ex_trigh = Point::read(&b[26..30])?; - let ex_bleft = Point::read(&b[30..34])?; - let ex_brigh = Point::read(&b[34..38])?; + let tex_pri = SideTex::read(c_data(b, 4..10)?)?; + let tex_sec = SideTex::read(c_data(b, 10..16)?)?; + let tex_tra = SideTex::read(c_data(b, 16..22)?)?; + let ex_tleft = Point::read(c_data(b, 22..26)?)?; + let ex_trigh = Point::read(c_data(b, 26..30)?)?; + let ex_bleft = Point::read(c_data(b, 30..34)?)?; + let ex_brigh = Point::read(c_data(b, 34..38)?)?; let paneltyp = b.c_u16b(38)?; let paneldat = b.c_i16b(40)?; let xfer_pri = b.c_u16b(42)?; let xfer_sec = b.c_u16b(44)?; let xfer_tra = b.c_u16b(46)?; let shade = b.c_u32b(48)?; - let flags = SideFlags::from_bits(flags).ok_or_else(bad_flag)?; + let flags = ok!(SideFlags::from_bits(flags), "bad SideFlags")?; let shade = Fx32::from_bits(shade); Ok(Side{stype, flags, tex_pri, tex_sec, tex_tra, ex_tleft, ex_trigh, ex_bleft, ex_brigh, paneltyp, paneldat, xfer_pri, xfer_sec, @@ -101,11 +101,11 @@ impl Chunker for Minf let music_id = b.c_u16b(4)?; let msn_flag = b.c_u16b(6)?; let env_flag = b.c_u16b(8)?; - let levelnam = mac_roman_conv(&b[18..84]); + let levelnam = mac_roman_conv(c_data(b, 18..84)?); let ent_flag = b.c_u32b(84)?; - let msn_flag = MsnFlags::from_bits(msn_flag).ok_or_else(bad_flag)?; - let env_flag = EnvFlags::from_bits(env_flag).ok_or_else(bad_flag)?; - let ent_flag = EntFlags::from_bits(ent_flag).ok_or_else(bad_flag)?; + let msn_flag = ok!(MsnFlags::from_bits(msn_flag), "bad MsnFlags")?; + let env_flag = ok!(EnvFlags::from_bits(env_flag), "bad EnvFlags")?; + let ent_flag = ok!(EntFlags::from_bits(ent_flag), "bad EntFlags")?; Ok(Minf{env_code, physi_id, music_id, msn_flag, env_flag, ent_flag, levelnam}) } @@ -122,7 +122,7 @@ pub struct Point #[derive(Debug)] pub struct Endpoint { - flags: EndpointFlags, + flags: EndpFlags, adj_hi: Unit, adj_lo: Unit, pos: Point, @@ -184,7 +184,7 @@ pub struct Minf } bitflags! { - pub struct EndpointFlags: u16 + pub struct EndpFlags: u16 { const Solid = 0x00_01; const SameHeight = 0x00_02; diff --git a/src/marathon/pict.rs b/src/marathon/pict.rs index ebb25be..8207773 100644 --- a/src/marathon/pict.rs +++ b/src/marathon/pict.rs @@ -38,18 +38,18 @@ pub fn read_bitmap_area(mut im: Image8, // clut_id = b.c_u32b(p+38)?; if pitch_fl & 0x8000 == 0 { - return Err(err_msg("PICT1 not supported")); + bail!("PICT1 not supported"); } if right - left != w || bottom - top != h { - return Err(err_msg("image bounds are incorrect")); + bail!("image bounds are incorrect"); } p += 46; // size of header // get CLUT if packed let clut = if packed { - let (clut, sz) = get_clut(&b[p..])?; + let (clut, sz) = get_clut(c_data(b, p..)?)?; p += sz; Some(clut) } else { @@ -70,12 +70,13 @@ pub fn read_bitmap_area(mut im: Image8, match depth { 1 | 2 | 4 | 8 => { - let clut = clut.ok_or_else(|| err_msg("no clut in indexed mode"))?; + let clut = ok!(clut, "no CLUT in indexed mode")?; if pitch < 8 && depth == 8 { // uncompressed 8-bit colormap indices for _ in 0..h { for _ in 0..w { - im.cr.push(clut[b[(p, p += 1).0] as usize].clone()); + let idx = b.c_byte((p, p += 1).0)? as usize; + im.cr.push(ok!(clut.get(idx), "invalid index")?.clone()); } } @@ -83,13 +84,14 @@ pub fn read_bitmap_area(mut im: Image8, } else if rle { // RLE compressed 1, 2, 4 or 8 bit colormap indices for _ in 0..h { - let (d, pp) = read_rle(&b[p..], pitch, false)?; + let (d, pp) = read_rle(c_data(b, p..)?, pitch, false)?; let d = if depth < 8 {expand_data(d, depth)?} else {d}; p += pp; for x in 0..w { - im.cr.push(clut[d[x] as usize].clone()); + let idx = d.c_byte(x)? as usize; + im.cr.push(ok!(clut.get(idx), "invalid index")?.clone()); } } @@ -111,7 +113,7 @@ pub fn read_bitmap_area(mut im: Image8, } else if rle { // RLE compressed R5G5B5 for _ in 0..h { - let (d, pp) = read_rle(&b[p..], pitch, true)?; + let (d, pp) = read_rle(c_data(b, p..)?, pitch, true)?; p += pp; @@ -133,7 +135,9 @@ pub fn read_bitmap_area(mut im: Image8, if pack_typ != PACK_NOPAD { p += 1; } - let (r, g, b) = (b[p], b[p + 1], b[p + 2]); + let r = b.c_byte(p)?; + let g = b.c_byte(p + 1)?; + let b = b.c_byte(p + 2)?; p += 3; im.cr.push(Color8::new(r, g, b)); } @@ -144,12 +148,14 @@ pub fn read_bitmap_area(mut im: Image8, // RLE compressed RGB8 let pitch = pitch - w; // remove padding byte from pitch for _ in 0..h { - let (d, pp) = read_rle(&b[p..], pitch, false)?; + let (d, pp) = read_rle(c_data(b, p..)?, pitch, false)?; p += pp; for x in 0..w { - let (r, g, b) = (d[x + w * 0], d[x + w * 1], d[x + w * 2]); + let r = d.c_byte(x + w)?; + let g = d.c_byte(x + w * 1)?; + let b = d.c_byte(x + w * 2)?; im.cr.push(Color8::new(r, g, b)); } } @@ -187,23 +193,23 @@ pub fn load_pict(b: &[u8]) -> ResultS match op { 0x0098 => { // PackBitsRect - return read_bitmap_area(im, &b[p..], true, false); + return read_bitmap_area(im, c_data(b, p..)?, true, false); } 0x0099 => { // PackBitsRgn - return read_bitmap_area(im, &b[p..], true, true); + return read_bitmap_area(im, c_data(b, p..)?, true, true); } 0x009a => { // DirectBitsRect - return read_bitmap_area(im, &b[p..], false, false); + return read_bitmap_area(im, c_data(b, p..)?, false, false); } 0x009b => { // DirectBitsRgn - return read_bitmap_area(im, &b[p..], false, true); + return read_bitmap_area(im, c_data(b, p..)?, false, true); } 0x8200 => { // CompressedQuickTime - return read_quicktime_c(im, &b[p..]); + return read_quicktime_c(im, c_data(b, p..)?); } 0x00ff => { // OpEndPic @@ -259,7 +265,7 @@ pub fn load_pict(b: &[u8]) -> ResultS 0x100..= 0x7fff => p += (op >> 8) as usize * 2, // Reserved _ => { - return Err(err_msg("invalid op in PICT")); + bail!("invalid op in PICT"); } } } @@ -279,16 +285,16 @@ pub fn get_clut(b: &[u8]) -> ResultS<(Vec, usize)> for i in 0..num { // with device mapping, we ignore the index entirely - let n = if !dev {b[p + 1] as usize} else {i}; - let r = b[p + 2]; - let g = b[p + 4]; - let b = b[p + 6]; + let n = if !dev {b.c_byte(p + 1)? as usize} else {i}; + let r = b.c_byte(p + 2)?; + let g = b.c_byte(p + 4)?; + let b = b.c_byte(p + 6)?; if n >= clut.len() { - return Err(err_msg("bad clut index")); + bail!("bad clut index"); } - clut[n] = Color8::new(r, g, b); + *ok!(clut.get_mut(n), "invalid index")? = Color8::new(r, g, b); p += 8; } @@ -305,11 +311,11 @@ pub fn read_rle(b: &[u8], pitch: usize, ln: bool) -> ResultS<(Vec, usize)> let sz = if pitch > 250 { (b.c_u16b(0)? as usize + 2, p += 2).0 } else { - (b[0] as usize + 1, p += 1).0 + (b.c_byte(0)? as usize + 1, p += 1).0 }; while p < sz { - let szf = b[(p, p += 1).0]; + let szf = b.c_byte((p, p += 1).0)?; let cmp = szf & 0x80 != 0; let len = if cmp {!szf + 2} else {szf + 1} as usize; @@ -359,7 +365,7 @@ pub fn expand_data(b: Vec, depth: u16) -> ResultS> 4 => b.len() * 2, 2 => b.len() * 4, 1 => b.len() * 8, - _ => return Err(err_msg("invalid bit depth")), + _ => bail!("invalid bit depth"), }); for ch in b { @@ -367,7 +373,7 @@ pub fn expand_data(b: Vec, depth: u16) -> ResultS> 4 => {for i in 1..=0 {o.push(ch >> i * 4 & 0xFu8);}} // 2 nibbles 2 => {for i in 3..=0 {o.push(ch >> i * 2 & 0x3u8);}} // 4 dibits 1 => {for i in 7..=0 {o.push(ch >> i * 1 & 0x1u8);}} // 8 bits - _ => return Err(err_msg("invalid bit depth")), + _ => bail!("invalid bit depth"), } } diff --git a/src/marathon/term.rs b/src/marathon/term.rs index 6d24271..57083c9 100644 --- a/src/marathon/term.rs +++ b/src/marathon/term.rs @@ -9,7 +9,8 @@ fn read_group(b: &[u8], text: &[u8]) -> ResultS let start = b.c_u16b(6)? as usize; let size = b.c_u16b(8)? as usize; let lines = b.c_u16b(10)?; - let text = mac_roman_conv(&text[start..start + size]); + let text = c_data(text, start..start + size)?; + let text = mac_roman_conv(text); let ttype = GroupType::from_repr(ttype)?; Ok(Group{ttype, pdata, lines, text}) @@ -41,7 +42,7 @@ fn read_terminal(b: &[u8]) -> ResultS<(usize, Terminal)> let mut p = 10; // size of header let text_st = p + SIZE_GROUP * group_n + SIZE_FACE * face_n; - let text = &b[text_st..end]; + let text = c_data(b, text_st..end)?; let text = if encoded { fuck_string(text) } else { @@ -49,12 +50,12 @@ fn read_terminal(b: &[u8]) -> ResultS<(usize, Terminal)> }; for _ in 0..group_n { - groups.push(read_group(&b[p..], &text)?); + groups.push(read_group(c_data(b, p..)?, &text)?); p += SIZE_GROUP; } for _ in 0..face_n { - faces.push(read_face(&b[p..])?); + faces.push(read_face(c_data(b, p..)?)?); p += SIZE_FACE; } @@ -69,7 +70,7 @@ impl Chunker> for Terminal let mut p = 0; while p < b.len() { - let (size, trm) = read_terminal(&b[p..])?; + let (size, trm) = read_terminal(c_data(b, p..)?)?; v.push(trm); p += size; } diff --git a/src/marathon/wad.rs b/src/marathon/wad.rs index af60e4d..5a30b08 100644 --- a/src/marathon/wad.rs +++ b/src/marathon/wad.rs @@ -7,13 +7,9 @@ impl Wad<'_> { pub fn new(b: &[u8]) -> ResultS { - if b.len() < 128 { - return Err(err_msg("not enough data for Wad header")); - } - let wadver = b.c_u16b(0)?; let dataver = b.c_u16b(2)?; - let origname = mac_roman_conv(&b[4..68]); + let origname = c_data(b, 4..68)?; // crc = b.c_u32b(68)?; let dirofs = b.c_u32b(72)? as usize; let numents = b.c_u16b(76)? as usize; @@ -22,6 +18,7 @@ impl Wad<'_> let wentsize = b.c_u16b(82)? as usize; // parent = b.c_u32b(84)?; let wadver = Ver::from_repr(wadver)?; + let origname = mac_roman_conv(origname); let is_old = match wadver { Ver::Base => true, @@ -31,11 +28,11 @@ impl Wad<'_> let cnksize = if !is_old {16} else {12}; if entsize != wentsize { - return Err(err_msg("invalid entry size")); + bail!("invalid entry size"); } if cnksize != wcnksize { - return Err(err_msg("invalid chunk size")); + bail!("invalid chunk size"); } let mut entries = EntryMap::new(); @@ -47,11 +44,12 @@ impl Wad<'_> let index = if !is_old {b.c_u16b(p + 8)?} else {i as u16}; if offset + size > b.len() { - return Err(err_msg("not enough data for entry")); + bail!("not enough data for entry"); } - let chunks = get_chunks(&b[offset..offset + size], cnksize)?; - let appdata = &b[p..p + appsize]; + let cnkdata = c_data(b, offset..offset + size)?; + let chunks = get_chunks(cnkdata, cnksize)?; + let appdata = c_data(b, p..p + appsize)?; entries.insert(index, Entry{chunks, appdata}); @@ -74,7 +72,7 @@ fn get_chunks(b: &[u8], cnksize: usize) -> ResultS // pofs = b.c_u32b(p+12)?; let beg = p + cnksize; let end = beg + size; - chunks.insert(iden, &b[beg..end]); + chunks.insert(iden, c_data(b, beg..end)?); p = end; }