better and more error handling

png-branch
an 2019-02-10 05:31:57 -05:00
parent 824ff5cdd2
commit ab34bebcd5
12 changed files with 231 additions and 173 deletions

View File

@ -2,115 +2,115 @@
use crate::durandal::err::*; use crate::durandal::err::*;
use std::{fmt, use std::{fmt,
num::NonZeroU16}; num::NonZeroU16,
slice::SliceIndex};
pub fn c_data<I>(b: &[u8], i: I) -> ResultS<&<I as SliceIndex<[u8]>>::Output>
where I: SliceIndex<[u8]>
{
ok!(b.get(i), "not enough data")
}
pub trait BinUtil pub trait BinUtil
{ {
/// Returns a byte from `self` at `i`.
fn c_byte(&self, i: usize) -> ResultS<u8>;
/// Returns a four-character-code identifier from `self` at `i`. /// Returns a four-character-code identifier from `self` at `i`.
fn c_iden(&self, i: usize) -> ResultS<Ident>; fn c_iden(&self, i: usize) -> ResultS<Ident>
{
ok!(self.o_iden(i), "not enough data")
}
/// Returns a big-endian `u32` from `self` at `i`. /// Returns a big-endian `u32` from `self` at `i`.
fn c_u32b(&self, i: usize) -> ResultS<u32>; fn c_u32b(&self, i: usize) -> ResultS<u32>
{
ok!(self.o_u32b(i), "not enough data")
}
/// Returns a big-endian `u16` from `self` at `i`. /// Returns a big-endian `u16` from `self` at `i`.
fn c_u16b(&self, i: usize) -> ResultS<u16>; fn c_u16b(&self, i: usize) -> ResultS<u16>
{
ok!(self.o_u16b(i), "not enough data")
}
/// Returns a big-endian `i32` from `self` at `i`. /// Returns a big-endian `i32` from `self` at `i`.
fn c_i32b(&self, i: usize) -> ResultS<i32> fn c_i32b(&self, i: usize) -> ResultS<i32>
{ {
match self.c_u32b(i) { ok!(self.o_i32b(i), "not enough data")
Ok(n) => Ok(n as i32),
Err(e) => Err(e),
}
} }
/// Returns a big-endian `i16` from `self` at `i`. /// Returns a big-endian `i16` from `self` at `i`.
fn c_i16b(&self, i: usize) -> ResultS<i16> fn c_i16b(&self, i: usize) -> ResultS<i16>
{ {
match self.c_u16b(i) { ok!(self.o_i16b(i), "not enough data")
Ok(n) => Ok(n as i16), }
Err(e) => Err(e),
/// Returns a four-character-code identifier from `self` at `i`.
fn o_iden(&self, i: usize) -> Option<Ident>;
/// Returns a big-endian `u32` from `self` at `i`.
fn o_u32b(&self, i: usize) -> Option<u32>;
/// Returns a big-endian `u16` from `self` at `i`.
fn o_u16b(&self, i: usize) -> Option<u16>;
/// Returns a big-endian `i32` from `self` at `i`.
fn o_i32b(&self, i: usize) -> Option<i32>
{
match self.o_u32b(i) {
Some(n) => Some(n as i32),
None => None,
} }
} }
/// The same as `c_iden`, but returns `Option`. /// Returns a big-endian `i16` from `self` at `i`.
fn o_iden(&self, i: usize) -> Option<Ident>
{
self.c_iden(i).ok()
}
/// The same as `c_u32b`, but returns `Option`.
fn o_u32b(&self, i: usize) -> Option<u32>
{
self.c_u32b(i).ok()
}
/// The same as `c_u16b`, but returns `Option`.
fn o_u16b(&self, i: usize) -> Option<u16>
{
self.c_u16b(i).ok()
}
/// The same as `c_i32b`, but returns `Option`.
fn o_i32b(&self, i: usize) -> Option<i32>
{
self.c_i32b(i).ok()
}
/// The same as `c_i16b`, but returns `Option`.
fn o_i16b(&self, i: usize) -> Option<i16> fn o_i16b(&self, i: usize) -> Option<i16>
{ {
self.c_i16b(i).ok() match self.o_u16b(i) {
Some(n) => Some(n as i16),
None => None,
}
} }
} }
impl BinUtil for [u8] impl BinUtil for [u8]
{ {
fn c_iden(&self, i: usize) -> ResultS<Ident> fn c_byte(&self, i: usize) -> ResultS<u8>
{ {
if i + 3 < self.len() { match self.get(i) {
Ok([self[i], self[i + 1], self[i + 2], self[i + 3]]) Some(&v) => Ok(v),
} else { None => Err(err_msg("not enough data")),
Err(err_msg("not enough data"))
} }
} }
fn c_u32b(&self, i: usize) -> ResultS<u32> fn o_iden(&self, i: usize) -> Option<Ident>
{ {
if i + 3 < self.len() { if i + 3 < self.len() {
Ok(u32::from_be_bytes([self[i], Some([self[i], self[i + 1], self[i + 2], self[i + 3]])
self[i + 1],
self[i + 2],
self[i + 3]]))
} else { } else {
Err(err_msg("not enough data")) None
} }
} }
fn c_u16b(&self, i: usize) -> ResultS<u16> fn o_u32b(&self, i: usize) -> Option<u32>
{
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<u16>
{ {
if i + 1 < self.len() { 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 { } else {
Err(err_msg("not enough data")) None
}
}
}
/// 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<NonZeroU16>);
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()),
} }
} }
} }
@ -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<NonZeroU16>);
// EOF // EOF

View File

@ -1,6 +1,6 @@
//! Cyclic redundancy check function. //! Cyclic redundancy check function.
fn crc_accum(a: u32) -> u32 fn crc_accum(a: u32, _: u32) -> u32
{ {
if a & 1 == 1 { if a & 1 == 1 {
0xedb88320 ^ a >> 1 0xedb88320 ^ a >> 1
@ -13,7 +13,7 @@ fn crc_init() -> [u32; 256]
{ {
let mut t = [0; 256]; let mut t = [0; 256];
for n in 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 t
} }

View File

@ -1,14 +1,34 @@
//! Error handling. //! Error handling.
pub use failure::{err_msg, Error, Fail}; pub use failure::{Error, Fail};
use crate::durandal::traits::PrimInt; use crate::durandal::traits::PrimInt;
use std::fmt; use std::fmt;
#[derive(PartialEq)] macro_rules! ok
pub struct ReprError<T>(pub T) where T: PrimInt; {
($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<T> Fail for ReprError<T> where T: PrimInt {} impl<T> Fail for ReprError<T> where T: PrimInt {}
impl Fail for ErrMsg {}
impl<T> fmt::Display for ReprError<T> where T: PrimInt impl<T> fmt::Display for ReprError<T> where T: PrimInt
{ {
@ -26,11 +46,27 @@ impl<T> fmt::Debug for ReprError<T> where T: PrimInt
} }
} }
pub type ResultS<T> = Result<T, Error>; impl fmt::Display for ErrMsg
pub fn bad_flag() -> Error
{ {
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<T>(pub T) where T: PrimInt;
struct ErrMsg(&'static str);
pub type ResultS<T> = Result<T, Error>;
// EOF // EOF

View File

@ -36,7 +36,7 @@ pub fn write_ppm<T: Image>(out: &mut impl io::Write, im: &T) -> ResultS<()>
for y in 0..im.h() { for y in 0..im.h() {
for x in 0..im.w() { 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())?; write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?;
} }
} }
@ -56,7 +56,7 @@ pub trait Image
pub trait Color pub trait Color
{ {
type Output: PrimInt; type Output: PrimInt;
const MAX: usize; const MAX: u32;
fn r(&self) -> Self::Output; fn r(&self) -> Self::Output;
fn g(&self) -> Self::Output; fn g(&self) -> Self::Output;
@ -119,7 +119,7 @@ impl Color16
impl Color for Color16 impl Color for Color16
{ {
type Output = u16; 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 r(&self) -> u16 {self.0}
fn g(&self) -> u16 {self.1} fn g(&self) -> u16 {self.1}
@ -138,7 +138,7 @@ impl Color8
impl Color for Color8 impl Color for Color8
{ {
type Output = u8; 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 r(&self) -> u8 {self.0}
fn g(&self) -> u8 {self.1} fn g(&self) -> u8 {self.1}

View File

@ -1,11 +1,13 @@
//! Library for various utilities. //! Library for various utilities.
pub mod bin;
#[macro_use] #[macro_use]
pub mod cenum; pub mod cenum;
#[macro_use]
pub mod err;
pub mod bin;
pub mod chunk; pub mod chunk;
pub mod crc; pub mod crc;
pub mod err;
pub mod fx32; pub mod fx32;
pub mod image; pub mod image;
pub mod text; pub mod text;

View File

@ -1,7 +1,5 @@
//! Text conversion utilities. //! Text conversion utilities.
use crate::durandal::err::*;
/// Dumps a slice of memory as text to stderr. /// Dumps a slice of memory as text to stderr.
pub fn dump_mem(b: &[u8]) pub fn dump_mem(b: &[u8])
{ {
@ -60,6 +58,7 @@ pub fn fuck_string(s: &[u8]) -> Vec<u8>
v[p + 1] ^= 0xed; v[p + 1] ^= 0xed;
p += 2; p += 2;
} }
for _ in 0..l % 4 { for _ in 0..l % 4 {
v[p] ^= 0xfe; v[p] ^= 0xfe;
p += 1; p += 1;
@ -69,18 +68,10 @@ pub fn fuck_string(s: &[u8]) -> Vec<u8>
} }
/// Reads a Pascal-style byte string with bounds checking. /// 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 { let s = *b.get(0)? as usize;
Err(err_msg("not enough data for string")) b.get(1..1 + s)
} 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])
}
}
} }
/// Converts input from Mac Roman to a Unicode string. /// Converts input from Mac Roman to a Unicode string.

View File

@ -3,45 +3,51 @@ use maraiah::{durandal::{bin::*, chunk::*, err::*, image::*, text::*},
use std::{env, fs, use std::{env, fs,
io::{self, Write}}; 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<()> fn read_chunk(cid: &Ident, cnk: &[u8], eid: u16) -> ResultS<()>
{ {
match cid { match cid {
b"PICT" => { b"PICT" => {
let im = pict::load_pict(cnk)?; 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 out = fs::File::create(&format!("out/{}.ppm", eid))?;
let mut out = io::BufWriter::new(out); let mut out = io::BufWriter::new(out);
write_ppm(&mut out, &im)?; write_ppm(&mut out, &im)?;
} }
b"Minf" => { b"Minf" => {
let minf = map::Minf::chunk(cnk)?; let minf = map::Minf::chunk(cnk)?;
println!("entry {} has {:#?}", eid, minf); eprintln!("entry {} has {:#?}", eid, minf);
} }
b"EPNT" => { b"EPNT" => {
let epnt = map::Endpoint::chunk(cnk)?; let epnt = map::Endpoint::chunk(cnk)?;
println!("entry {} has EPNT {:#?}", eid, epnt); eprintln!("entry {} has EPNT {:#?}", eid, epnt);
} }
b"PNTS" => { b"PNTS" => {
let epnt = map::Point::chunk(cnk)?; let epnt = map::Point::chunk(cnk)?;
println!("entry {} has PNTS {:#?}", eid, epnt); eprintln!("entry {} has PNTS {:#?}", eid, epnt);
} }
b"LINS" => { b"LINS" => {
let line = map::Line::chunk(cnk)?; let line = map::Line::chunk(cnk)?;
println!("entry {} has LINS {:#?}", eid, line); eprintln!("entry {} has LINS {:#?}", eid, line);
} }
b"SIDS" => { b"SIDS" => {
let line = map::Side::chunk(cnk)?; let line = map::Side::chunk(cnk)?;
println!("entry {} has SIDS {:#?}", eid, line); eprintln!("entry {} has SIDS {:#?}", eid, line);
} }
b"term" => { b"term" => {
let term = term::Terminal::chunk(cnk)?; let term = term::Terminal::chunk(cnk)?;
println!("entry {} has term {:#?}", eid, term); eprintln!("entry {} has term {:#?}", eid, term);
} }
cid => { cid => {
let fname = format!("out/{:04}{}.bin", eid, mac_roman_conv(cid)); write_chunk(cid, cnk, eid)?;
let out = fs::File::create(&fname)?;
let mut out = io::BufWriter::new(out);
out.write(cnk)?;
} }
} }
@ -52,7 +58,7 @@ fn process_wad(b: &[u8]) -> ResultS<()>
{ {
let wad = wad::Wad::new(b)?; let wad = wad::Wad::new(b)?;
println!("{:#?}", wad); eprintln!("{:#?}", wad);
for (eid, ent) in wad.entries { for (eid, ent) in wad.entries {
for (cid, cnk) in ent.chunks { for (cid, cnk) in ent.chunks {
@ -81,7 +87,7 @@ fn main() -> ResultS<()>
let fp = fs::File::open(fna)?; let fp = fs::File::open(fna)?;
let mm = unsafe {Mmap::map(&fp)?}; 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 { match typ {
"wad:" => process_wad(b), "wad:" => process_wad(b),

View File

@ -6,7 +6,7 @@ use crate::durandal::bin::*;
pub fn check_apple_single(b: &[u8]) -> Option<usize> pub fn check_apple_single(b: &[u8]) -> Option<usize>
{ {
// check magic numbers // 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; return None;
} }
@ -31,7 +31,7 @@ pub fn check_apple_single(b: &[u8]) -> Option<usize>
pub fn check_macbin(b: &[u8]) -> Option<usize> pub fn check_macbin(b: &[u8]) -> Option<usize>
{ {
// check legacy version, length, zero fill, and macbin2 version // 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; return None;
} }

View File

@ -23,9 +23,9 @@ impl Chunked<Endpoint> for Endpoint
let flags = b.c_u16b(0)?; let flags = b.c_u16b(0)?;
let adj_hi = b.c_i16b(2)?; let adj_hi = b.c_i16b(2)?;
let adj_lo = b.c_i16b(4)?; 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 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}) Ok(Endpoint{flags, adj_hi, adj_lo, pos, support})
} }
} }
@ -46,7 +46,7 @@ impl Chunked<Line> for Line
let side_b = b.c_u16b(14)?; let side_b = b.c_u16b(14)?;
let poly_f = b.c_u16b(16)?; let poly_f = b.c_u16b(16)?;
let poly_b = b.c_u16b(18)?; 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, Ok(Line{flags, length, adj_hi, adj_lo, epnt_f, epnt_b, side_f, side_b,
poly_f, poly_b}) poly_f, poly_b})
} }
@ -56,7 +56,7 @@ impl SideTex
{ {
fn read(b: &[u8]) -> ResultS<Self> fn read(b: &[u8]) -> ResultS<Self>
{ {
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 = b.c_u16b(4)?;
let tex_id = ObjID::from_repr(tex_id); let tex_id = ObjID::from_repr(tex_id);
Ok(SideTex{offs, tex_id}) Ok(SideTex{offs, tex_id})
@ -71,20 +71,20 @@ impl Chunked<Side> for Side
{ {
let stype = b.c_u16b(0)?; let stype = b.c_u16b(0)?;
let flags = b.c_u16b(2)?; let flags = b.c_u16b(2)?;
let tex_pri = SideTex::read(&b[4..10])?; let tex_pri = SideTex::read(c_data(b, 4..10)?)?;
let tex_sec = SideTex::read(&b[10..16])?; let tex_sec = SideTex::read(c_data(b, 10..16)?)?;
let tex_tra = SideTex::read(&b[16..22])?; let tex_tra = SideTex::read(c_data(b, 16..22)?)?;
let ex_tleft = Point::read(&b[22..26])?; let ex_tleft = Point::read(c_data(b, 22..26)?)?;
let ex_trigh = Point::read(&b[26..30])?; let ex_trigh = Point::read(c_data(b, 26..30)?)?;
let ex_bleft = Point::read(&b[30..34])?; let ex_bleft = Point::read(c_data(b, 30..34)?)?;
let ex_brigh = Point::read(&b[34..38])?; let ex_brigh = Point::read(c_data(b, 34..38)?)?;
let paneltyp = b.c_u16b(38)?; let paneltyp = b.c_u16b(38)?;
let paneldat = b.c_i16b(40)?; let paneldat = b.c_i16b(40)?;
let xfer_pri = b.c_u16b(42)?; let xfer_pri = b.c_u16b(42)?;
let xfer_sec = b.c_u16b(44)?; let xfer_sec = b.c_u16b(44)?;
let xfer_tra = b.c_u16b(46)?; let xfer_tra = b.c_u16b(46)?;
let shade = b.c_u32b(48)?; 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); let shade = Fx32::from_bits(shade);
Ok(Side{stype, flags, tex_pri, tex_sec, tex_tra, ex_tleft, ex_trigh, Ok(Side{stype, flags, tex_pri, tex_sec, tex_tra, ex_tleft, ex_trigh,
ex_bleft, ex_brigh, paneltyp, paneldat, xfer_pri, xfer_sec, ex_bleft, ex_brigh, paneltyp, paneldat, xfer_pri, xfer_sec,
@ -101,11 +101,11 @@ impl Chunker<Minf> for Minf
let music_id = b.c_u16b(4)?; let music_id = b.c_u16b(4)?;
let msn_flag = b.c_u16b(6)?; let msn_flag = b.c_u16b(6)?;
let env_flag = b.c_u16b(8)?; 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 ent_flag = b.c_u32b(84)?;
let msn_flag = MsnFlags::from_bits(msn_flag).ok_or_else(bad_flag)?; let msn_flag = ok!(MsnFlags::from_bits(msn_flag), "bad MsnFlags")?;
let env_flag = EnvFlags::from_bits(env_flag).ok_or_else(bad_flag)?; let env_flag = ok!(EnvFlags::from_bits(env_flag), "bad EnvFlags")?;
let ent_flag = EntFlags::from_bits(ent_flag).ok_or_else(bad_flag)?; 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, Ok(Minf{env_code, physi_id, music_id, msn_flag, env_flag, ent_flag,
levelnam}) levelnam})
} }
@ -122,7 +122,7 @@ pub struct Point
#[derive(Debug)] #[derive(Debug)]
pub struct Endpoint pub struct Endpoint
{ {
flags: EndpointFlags, flags: EndpFlags,
adj_hi: Unit, adj_hi: Unit,
adj_lo: Unit, adj_lo: Unit,
pos: Point, pos: Point,
@ -184,7 +184,7 @@ pub struct Minf
} }
bitflags! { bitflags! {
pub struct EndpointFlags: u16 pub struct EndpFlags: u16
{ {
const Solid = 0x00_01; const Solid = 0x00_01;
const SameHeight = 0x00_02; const SameHeight = 0x00_02;

View File

@ -38,18 +38,18 @@ pub fn read_bitmap_area(mut im: Image8,
// clut_id = b.c_u32b(p+38)?; // clut_id = b.c_u32b(p+38)?;
if pitch_fl & 0x8000 == 0 { if pitch_fl & 0x8000 == 0 {
return Err(err_msg("PICT1 not supported")); bail!("PICT1 not supported");
} }
if right - left != w || bottom - top != h { 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 p += 46; // size of header
// get CLUT if packed // get CLUT if packed
let 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; p += sz;
Some(clut) Some(clut)
} else { } else {
@ -70,12 +70,13 @@ pub fn read_bitmap_area(mut im: Image8,
match depth { match depth {
1 | 2 | 4 | 8 => { 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 { if pitch < 8 && depth == 8 {
// uncompressed 8-bit colormap indices // uncompressed 8-bit colormap indices
for _ in 0..h { for _ in 0..h {
for _ in 0..w { 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 { } else if rle {
// RLE compressed 1, 2, 4 or 8 bit colormap indices // RLE compressed 1, 2, 4 or 8 bit colormap indices
for _ in 0..h { 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}; let d = if depth < 8 {expand_data(d, depth)?} else {d};
p += pp; p += pp;
for x in 0..w { 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 { } else if rle {
// RLE compressed R5G5B5 // RLE compressed R5G5B5
for _ in 0..h { 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; p += pp;
@ -133,7 +135,9 @@ pub fn read_bitmap_area(mut im: Image8,
if pack_typ != PACK_NOPAD { if pack_typ != PACK_NOPAD {
p += 1; 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; p += 3;
im.cr.push(Color8::new(r, g, b)); im.cr.push(Color8::new(r, g, b));
} }
@ -144,12 +148,14 @@ pub fn read_bitmap_area(mut im: Image8,
// RLE compressed RGB8 // RLE compressed RGB8
let pitch = pitch - w; // remove padding byte from pitch let pitch = pitch - w; // remove padding byte from pitch
for _ in 0..h { 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; p += pp;
for x in 0..w { 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)); im.cr.push(Color8::new(r, g, b));
} }
} }
@ -187,23 +193,23 @@ pub fn load_pict(b: &[u8]) -> ResultS<Image8>
match op { match op {
0x0098 => { 0x0098 => {
// PackBitsRect // PackBitsRect
return read_bitmap_area(im, &b[p..], true, false); return read_bitmap_area(im, c_data(b, p..)?, true, false);
} }
0x0099 => { 0x0099 => {
// PackBitsRgn // PackBitsRgn
return read_bitmap_area(im, &b[p..], true, true); return read_bitmap_area(im, c_data(b, p..)?, true, true);
} }
0x009a => { 0x009a => {
// DirectBitsRect // DirectBitsRect
return read_bitmap_area(im, &b[p..], false, false); return read_bitmap_area(im, c_data(b, p..)?, false, false);
} }
0x009b => { 0x009b => {
// DirectBitsRgn // DirectBitsRgn
return read_bitmap_area(im, &b[p..], false, true); return read_bitmap_area(im, c_data(b, p..)?, false, true);
} }
0x8200 => { 0x8200 => {
// CompressedQuickTime // CompressedQuickTime
return read_quicktime_c(im, &b[p..]); return read_quicktime_c(im, c_data(b, p..)?);
} }
0x00ff => { 0x00ff => {
// OpEndPic // OpEndPic
@ -259,7 +265,7 @@ pub fn load_pict(b: &[u8]) -> ResultS<Image8>
0x100..= 0x100..=
0x7fff => p += (op >> 8) as usize * 2, // Reserved 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<Color8>, usize)>
for i in 0..num { for i in 0..num {
// with device mapping, we ignore the index entirely // with device mapping, we ignore the index entirely
let n = if !dev {b[p + 1] as usize} else {i}; let n = if !dev {b.c_byte(p + 1)? as usize} else {i};
let r = b[p + 2]; let r = b.c_byte(p + 2)?;
let g = b[p + 4]; let g = b.c_byte(p + 4)?;
let b = b[p + 6]; let b = b.c_byte(p + 6)?;
if n >= clut.len() { 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; p += 8;
} }
@ -305,11 +311,11 @@ pub fn read_rle(b: &[u8], pitch: usize, ln: bool) -> ResultS<(Vec<u8>, usize)>
let sz = if pitch > 250 { let sz = if pitch > 250 {
(b.c_u16b(0)? as usize + 2, p += 2).0 (b.c_u16b(0)? as usize + 2, p += 2).0
} else { } else {
(b[0] as usize + 1, p += 1).0 (b.c_byte(0)? as usize + 1, p += 1).0
}; };
while p < sz { 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 cmp = szf & 0x80 != 0;
let len = if cmp {!szf + 2} else {szf + 1} as usize; let len = if cmp {!szf + 2} else {szf + 1} as usize;
@ -359,7 +365,7 @@ pub fn expand_data(b: Vec<u8>, depth: u16) -> ResultS<Vec<u8>>
4 => b.len() * 2, 4 => b.len() * 2,
2 => b.len() * 4, 2 => b.len() * 4,
1 => b.len() * 8, 1 => b.len() * 8,
_ => return Err(err_msg("invalid bit depth")), _ => bail!("invalid bit depth"),
}); });
for ch in b { for ch in b {
@ -367,7 +373,7 @@ pub fn expand_data(b: Vec<u8>, depth: u16) -> ResultS<Vec<u8>>
4 => {for i in 1..=0 {o.push(ch >> i * 4 & 0xFu8);}} // 2 nibbles 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 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 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"),
} }
} }

View File

@ -9,7 +9,8 @@ fn read_group(b: &[u8], text: &[u8]) -> ResultS<Group>
let start = b.c_u16b(6)? as usize; let start = b.c_u16b(6)? as usize;
let size = b.c_u16b(8)? as usize; let size = b.c_u16b(8)? as usize;
let lines = b.c_u16b(10)?; 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)?; let ttype = GroupType::from_repr(ttype)?;
Ok(Group{ttype, pdata, lines, text}) 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 mut p = 10; // size of header
let text_st = p + SIZE_GROUP * group_n + SIZE_FACE * face_n; 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 { let text = if encoded {
fuck_string(text) fuck_string(text)
} else { } else {
@ -49,12 +50,12 @@ fn read_terminal(b: &[u8]) -> ResultS<(usize, Terminal)>
}; };
for _ in 0..group_n { for _ in 0..group_n {
groups.push(read_group(&b[p..], &text)?); groups.push(read_group(c_data(b, p..)?, &text)?);
p += SIZE_GROUP; p += SIZE_GROUP;
} }
for _ in 0..face_n { for _ in 0..face_n {
faces.push(read_face(&b[p..])?); faces.push(read_face(c_data(b, p..)?)?);
p += SIZE_FACE; p += SIZE_FACE;
} }
@ -69,7 +70,7 @@ impl Chunker<Vec<Terminal>> for Terminal
let mut p = 0; let mut p = 0;
while p < b.len() { while p < b.len() {
let (size, trm) = read_terminal(&b[p..])?; let (size, trm) = read_terminal(c_data(b, p..)?)?;
v.push(trm); v.push(trm);
p += size; p += size;
} }

View File

@ -7,13 +7,9 @@ impl Wad<'_>
{ {
pub fn new(b: &[u8]) -> ResultS<Wad> pub fn new(b: &[u8]) -> ResultS<Wad>
{ {
if b.len() < 128 {
return Err(err_msg("not enough data for Wad header"));
}
let wadver = b.c_u16b(0)?; let wadver = b.c_u16b(0)?;
let dataver = b.c_u16b(2)?; 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)?; // crc = b.c_u32b(68)?;
let dirofs = b.c_u32b(72)? as usize; let dirofs = b.c_u32b(72)? as usize;
let numents = b.c_u16b(76)? as usize; let numents = b.c_u16b(76)? as usize;
@ -22,6 +18,7 @@ impl Wad<'_>
let wentsize = b.c_u16b(82)? as usize; let wentsize = b.c_u16b(82)? as usize;
// parent = b.c_u32b(84)?; // parent = b.c_u32b(84)?;
let wadver = Ver::from_repr(wadver)?; let wadver = Ver::from_repr(wadver)?;
let origname = mac_roman_conv(origname);
let is_old = match wadver { let is_old = match wadver {
Ver::Base => true, Ver::Base => true,
@ -31,11 +28,11 @@ impl Wad<'_>
let cnksize = if !is_old {16} else {12}; let cnksize = if !is_old {16} else {12};
if entsize != wentsize { if entsize != wentsize {
return Err(err_msg("invalid entry size")); bail!("invalid entry size");
} }
if cnksize != wcnksize { if cnksize != wcnksize {
return Err(err_msg("invalid chunk size")); bail!("invalid chunk size");
} }
let mut entries = EntryMap::new(); 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}; let index = if !is_old {b.c_u16b(p + 8)?} else {i as u16};
if offset + size > b.len() { 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 cnkdata = c_data(b, offset..offset + size)?;
let appdata = &b[p..p + appsize]; let chunks = get_chunks(cnkdata, cnksize)?;
let appdata = c_data(b, p..p + appsize)?;
entries.insert(index, Entry{chunks, appdata}); entries.insert(index, Entry{chunks, appdata});
@ -74,7 +72,7 @@ fn get_chunks(b: &[u8], cnksize: usize) -> ResultS<ChunkMap>
// pofs = b.c_u32b(p+12)?; // pofs = b.c_u32b(p+12)?;
let beg = p + cnksize; let beg = p + cnksize;
let end = beg + size; let end = beg + size;
chunks.insert(iden, &b[beg..end]); chunks.insert(iden, c_data(b, beg..end)?);
p = end; p = end;
} }