1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
#![feature(ascii_char, iter_array_chunks)]
mod interpreter;
mod glk;
use interpreter::Interpreter;
use std::{env, fs, process::exit};
const MAJOR_VERSION : u16 = 3;
const MINOR_VERSION : u8 = 1;
const PATCH_VERSION : u8 = 3;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("No story file specified");
exit(1);
}
if args.len() > 2 {
println!("Too many arguments");
exit(1);
}
let path = &args[1];
let file_data: Vec<u8> = fs::read(path).expect("Could not open file");
let _magic_number = &file_data[0..4]
.as_ascii()
.map(|mn| if mn.as_str().eq("Glul") {Some(mn.as_str())} else {None})
.flatten()
.unwrap_or_else(|| panic!("Invalid magic number: {} {} {} {}", file_data[0], file_data[1], file_data[2], file_data[3]));
let version_major = u16::from_be_bytes(file_data[4..6].try_into().unwrap());
let version_minor = file_data[6];
let version_patch = file_data[7];
let ram_start = u32::from_be_bytes(file_data[8..12].try_into().unwrap());
let ext_start = u32::from_be_bytes(file_data[12..16].try_into().unwrap());
let end_mem = u32::from_be_bytes(file_data[16..20].try_into().unwrap());
let stack_size = u32::from_be_bytes(file_data[20..24].try_into().unwrap());
let start_func = u32::from_be_bytes(file_data[24..28].try_into().unwrap());
let str_decode = u32::from_be_bytes(file_data[28..32].try_into().unwrap());
let exp_checksum = u32::from_be_bytes(file_data[32..36].try_into().unwrap());
let actual_sum = file_data.iter()
.map(|b| *b)
.array_chunks::<4>()
.map(|bytes| u32::from_be_bytes(bytes))
// Subtract expected as we're supposed to compute it with that blanked
.fold(0u32, |a,b| a.overflowing_add(b).0) - exp_checksum;
if file_data.len() % 4 != 0 {
panic!("Invalid checksum: Uneven number of bytes");
}
if exp_checksum != actual_sum {
panic!("Invalid checksum: Expected {exp_checksum}, got {actual_sum}");
}
if ram_start % 256 != 0 || ext_start % 256 != 0 || end_mem % 256 != 0 {
panic!("Invalid memory boundaries");
}
if stack_size % 256 != 0 {
panic!("Invalid stack size");
}
if version_major != 2 && version_major != 3 {
panic!("This glulx implementation cannot handle version {version_major}, it is version {MAJOR_VERSION}");
}
if version_major == MAJOR_VERSION && version_minor > MINOR_VERSION {
panic!("This file is a newer minor version than this glulx implementation ({version_major}.{version_minor} > {MAJOR_VERSION}.{MINOR_VERSION})");
}
println!("Loaded {path}, ({} bytes, file version {version_major}.{version_minor}.{version_patch}, glulx {MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION})", file_data.len());
let mut interpreter = Interpreter::init(
file_data,
ram_start,
ext_start,
end_mem,
stack_size,
str_decode
);
interpreter.run(start_func);
}
|