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