diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..33df203 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,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); +} |