Skip to content

Commit a8883a6

Browse files
committed
Split tiff::Parser::parse_ifd_entry and unit-test it.
1 parent 463396d commit a8883a6

File tree

1 file changed

+59
-21
lines changed

1 file changed

+59
-21
lines changed

src/tiff.rs

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -224,33 +224,19 @@ impl Parser {
224224
return Err(Error::InvalidFormat("Truncated IFD"));
225225
}
226226
for i in 0..count as usize {
227-
let tag = E::loadu16(data, offset + 2 + i * 12);
228-
let typ = E::loadu16(data, offset + 2 + i * 12 + 2);
229-
let cnt = E::loadu32(data, offset + 2 + i * 12 + 4);
230-
let valofs_at = offset + 2 + i * 12 + 8;
231-
let (unitlen, _parser) = get_type_info::<E>(typ);
232-
let vallen = unitlen.checked_mul(cnt as usize).ok_or(
233-
Error::InvalidFormat("Invalid entry count"))?;
234-
let mut val = if vallen <= 4 {
235-
Value::Unknown(typ, cnt, valofs_at as u32)
236-
} else {
237-
let ofs = E::loadu32(data, valofs_at) as usize;
238-
if data.len() < ofs || data.len() - ofs < vallen {
239-
return Err(Error::InvalidFormat("Truncated field value"));
240-
}
241-
Value::Unknown(typ, cnt, ofs as u32)
242-
};
227+
let (tag, val) =
228+
Self::parse_ifd_entry::<E>(data, offset + 2 + i * 12)?;
243229

244230
// No infinite recursion will occur because the context is not
245231
// recursively defined.
246232
let tag = Tag(ctx, tag);
247233
match tag {
248234
Tag::ExifIFDPointer => self.parse_child_ifd::<E>(
249-
data, &mut val, Context::Exif, ifd_num)?,
235+
data, val, Context::Exif, ifd_num)?,
250236
Tag::GPSInfoIFDPointer => self.parse_child_ifd::<E>(
251-
data, &mut val, Context::Gps, ifd_num)?,
237+
data, val, Context::Gps, ifd_num)?,
252238
Tag::InteropIFDPointer => self.parse_child_ifd::<E>(
253-
data, &mut val, Context::Interop, ifd_num)?,
239+
data, val, Context::Interop, ifd_num)?,
254240
_ => self.entries.push(IfdEntry { field: Field {
255241
tag: tag, ifd_num: In(ifd_num), value: val }.into()}),
256242
}
@@ -264,11 +250,33 @@ impl Parser {
264250
Ok(next_ifd_offset as usize)
265251
}
266252

253+
fn parse_ifd_entry<E>(data: &[u8], offset: usize)
254+
-> Result<(u16, Value), Error> where E: Endian {
255+
// The size of entry has been checked in parse_ifd().
256+
let tag = E::loadu16(data, offset);
257+
let typ = E::loadu16(data, offset + 2);
258+
let cnt = E::loadu32(data, offset + 4);
259+
let valofs_at = offset + 8;
260+
let (unitlen, _parser) = get_type_info::<E>(typ);
261+
let vallen = unitlen.checked_mul(cnt as usize).ok_or(
262+
Error::InvalidFormat("Invalid entry count"))?;
263+
let val = if vallen <= 4 {
264+
Value::Unknown(typ, cnt, valofs_at as u32)
265+
} else {
266+
let ofs = E::loadu32(data, valofs_at) as usize;
267+
if data.len() < ofs || data.len() - ofs < vallen {
268+
return Err(Error::InvalidFormat("Truncated field value"));
269+
}
270+
Value::Unknown(typ, cnt, ofs as u32)
271+
};
272+
Ok((tag, val))
273+
}
274+
267275
fn parse_child_ifd<E>(&mut self, data: &[u8],
268-
pointer: &mut Value, ctx: Context, ifd_num: u16)
276+
mut pointer: Value, ctx: Context, ifd_num: u16)
269277
-> Result<(), Error> where E: Endian {
270278
// The pointer is not yet parsed, so do it here.
271-
IfdEntry::parse_value::<E>(pointer, data);
279+
IfdEntry::parse_value::<E>(&mut pointer, data);
272280

273281
// A pointer field has type == LONG and count == 1, so the
274282
// value (IFD offset) must be embedded in the "value offset"
@@ -589,6 +597,36 @@ mod tests {
589597
assert_pat!(v[0].value, Value::Unknown(0xffff, 1, 0x12));
590598
}
591599

600+
#[test]
601+
fn parse_ifd_entry() {
602+
// BYTE (type == 1)
603+
let data = b"\x02\x03\x00\x01\0\0\0\x04ABCD";
604+
assert_pat!(Parser::parse_ifd_entry::<BigEndian>(data, 0).unwrap(),
605+
(0x0203, Value::Unknown(1, 4, 8)));
606+
let data = b"\x02\x03\x00\x01\0\0\0\x05\0\0\0\x0cABCDE";
607+
assert_pat!(Parser::parse_ifd_entry::<BigEndian>(data, 0).unwrap(),
608+
(0x0203, Value::Unknown(1, 5, 12)));
609+
let data = b"\x02\x03\x00\x01\0\0\0\x05\0\0\0\x0cABCD";
610+
assert_err_pat!(Parser::parse_ifd_entry::<BigEndian>(data, 0),
611+
Error::InvalidFormat("Truncated field value"));
612+
613+
// SHORT (type == 3)
614+
let data = b"X\x04\x05\x00\x03\0\0\0\x02ABCD";
615+
assert_pat!(Parser::parse_ifd_entry::<BigEndian>(data, 1).unwrap(),
616+
(0x0405, Value::Unknown(3, 2, 9)));
617+
let data = b"X\x04\x05\x00\x03\0\0\0\x03\0\0\0\x0eXABCDEF";
618+
assert_pat!(Parser::parse_ifd_entry::<BigEndian>(data, 1).unwrap(),
619+
(0x0405, Value::Unknown(3, 3, 14)));
620+
let data = b"X\x04\x05\x00\x03\0\0\0\x03\0\0\0\x0eXABCDE";
621+
assert_err_pat!(Parser::parse_ifd_entry::<BigEndian>(data, 1),
622+
Error::InvalidFormat("Truncated field value"));
623+
624+
// Really unknown
625+
let data = b"X\x01\x02\x03\x04\x05\x06\x07\x08ABCD";
626+
assert_pat!(Parser::parse_ifd_entry::<BigEndian>(data, 1).unwrap(),
627+
(0x0102, Value::Unknown(0x0304, 0x05060708, 9)));
628+
}
629+
592630
#[test]
593631
fn date_time() {
594632
let mut dt = DateTime::from_ascii(b"2016:05:04 03:02:01").unwrap();

0 commit comments

Comments
 (0)