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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2025-2026 Gabriel Bjørnager Jensen.
//
// This Source Code Form is subject to the terms of
// the Mozilla Public License, v. 2.0. If a copy of
// the MPL was not distributed with this file, you
// can obtain one at:
// <https://mozilla.org/MPL/2.0/>.
//! The [`Lump`] type.
use crate::wad::{Compression, LumpType, RawLump};
use oct::IntoOcts;
/// A WAD lump.
#[derive(Clone, Debug)]
pub struct Lump<'a> {
/// The lump name.
pub(super) name: &'a [i8],
/// The lump's uncompressed data.
pub(super) data: &'a [u8],
/// The lump's compression format.
pub(super) compression: Option<Compression>,
/// The lump type.
pub(super) lump_type: Option<LumpType>,
}
impl<'a> Lump<'a> {
/// Constructs a validated lump from a raw one.
///
/// # Panics
///
/// If the provided, raw lump is not valid, this
/// function will panic.
#[must_use]
#[track_caller]
pub(super) fn from_raw(buf: &'a [u8], raw: RawLump<'a>) -> Self {
// Assume that all fields have already been vali-
// dated.
debug_assert!(usize::try_from(raw.filepos().cast_unsigned()).is_ok());
debug_assert!(usize::try_from(raw.disksize().cast_unsigned()).is_ok());
debug_assert!(usize::try_from(raw.size().cast_unsigned()).is_ok());
let name = raw.name();
let data = if raw.disksize() > 0 {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_wrap)]
let start = raw.filepos().cast_unsigned() as usize;
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_wrap)]
let stop = start + raw.disksize().cast_unsigned() as usize;
&buf[start..stop]
} else {
Default::default()
};
let compression = Compression::from_i8(raw.compression());
let lump_type = LumpType::from_i8(raw.r#type());
Lump {
name,
data,
compression,
lump_type,
}
}
/// Retrieves the lump's name.
///
/// If the name cannot be represented as a UTF-8
/// string, this method returns [`None`]. See
/// [`raw_name`] for more information.
///
/// [`raw_name`]: Self::raw_name
#[inline]
#[must_use]
pub fn name(&self) -> Option<&'a str> {
str::from_utf8(self.raw_name().as_octs()).ok()
}
/// Retrieves the lump's raw name.
///
/// The format of the returned data is technically
/// unspecified but was initially often either
/// ASCII or the [code page 437] format used by the
/// IBM PC. For new WAD files, it is recommended to
/// use ASCII if backwards-compatibility is
/// necessary and UTF-8 if it isn't.
///
/// [code page 437]: <https://en.wikipedia.org/wiki/Code_page_437>
#[inline]
#[must_use]
pub fn raw_name(&self) -> &'a [i8] {
let name_len = self.name.iter()
.position(|&c| c == 0)
.unwrap_or(self.name.len());
&self.name[..name_len]
}
/// Retrieves the uncompressed data for the lump.
///
/// Note that GoldForge does not currently implement
/// the LZSS algorithm that is theoretically
/// supported by Quake. Users should therefore
/// uncompress such lumps themselves.
#[inline(always)]
#[must_use]
pub fn data(&self) -> &'a [u8] {
self.data
}
/// Retrieves the compression format.
///
/// For DOOM lumps, this always yields [`None`]..
#[inline(always)]
#[must_use]
pub fn compression(&self) -> Option<Compression> {
self.compression
}
/// Retrieves the lump type.
///
/// For DOOM lumps, this always yields [`None`].
#[inline(always)]
#[must_use]
pub fn lump_type(&self) -> Option<LumpType> {
self.lump_type
}
}