quake_util/lump/
parse.rs

1use crate::common::Palette;
2use crate::error;
3use crate::lump::{Image, MipTexture, MipTextureHead};
4use crate::BinParseResult;
5use std::boxed::Box;
6use std::io::{Read, Seek, SeekFrom};
7use std::mem::{size_of, transmute, MaybeUninit};
8use std::string::ToString;
9
10/// Attempt to parse bytes into a mip-mapped texture
11pub fn parse_mip_texture(
12    cursor: &mut (impl Seek + Read),
13) -> BinParseResult<MipTexture> {
14    let mut head_bytes = [0u8; size_of::<MipTextureHead>()];
15    let lump_start = cursor.stream_position()?;
16
17    cursor.read_exact(&mut head_bytes)?;
18
19    let head: MipTextureHead = head_bytes.try_into()?;
20    let mip0_length = u64::from(head.width) * u64::from(head.height);
21    const UNINIT_IMAGE: MaybeUninit<Image> = MaybeUninit::uninit();
22    let mut mips = [UNINIT_IMAGE; 4];
23
24    for i in 0u32..4u32 {
25        let pix_start: u64 = head.offsets[i as usize].into();
26        let length: usize = (mip0_length >> (i * 2)).try_into().unwrap();
27
28        cursor.seek(SeekFrom::Start(
29            lump_start
30                .checked_add(pix_start)
31                .ok_or(error::BinParse::Parse("Bad offset".to_string()))?,
32        ))?;
33
34        let mut pixels = vec![0u8; length].into_boxed_slice();
35        cursor.read_exact(&mut pixels)?;
36
37        mips[i as usize].write(Image::from_pixels(head.width >> i, pixels));
38    }
39
40    Ok(MipTexture::from_parts(head.name, unsafe {
41        mips.map(|elem| elem.assume_init())
42    }))
43}
44
45/// Attempt to parse 768 bytes into a palette
46pub fn parse_palette(reader: &mut impl Read) -> BinParseResult<Box<Palette>> {
47    let mut bytes = [0u8; size_of::<Palette>()];
48    reader.read_exact(&mut bytes[..])?;
49    Ok(Box::from(unsafe {
50        transmute::<[u8; size_of::<Palette>()], Palette>(bytes)
51    }))
52}
53
54/// Attempt to parse a 2D image
55pub fn parse_image(reader: &mut impl Read) -> BinParseResult<Image> {
56    let mut u32_buf = [0u8; size_of::<u32>()];
57    reader.read_exact(&mut u32_buf[..])?;
58    let width = u32::from_le_bytes(u32_buf);
59    reader.read_exact(&mut u32_buf[..])?;
60    let height = u32::from_le_bytes(u32_buf);
61
62    let pixel_ct = width
63        .checked_mul(height)
64        .ok_or(error::BinParse::Parse("Image too large".to_string()))?;
65
66    let mut pixels = vec![0u8; pixel_ct as usize].into_boxed_slice();
67    reader.read_exact(&mut pixels)?;
68
69    Ok(Image::from_pixels(width, pixels))
70}
71
72/// Read `length` bytes into a boxed slice
73pub fn read_raw(
74    reader: &mut impl Read,
75    length: usize,
76) -> BinParseResult<Box<[u8]>> {
77    let mut bytes = vec![0u8; length].into_boxed_slice();
78    reader.read_exact(&mut bytes)?;
79    Ok(bytes)
80}