summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs88
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);
+}