Merge pull request 'Added ability to read WAD directory' (#1) from dir-reader into main
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/target
|
||||||
|
|
||||||
|
# This may change as we write a UI for the app
|
||||||
|
Cargo.lock
|
||||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "wad-reader"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
BIN
WADs/doom1.wad
Normal file
BIN
WADs/doom1.wad
Normal file
Binary file not shown.
8
src/lib.rs
Normal file
8
src/lib.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
mod lumps;
|
||||||
|
mod utils;
|
||||||
|
mod wad;
|
||||||
|
|
||||||
|
pub use wad::WADFile;
|
||||||
0
src/lumps/mod.rs
Normal file
0
src/lumps/mod.rs
Normal file
15
src/tests/helpers.rs
Normal file
15
src/tests/helpers.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use crate::utils::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn valid_wad() {
|
||||||
|
let wad_path = String::from("WADs/doom1.wad");
|
||||||
|
|
||||||
|
assert!(validate_wad(wad_path.as_str()).unwrap_or(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn wad_path_invalid() {
|
||||||
|
let wad_path = String::from("WADs/invalid.wad");
|
||||||
|
|
||||||
|
assert!(!validate_wad(wad_path.as_str()).unwrap_or(false));
|
||||||
|
}
|
||||||
5
src/tests/mod.rs
Normal file
5
src/tests/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod wad;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod helpers;
|
||||||
36
src/tests/wad.rs
Normal file
36
src/tests/wad.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use crate::WADFile;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn successful_wad_id() {
|
||||||
|
let wad_file = WADFile::new(String::from("WADs/doom1.wad"));
|
||||||
|
|
||||||
|
assert_eq!(wad_file.wad_id, "IWAD");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn correct_lumps() {
|
||||||
|
let wad_file = WADFile::new(String::from("WADs/doom1.wad"));
|
||||||
|
|
||||||
|
assert_eq!(wad_file.num_lumps, 1264);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn correct_dir_size() {
|
||||||
|
let wad_file = WADFile::new(String::from("WADs/doom1.wad"));
|
||||||
|
|
||||||
|
assert_eq!(wad_file.directory.len(), 1264);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn correct_lump_name() {
|
||||||
|
let wad_file = WADFile::new(String::from("WADs/doom1.wad"));
|
||||||
|
|
||||||
|
assert_eq!(wad_file.directory[0].name, "PLAYPAL");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn read_level_lump() {
|
||||||
|
let wad_file = WADFile::new(String::from("WADs/doom1.wad"));
|
||||||
|
|
||||||
|
assert_eq!(wad_file.directory[6].name, "E1M1");
|
||||||
|
}
|
||||||
0
src/utils/error.rs
Normal file
0
src/utils/error.rs
Normal file
43
src/utils/helpers.rs
Normal file
43
src/utils/helpers.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{self, Read},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Validates a WAD file to make sure that it is a legitimate file
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - path: &str - Path to the WAD to validate
|
||||||
|
pub fn validate_wad(path: &str) -> io::Result<bool> {
|
||||||
|
let wad_file = Path::new(path);
|
||||||
|
|
||||||
|
// Check to see if the WAD exists
|
||||||
|
if !(wad_file.exists()) {
|
||||||
|
// Return back false because we didn't pass a valid file
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the file exists open it and read the first 4 bytes
|
||||||
|
// of the file and see if we get "IWAD" or "PWAD"
|
||||||
|
let mut file = File::open(wad_file)?;
|
||||||
|
let mut magic = [0u8; 4];
|
||||||
|
file.read_exact(&mut magic)?;
|
||||||
|
|
||||||
|
// Now we return based on what we found
|
||||||
|
Ok(magic == *b"IWAD" || magic == *b"PWAD")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_ascii(bytes: &[u8]) -> String {
|
||||||
|
std::str::from_utf8(&bytes[..bytes.len()])
|
||||||
|
.unwrap_or("")
|
||||||
|
.trim_end_matches('\0')
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_u32_le(bytes: &[u8]) -> u32 {
|
||||||
|
if bytes.len() < 4 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
u32::from_le_bytes(bytes[..4].try_into().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/utils/mod.rs
Normal file
6
src/utils/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
mod error;
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
pub use helpers::read_ascii;
|
||||||
|
pub use helpers::read_u32_le;
|
||||||
|
pub use helpers::validate_wad;
|
||||||
5
src/wad/directory.rs
Normal file
5
src/wad/directory.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub struct Directory {
|
||||||
|
pub filepos: u32,
|
||||||
|
pub size: u32,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
21
src/wad/header.rs
Normal file
21
src/wad/header.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
pub struct Header {
|
||||||
|
pub wad_id: String,
|
||||||
|
pub num_lumps: u32,
|
||||||
|
pub dir_offset: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::utils::{read_ascii, read_u32_le};
|
||||||
|
|
||||||
|
impl Header {
|
||||||
|
pub fn read_data(data: &[u8]) -> Self {
|
||||||
|
let id = read_ascii(&data[..4]);
|
||||||
|
let lumps = read_u32_le(&data[4..8]);
|
||||||
|
let offset = read_u32_le(&data[8..12]);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
wad_id: id,
|
||||||
|
num_lumps: lumps,
|
||||||
|
dir_offset: offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/wad/mod.rs
Normal file
5
src/wad/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
mod directory;
|
||||||
|
mod header;
|
||||||
|
mod wadfile;
|
||||||
|
|
||||||
|
pub use wadfile::WADFile;
|
||||||
54
src/wad/wadfile.rs
Normal file
54
src/wad/wadfile.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
use std::{fs::File, io::Read, path::Path};
|
||||||
|
|
||||||
|
use super::{directory::Directory, header::Header};
|
||||||
|
use crate::utils::{read_ascii, read_u32_le, validate_wad};
|
||||||
|
|
||||||
|
pub struct WADFile {
|
||||||
|
pub path: String,
|
||||||
|
pub wad_id: String,
|
||||||
|
pub num_lumps: u32,
|
||||||
|
pub dir_offset: u32,
|
||||||
|
pub directory: Vec<Directory>,
|
||||||
|
pub wad_data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WADFile {
|
||||||
|
pub fn new(path: String) -> Self {
|
||||||
|
if !(validate_wad(path.as_str()).unwrap()) {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_path = Path::new(path.as_str());
|
||||||
|
let mut wad_file = File::open(file_path).unwrap();
|
||||||
|
let file_size = wad_file.metadata().unwrap().len() as usize;
|
||||||
|
let mut file_buffer: Vec<u8> = Vec::with_capacity(file_size);
|
||||||
|
|
||||||
|
wad_file.read_to_end(&mut file_buffer).unwrap();
|
||||||
|
|
||||||
|
let wad_header = Header::read_data(&file_buffer[0..12]);
|
||||||
|
|
||||||
|
let mut wad_dir: Vec<Directory> = Vec::with_capacity(wad_header.num_lumps as usize);
|
||||||
|
let offset = wad_header.dir_offset;
|
||||||
|
|
||||||
|
for entry in 0..wad_header.num_lumps {
|
||||||
|
let startpos = (offset + 16 * entry) as usize;
|
||||||
|
let filepos = read_u32_le(&file_buffer[startpos..startpos + 4]);
|
||||||
|
let size = read_u32_le(&file_buffer[startpos + 4..startpos + 8]);
|
||||||
|
let name = read_ascii(&file_buffer[startpos + 8..startpos + 16]);
|
||||||
|
wad_dir.push(Directory {
|
||||||
|
filepos,
|
||||||
|
name,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
path,
|
||||||
|
wad_id: wad_header.wad_id,
|
||||||
|
num_lumps: wad_header.num_lumps,
|
||||||
|
dir_offset: wad_header.dir_offset,
|
||||||
|
directory: wad_dir,
|
||||||
|
wad_data: file_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user