Skip to main content

tiff_reader/
tag.rs

1use crate::error::{Error, Result};
2use crate::header::ByteOrder;
3use crate::io::Cursor;
4use crate::source::TiffSource;
5
6pub use tiff_core::{Tag, TagType, TagValue};
7
8/// Parse a classic TIFF tag entry (12-byte IFD entry).
9pub fn parse_tag_classic(
10    code: u16,
11    type_code: u16,
12    count: u64,
13    value_offset_bytes: &[u8],
14    source: &dyn TiffSource,
15    byte_order: ByteOrder,
16) -> Result<Tag> {
17    let tag_type = TagType::from_code(type_code);
18    let total_size = value_len(code, count, tag_type.element_size())?;
19
20    let owned;
21    let value_bytes = if total_size <= 4 {
22        &value_offset_bytes[..total_size]
23    } else {
24        let offset = match byte_order {
25            ByteOrder::LittleEndian => u32::from_le_bytes(value_offset_bytes.try_into().unwrap()),
26            ByteOrder::BigEndian => u32::from_be_bytes(value_offset_bytes.try_into().unwrap()),
27        } as u64;
28        owned = read_value_bytes(source, offset, total_size)?;
29        owned.as_slice()
30    };
31
32    let value = decode_value(&tag_type, count, value_bytes, byte_order)?;
33    Ok(Tag {
34        code,
35        tag_type,
36        count,
37        value,
38    })
39}
40
41/// Parse a BigTIFF tag entry (20-byte IFD entry).
42pub fn parse_tag_bigtiff(
43    code: u16,
44    type_code: u16,
45    count: u64,
46    value_offset_bytes: &[u8],
47    source: &dyn TiffSource,
48    byte_order: ByteOrder,
49) -> Result<Tag> {
50    let tag_type = TagType::from_code(type_code);
51    let total_size = value_len(code, count, tag_type.element_size())?;
52
53    let owned;
54    let value_bytes = if total_size <= 8 {
55        &value_offset_bytes[..total_size]
56    } else {
57        let offset = match byte_order {
58            ByteOrder::LittleEndian => u64::from_le_bytes(value_offset_bytes.try_into().unwrap()),
59            ByteOrder::BigEndian => u64::from_be_bytes(value_offset_bytes.try_into().unwrap()),
60        };
61        owned = read_value_bytes(source, offset, total_size)?;
62        owned.as_slice()
63    };
64
65    let value = decode_value(&tag_type, count, value_bytes, byte_order)?;
66    Ok(Tag {
67        code,
68        tag_type,
69        count,
70        value,
71    })
72}
73
74fn read_value_bytes(source: &dyn TiffSource, offset: u64, len: usize) -> Result<Vec<u8>> {
75    if let Some(data) = source.as_slice() {
76        return Ok(slice_at(data, offset, len)?.to_vec());
77    }
78    source.read_exact_at(offset, len)
79}
80
81fn value_len(tag: u16, count: u64, element_size: usize) -> Result<usize> {
82    let count = usize::try_from(count).map_err(|_| Error::InvalidTagValue {
83        tag,
84        reason: "value count does not fit in memory".into(),
85    })?;
86    count
87        .checked_mul(element_size)
88        .ok_or_else(|| Error::InvalidTagValue {
89            tag,
90            reason: "value byte length overflows usize".into(),
91        })
92}
93
94fn slice_at(data: &[u8], offset: u64, len: usize) -> Result<&[u8]> {
95    let start = usize::try_from(offset).map_err(|_| Error::OffsetOutOfBounds {
96        offset,
97        length: len as u64,
98        data_len: data.len() as u64,
99    })?;
100    let end = start.checked_add(len).ok_or(Error::OffsetOutOfBounds {
101        offset,
102        length: len as u64,
103        data_len: data.len() as u64,
104    })?;
105    if end > data.len() {
106        return Err(Error::OffsetOutOfBounds {
107            offset,
108            length: len as u64,
109            data_len: data.len() as u64,
110        });
111    }
112    Ok(&data[start..end])
113}
114
115fn decode_value(
116    tag_type: &TagType,
117    count: u64,
118    bytes: &[u8],
119    byte_order: ByteOrder,
120) -> Result<TagValue> {
121    let mut cursor = Cursor::new(bytes, byte_order);
122    let n = count as usize;
123
124    Ok(match tag_type {
125        TagType::Byte | TagType::Unknown(_) => TagValue::Byte(cursor.read_bytes(n)?.to_vec()),
126        TagType::Ascii => {
127            let raw = cursor.read_bytes(n)?;
128            let s = String::from_utf8_lossy(raw)
129                .trim_end_matches('\0')
130                .to_string();
131            TagValue::Ascii(s)
132        }
133        TagType::Short => {
134            let mut v = Vec::with_capacity(n);
135            for _ in 0..n {
136                v.push(cursor.read_u16()?);
137            }
138            TagValue::Short(v)
139        }
140        TagType::Long => {
141            let mut v = Vec::with_capacity(n);
142            for _ in 0..n {
143                v.push(cursor.read_u32()?);
144            }
145            TagValue::Long(v)
146        }
147        TagType::Rational => {
148            let mut v = Vec::with_capacity(n);
149            for _ in 0..n {
150                let num = cursor.read_u32()?;
151                let den = cursor.read_u32()?;
152                v.push([num, den]);
153            }
154            TagValue::Rational(v)
155        }
156        TagType::SByte => {
157            let raw = cursor.read_bytes(n)?;
158            TagValue::SByte(raw.iter().map(|&b| b as i8).collect())
159        }
160        TagType::Undefined => TagValue::Undefined(cursor.read_bytes(n)?.to_vec()),
161        TagType::SShort => {
162            let mut v = Vec::with_capacity(n);
163            for _ in 0..n {
164                v.push(cursor.read_u16()? as i16);
165            }
166            TagValue::SShort(v)
167        }
168        TagType::SLong => {
169            let mut v = Vec::with_capacity(n);
170            for _ in 0..n {
171                v.push(cursor.read_u32()? as i32);
172            }
173            TagValue::SLong(v)
174        }
175        TagType::SRational => {
176            let mut v = Vec::with_capacity(n);
177            for _ in 0..n {
178                let num = cursor.read_u32()? as i32;
179                let den = cursor.read_u32()? as i32;
180                v.push([num, den]);
181            }
182            TagValue::SRational(v)
183        }
184        TagType::Float => {
185            let mut v = Vec::with_capacity(n);
186            for _ in 0..n {
187                let bits = cursor.read_u32()?;
188                v.push(f32::from_bits(bits));
189            }
190            TagValue::Float(v)
191        }
192        TagType::Double => {
193            let mut v = Vec::with_capacity(n);
194            for _ in 0..n {
195                v.push(cursor.read_f64()?);
196            }
197            TagValue::Double(v)
198        }
199        TagType::Long8 | TagType::Ifd8 => {
200            let mut v = Vec::with_capacity(n);
201            for _ in 0..n {
202                v.push(cursor.read_u64()?);
203            }
204            TagValue::Long8(v)
205        }
206        TagType::SLong8 => {
207            let mut v = Vec::with_capacity(n);
208            for _ in 0..n {
209                v.push(cursor.read_u64()? as i64);
210            }
211            TagValue::SLong8(v)
212        }
213    })
214}