1use byteorder::{LittleEndian, ReadBytesExt};
2use std::io::{self, Cursor, Read, Seek, SeekFrom};
3use std::marker::PhantomData;
4use std::{error, fmt, mem};
5
6use crate::color::ColorType;
7use crate::error::{
8 DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
9};
10use crate::image::{self, ImageDecoder, ImageFormat};
11
12use self::InnerDecoder::*;
13use crate::codecs::bmp::BmpDecoder;
14use crate::codecs::png::{PngDecoder, PNG_SIGNATURE};
15
16#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
18enum DecoderError {
19 NoEntries,
21 IcoEntryTooManyPlanesOrHotspot,
23 IcoEntryTooManyBitsPerPixelOrHotspot,
25
26 PngShorterThanHeader,
28 PngNotRgba,
30
31 InvalidDataSize,
33
34 ImageEntryDimensionMismatch {
36 format: IcoEntryImageFormat,
38 entry: (u16, u16),
40 image: (u32, u32),
42 },
43}
44
45impl fmt::Display for DecoderError {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 match self {
48 DecoderError::NoEntries => f.write_str("ICO directory contains no image"),
49 DecoderError::IcoEntryTooManyPlanesOrHotspot => {
50 f.write_str("ICO image entry has too many color planes or too large hotspot value")
51 }
52 DecoderError::IcoEntryTooManyBitsPerPixelOrHotspot => f.write_str(
53 "ICO image entry has too many bits per pixel or too large hotspot value",
54 ),
55 DecoderError::PngShorterThanHeader => {
56 f.write_str("Entry specified a length that is shorter than PNG header!")
57 }
58 DecoderError::PngNotRgba => f.write_str("The PNG is not in RGBA format!"),
59 DecoderError::InvalidDataSize => {
60 f.write_str("ICO image data size did not match expected size")
61 }
62 DecoderError::ImageEntryDimensionMismatch {
63 format,
64 entry,
65 image,
66 } => f.write_fmt(format_args!(
67 "Entry{:?} and {}{:?} dimensions do not match!",
68 entry, format, image
69 )),
70 }
71 }
72}
73
74impl From<DecoderError> for ImageError {
75 fn from(e: DecoderError) -> ImageError {
76 ImageError::Decoding(DecodingError::new(ImageFormat::Ico.into(), e))
77 }
78}
79
80impl error::Error for DecoderError {}
81
82#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
84enum IcoEntryImageFormat {
85 Png,
87 Bmp,
89}
90
91impl fmt::Display for IcoEntryImageFormat {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 f.write_str(match self {
94 IcoEntryImageFormat::Png => "PNG",
95 IcoEntryImageFormat::Bmp => "BMP",
96 })
97 }
98}
99
100impl From<IcoEntryImageFormat> for ImageFormat {
101 fn from(val: IcoEntryImageFormat) -> Self {
102 match val {
103 IcoEntryImageFormat::Png => ImageFormat::Png,
104 IcoEntryImageFormat::Bmp => ImageFormat::Bmp,
105 }
106 }
107}
108
109pub struct IcoDecoder<R: Read> {
111 selected_entry: DirEntry,
112 inner_decoder: InnerDecoder<R>,
113}
114
115enum InnerDecoder<R: Read> {
116 Bmp(BmpDecoder<R>),
117 Png(Box<PngDecoder<R>>),
118}
119
120#[derive(Clone, Copy, Default)]
121struct DirEntry {
122 width: u8,
123 height: u8,
124 #[allow(unused)]
127 color_count: u8,
128 #[allow(unused)]
133 reserved: u8,
134
135 #[allow(unused)]
138 num_color_planes: u16,
139 bits_per_pixel: u16,
140
141 image_length: u32,
142 image_offset: u32,
143}
144
145impl<R: Read + Seek> IcoDecoder<R> {
146 pub fn new(mut r: R) -> ImageResult<IcoDecoder<R>> {
148 let entries = read_entries(&mut r)?;
149 let entry = best_entry(entries)?;
150 let decoder = entry.decoder(r)?;
151
152 Ok(IcoDecoder {
153 selected_entry: entry,
154 inner_decoder: decoder,
155 })
156 }
157}
158
159fn read_entries<R: Read>(r: &mut R) -> ImageResult<Vec<DirEntry>> {
160 let _reserved = r.read_u16::<LittleEndian>()?;
161 let _type = r.read_u16::<LittleEndian>()?;
162 let count = r.read_u16::<LittleEndian>()?;
163 (0..count).map(|_| read_entry(r)).collect()
164}
165
166fn read_entry<R: Read>(r: &mut R) -> ImageResult<DirEntry> {
167 Ok(DirEntry {
168 width: r.read_u8()?,
169 height: r.read_u8()?,
170 color_count: r.read_u8()?,
171 reserved: r.read_u8()?,
172 num_color_planes: {
173 let num = r.read_u16::<LittleEndian>()?;
176 if num > 256 {
177 return Err(DecoderError::IcoEntryTooManyPlanesOrHotspot.into());
178 }
179 num
180 },
181 bits_per_pixel: {
182 let num = r.read_u16::<LittleEndian>()?;
185 if num > 256 {
186 return Err(DecoderError::IcoEntryTooManyBitsPerPixelOrHotspot.into());
187 }
188 num
189 },
190 image_length: r.read_u32::<LittleEndian>()?,
191 image_offset: r.read_u32::<LittleEndian>()?,
192 })
193}
194
195fn best_entry(mut entries: Vec<DirEntry>) -> ImageResult<DirEntry> {
197 let mut best = entries.pop().ok_or(DecoderError::NoEntries)?;
198
199 let mut best_score = (
200 best.bits_per_pixel,
201 u32::from(best.real_width()) * u32::from(best.real_height()),
202 );
203
204 for entry in entries {
205 let score = (
206 entry.bits_per_pixel,
207 u32::from(entry.real_width()) * u32::from(entry.real_height()),
208 );
209 if score > best_score {
210 best = entry;
211 best_score = score;
212 }
213 }
214 Ok(best)
215}
216
217impl DirEntry {
218 fn real_width(&self) -> u16 {
219 match self.width {
220 0 => 256,
221 w => u16::from(w),
222 }
223 }
224
225 fn real_height(&self) -> u16 {
226 match self.height {
227 0 => 256,
228 h => u16::from(h),
229 }
230 }
231
232 fn matches_dimensions(&self, width: u32, height: u32) -> bool {
233 u32::from(self.real_width()) == width.min(256)
234 && u32::from(self.real_height()) == height.min(256)
235 }
236
237 fn seek_to_start<R: Read + Seek>(&self, r: &mut R) -> ImageResult<()> {
238 r.seek(SeekFrom::Start(u64::from(self.image_offset)))?;
239 Ok(())
240 }
241
242 fn is_png<R: Read + Seek>(&self, r: &mut R) -> ImageResult<bool> {
243 self.seek_to_start(r)?;
244
245 let mut signature = [0u8; 8];
247 r.read_exact(&mut signature)?;
248
249 Ok(signature == PNG_SIGNATURE)
250 }
251
252 fn decoder<R: Read + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>> {
253 let is_png = self.is_png(&mut r)?;
254 self.seek_to_start(&mut r)?;
255
256 if is_png {
257 Ok(Png(Box::new(PngDecoder::new(r)?)))
258 } else {
259 Ok(Bmp(BmpDecoder::new_with_ico_format(r)?))
260 }
261 }
262}
263
264pub struct IcoReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
266impl<R> Read for IcoReader<R> {
267 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
268 self.0.read(buf)
269 }
270 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
271 if self.0.position() == 0 && buf.is_empty() {
272 mem::swap(buf, self.0.get_mut());
273 Ok(buf.len())
274 } else {
275 self.0.read_to_end(buf)
276 }
277 }
278}
279
280impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for IcoDecoder<R> {
281 type Reader = IcoReader<R>;
282
283 fn dimensions(&self) -> (u32, u32) {
284 match self.inner_decoder {
285 Bmp(ref decoder) => decoder.dimensions(),
286 Png(ref decoder) => decoder.dimensions(),
287 }
288 }
289
290 fn color_type(&self) -> ColorType {
291 match self.inner_decoder {
292 Bmp(ref decoder) => decoder.color_type(),
293 Png(ref decoder) => decoder.color_type(),
294 }
295 }
296
297 fn into_reader(self) -> ImageResult<Self::Reader> {
298 Ok(IcoReader(
299 Cursor::new(image::decoder_to_vec(self)?),
300 PhantomData,
301 ))
302 }
303
304 fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
305 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
306 match self.inner_decoder {
307 Png(decoder) => {
308 if self.selected_entry.image_length < PNG_SIGNATURE.len() as u32 {
309 return Err(DecoderError::PngShorterThanHeader.into());
310 }
311
312 let (width, height) = decoder.dimensions();
314 if !self.selected_entry.matches_dimensions(width, height) {
315 return Err(DecoderError::ImageEntryDimensionMismatch {
316 format: IcoEntryImageFormat::Png,
317 entry: (
318 self.selected_entry.real_width(),
319 self.selected_entry.real_height(),
320 ),
321 image: (width, height),
322 }
323 .into());
324 }
325
326 if decoder.color_type() != ColorType::Rgba8 {
329 return Err(DecoderError::PngNotRgba.into());
330 }
331
332 decoder.read_image(buf)
333 }
334 Bmp(mut decoder) => {
335 let (width, height) = decoder.dimensions();
336 if !self.selected_entry.matches_dimensions(width, height) {
337 return Err(DecoderError::ImageEntryDimensionMismatch {
338 format: IcoEntryImageFormat::Bmp,
339 entry: (
340 self.selected_entry.real_width(),
341 self.selected_entry.real_height(),
342 ),
343 image: (width, height),
344 }
345 .into());
346 }
347
348 if decoder.color_type() != ColorType::Rgba8 {
350 return Err(ImageError::Unsupported(
351 UnsupportedError::from_format_and_kind(
352 ImageFormat::Bmp.into(),
353 UnsupportedErrorKind::Color(decoder.color_type().into()),
354 ),
355 ));
356 }
357
358 decoder.read_image_data(buf)?;
359
360 let r = decoder.reader();
361 let image_end = r.stream_position()?;
362 let data_end = u64::from(self.selected_entry.image_offset)
363 + u64::from(self.selected_entry.image_length);
364
365 let mask_row_bytes = ((width + 31) / 32) * 4;
366 let mask_length = u64::from(mask_row_bytes) * u64::from(height);
367
368 if data_end >= image_end + mask_length {
376 for y in 0..height {
378 let mut x = 0;
379 for _ in 0..mask_row_bytes {
380 let mask_byte = r.read_u8()?;
382 for bit in (0..8).rev() {
383 if x >= width {
384 break;
385 }
386 if mask_byte & (1 << bit) != 0 {
387 buf[((height - y - 1) * width + x) as usize * 4 + 3] = 0;
389 }
390 x += 1;
391 }
392 }
393 }
394
395 Ok(())
396 } else if data_end == image_end {
397 Ok(())
399 } else {
400 Err(DecoderError::InvalidDataSize.into())
401 }
402 }
403 }
404 }
405}
406
407#[cfg(test)]
408mod test {
409 use super::*;
410
411 #[test]
414 fn bmp_16_with_missing_alpha_channel() {
415 let data = vec![
416 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0e, 0x04, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00,
417 0x7c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x01, 0x00,
418 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
422 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
423 0x00, 0x00, 0x00, 0x8f, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
424 0x20, 0x66, 0x74, 0x83, 0x70, 0x61, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
425 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xeb, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00,
426 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x47, 0x0d,
427 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x62, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00,
428 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c,
429 0x00, 0x00, 0x00, 0xc3, 0x3f, 0x94, 0x61, 0xaa, 0x17, 0x4d, 0x8d, 0x79, 0x1d, 0x8b,
430 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2e, 0x28, 0x40, 0xe5, 0x9f,
431 0x4b, 0x4d, 0xe9, 0x87, 0xd3, 0xda, 0xd6, 0x89, 0x81, 0xc5, 0xa4, 0xa1, 0x60, 0x98,
432 0x31, 0xc7, 0x1d, 0xb6, 0x8f, 0x20, 0xc8, 0x3e, 0xee, 0xd8, 0xe4, 0x8f, 0xee, 0x7b,
433 0x48, 0x9b, 0x88, 0x25, 0x13, 0xda, 0xa4, 0x13, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x40,
434 0x16, 0x01, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
435 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
436 0x00, 0x00, 0xa3, 0x66, 0x64, 0x41, 0x54, 0xa3, 0xa3, 0x00, 0x00, 0x00, 0xb8, 0x00,
437 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
438 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x66, 0x64, 0x41, 0x54, 0xa3, 0xa3,
439 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
441 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xf6, 0xff, 0xff,
442 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x83, 0x70, 0x61, 0x76,
443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
444 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
445 0x00, 0x00, 0x00, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x62, 0x49,
446 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
447 0x00, 0x00, 0x00, 0xff, 0xff, 0x94, 0xc8, 0x00, 0x02, 0x0c, 0x00, 0xff, 0xff, 0xc6,
448 0x84, 0x00, 0x2a, 0x75, 0x03, 0xa3, 0x05, 0xfb, 0xe1, 0x6e, 0xe8, 0x27, 0xd6, 0xd3,
449 0x96, 0xc1, 0xe4, 0x30, 0x0c, 0x05, 0xb9, 0xa3, 0x8b, 0x29, 0xda, 0xa4, 0xf1, 0x4d,
450 0xf3, 0xb2, 0x98, 0x2b, 0xe6, 0x93, 0x07, 0xf9, 0xca, 0x2b, 0xc2, 0x39, 0x20, 0xba,
451 0x7c, 0xa0, 0xb1, 0x43, 0xe6, 0xf9, 0xdc, 0xd1, 0xc2, 0x52, 0xdc, 0x41, 0xc1, 0x2f,
452 0x29, 0xf7, 0x46, 0x32, 0xda, 0x1b, 0x72, 0x8c, 0xe6, 0x2b, 0x01, 0xe5, 0x49, 0x21,
453 0x89, 0x89, 0xe4, 0x3d, 0xa1, 0xdb, 0x3b, 0x4a, 0x0b, 0x52, 0x86, 0x52, 0x33, 0x9d,
454 0xb2, 0xcf, 0x4a, 0x86, 0x53, 0xd7, 0xa9, 0x4b, 0xaf, 0x62, 0x06, 0x49, 0x53, 0x00,
455 0xc3, 0x3f, 0x94, 0x61, 0xaa, 0x17, 0x4d, 0x8d, 0x79, 0x1d, 0x8b, 0x10, 0x00, 0x00,
456 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2e, 0x28, 0x40, 0xe5, 0x9f, 0x4b, 0x4d, 0xe9,
457 0x87, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xc5, 0x00,
458 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x50, 0x31, 0x00, 0x00, 0x00, 0x00,
459 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x76, 0x76, 0x01, 0x00, 0x00, 0x00, 0x76, 0x00,
460 0x00, 0x23, 0x3f, 0x52, 0x41, 0x44, 0x49, 0x41, 0x4e, 0x43, 0x45, 0x61, 0x50, 0x35,
461 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4d, 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x05,
462 0x50, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x37, 0x61,
463 ];
464
465 let decoder = IcoDecoder::new(Cursor::new(&data)).unwrap();
466 let mut buf = vec![0; usize::try_from(decoder.total_bytes()).unwrap()];
467 assert!(decoder.read_image(&mut buf).is_err());
468 }
469}