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