1use std::io::Read;
9use std::{error, fmt};
10
11use byteorder_lite::{LittleEndian, ReadBytesExt};
12
13#[allow(deprecated)]
14use crate::codecs::dxt::{DxtDecoder, DxtVariant};
15use crate::color::ColorType;
16use crate::error::{
17 DecodingError, ImageError, ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind,
18};
19use crate::image::{ImageDecoder, ImageFormat};
20
21#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
23#[allow(clippy::enum_variant_names)]
24enum DecoderError {
25 PixelFormatSizeInvalid(u32),
27 HeaderSizeInvalid(u32),
29 HeaderFlagsInvalid(u32),
31
32 DxgiFormatInvalid(u32),
34 ResourceDimensionInvalid(u32),
36 Dx10FlagsInvalid(u32),
38 Dx10ArraySizeInvalid(u32),
40
41 DdsSignatureInvalid,
43}
44
45impl fmt::Display for DecoderError {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 match self {
48 DecoderError::PixelFormatSizeInvalid(s) => {
49 f.write_fmt(format_args!("Invalid DDS PixelFormat size: {s}"))
50 }
51 DecoderError::HeaderSizeInvalid(s) => {
52 f.write_fmt(format_args!("Invalid DDS header size: {s}"))
53 }
54 DecoderError::HeaderFlagsInvalid(fs) => {
55 f.write_fmt(format_args!("Invalid DDS header flags: {fs:#010X}"))
56 }
57 DecoderError::DxgiFormatInvalid(df) => {
58 f.write_fmt(format_args!("Invalid DDS DXGI format: {df}"))
59 }
60 DecoderError::ResourceDimensionInvalid(d) => {
61 f.write_fmt(format_args!("Invalid DDS resource dimension: {d}"))
62 }
63 DecoderError::Dx10FlagsInvalid(fs) => {
64 f.write_fmt(format_args!("Invalid DDS DX10 header flags: {fs:#010X}"))
65 }
66 DecoderError::Dx10ArraySizeInvalid(s) => {
67 f.write_fmt(format_args!("Invalid DDS DX10 array size: {s}"))
68 }
69 DecoderError::DdsSignatureInvalid => f.write_str("DDS signature not found"),
70 }
71 }
72}
73
74impl From<DecoderError> for ImageError {
75 fn from(e: DecoderError) -> ImageError {
76 ImageError::Decoding(DecodingError::new(ImageFormat::Dds.into(), e))
77 }
78}
79
80impl error::Error for DecoderError {}
81
82#[derive(Debug)]
84struct Header {
85 _flags: u32,
86 height: u32,
87 width: u32,
88 _pitch_or_linear_size: u32,
89 _depth: u32,
90 _mipmap_count: u32,
91 pixel_format: PixelFormat,
92 _caps: u32,
93 _caps2: u32,
94}
95
96#[derive(Debug)]
98struct DX10Header {
99 dxgi_format: u32,
100 resource_dimension: u32,
101 misc_flag: u32,
102 array_size: u32,
103 misc_flags_2: u32,
104}
105
106#[derive(Debug)]
108struct PixelFormat {
109 flags: u32,
110 fourcc: [u8; 4],
111 _rgb_bit_count: u32,
112 _r_bit_mask: u32,
113 _g_bit_mask: u32,
114 _b_bit_mask: u32,
115 _a_bit_mask: u32,
116}
117
118impl PixelFormat {
119 fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
120 let size = r.read_u32::<LittleEndian>()?;
121 if size != 32 {
122 return Err(DecoderError::PixelFormatSizeInvalid(size).into());
123 }
124
125 Ok(Self {
126 flags: r.read_u32::<LittleEndian>()?,
127 fourcc: {
128 let mut v = [0; 4];
129 r.read_exact(&mut v)?;
130 v
131 },
132 _rgb_bit_count: r.read_u32::<LittleEndian>()?,
133 _r_bit_mask: r.read_u32::<LittleEndian>()?,
134 _g_bit_mask: r.read_u32::<LittleEndian>()?,
135 _b_bit_mask: r.read_u32::<LittleEndian>()?,
136 _a_bit_mask: r.read_u32::<LittleEndian>()?,
137 })
138 }
139}
140
141impl Header {
142 fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
143 let size = r.read_u32::<LittleEndian>()?;
144 if size != 124 {
145 return Err(DecoderError::HeaderSizeInvalid(size).into());
146 }
147
148 const REQUIRED_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x1000;
149 const VALID_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x8 | 0x1000 | 0x20000 | 0x80000 | 0x0080_0000;
150 let flags = r.read_u32::<LittleEndian>()?;
151 if flags & (REQUIRED_FLAGS | !VALID_FLAGS) != REQUIRED_FLAGS {
152 return Err(DecoderError::HeaderFlagsInvalid(flags).into());
153 }
154
155 let height = r.read_u32::<LittleEndian>()?;
156 let width = r.read_u32::<LittleEndian>()?;
157 let pitch_or_linear_size = r.read_u32::<LittleEndian>()?;
158 let depth = r.read_u32::<LittleEndian>()?;
159 let mipmap_count = r.read_u32::<LittleEndian>()?;
160 {
162 let mut skipped = [0; 4 * 11];
163 r.read_exact(&mut skipped)?;
164 }
165 let pixel_format = PixelFormat::from_reader(r)?;
166 let caps = r.read_u32::<LittleEndian>()?;
167 let caps2 = r.read_u32::<LittleEndian>()?;
168 {
170 let mut skipped = [0; 4 + 4 + 4];
171 r.read_exact(&mut skipped)?;
172 }
173
174 Ok(Self {
175 _flags: flags,
176 height,
177 width,
178 _pitch_or_linear_size: pitch_or_linear_size,
179 _depth: depth,
180 _mipmap_count: mipmap_count,
181 pixel_format,
182 _caps: caps,
183 _caps2: caps2,
184 })
185 }
186}
187
188impl DX10Header {
189 fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
190 let dxgi_format = r.read_u32::<LittleEndian>()?;
191 let resource_dimension = r.read_u32::<LittleEndian>()?;
192 let misc_flag = r.read_u32::<LittleEndian>()?;
193 let array_size = r.read_u32::<LittleEndian>()?;
194 let misc_flags_2 = r.read_u32::<LittleEndian>()?;
195
196 let dx10_header = Self {
197 dxgi_format,
198 resource_dimension,
199 misc_flag,
200 array_size,
201 misc_flags_2,
202 };
203 dx10_header.validate()?;
204
205 Ok(dx10_header)
206 }
207
208 fn validate(&self) -> Result<(), ImageError> {
209 if self.dxgi_format > 132 {
211 return Err(DecoderError::DxgiFormatInvalid(self.dxgi_format).into());
213 }
214
215 if self.resource_dimension < 2 || self.resource_dimension > 4 {
216 return Err(DecoderError::ResourceDimensionInvalid(self.resource_dimension).into());
219 }
220
221 if self.misc_flag != 0x0 && self.misc_flag != 0x4 {
222 return Err(DecoderError::Dx10FlagsInvalid(self.misc_flag).into());
225 }
226
227 if self.resource_dimension == 4 && self.array_size != 1 {
228 return Err(DecoderError::Dx10ArraySizeInvalid(self.array_size).into());
231 }
232
233 if self.misc_flags_2 > 0x4 {
234 return Err(DecoderError::Dx10FlagsInvalid(self.misc_flags_2).into());
236 }
237
238 Ok(())
239 }
240}
241
242pub struct DdsDecoder<R: Read> {
244 #[allow(deprecated)]
245 inner: DxtDecoder<R>,
246}
247
248impl<R: Read> DdsDecoder<R> {
249 pub fn new(mut r: R) -> ImageResult<Self> {
251 let mut magic = [0; 4];
252 r.read_exact(&mut magic)?;
253 if magic != b"DDS "[..] {
254 return Err(DecoderError::DdsSignatureInvalid.into());
255 }
256
257 let header = Header::from_reader(&mut r)?;
258
259 if header.pixel_format.flags & 0x4 != 0 {
260 #[allow(deprecated)]
261 let variant = match &header.pixel_format.fourcc {
262 b"DXT1" => DxtVariant::DXT1,
263 b"DXT3" => DxtVariant::DXT3,
264 b"DXT5" => DxtVariant::DXT5,
265 b"DX10" => {
266 let dx10_header = DX10Header::from_reader(&mut r)?;
267 match dx10_header.dxgi_format {
271 70..=72 => DxtVariant::DXT1, 73..=75 => DxtVariant::DXT3, 76..=78 => DxtVariant::DXT5, _ => {
275 return Err(ImageError::Unsupported(
276 UnsupportedError::from_format_and_kind(
277 ImageFormat::Dds.into(),
278 UnsupportedErrorKind::GenericFeature(format!(
279 "DDS DXGI Format {}",
280 dx10_header.dxgi_format
281 )),
282 ),
283 ))
284 }
285 }
286 }
287 fourcc => {
288 return Err(ImageError::Unsupported(
289 UnsupportedError::from_format_and_kind(
290 ImageFormat::Dds.into(),
291 UnsupportedErrorKind::GenericFeature(format!("DDS FourCC {fourcc:?}")),
292 ),
293 ))
294 }
295 };
296
297 #[allow(deprecated)]
298 let bytes_per_pixel = variant.color_type().bytes_per_pixel();
299
300 if crate::utils::check_dimension_overflow(header.width, header.height, bytes_per_pixel)
301 {
302 return Err(ImageError::Unsupported(
303 UnsupportedError::from_format_and_kind(
304 ImageFormat::Dds.into(),
305 UnsupportedErrorKind::GenericFeature(format!(
306 "Image dimensions ({}x{}) are too large",
307 header.width, header.height
308 )),
309 ),
310 ));
311 }
312
313 #[allow(deprecated)]
314 let inner = DxtDecoder::new(r, header.width, header.height, variant)?;
315 Ok(Self { inner })
316 } else {
317 Err(ImageError::Unsupported(
319 UnsupportedError::from_format_and_kind(
320 ImageFormat::Dds.into(),
321 UnsupportedErrorKind::Format(ImageFormatHint::Name("DDS".to_string())),
322 ),
323 ))
324 }
325 }
326}
327
328impl<R: Read> ImageDecoder for DdsDecoder<R> {
329 fn dimensions(&self) -> (u32, u32) {
330 self.inner.dimensions()
331 }
332
333 fn color_type(&self) -> ColorType {
334 self.inner.color_type()
335 }
336
337 fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
338 self.inner.read_image(buf)
339 }
340
341 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
342 (*self).read_image(buf)
343 }
344}
345
346#[cfg(test)]
347mod test {
348 use super::*;
349
350 #[test]
351 fn dimension_overflow() {
352 let header = [
354 0x44, 0x44, 0x53, 0x20, 0x7C, 0x0, 0x0, 0x0, 0x7, 0x10, 0x8, 0x0, 0xFC, 0xFF, 0xFF,
355 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x0, 0xC0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
356 0x0, 0x49, 0x4D, 0x41, 0x47, 0x45, 0x4D, 0x41, 0x47, 0x49, 0x43, 0x4B, 0x0, 0x0, 0x0,
357 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
358 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
359 0x4, 0x0, 0x0, 0x0, 0x44, 0x58, 0x54, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
360 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0,
361 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
362 ];
363
364 assert!(DdsDecoder::new(&header[..]).is_err());
365 }
366}