1use std::{fmt::Display, num::ParseIntError, path::PathBuf};
4use thiserror::Error;
5
6pub type Result<T, E = Error> = std::result::Result<T, E>;
8
9#[derive(Debug, Error)]
11pub enum Error {
12 #[error("parent index {index} in .lsf file not found when parsing {context}")]
14 InvalidParentIndex { context: String, index: u32 },
15
16 #[error("unknown compression type specified with {value} found when {context}")]
18 UnknownCompressionType { value: u32, context: String },
19
20 #[error(
22 "compressed file offset {compressed_file_offset_found} doesn't specify a valid location \
23 in the file"
24 )]
25 InvalidCompressedFileOffset { compressed_file_offset_found: u64 },
26
27 #[error(
29 "{} bytes found after footer offset {footer_offset_found}, but the footer indicated a length of {footer_length_found}",
30 num_bytes - footer_offset_found
31 )]
32 InvalidFooterLength {
33 footer_length_found: usize,
34 footer_offset_found: usize,
35 num_bytes: usize,
36 },
37
38 #[error("footer offset {footer_offset_found} doesn't specify a valid location in the file")]
40 InvalidFooterOffset { footer_offset_found: u64 },
41
42 #[error(
44 "tried to LZ4 decompress {context} with compressed_length 0x{compressed_length:x} and \
45 decompressed length 0x{decompressed_length:x} but got {error}"
46 )]
47 Lz4DecompressionFailed {
48 context: String,
49 error: lz4_flex::block::DecompressError,
50 compressed_length: usize,
51 decompressed_length: usize,
52 },
53
54 #[error(
56 "during {context} got {value} entries which is too many to fit into a {bit_width}-bit \
57 integer"
58 )]
59 NumberOfEntriesTooHigh {
60 context: String,
61 value: u64,
62 bit_width: u32,
63 },
64
65 #[error(
67 "during {context} got {value} bytes which is too large to fit into a {bit_width}-bit \
68 integer"
69 )]
70 CompressedFileSizeTooHigh {
71 context: String,
72 value: u64,
73 bit_width: u32,
74 },
75
76 #[error(
78 "during {context} got {value} bytes which is too large to fit into a {bit_width}-bit \
79 integer"
80 )]
81 DecompressedFileSizeTooHigh {
82 context: String,
83 value: u64,
84 bit_width: u32,
85 },
86
87 #[error(
89 "during {context} got metadata length of {value} bytes which is too large to fit into a \
90 {bit_width}-bit integer"
91 )]
92 CompressedMetadataSizeTooHigh {
93 context: String,
94 value: u64,
95 bit_width: u32,
96 },
97
98 #[error("string length {value} for {context} does not fit into {bit_width} bits")]
100 StringLengthTooHigh {
101 context: String,
102 value: u64,
103 bit_width: u32,
104 },
105
106 #[error(
108 "during {context} got index {value} which is too large to fit into a signed \
109 {bit_width}-bit integer"
110 )]
111 IndexTooHigh {
112 context: String,
113 value: u32,
114 bit_width: u32,
115 },
116
117 #[error("found {bytes_found:?} instead of {bytes_found:?}")]
119 InvalidIdentifier {
120 expected_bytes: [u8; 4],
121 bytes_found: [u8; 4],
122 },
123
124 #[error("mod info had {found} attributes instead of 6")]
126 InvalidModInfoAttributeCount { found: usize },
127
128 #[error("meta.lsx in the LSPK file didn't match expected schema due to {context}")]
131 InvalidMetadataFile { context: String },
132
133 #[error("mod info missing folder attribute")]
135 MissingModInfoFolder,
136
137 #[error("mod info missing md5 attribute")]
139 MissingModInfoMd5,
140
141 #[error("mod info missing name attribute")]
143 MissingModInfoName,
144
145 #[error("mod info missing publish_handle attribute")]
147 MissingModInfoPublishHandle,
148
149 #[error("mod info missing uuid attribute")]
151 MissingModInfoUuid,
152
153 #[error("mod info missing version attribute")]
155 MissingModInfoVersion,
156
157 #[error("when {context} got {inner}")]
159 Io {
160 context: String,
161 inner: std::io::Error,
162 },
163
164 #[error("no value found for attribute {name}")]
166 MissingAttributeValue { name: &'static str },
167
168 #[error("no file with the correct extension was found in the zip")]
171 MissingLspkFileInZip,
172
173 #[error("no meta.lsx was found in the LSPK file")]
175 MissingMetadataFile,
176
177 #[error(
179 "no node found with XPath \
180 /save/region[@id='Config']/node[@id='root']/children/node[@id='ModuleInfo']"
181 )]
182 MissingModuleInfo,
183
184 #[error("could not parse {location} as integer because {inner}")]
186 ParseIntError {
187 inner: ParseIntError,
188 location: &'static str,
189 },
190
191 #[error("tried to decompress table but got {0}")]
193 TableEntryDecompressionFailed(lz4_flex::block::DecompressError),
194
195 #[error("not enough bytes to be a valid file of the given format")]
198 TooShort,
199
200 #[error("this tool does not support version number {version_number_found}")]
202 UnsupportedVersion { version_number_found: u32 },
203
204 #[error("can't pack mods at path `{0}`; try moving them to a named directory before packing")]
206 UnsupportedModPath(PathBuf),
207
208 #[cfg(feature = "zip")]
210 #[error("{0}")]
211 UnableToReadZipFile(#[from] rc_zip_sync::rc_zip::error::Error),
212
213 #[error("tried to decompress {} but got {error}", path.display())]
215 ZlibDecompressionFailed {
216 path: PathBuf,
217 error: std::io::Error,
218 },
219
220 #[error("tried to decompress {} but got {error}", path.display())]
221 ZstdDecompressionFailed { path: PathBuf, error: String },
222
223 #[error("zstd-compressed data in .pak not currently supported")]
225 ZstdNotSupported,
226
227 #[error("failed to deserialize XML: {0}")]
229 XmlDeserialize(#[from] quick_xml::DeError),
230
231 #[error("failed to serialize XML: {0}")]
233 XmlSerialize(#[from] quick_xml::SeError),
234
235 #[error("failed to write XML: {0}")]
237 XmlWrite(std::io::Error),
238
239 #[error("LSF XML attribute '{attribute_id}': missing required field '{field}'")]
241 LsfXmlMissingField {
242 attribute_id: String,
243 field: &'static str,
244 },
245
246 #[error("LSF XML attribute '{attribute_id}': unknown type '{type_name}'")]
248 LsfXmlUnknownType {
249 attribute_id: String,
250 type_name: String,
251 },
252
253 #[error(
255 "LSF XML attribute '{attribute_id}': expected {expected} space-separated values but got \
256 {found}"
257 )]
258 LsfXmlWrongComponentCount {
259 attribute_id: String,
260 expected: usize,
261 found: usize,
262 },
263
264 #[error(
266 "failed to parse LSF XML `{attribute_id}` attribute `{value}` as {expected_type} due to \
267 {inner}"
268 )]
269 LsfXmlParse {
270 attribute_id: String,
271 expected_type: String,
272 value: String,
273 inner: String,
274 },
275
276 #[error("LSF XML attribute '{attribute_id}': failed to decode base64: {inner}")]
278 LsfXmlDecodeBase64 {
279 attribute_id: String,
280 inner: base64::DecodeError,
281 },
282}
283
284impl Error {
285 pub fn custom_io(context: impl Display, inner: std::io::Error) -> Self {
286 Self::Io {
287 context: format!("{context}"),
288 inner,
289 }
290 }
291
292 pub fn read_io(context: impl Display, inner: std::io::Error) -> Self {
293 Self::Io {
294 context: format!("reading {context}"),
295 inner,
296 }
297 }
298
299 pub fn write_io(context: impl Display, inner: std::io::Error) -> Self {
300 Self::Io {
301 context: format!("writing {context}"),
302 inner,
303 }
304 }
305}