@@ -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 \x04 ABCD" ;
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 \x0c ABCDE" ;
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 \x0c ABCD" ;
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 \x02 ABCD" ;
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 \x0e XABCDEF" ;
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 \x0e XABCDE" ;
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 \x08 ABCD" ;
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