better and more error handling
parent
824ff5cdd2
commit
ab34bebcd5
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
32
src/main.rs
32
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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue