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