diff --git a/src/reader.rs b/src/reader.rs index 8bcdba9..d383738 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -178,8 +178,27 @@ impl Exif { self.entry_map.get(&(ifd_num, tag)) .map(|&i| self.entries[i].ref_field(&self.buf, self.little_endian)) } + + // Returns the content of the UserComment tag, converted to a String, if the tag + // saved in an Unicode format. + pub fn get_user_comment(&self, ifd_num: In) -> Option { + self.get_field(Tag::UserComment, ifd_num) + .and_then(|field| match &field.value { + crate::Value::Undefined(buffer, _) if buffer.len() > 8 => { + let unicode_prefix = "UNICODE\0".as_bytes(); + if &buffer[..8] == unicode_prefix { + Some(crate::util::ucs2_to_string(&buffer[8..])) + } else { + None + } + } + _ => None, + }) + } } + + impl<'a> ProvideUnit<'a> for &'a Exif { fn get_field(self, tag: Tag, ifd_num: In) -> Option<&'a Field> { self.get_field(tag, ifd_num) diff --git a/src/tiff.rs b/src/tiff.rs index d27d25d..bee259a 100644 --- a/src/tiff.rs +++ b/src/tiff.rs @@ -247,6 +247,10 @@ impl Parser { return Err(Error::InvalidFormat("Truncated next IFD offset")); } let next_ifd_offset = E::loadu32(data, offset + 2 + count * 12); + if next_ifd_offset != 0 && ctx != Context::Tiff { + // Invalid Next IFD offset. ignored. + return Ok(0usize); + } Ok(next_ifd_offset as usize) } @@ -584,8 +588,11 @@ mod tests { \x00\x00\x00\x00\ \x00\x01\x90\x00\x00\x07\x00\x00\x00\x040231\ \x00\x00\x00\x08"; - assert_err_pat!(parse_exif(data), - Error::InvalidFormat("Unexpected next IFD")); + let (v, _le) = parse_exif(data).unwrap(); + assert_eq!(v.len(), 1); + println!("result : {:?}", v); + let undef_data = Value::Undefined(b"30323331".to_vec(), 0x24); + assert_pat!(&v[0].value, undef_data); } #[test] diff --git a/src/util.rs b/src/util.rs index 2da8ba0..683fa4b 100644 --- a/src/util.rs +++ b/src/util.rs @@ -126,6 +126,20 @@ pub fn ctou32(c: u8) -> Result { Ok((c - ASCII_0) as u32) } +pub fn ucs2_to_string(bytes: &[u8]) -> String { + let mut string = String::with_capacity(bytes.len() / 2); + + let mut index = 0; + while index < bytes.len() { + let code_point = (bytes[index + 1] as u16) | ((bytes[index] as u16) << 8); + string.push(char::from_u32(code_point.into()).unwrap()); + + index += 2; + } + + string +} + #[cfg(test)] mod tests { use std::io::ErrorKind;