Add initial test code
commit
f5984c9739
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
perf.data*
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "maraiah"
|
||||
version = "0.1.0"
|
||||
authors = ["marrub"]
|
||||
|
||||
[dependencies]
|
||||
memmap = "0.6"
|
||||
#gtk = "0.4"
|
|
@ -0,0 +1,24 @@
|
|||
//! Binary data conversion utilities.
|
||||
|
||||
pub type Ident = [u8; 4];
|
||||
|
||||
pub fn b_iden(b: &[u8]) -> Ident {[b[0], b[1], b[2], b[3]]}
|
||||
|
||||
pub fn b_u32l(b: &[u8]) -> u32 {b[3] as (u32) << 24 | b[2] as (u32) << 16 |
|
||||
b[1] as (u32) << 8 | b[0] as u32}
|
||||
pub fn b_u16l(b: &[u8]) -> u16 {b[1] as (u16) << 8 | b[0] as u16}
|
||||
pub fn b_u32b(b: &[u8]) -> u32 {b[0] as (u32) << 24 | b[1] as (u32) << 16 |
|
||||
b[2] as (u32) << 8 | b[3] as u32}
|
||||
pub fn b_u16b(b: &[u8]) -> u16 {b[0] as (u16) << 8 | b[1] as u16}
|
||||
pub fn b_i32l(b: &[u8]) -> i32 {b_u32l(b) as i32}
|
||||
pub fn b_i16l(b: &[u8]) -> i16 {b_u16l(b) as i16}
|
||||
pub fn b_i32b(b: &[u8]) -> i32 {b_u32b(b) as i32}
|
||||
pub fn b_i16b(b: &[u8]) -> i16 {b_u16b(b) as i16}
|
||||
|
||||
pub fn d_u32b(n: u32) -> [u8; 4] {[(n >> 24) as u8, (n >> 16) as u8,
|
||||
(n >> 8) as u8, (n >> 0) as u8]}
|
||||
pub fn d_u16b(n: u16) -> [u8; 2] {[(n >> 8) as u8, (n >> 0) as u8]}
|
||||
pub fn d_i32b(n: i32) -> [u8; 4] {d_u32b(n as u32)}
|
||||
pub fn d_i16b(n: i16) -> [u8; 2] {d_u16b(n as u16)}
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,59 @@
|
|||
//! Image and color representations.
|
||||
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
/// RGBA8 color.
|
||||
#[derive(Clone)]
|
||||
pub struct Color
|
||||
{
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
pub a: u8,
|
||||
}
|
||||
|
||||
/// Image with width and height.
|
||||
pub struct Image
|
||||
{
|
||||
w: usize,
|
||||
h: usize,
|
||||
cr: Vec<Color>,
|
||||
}
|
||||
|
||||
impl Color
|
||||
{
|
||||
/// Converts a R5G5B5 format color to RGBA8.
|
||||
pub fn from_r5g5b5(rgb: u16) -> Color
|
||||
{
|
||||
Color{r: (rgb >> 10 ) as u8 * 8,
|
||||
g: (rgb >> 5 & 31) as u8 * 8,
|
||||
b: (rgb & 31) as u8 * 8,
|
||||
a: 255}
|
||||
}
|
||||
}
|
||||
|
||||
impl Image
|
||||
{
|
||||
/// Creates a new Image structure.
|
||||
pub fn new(w: usize, h: usize) -> Image
|
||||
{Image{w, h, cr: Vec::with_capacity(w as usize * h as usize)}}
|
||||
|
||||
pub fn w(&self) -> usize {self.w}
|
||||
pub fn h(&self) -> usize {self.h}
|
||||
}
|
||||
|
||||
impl Index<(usize, usize)> for Image
|
||||
{
|
||||
type Output = Color;
|
||||
|
||||
fn index(&self, (x, y): (usize, usize)) -> &Color
|
||||
{&self.cr[x + y * self.w]}
|
||||
}
|
||||
|
||||
impl IndexMut<(usize, usize)> for Image
|
||||
{
|
||||
fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Color
|
||||
{&mut self.cr[x + y * self.w]}
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,53 @@
|
|||
//! Macintosh archived format header utilities.
|
||||
|
||||
use durandal::bin::*;
|
||||
|
||||
/// Checks for an AppleSingle header. Returns offset to the resource fork.
|
||||
pub fn check_apple_single(b: &[u8]) -> usize
|
||||
{
|
||||
if b_u32b(&b[0..4]) != 0x51600 || b_u32b(&b[4..8]) != 0x20000
|
||||
{return 0}
|
||||
|
||||
let num = b_u16b(&b[24..26]) as usize;
|
||||
|
||||
for i in 0..num
|
||||
{
|
||||
let p = 26 + (12 * i);
|
||||
let fid = b_u32b(&b[p+0..p+ 4]);
|
||||
let ofs = b_u32b(&b[p+4..p+ 8]) as usize;
|
||||
let len = b_u32b(&b[p+8..p+12]) as usize;
|
||||
|
||||
if fid == 1 {return if ofs + len > b.len() {0} else {ofs}}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
/// Checks for a MacBin header. Returns offset to the resource fork.
|
||||
pub fn check_mac_bin(b: &[u8]) -> usize
|
||||
{
|
||||
if b[0] != 0 || b[1] > 63 || b[74] != 0 || b[123] > 0x81 {return 0}
|
||||
|
||||
let mut crc = 0;
|
||||
|
||||
for i in 0..124 {
|
||||
for j in 8..16
|
||||
{
|
||||
let d = b[i] as (u16) << j;
|
||||
if (d ^ crc) & 0x8000 != 0 {crc = crc << 1 ^ 0x1021}
|
||||
else {crc <<= 1}
|
||||
}
|
||||
}
|
||||
|
||||
if crc == b_u16b(&b[124..126]) {128} else {0}
|
||||
}
|
||||
|
||||
/// Reads a MacBin or AppleSingle header if there is one and returns the
|
||||
/// offset from the start of the header to the resource fork (if one is found.)
|
||||
pub fn try_mac_header(b: &[u8]) -> usize
|
||||
{
|
||||
let ofs = check_mac_bin(b);
|
||||
if ofs != 0 {ofs} else {check_apple_single(b)}
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,10 @@
|
|||
//! Library for file reading utilities and mac format utilities.
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub mod bin;
|
||||
pub mod machead;
|
||||
pub mod text;
|
||||
pub mod image;
|
||||
pub mod pict;
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,336 @@
|
|||
//! QuickDraw PICT format loader.
|
||||
|
||||
use durandal::image::*;
|
||||
use durandal::bin::*;
|
||||
|
||||
const PACK_DEFAULT: u16 = 0;
|
||||
const PACK_NONE : u16 = 1;
|
||||
const PACK_NOALPHA: u16 = 2;
|
||||
const PACK_RLE16 : u16 = 3;
|
||||
const PACK_RLE32 : u16 = 4;
|
||||
|
||||
struct PixMap
|
||||
{
|
||||
pack: u16,
|
||||
dept: u16,
|
||||
rle : bool,
|
||||
cmap: Vec<Color>,
|
||||
}
|
||||
|
||||
impl PixMap
|
||||
{
|
||||
fn empty() -> PixMap
|
||||
{PixMap{pack: PACK_DEFAULT, dept: 1, rle: false, cmap: Vec::new()}}
|
||||
|
||||
fn new(b: &[u8], packed: bool) -> (usize, PixMap)
|
||||
{
|
||||
// version = b_u16b(&b[ 0.. 2]);
|
||||
let pack = b_u16b(&b[ 2.. 4]);
|
||||
// packSize = b_u32b(&b[ 4.. 8]) as usize;
|
||||
// horzDPI = b_u32b(&b[ 8..12]);
|
||||
// vertDPI = b_u32b(&b[12..16]);
|
||||
// pixelType = b_u16b(&b[16..18]);
|
||||
let dept = b_u16b(&b[18..20]);
|
||||
// components = b_u16b(&b[20..22]);
|
||||
// compDepth = b_u16b(&b[22..24]);
|
||||
// planeOffs = b_u32b(&b[24..28]);
|
||||
// colorTable = b_u32b(&b[28..32]);
|
||||
// reserved = b_u32b(&b[32..36]);
|
||||
|
||||
let mut px = PixMap{
|
||||
pack,
|
||||
dept,
|
||||
rle: pack == PACK_DEFAULT ||
|
||||
(dept == 16 && pack == PACK_RLE16) ||
|
||||
(dept == 32 && pack == PACK_RLE32),
|
||||
cmap: Vec::new(),
|
||||
};
|
||||
|
||||
// if it's packed we need to grab the color map
|
||||
if packed
|
||||
{
|
||||
// table = b_u32b(&b[36..40]);
|
||||
let dev = b_u16b(&b[40..42]) & 0x8000 != 0;
|
||||
let colo = b_u16b(&b[42..44]) as usize + 1;
|
||||
|
||||
px.cmap.resize(colo as usize, Color{r: 0, g: 0, b: 0, a: 0});
|
||||
for i in 0..colo
|
||||
{
|
||||
let p = 44 + i * 8;
|
||||
let n = (b_u16b(&b[p+0..p+ 2]) & 0xff) as usize;
|
||||
let r = (b_u16b(&b[p+2..p+ 4]) / 257) as u8;
|
||||
let g = (b_u16b(&b[p+6..p+ 8]) / 257) as u8;
|
||||
let b = (b_u16b(&b[p+8..p+10]) / 257) as u8;
|
||||
|
||||
// with device mapping, we ignore the index entirely
|
||||
let n = if dev {i} else {n};
|
||||
|
||||
px.cmap[n] = Color{r, g, b, a: 255};
|
||||
}
|
||||
|
||||
(44 + colo * 8, px)
|
||||
}
|
||||
else
|
||||
{(36, px)}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read run-length encoded data.
|
||||
fn read_rle<T, F>(b: &[u8], long: bool, rd: F) -> Vec<T>
|
||||
where T: Copy,
|
||||
F: Fn(&mut usize) -> T
|
||||
{
|
||||
let (st, sz) = if long {(2usize, b_u16b(&b[0..2]) as usize)}
|
||||
else {(1usize, b[0] as usize)};
|
||||
|
||||
let mut o = Vec::with_capacity(sz);
|
||||
let mut p = st;
|
||||
|
||||
while p < sz
|
||||
{
|
||||
// size and flags are in one byte, we interpret it as a signed integer
|
||||
// because it's easier to handle
|
||||
let szf = b[(p, p += 1).0] as i8;
|
||||
let sz = if szf < 0 {-szf + 1} else {szf + 1};
|
||||
|
||||
o.reserve(sz as usize);
|
||||
|
||||
// either repeated or unique data
|
||||
if szf < 0 {let d = rd(&mut p); for _ in 0..sz { o.push(d)}}
|
||||
else {for _ in 0..sz {let d = rd(&mut p); o.push(d)}}
|
||||
}
|
||||
|
||||
o
|
||||
}
|
||||
|
||||
fn read_rle8(b: &[u8], long: bool) -> Vec<u8>
|
||||
{read_rle(b, long, |p| (b[*p], *p += 1).0)}
|
||||
|
||||
fn read_rle16(b: &[u8], long: bool) -> Vec<u16>
|
||||
{read_rle(b, long, |p| (b_u16b(&b[*p..*p+2]), *p += 2).0)}
|
||||
|
||||
/// Expand packed pixel data based on bit depth.
|
||||
fn expand_data(b: Vec<u8>, depth: u16) -> Result<Vec<u8>, &'static str>
|
||||
{
|
||||
let mut o = Vec::with_capacity(match depth {
|
||||
4 => b.len() * 2,
|
||||
2 => b.len() * 4,
|
||||
1 => b.len() * 8,
|
||||
_ => return Err("invalid bit depth")
|
||||
});
|
||||
|
||||
for ch in b
|
||||
{
|
||||
match depth {
|
||||
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("invalid bit depth")
|
||||
}
|
||||
}
|
||||
|
||||
Ok(o)
|
||||
}
|
||||
|
||||
/// Process a CopyBits operation.
|
||||
fn read_bitmap_area(mut im: Image, b: &[u8], packed: bool, clip: bool) -> Result<Image, &str>
|
||||
{
|
||||
let mut p = if !packed {/*baseAddress = b_u32b(&b[0..4]);*/ 4} else {0};
|
||||
|
||||
// get pitch and flags, flags are packed into the upper 2 bits
|
||||
let pf = b_u16b(&b[p..p+2]);
|
||||
let pm = pf & 0x8000 != 0;
|
||||
let pt = pf & 0x3fff;
|
||||
|
||||
let (w, h) = (im.w(), im.h());
|
||||
|
||||
let yb = b_u16b(&b[p+2..p+ 4]) as usize;
|
||||
let xb = b_u16b(&b[p+4..p+ 6]) as usize;
|
||||
let ye = b_u16b(&b[p+6..p+ 8]) as usize;
|
||||
let xe = b_u16b(&b[p+8..p+10]) as usize;
|
||||
|
||||
if xe - xb < w || ye - yb < h {return Err("image size is incorrect")}
|
||||
|
||||
let pxm =
|
||||
if pm {let (pp, pxm) = PixMap::new(&b[p+10..], packed); p += pp; pxm}
|
||||
else {PixMap::empty()};
|
||||
|
||||
if clip {let sz = b_u16b(&b[p..p+2]) as usize; p += sz}
|
||||
|
||||
match pxm.dept {
|
||||
1 | 2 | 4 | 8 =>
|
||||
// uncompressed 8-bit colormap indices
|
||||
if pt < 8 && pxm.dept == 8
|
||||
{
|
||||
for y in 0..h {
|
||||
for x in 0..w
|
||||
{im[(x, y)] = pxm.cmap[b[(p, p += 1).0] as usize].clone()}
|
||||
}
|
||||
|
||||
Ok(im)
|
||||
}
|
||||
|
||||
// RLE compressed 1, 2, 4 or 8 bit colormap indices
|
||||
else if pxm.rle
|
||||
{
|
||||
for y in 0..h
|
||||
{
|
||||
let d = read_rle8(&b[p..], pt > 250);
|
||||
let d = if pxm.dept < 8 {expand_data(d, pxm.dept)?} else {d};
|
||||
|
||||
for x in 0..w {im[(x, y)] = pxm.cmap[d[x] as usize].clone()}
|
||||
}
|
||||
|
||||
Ok(im)
|
||||
}
|
||||
|
||||
// invalid
|
||||
else {Err("invalid configuration")},
|
||||
16 =>
|
||||
// uncompressed R5G5B5
|
||||
if pt < 8 || pxm.pack == PACK_NONE
|
||||
{
|
||||
for y in 0..h {
|
||||
for x in 0..w
|
||||
{im[(x, y)] = Color::from_r5g5b5(b_u16b((&b[p..p+2], p += 2).0))}
|
||||
}
|
||||
|
||||
Ok(im)
|
||||
}
|
||||
|
||||
// RLE compressed R5G5B5
|
||||
else if pxm.rle
|
||||
{
|
||||
for y in 0..h
|
||||
{
|
||||
let d = read_rle16(&b[p..], pt > 250);
|
||||
for x in 0..w {im[(x, y)] = Color::from_r5g5b5(d[x])}
|
||||
}
|
||||
|
||||
Ok(im)
|
||||
}
|
||||
|
||||
// invalid
|
||||
else {Err("invalid configuration")},
|
||||
32 =>
|
||||
// uncompressed RGB8 or ARGB8
|
||||
if pt < 8 || pxm.pack == PACK_NONE || pxm.pack == PACK_NOALPHA
|
||||
{
|
||||
for y in 0..h {
|
||||
for x in 0..w
|
||||
{
|
||||
let a = if pxm.pack != PACK_NOALPHA {(b[p], p += 1).0} else {255};
|
||||
let r = b[p+0];
|
||||
let g = b[p+1];
|
||||
let b = b[p+2];
|
||||
p += 3;
|
||||
im[(x, y)] = Color{r, g, b, a};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(im)
|
||||
}
|
||||
|
||||
// RLE compressed RGB8
|
||||
else if pxm.rle
|
||||
{
|
||||
for y in 0..h
|
||||
{
|
||||
let d = read_rle8(&b[p..], pt > 250);
|
||||
for x in 0..w
|
||||
{
|
||||
let r = d[x + w * 0];
|
||||
let g = d[x + w * 1];
|
||||
let b = d[x + w * 2];
|
||||
im[(x, y)] = Color{r, g, b, a: 255};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(im)
|
||||
}
|
||||
|
||||
// invalid
|
||||
else {Err("invalid configuration")},
|
||||
_ => Err("invalid bit depth")
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a CompressedQuickTime operation.
|
||||
fn read_quicktime_c(_im: Image, _b: &[u8]) -> Result<Image, &str>
|
||||
{Err("compressed quicktime format not implemented")}
|
||||
|
||||
/// Load a PICT image.
|
||||
pub fn load_pict(b: &[u8]) -> Result<Image, &str>
|
||||
{
|
||||
// size = b_u16b(&b[0.. 2]);
|
||||
// top = b_u16b(&b[2.. 4]);
|
||||
// left = b_u16b(&b[4.. 6]);
|
||||
let w = b_u16b(&b[6.. 8]) as usize;
|
||||
let h = b_u16b(&b[8..10]) as usize;
|
||||
let im = Image::new(w, h);
|
||||
let mut p = 10;
|
||||
|
||||
while p < b.len()
|
||||
{
|
||||
let op = b_u16b(&b[p..p+2]);
|
||||
p += 2;
|
||||
match op {
|
||||
0x0098 => return read_bitmap_area(im, &b[p..], true, false), // PackBitsRect
|
||||
0x0099 => return read_bitmap_area(im, &b[p..], true, true ), // PackBitsRgn
|
||||
0x009a => return read_bitmap_area(im, &b[p..], false, false), // DirectBitsRect
|
||||
0x009b => return read_bitmap_area(im, &b[p..], false, true ), // DirectBitsRgn
|
||||
0x8200 => return read_quicktime_c(im, &b[p..]), // CompressedQuickTime
|
||||
0x00ff => break, // OpEndPic
|
||||
// help i'm trapped in an awful metafile format from the 80s
|
||||
0x0000 => (), // NoOp
|
||||
0x001c => (), // HiliteMode
|
||||
0x001e => (), // DefHilite
|
||||
0x0038 => (), // FrameSameRect
|
||||
0x0039 => (), // PaintSameRect
|
||||
0x003a => (), // EraseSameRect
|
||||
0x003b => (), // InvertSameRect
|
||||
0x003c => (), // FillSameRect
|
||||
0x8000 => (), // Reserved
|
||||
0x8100 => (), // Reserved
|
||||
0x0003 => p += 2, // TxFont
|
||||
0x0004 => p += 2, // TxFace
|
||||
0x0005 => p += 2, // TxMode
|
||||
0x0008 => p += 2, // PnMode
|
||||
0x000d => p += 2, // TxSize
|
||||
0x0011 => p += 2, // VersionOp
|
||||
0x0015 => p += 2, // PnLocHFrac
|
||||
0x0016 => p += 2, // ChExtra
|
||||
0x0023 => p += 2, // ShortLineFrom
|
||||
0x00a0 => p += 2, // ShortComment
|
||||
0x02ff => p += 2, // Version
|
||||
0x0006 => p += 4, // SpExtra
|
||||
0x0007 => p += 4, // PnSize
|
||||
0x000b => p += 4, // OvSize
|
||||
0x000c => p += 4, // Origin
|
||||
0x000e => p += 4, // FgCol
|
||||
0x000f => p += 4, // BkCol
|
||||
0x0021 => p += 4, // LineFrom
|
||||
0x001a => p += 6, // RGBFgCol
|
||||
0x001b => p += 6, // RGBBkCol
|
||||
0x001d => p += 6, // TxRatio
|
||||
0x0022 => p += 6, // ShortLine
|
||||
0x0002 => p += 8, // BkPat
|
||||
0x0009 => p += 8, // PnPat
|
||||
0x0010 => p += 8, // TxRatio
|
||||
0x0020 => p += 8, // Line
|
||||
0x002e => p += 8, // GlyphState
|
||||
0x0030 => p += 8, // FrameRect
|
||||
0x0031 => p += 8, // PaintRect
|
||||
0x0032 => p += 8, // EraseRect
|
||||
0x0033 => p += 8, // InvertRect
|
||||
0x0034 => p += 8, // FillRect
|
||||
0x002d => p += 10, // LineJustify
|
||||
0x0c00 => p += 24, // HeaderOp
|
||||
_ =>
|
||||
if op >= 0x100 && op <= 0x7fff {p += ((op as usize & 0xff00) >> 8) * 2}
|
||||
else {return Err("invalid opcode in PICT")}
|
||||
}
|
||||
}
|
||||
|
||||
Err("no image in data")
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
//! Text conversion utilities.
|
||||
|
||||
/// Formats a binary size string for any given number.
|
||||
pub fn to_binsize(n: u64) -> String
|
||||
{
|
||||
let names = ["kB", "MB", "GB", "TB"];
|
||||
|
||||
// empty size
|
||||
if n == 0 {return String::from("empty")}
|
||||
|
||||
// terabytes, gigabytes, megabytes, kilobytes
|
||||
for i in 4..=1
|
||||
{
|
||||
if n >= 1000u64.pow(i)
|
||||
{
|
||||
let x = n as f64 / 1000f64.powi(i as i32);
|
||||
return format!("{:1}{}", x, names[i as usize - 1])
|
||||
}
|
||||
}
|
||||
|
||||
// or, just bytes
|
||||
format!("{} {}", n, if n != 1 {"bytes"} else {"byte"})
|
||||
}
|
||||
|
||||
/// Encodes or decodes a string in the terminal encryption format.
|
||||
pub fn fuck_string(s: &[u8]) -> Vec<u8>
|
||||
{
|
||||
let mut v = s.to_vec();
|
||||
let l = s.len();
|
||||
let mut p = 0;
|
||||
|
||||
for _ in 0..l / 4 {p += 2; v[p] ^= 0xfe; v[p + 1] ^= 0xed; p += 2}
|
||||
for _ in 0..l % 4 {v[p] ^= 0xfe; p += 1}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
/// Converts input from Mac Roman to a Unicode string.
|
||||
pub fn mac_roman_conv(s: &[u8]) -> String
|
||||
{
|
||||
let tr = [
|
||||
'\u{00c4}', '\u{00c5}', '\u{00c7}', '\u{00c9}',
|
||||
'\u{00d1}', '\u{00d6}', '\u{00dc}', '\u{00e1}',
|
||||
'\u{00e0}', '\u{00e2}', '\u{00e4}', '\u{00e3}',
|
||||
'\u{00e5}', '\u{00e7}', '\u{00e9}', '\u{00e8}',
|
||||
'\u{00ea}', '\u{00eb}', '\u{00ed}', '\u{00ec}',
|
||||
'\u{00ee}', '\u{00ef}', '\u{00f1}', '\u{00f3}',
|
||||
'\u{00f2}', '\u{00f4}', '\u{00f6}', '\u{00f5}',
|
||||
'\u{00fa}', '\u{00f9}', '\u{00fb}', '\u{00fc}',
|
||||
'\u{2020}', '\u{00b0}', '\u{00a2}', '\u{00a3}',
|
||||
'\u{00a7}', '\u{2022}', '\u{00b6}', '\u{00df}',
|
||||
'\u{00ae}', '\u{00a9}', '\u{2122}', '\u{00b4}',
|
||||
'\u{00a8}', '\u{2260}', '\u{00c6}', '\u{00d8}',
|
||||
'\u{221e}', '\u{00b1}', '\u{2264}', '\u{2265}',
|
||||
'\u{00a5}', '\u{00b5}', '\u{2202}', '\u{2211}',
|
||||
'\u{220f}', '\u{03c0}', '\u{222b}', '\u{00aa}',
|
||||
'\u{00ba}', '\u{03a9}', '\u{00e6}', '\u{00f8}',
|
||||
'\u{00bf}', '\u{00a1}', '\u{00ac}', '\u{221a}',
|
||||
'\u{0192}', '\u{2248}', '\u{2206}', '\u{00ab}',
|
||||
'\u{00bb}', '\u{2026}', '\u{00a0}', '\u{00c0}',
|
||||
'\u{00c3}', '\u{00d5}', '\u{0152}', '\u{0153}',
|
||||
'\u{2013}', '\u{2014}', '\u{201c}', '\u{201d}',
|
||||
'\u{2018}', '\u{2019}', '\u{00f7}', '\u{25ca}',
|
||||
'\u{00ff}', '\u{0178}', '\u{2044}', '\u{20ac}',
|
||||
'\u{2039}', '\u{203a}', '\u{fb01}', '\u{fb02}',
|
||||
'\u{2021}', '\u{00b7}', '\u{201a}', '\u{201e}',
|
||||
'\u{2030}', '\u{00c2}', '\u{00ca}', '\u{00c1}',
|
||||
'\u{00cb}', '\u{00c8}', '\u{00cd}', '\u{00ce}',
|
||||
'\u{00cf}', '\u{00cc}', '\u{00d3}', '\u{00d4}',
|
||||
'\u{f8ff}', '\u{00d2}', '\u{00da}', '\u{00db}',
|
||||
'\u{00d9}', '\u{0131}', '\u{02c6}', '\u{02dc}',
|
||||
'\u{00af}', '\u{02d8}', '\u{02d9}', '\u{02da}',
|
||||
'\u{00b8}', '\u{02dd}', '\u{02db}', '\u{02c7}'
|
||||
];
|
||||
|
||||
let l = s.len();
|
||||
let mut v = String::with_capacity(l);
|
||||
|
||||
for i in 0..l
|
||||
{
|
||||
if s[i] == 0 {break}
|
||||
|
||||
if s[i] & 0x80 != 0 {v.push(tr[s[i] as usize & 0x7f])}
|
||||
else if s[i] == b'\r' {v.push('\n')}
|
||||
else {v.push(s[i] as char)}
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,47 @@
|
|||
extern crate memmap;
|
||||
|
||||
pub mod durandal;
|
||||
pub mod marathon;
|
||||
|
||||
use std::{io, fs};
|
||||
use memmap::Mmap;
|
||||
|
||||
fn main() -> io::Result<()>
|
||||
{
|
||||
let fp = fs::File::open("data/Rubicon Map.sceA")?;
|
||||
let mm = unsafe{Mmap::map(&fp)?};
|
||||
println!("{:?}", marathon::wad::Wad::new(&mm));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
extern crate gtk;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, Window, WindowType};
|
||||
|
||||
fn main()
|
||||
{
|
||||
if gtk::init().is_err() {
|
||||
println!("failed to initialize GTK");
|
||||
return
|
||||
}
|
||||
|
||||
let win = Window::new(WindowType::Toplevel);
|
||||
win.set_title("GTK test");
|
||||
win.set_default_size(350, 70);
|
||||
let btn = Button::new_with_label("butts");
|
||||
win.add(&btn);
|
||||
win.show_all();
|
||||
|
||||
win.connect_delete_event(|_, _| {
|
||||
gtk::main_quit();
|
||||
Inhibit(false)
|
||||
});
|
||||
|
||||
btn.connect_clicked(|_| {println!("clicc");});
|
||||
|
||||
gtk::main();
|
||||
}
|
||||
*/
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,5 @@
|
|||
//! Library for Marathon data formats.
|
||||
|
||||
pub mod wad;
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,100 @@
|
|||
//! Marathon Wad format handling.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
||||
use durandal::bin::*;
|
||||
use durandal::machead::try_mac_header;
|
||||
use durandal::text::mac_roman_conv;
|
||||
|
||||
type Chunk <'a> = &'a[u8];
|
||||
type ChunkMap<'a> = BTreeMap<Ident, Chunk<'a>>;
|
||||
type EntryMap<'a> = BTreeMap<u16 , Entry<'a>>;
|
||||
|
||||
pub struct Entry<'a>
|
||||
{
|
||||
map: ChunkMap<'a>,
|
||||
ext: &'a[u8],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Wad<'a>
|
||||
{
|
||||
ver: u16,
|
||||
dvr: u16,
|
||||
ext: usize,
|
||||
nam: String,
|
||||
ent: EntryMap<'a>,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Entry<'a>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
|
||||
{
|
||||
write!(f, "Entry {{ ")?;
|
||||
for (k, _) in &self.map {write!(f, "{} ", mac_roman_conv(&k[..]))?}
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Wad<'a>
|
||||
{
|
||||
pub fn new(b: &[u8]) -> Wad
|
||||
{
|
||||
let b = &b[try_mac_header(b)..];
|
||||
let ver = b_u16b(&b[ 0.. 2]);
|
||||
let dvr = b_u16b(&b[ 2.. 4]);
|
||||
let nam = &b[ 4..68];
|
||||
let crc = b_u32b(&b[68..72]);
|
||||
let dir = b_u32b(&b[72..76]) as usize;
|
||||
let num = b_u16b(&b[76..78]) as usize;
|
||||
let ext = b_u16b(&b[78..80]) as usize;
|
||||
|
||||
println!("{:x}", crc);
|
||||
|
||||
Wad{ver, dvr, ext,
|
||||
nam: mac_roman_conv(nam),
|
||||
ent: get_entries(num, ext, dir, b)}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_entries(num: usize, ext: usize, dir: usize, b: &[u8]) -> EntryMap
|
||||
{
|
||||
let mut p = dir;
|
||||
let mut map = EntryMap::new();
|
||||
|
||||
for _ in 0..num
|
||||
{
|
||||
let ofs = b_u32b(&b[p+0..p+ 4]) as usize;
|
||||
let len = b_u32b(&b[p+4..p+ 8]) as usize;
|
||||
let ind = b_u16b(&b[p+8..p+10]);
|
||||
let ent = Entry{map: get_chunks(&b[ ofs.. ofs+len]),
|
||||
ext: &b[p+10..p+10+ext]};
|
||||
|
||||
map.insert(ind, ent);
|
||||
|
||||
p += 10 + ext;
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
fn get_chunks(b: &[u8]) -> ChunkMap
|
||||
{
|
||||
let mut p = 0;
|
||||
let mut map = ChunkMap::new();
|
||||
|
||||
while p < b.len()
|
||||
{
|
||||
let k = b_iden(&b[p+ 0..p+ 4]);
|
||||
// nx = b_u32b(&b[p+ 4..p+ 8]);
|
||||
let l = b_u32b(&b[p+ 8..p+12]) as usize;
|
||||
// ?? = b_u32b(&b[p+12..p+16]);
|
||||
map.insert(k, &b[p+16..p+ l]);
|
||||
p += l + 16;
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
// EOF
|
Loading…
Reference in New Issue