1use std::io::{BufRead, Seek, SeekFrom};
2
3use crate::{util::*, ImageResult, ImageSize};
4
5pub fn size<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageSize> {
6    reader.seek(SeekFrom::Start(12))?;
7
8    let width = read_u16(reader, &Endian::Little)? as usize;
9    let height = read_u16(reader, &Endian::Little)? as usize;
10
11    Ok(ImageSize { width, height })
12}
13
14pub fn matches<R: BufRead + Seek>(header: &[u8], reader: &mut R) -> bool {
15    let colormap_type = header[1];
17    let image_type = header[2];
18
19    if image_type != 1
22        && image_type != 2
23        && image_type != 3
24        && image_type != 9
25        && image_type != 10
26        && image_type != 11
27    {
28        return false;
29    }
30
31    if colormap_type >= 2 {
34        return false;
35    }
36
37    is_tga(reader, image_type, colormap_type).unwrap_or(false)
38}
39
40fn is_tga<R: BufRead + Seek>(
41    reader: &mut R,
42    image_type: u8,
43    colormap_type: u8,
44) -> ImageResult<bool> {
45    reader.seek(SeekFrom::End(-18))?;
48
49    let mut signature = [0; 18];
51    reader.read_exact(&mut signature)?;
52
53    if &signature == b"TRUEVISION-XFILE.\0" {
58        return Ok(true);
59    }
60
61    if (image_type == 1 || image_type == 9) && colormap_type != 1 {
68        return Ok(false);
69    }
70
71    reader.seek(SeekFrom::Start(3))?;
73
74    let colormap_offset = read_u32(reader, &Endian::Little)?;
75    let colormap_size = read_u8(reader)?;
76
77    if colormap_type == 0 {
79        if colormap_offset != 0 {
80            return Ok(false);
81        }
82
83        if colormap_size != 0 {
84            return Ok(false);
85        }
86    }
87
88    if colormap_type == 1
90        && (colormap_size != 0
91            && colormap_size != 8
92            && colormap_size != 16
93            && colormap_size != 24
94            && colormap_size != 32)
95    {
96        return Ok(false);
97    }
98
99    reader.seek(SeekFrom::Start(16))?;
100    let pixel_size = read_u8(reader)?;
101    let descriptor = read_u8(reader)?;
102    let alpha_bits = descriptor & 0x0F;
103
104    if descriptor & 0x10 != 0 {
106        return Ok(false);
107    }
108
109    if pixel_size != 8 && pixel_size != 16 && pixel_size != 24 && pixel_size != 32 {
111        return Ok(false);
112    }
113
114    if (pixel_size == 8 || pixel_size == 24) && alpha_bits != 0 {
118        return Ok(false);
119    }
120
121    if pixel_size == 16 && alpha_bits >= 2 {
123        return Ok(false);
124    }
125
126    if pixel_size == 32 && (alpha_bits != 8 && alpha_bits != 0) {
128        return Ok(false);
129    }
130
131    Ok(true)
132}