normalize line endings
parent
69063cc41a
commit
dd5bf03252
|
@ -1,28 +1,28 @@
|
||||||
//! Cyclic redundancy check function.
|
//! Cyclic redundancy check function.
|
||||||
|
|
||||||
fn crc_accum(a: u32) -> u32
|
fn crc_accum(a: u32) -> u32
|
||||||
{
|
{
|
||||||
if a & 1 == 1 {0xedb88320 ^ a >> 1}
|
if a & 1 == 1 {0xedb88320 ^ a >> 1}
|
||||||
else {a >> 1}
|
else {a >> 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn crc_init() -> [u32; 256]
|
fn crc_init() -> [u32; 256]
|
||||||
{
|
{
|
||||||
let mut t = [0; 256];
|
let mut t = [0; 256];
|
||||||
for n in 0..256 {t[n] = (0..8).fold(n as u32, |a, _| crc_accum(a));}
|
for n in 0..256 {t[n] = (0..8).fold(n as u32, |a, _| crc_accum(a));}
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn crc32(b: &[u8], s: u32) -> u32
|
pub fn crc32(b: &[u8], s: u32) -> u32
|
||||||
{
|
{
|
||||||
let t = crc_init();
|
let t = crc_init();
|
||||||
!b.iter().fold(s, |a, &o| {a >> 8 ^ t[(a & 0xff ^ o as u32) as usize]})
|
!b.iter().fold(s, |a, &o| {a >> 8 ^ t[(a & 0xff ^ o as u32) as usize]})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crc32_lorem_ipsum()
|
fn crc32_lorem_ipsum()
|
||||||
{
|
{
|
||||||
assert_eq!(crc32(b"Lorem ipsum dolor sit amet", !0), 0x5F29D461);
|
assert_eq!(crc32(b"Lorem ipsum dolor sit amet", !0), 0x5F29D461);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! Library for file data formats.
|
//! Library for file data formats.
|
||||||
|
|
||||||
pub mod machdr;
|
pub mod machdr;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod pict;
|
pub mod pict;
|
||||||
pub mod term;
|
pub mod term;
|
||||||
pub mod wad;
|
pub mod wad;
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -1,135 +1,135 @@
|
||||||
use crate::durandal::{bin::*, chunk::*, err::*, text::*};
|
use crate::durandal::{bin::*, chunk::*, err::*, text::*};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
fn read_group(b: &[u8], text: &[u8]) -> ResultS<Group>
|
fn read_group(b: &[u8], text: &[u8]) -> ResultS<Group>
|
||||||
{
|
{
|
||||||
// flags = b.c_u16b( 0)?;
|
// flags = b.c_u16b( 0)?;
|
||||||
let ttype = b.c_u16b( 2)?;
|
let ttype = b.c_u16b( 2)?;
|
||||||
let pdata = b.c_i16b( 4)?;
|
let pdata = b.c_i16b( 4)?;
|
||||||
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 = mac_roman_conv(&text[start..start+size]);
|
||||||
let ttype = GroupType::from_repr(ttype)?;
|
let ttype = GroupType::from_repr(ttype)?;
|
||||||
|
|
||||||
Ok(Group{ttype, pdata, lines, text})
|
Ok(Group{ttype, pdata, lines, text})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_face(b: &[u8]) -> ResultS<Face>
|
fn read_face(b: &[u8]) -> ResultS<Face>
|
||||||
{
|
{
|
||||||
let start = b.c_u16b(0)? as usize;
|
let start = b.c_u16b(0)? as usize;
|
||||||
let face = b.c_u16b(2)?;
|
let face = b.c_u16b(2)?;
|
||||||
let color = b.c_u16b(4)?;
|
let color = b.c_u16b(4)?;
|
||||||
|
|
||||||
Ok(Face{start, face, color})
|
Ok(Face{start, face, color})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_terminal(b: &[u8]) -> ResultS<(usize, Terminal)>
|
fn read_terminal(b: &[u8]) -> ResultS<(usize, Terminal)>
|
||||||
{
|
{
|
||||||
const SIZE_GROUP: usize = 12;
|
const SIZE_GROUP: usize = 12;
|
||||||
const SIZE_FACE : usize = 6;
|
const SIZE_FACE : usize = 6;
|
||||||
|
|
||||||
let end = b.c_u16b(0)? as usize;
|
let end = b.c_u16b(0)? as usize;
|
||||||
let encoded = b.c_u16b(2)? & 1 != 0;
|
let encoded = b.c_u16b(2)? & 1 != 0;
|
||||||
let lines = b.c_u16b(4)?;
|
let lines = b.c_u16b(4)?;
|
||||||
let group_n = b.c_u16b(6)? as usize;
|
let group_n = b.c_u16b(6)? as usize;
|
||||||
let face_n = b.c_u16b(8)? as usize;
|
let face_n = b.c_u16b(8)? as usize;
|
||||||
|
|
||||||
let mut groups = Vec::with_capacity(group_n);
|
let mut groups = Vec::with_capacity(group_n);
|
||||||
let mut faces = Vec::with_capacity( face_n);
|
let mut faces = Vec::with_capacity( face_n);
|
||||||
|
|
||||||
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 = &b[text_st..end];
|
||||||
let text = if encoded {fuck_string(text)} else {text.to_vec()};
|
let text = if encoded {fuck_string(text)} else {text.to_vec()};
|
||||||
|
|
||||||
for _ in 0..group_n {
|
for _ in 0..group_n {
|
||||||
groups.push(read_group(&b[p..], &text)?);
|
groups.push(read_group(&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(&b[p..])?);
|
||||||
p += SIZE_FACE;
|
p += SIZE_FACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((end, Terminal{lines, groups, faces}))
|
Ok((end, Terminal{lines, groups, faces}))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunker<Vec<Terminal>> for Terminal
|
impl Chunker<Vec<Terminal>> for Terminal
|
||||||
{
|
{
|
||||||
fn chunk(b: &[u8]) -> ResultS<Vec<Terminal>>
|
fn chunk(b: &[u8]) -> ResultS<Vec<Terminal>>
|
||||||
{
|
{
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
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(&b[p..])?;
|
||||||
v.push(trm);
|
v.push(trm);
|
||||||
p += size;
|
p += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Terminal
|
pub struct Terminal
|
||||||
{
|
{
|
||||||
lines: u16,
|
lines: u16,
|
||||||
groups: Vec<Group>,
|
groups: Vec<Group>,
|
||||||
faces: Vec<Face>,
|
faces: Vec<Face>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Face
|
pub struct Face
|
||||||
{
|
{
|
||||||
start: usize,
|
start: usize,
|
||||||
face: u16,
|
face: u16,
|
||||||
color: u16,
|
color: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Group
|
pub struct Group
|
||||||
{
|
{
|
||||||
ttype: GroupType,
|
ttype: GroupType,
|
||||||
pdata: i16,
|
pdata: i16,
|
||||||
lines: u16,
|
lines: u16,
|
||||||
text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
c_enum! {
|
c_enum! {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum GroupType: u16
|
pub enum GroupType: u16
|
||||||
{
|
{
|
||||||
0 => Logon,
|
0 => Logon,
|
||||||
1 => Unfinished,
|
1 => Unfinished,
|
||||||
2 => Success,
|
2 => Success,
|
||||||
3 => Failure,
|
3 => Failure,
|
||||||
4 => Info,
|
4 => Info,
|
||||||
5 => End,
|
5 => End,
|
||||||
6 => TeleInter,
|
6 => TeleInter,
|
||||||
7 => TeleIntra,
|
7 => TeleIntra,
|
||||||
8 => Checkpoint,
|
8 => Checkpoint,
|
||||||
9 => Sound,
|
9 => Sound,
|
||||||
10 => Movie,
|
10 => Movie,
|
||||||
11 => Track,
|
11 => Track,
|
||||||
12 => Pict,
|
12 => Pict,
|
||||||
13 => Logoff,
|
13 => Logoff,
|
||||||
14 => Camera,
|
14 => Camera,
|
||||||
15 => Static,
|
15 => Static,
|
||||||
16 => Tag,
|
16 => Tag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Group
|
impl fmt::Debug for Group
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
|
||||||
{
|
{
|
||||||
write!(f, "Group{{{:?} {} {}", self.ttype, self.pdata, self.lines)?;
|
write!(f, "Group{{{:?} {} {}", self.ttype, self.pdata, self.lines)?;
|
||||||
if self.text.len() != 0 {write!(f, ";\n{}", self.text)?;}
|
if self.text.len() != 0 {write!(f, ";\n{}", self.text)?;}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -1,114 +1,114 @@
|
||||||
//! Marathon Wad format handling.
|
//! Marathon Wad format handling.
|
||||||
|
|
||||||
use crate::durandal::{bin::*, err::*, text::mac_roman_conv};
|
use crate::durandal::{bin::*, err::*, text::mac_roman_conv};
|
||||||
use std::{collections::BTreeMap, fmt};
|
use std::{collections::BTreeMap, fmt};
|
||||||
|
|
||||||
impl Wad<'_>
|
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"));}
|
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 = mac_roman_conv(&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;
|
||||||
let appsize = b.c_u16b(78)? as usize;
|
let appsize = b.c_u16b(78)? as usize;
|
||||||
let wcnksize = b.c_u16b(80)? as usize;
|
let wcnksize = b.c_u16b(80)? as usize;
|
||||||
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 is_old = match wadver {Ver::Base => true, _ => false};
|
let is_old = match wadver {Ver::Base => true, _ => false};
|
||||||
let entsize = if !is_old {10} else {8 };
|
let entsize = if !is_old {10} else {8 };
|
||||||
let cnksize = if !is_old {16} else {12};
|
let cnksize = if !is_old {16} else {12};
|
||||||
|
|
||||||
if entsize != wentsize {return Err(err_msg("invalid entry size"));}
|
if entsize != wentsize {return Err(err_msg("invalid entry size"));}
|
||||||
if cnksize != wcnksize {return Err(err_msg("invalid chunk size"));}
|
if cnksize != wcnksize {return Err(err_msg("invalid chunk size"));}
|
||||||
|
|
||||||
let mut entries = EntryMap::new();
|
let mut entries = EntryMap::new();
|
||||||
let mut p = dirofs;
|
let mut p = dirofs;
|
||||||
|
|
||||||
for i in 0..numents {
|
for i in 0..numents {
|
||||||
let offset = b.c_u32b(p )? as usize;
|
let offset = b.c_u32b(p )? as usize;
|
||||||
let size = b.c_u32b(p+4)? as usize;
|
let size = b.c_u32b(p+4)? as usize;
|
||||||
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() {return Err(err_msg("not enough data for entry"));}
|
if offset + size > b.len() {return Err(err_msg("not enough data for entry"));}
|
||||||
|
|
||||||
let chunks = get_chunks(&b[offset..offset+size], cnksize)?;
|
let chunks = get_chunks(&b[offset..offset+size], cnksize)?;
|
||||||
let appdata = &b[p..p+appsize];
|
let appdata = &b[p..p+appsize];
|
||||||
|
|
||||||
entries.insert(index, Entry{chunks, appdata});
|
entries.insert(index, Entry{chunks, appdata});
|
||||||
|
|
||||||
p += entsize + appsize;
|
p += entsize + appsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Wad{wadver, dataver, appsize, origname, entries})
|
Ok(Wad{wadver, dataver, appsize, origname, entries})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_chunks(b: &[u8], cnksize: usize) -> ResultS<ChunkMap>
|
fn get_chunks(b: &[u8], cnksize: usize) -> ResultS<ChunkMap>
|
||||||
{
|
{
|
||||||
let mut chunks = ChunkMap::new();
|
let mut chunks = ChunkMap::new();
|
||||||
let mut p = 0;
|
let mut p = 0;
|
||||||
|
|
||||||
while p < b.len() {
|
while p < b.len() {
|
||||||
let iden = b.c_iden(p )?;
|
let iden = b.c_iden(p )?;
|
||||||
// ofs = b.c_u32b(p+ 4)?;
|
// ofs = b.c_u32b(p+ 4)?;
|
||||||
let size = b.c_u32b(p+ 8)? as usize;
|
let size = b.c_u32b(p+ 8)? as usize;
|
||||||
// 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, &b[beg..end]);
|
||||||
p = end;
|
p = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(chunks)
|
Ok(chunks)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Chunk <'a> = &'a[u8];
|
type Chunk <'a> = &'a[u8];
|
||||||
type ChunkMap<'a> = BTreeMap<Ident, Chunk<'a>>;
|
type ChunkMap<'a> = BTreeMap<Ident, Chunk<'a>>;
|
||||||
type EntryMap<'a> = BTreeMap<u16 , Entry<'a>>;
|
type EntryMap<'a> = BTreeMap<u16 , Entry<'a>>;
|
||||||
|
|
||||||
pub struct Entry<'a>
|
pub struct Entry<'a>
|
||||||
{
|
{
|
||||||
pub chunks: ChunkMap<'a>,
|
pub chunks: ChunkMap<'a>,
|
||||||
pub appdata: &'a[u8],
|
pub appdata: &'a[u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Wad<'a>
|
pub struct Wad<'a>
|
||||||
{
|
{
|
||||||
wadver: Ver,
|
wadver: Ver,
|
||||||
dataver: u16,
|
dataver: u16,
|
||||||
origname: String,
|
origname: String,
|
||||||
appsize: usize,
|
appsize: usize,
|
||||||
pub entries: EntryMap<'a>,
|
pub entries: EntryMap<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
c_enum! {
|
c_enum! {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Ver: u16
|
pub enum Ver: u16
|
||||||
{
|
{
|
||||||
0 => Base,
|
0 => Base,
|
||||||
1 => Dir,
|
1 => Dir,
|
||||||
2 => Over,
|
2 => Over,
|
||||||
4 => Inf,
|
4 => Inf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Entry<'_>
|
impl fmt::Debug for Entry<'_>
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
|
||||||
{
|
{
|
||||||
write!(f, "Entry{{ ")?;
|
write!(f, "Entry{{ ")?;
|
||||||
for (iden, _) in &self.chunks {write!(f, "{} ", mac_roman_conv(iden))?;}
|
for (iden, _) in &self.chunks {write!(f, "{} ", mac_roman_conv(iden))?;}
|
||||||
if self.appdata.len() != 0 {write!(f, "\nappdata: {:?} ", self.appdata)?;}
|
if self.appdata.len() != 0 {write!(f, "\nappdata: {:?} ", self.appdata)?;}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
Loading…
Reference in New Issue