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 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
{
/// 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`.
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`.
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`.
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`.
fn c_i32b(&self, i: usize) -> ResultS<i32>
{
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<i16>
{
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<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`.
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`.
/// Returns a big-endian `i16` from `self` at `i`.
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]
{
fn c_iden(&self, i: usize) -> ResultS<Ident>
fn c_byte(&self, i: usize) -> ResultS<u8>
{
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<u32>
fn o_iden(&self, i: usize) -> Option<Ident>
{
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<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() {
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<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()),
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<NonZeroU16>);
// EOF

View File

@ -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
}

View File

@ -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<T>(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<T> Fail for ReprError<T> where T: PrimInt {}
impl Fail for ErrMsg {}
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>;
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<T>(pub T) where T: PrimInt;
struct ErrMsg(&'static str);
pub type ResultS<T> = Result<T, Error>;
// 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 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}

View File

@ -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;

View File

@ -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<u8>
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<u8>
}
/// 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.

View File

@ -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),

View File

@ -6,7 +6,7 @@ use crate::durandal::bin::*;
pub fn check_apple_single(b: &[u8]) -> Option<usize>
{
// 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<usize>
pub fn check_macbin(b: &[u8]) -> Option<usize>
{
// 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;
}

View File

@ -23,9 +23,9 @@ impl Chunked<Endpoint> 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<Line> 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<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 = ObjID::from_repr(tex_id);
Ok(SideTex{offs, tex_id})
@ -71,20 +71,20 @@ impl Chunked<Side> 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<Minf> 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;

View File

@ -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<Image8>
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<Image8>
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<Color8>, 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<u8>, 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<u8>, depth: u16) -> ResultS<Vec<u8>>
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<u8>, depth: u16) -> ResultS<Vec<u8>>
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"),
}
}

View File

@ -9,7 +9,8 @@ fn read_group(b: &[u8], text: &[u8]) -> ResultS<Group>
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<Vec<Terminal>> 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;
}

View File

@ -7,13 +7,9 @@ impl 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 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<ChunkMap>
// 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;
}