diff --git a/Cargo.toml b/Cargo.toml index 1228f8a..c3ac1f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,6 @@ readme = "README" keywords = ["Exif", "JPEG", "parser", "reader", "TIFF"] categories = ["multimedia::encoding", "parser-implementations"] license = "BSD-2-Clause" + +[dependencies] +mutate_once = "0.1.1" diff --git a/examples/dumpexif.rs b/examples/dumpexif.rs index 0a88e5e..bd1eba6 100644 --- a/examples/dumpexif.rs +++ b/examples/dumpexif.rs @@ -49,9 +49,9 @@ fn dump_file(path: &Path) -> Result<(), exif::Error> { println!(" {}/{}: {}", f.ifd_num.index(), f.tag, f.display_value().with_unit(&reader)); - if let exif::Value::Ascii(ref s) = f.value { + if let exif::Value::Ascii(ref v) = f.value { println!(" Ascii({:?})", - s.iter().map(escape).collect::>()); + v.iter().map(|x| escape(x)).collect::>()); } else { println!(" {:?}", f.value); } @@ -59,9 +59,9 @@ fn dump_file(path: &Path) -> Result<(), exif::Error> { Ok(()) } -fn escape(bytes: &&[u8]) -> String { +fn escape(bytes: &[u8]) -> String { let mut buf = String::new(); - for &c in *bytes { + for &c in bytes { match c { b'\\' | b'"' => write!(buf, "\\{}", c as char).unwrap(), 0x20..=0x7e => buf.write_char(c as char).unwrap(), diff --git a/examples/reading.rs b/examples/reading.rs index 0bacb1c..d21eed2 100644 --- a/examples/reading.rs +++ b/examples/reading.rs @@ -72,7 +72,7 @@ fn main() { if let Some(field) = reader.get_field(Tag::DateTime, In::PRIMARY) { match field.value { Value::Ascii(ref vec) if !vec.is_empty() => { - if let Ok(datetime) = DateTime::from_ascii(vec[0]) { + if let Ok(datetime) = DateTime::from_ascii(&vec[0]) { println!("Year of DateTime is {}.", datetime.year); } }, diff --git a/src/lib.rs b/src/lib.rs index be74d38..a410e2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,13 +57,15 @@ //! * The type of `Context` was changed from enum to struct. The variants //! (e.g., `Context::Tiff`) were changed to associated constants and //! they are now spelled in all uppercase (e.g., `Context::TIFF`). +//! * `Value` became a self-contained type. The structures of `Value::Ascii` +//! and `Value::Undefined` have been changed to use Vec instead of &[u8]. pub use error::Error; pub use jpeg::get_exif_attr as get_exif_attr_from_jpeg; pub use reader::Reader; pub use tag::{Context, Tag}; pub use tiff::{DateTime, Field, In}; -pub use tiff::parse_exif; +pub use tiff::parse_exif_compat03 as parse_exif; pub use value::Value; pub use value::{Rational, SRational}; diff --git a/src/reader.rs b/src/reader.rs index 2b67d2c..e330aa1 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -64,11 +64,11 @@ pub struct Reader { // TIFF data. buf: Vec, // Exif fields. - fields: Vec>, + fields: Vec, // True if the TIFF data is little endian. little_endian: bool, // HashMap to find a field quickly. - field_map: HashMap<(Tag, In), &'static Field<'static>>, + field_map: HashMap<(Tag, In), &'static Field>, } impl Reader { @@ -89,11 +89,7 @@ impl Reader { return Err(Error::InvalidFormat("Unknown image format")); } - // Cheat on the type system and erase the lifetime by transmute(). - // The scope releases the inner `v` to unborrow `buf`. - let (fields, le) = { - let (v, le) = tiff::parse_exif(&buf)?; - (unsafe { mem::transmute::, Vec>(v) }, le) }; + let (fields, le) = tiff::parse_exif_compat03(&buf)?; // Initialize the HashMap of all fields. let mut field_map = HashMap::new(); @@ -118,7 +114,7 @@ impl Reader { /// Returns a slice of Exif fields. #[inline] - pub fn fields<'a>(&'a self) -> &[Field<'a>] { + pub fn fields<'a>(&'a self) -> &[Field] { &self.fields } @@ -137,7 +133,7 @@ impl Reader { } impl<'a> ProvideUnit<'a> for &'a Reader { - fn get_field(self, tag: Tag, ifd_num: In) -> Option<&'a Field<'a>> { + fn get_field(self, tag: Tag, ifd_num: In) -> Option<&'a Field> { self.get_field(tag, ifd_num) } } diff --git a/src/tag.rs b/src/tag.rs index c76cbb0..98f6da7 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -903,10 +903,10 @@ fn d_sensitivitytype(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // ExifVersion (Exif 0x9000), FlashpixVersion (Exif 0xa000) fn d_exifver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { - if let Value::Undefined(u, _) = *value { - if u.len() == 4 { - if let Ok(major) = atou16(&u[0..2]) { - if let Ok(minor) = atou16(&u[2..4]) { + if let Value::Undefined(ref v, _) = *value { + if v.len() == 4 { + if let Ok(major) = atou16(&v[0..2]) { + if let Ok(minor) = atou16(&v[2..4]) { if minor % 10 == 0 { return write!(w, "{}.{}", major, minor / 10); } else { @@ -921,8 +921,8 @@ fn d_exifver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // ComponentsConfiguration (Exif 0x9101) fn d_cpntcfg(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { - if let Value::Undefined(u, _) = *value { - for &x in u { + if let Value::Undefined(ref v, _) = *value { + for x in v { match x { 0 => w.write_char('_'), 1 => w.write_char('Y'), @@ -1092,7 +1092,7 @@ fn d_sensingmethod(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // FileSource (Exif 0xa300) fn d_filesrc(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { let s = match match *value { - Value::Undefined(s, _) => s.first().map(|&x| x), + Value::Undefined(ref v, _) => v.first().map(|&x| x), _ => None, } { Some(0) => "others", @@ -1107,7 +1107,7 @@ fn d_filesrc(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // SceneType (Exif 0xa301) fn d_scenetype(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { let s = match match *value { - Value::Undefined(s, _) => s.first().map(|&x| x), + Value::Undefined(ref v, _) => v.first().map(|&x| x), _ => None, } { Some(1) => "directly photographed image", @@ -1305,7 +1305,7 @@ fn d_gpstimestamp(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // GPSStatus (Exif/GPS 0x9) fn d_gpsstatus(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { let s = match match *value { - Value::Ascii(ref v) => v.first().map(|&x| x), + Value::Ascii(ref v) => v.first().map(|x| &x[..]), _ => None, } { Some(b"A") => "measurement in progress", @@ -1318,7 +1318,7 @@ fn d_gpsstatus(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // GPSMeasure (Exif/GPS 0xa) fn d_gpsmeasuremode(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { let s = match match *value { - Value::Ascii(ref v) => v.first().map(|&x| x), + Value::Ascii(ref v) => v.first().map(|x| &x[..]), _ => None, } { Some(b"2") => "2-dimensional measurement", @@ -1331,7 +1331,7 @@ fn d_gpsmeasuremode(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // GPSSpeedRef (Exif/GPS 0xc) fn d_gpsspeedref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { let s = match match *value { - Value::Ascii(ref v) => v.first().map(|&x| x), + Value::Ascii(ref v) => v.first().map(|x| &x[..]), _ => None, } { Some(b"K") => "km/h", @@ -1346,7 +1346,7 @@ fn d_gpsspeedref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // GPSDestBearingRef (Exif/GPS 0x17) fn d_gpsdirref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { let s = match match *value { - Value::Ascii(ref v) => v.first().map(|&x| x), + Value::Ascii(ref v) => v.first().map(|x| &x[..]), _ => None, } { Some(b"T") => "true direction", @@ -1359,7 +1359,7 @@ fn d_gpsdirref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { // GPSDestDistanceRef (Exif/GPS 0x19) fn d_gpsdistref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { let s = match match *value { - Value::Ascii(ref v) => v.first().map(|&x| x), + Value::Ascii(ref v) => v.first().map(|x| &x[..]), _ => None, } { Some(b"K") => "km", @@ -1401,7 +1401,7 @@ fn d_gpsdifferential(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_ascii_in_undef(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { match *value { - Value::Undefined(s, _) => d_sub_ascii(w, s), + Value::Undefined(ref v, _) => d_sub_ascii(w, v), _ => d_default(w, value), } } @@ -1439,7 +1439,7 @@ fn d_default(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { Value::Long(ref v) => d_sub_comma(w, v), Value::Rational(ref v) => d_sub_comma(w, v), Value::SByte(ref v) => d_sub_comma(w, v), - Value::Undefined(s, _) => d_sub_hex(w, s), + Value::Undefined(ref v, _) => d_sub_hex(w, v), Value::SShort(ref v) => d_sub_comma(w, v), Value::SLong(ref v) => d_sub_comma(w, v), Value::SRational(ref v) => d_sub_comma(w, v), diff --git a/src/tiff.rs b/src/tiff.rs index 0112596..51d7607 100644 --- a/src/tiff.rs +++ b/src/tiff.rs @@ -25,6 +25,7 @@ // use std::fmt; +use mutate_once::MutOnce; use crate::endian::{Endian, BigEndian, LittleEndian}; use crate::error::Error; @@ -41,15 +42,56 @@ const TIFF_FORTY_TWO: u16 = 0x002a; pub const TIFF_BE_SIG: [u8; 4] = [0x4d, 0x4d, 0x00, 0x2a]; pub const TIFF_LE_SIG: [u8; 4] = [0x49, 0x49, 0x2a, 0x00]; +// Partially parsed TIFF field (IFD entry). +// Value::Unknown is abused to represent a partially parsed value. +// Such a value must never be exposed to the users of this library. +#[derive(Debug)] +pub struct IfdEntry { + // When partially parsed, the value is stored as Value::Unknown. + // Do not leak this field to the outside. + field: MutOnce, +} + +impl IfdEntry { + fn into_field(self, data: &[u8], le: bool) -> Field { + self.parse(data, le); + self.field.into_inner() + } + + fn parse(&self, data: &[u8], le: bool) { + if !self.field.is_fixed() { + let mut field = self.field.get_mut(); + if le { + Self::parse_value::(&mut field.value, data); + } else { + Self::parse_value::(&mut field.value, data); + } + } + } + + // Converts a partially parsed value into a real one. + fn parse_value(value: &mut Value, data: &[u8]) where E: Endian { + match *value { + Value::Unknown(typ, cnt, ofs) => { + let (unitlen, parser) = get_type_info::(typ); + if unitlen != 0 { + *value = parser(data, ofs as usize, cnt as usize); + } + }, + _ => panic!("value is already parsed"), + } + } +} + /// A TIFF field. #[derive(Debug)] -pub struct Field<'a> { +pub struct Field { /// The tag of this field. pub tag: Tag, /// The index of the IFD to which this field belongs. pub ifd_num: In, /// The value of this field. - pub value: Value<'a>, + pub value: Value, } /// The IFD number. @@ -93,7 +135,15 @@ impl fmt::Display for In { /// Returns a Vec of Exif fields and a bool. /// The boolean value is true if the data is little endian. /// If an error occurred, `exif::Error` is returned. -pub fn parse_exif(data: &[u8]) -> Result<(Vec, bool), Error> { +pub fn parse_exif_compat03(data: &[u8]) -> Result<(Vec, bool), Error> { + parse_exif(data).map(|(entries, le)| { + let fields = entries.into_iter() + .map(|e| e.into_field(data, le)).collect(); + (fields, le) + }) +} + +pub fn parse_exif(data: &[u8]) -> Result<(Vec, bool), Error> { // Check the byte order and call the real parser. if data.len() < 8 { return Err(Error::InvalidFormat("Truncated TIFF header")); @@ -106,14 +156,14 @@ pub fn parse_exif(data: &[u8]) -> Result<(Vec, bool), Error> { } fn parse_exif_sub(data: &[u8]) - -> Result, Error> where E: Endian { + -> Result, Error> where E: Endian { // Parse the rest of the header (42 and the IFD offset). if E::loadu16(data, 2) != TIFF_FORTY_TWO { return Err(Error::InvalidFormat("Invalid forty two")); } let mut ifd_offset = E::loadu32(data, 4) as usize; let mut ifd_num_ck = Some(0); - let mut fields = Vec::new(); + let mut entries = Vec::new(); while ifd_offset != 0 { let ifd_num = ifd_num_ck.ok_or(Error::InvalidFormat("Too many IFDs"))?; // Limit the number of IFDs to defend against resource exhaustion @@ -122,16 +172,16 @@ fn parse_exif_sub(data: &[u8]) return Err(Error::InvalidFormat("Limit the IFD count to 8")); } ifd_offset = parse_ifd::( - &mut fields, data, ifd_offset, Context::TIFF, ifd_num)?; + &mut entries, data, ifd_offset, Context::TIFF, ifd_num)?; ifd_num_ck = ifd_num.checked_add(1); } - Ok(fields) + Ok(entries) } // Parse IFD [EXIF23 4.6.2]. -fn parse_ifd<'a, E>(fields: &mut Vec>, data: &'a [u8], - offset: usize, ctx: Context, ifd_num: u16) - -> Result where E: Endian { +fn parse_ifd(entries: &mut Vec, data: &[u8], + offset: usize, ctx: Context, ifd_num: u16) + -> Result where E: Endian { // Count (the number of the entries). if data.len() < offset || data.len() - offset < 2 { return Err(Error::InvalidFormat("Truncated IFD count")); @@ -145,36 +195,33 @@ fn parse_ifd<'a, E>(fields: &mut Vec>, data: &'a [u8], for i in 0..count as usize { let tag = E::loadu16(data, offset + 2 + i * 12); let typ = E::loadu16(data, offset + 2 + i * 12 + 2); - let cnt = E::loadu32(data, offset + 2 + i * 12 + 4) as usize; + let cnt = E::loadu32(data, offset + 2 + i * 12 + 4); let valofs_at = offset + 2 + i * 12 + 8; - let (unitlen, parser) = get_type_info::(typ); - let vallen = unitlen.checked_mul(cnt).ok_or( + let (unitlen, _parser) = get_type_info::(typ); + let vallen = unitlen.checked_mul(cnt as usize).ok_or( Error::InvalidFormat("Invalid entry count"))?; - let val; - if unitlen == 0 { - val = Value::Unknown(typ, cnt as u32, valofs_at as u32); - } else if vallen <= 4 { - val = parser(data, valofs_at, cnt); + let mut val = if vallen <= 4 { + Value::Unknown(typ, cnt, valofs_at as u32) } else { let ofs = E::loadu32(data, valofs_at) as usize; if data.len() < ofs || data.len() - ofs < vallen { return Err(Error::InvalidFormat("Truncated field value")); } - val = parser(data, ofs, cnt); - } + Value::Unknown(typ, cnt, ofs as u32) + }; // No infinite recursion will occur because the context is not // recursively defined. let tag = Tag(ctx, tag); match tag { Tag::ExifIFDPointer => parse_child_ifd::( - fields, data, &val, Context::EXIF, ifd_num)?, + entries, data, &mut val, Context::EXIF, ifd_num)?, Tag::GPSInfoIFDPointer => parse_child_ifd::( - fields, data, &val, Context::GPS, ifd_num)?, + entries, data, &mut val, Context::GPS, ifd_num)?, Tag::InteropIFDPointer => parse_child_ifd::( - fields, data, &val, Context::INTEROP, ifd_num)?, - _ => fields.push(Field { - tag: tag, ifd_num: In(ifd_num), value: val }), + entries, data, &mut val, Context::INTEROP, ifd_num)?, + _ => entries.push(IfdEntry { field: Field { + tag: tag, ifd_num: In(ifd_num), value: val }.into()}), } } @@ -186,15 +233,18 @@ fn parse_ifd<'a, E>(fields: &mut Vec>, data: &'a [u8], Ok(next_ifd_offset) } -fn parse_child_ifd<'a, E>(fields: &mut Vec>, data: &'a [u8], - pointer: &Value, ctx: Context, ifd_num: u16) - -> Result<(), Error> where E: Endian { +fn parse_child_ifd(entries: &mut Vec, data: &[u8], + pointer: &mut Value, ctx: Context, ifd_num: u16) + -> Result<(), Error> where E: Endian { + // The pointer is not yet parsed, so do it here. + IfdEntry::parse_value::(pointer, data); + // A pointer field has type == LONG and count == 1, so the // value (IFD offset) must be embedded in the "value offset" // element of the field. let ofs = pointer.get_uint(0).ok_or( Error::InvalidFormat("Invalid pointer"))? as usize; - match parse_ifd::(fields, data, ofs, ctx, ifd_num)? { + match parse_ifd::(entries, data, ofs, ctx, ifd_num)? { 0 => Ok(()), _ => Err(Error::InvalidFormat("Unexpected next IFD")), } @@ -308,7 +358,7 @@ impl fmt::Display for DateTime { } } -impl<'a> Field<'a> { +impl Field { /// Returns an object that implements `std::fmt::Display` for /// printing the value of this field in a tag-specific format. /// @@ -426,17 +476,17 @@ impl<'a, T> fmt::Display for DisplayValueUnit<'a, T> where T: ProvideUnit<'a> { } pub trait ProvideUnit<'a>: Copy { - fn get_field(self, tag: Tag, ifd_num: In) -> Option<&'a Field<'a>>; + fn get_field(self, tag: Tag, ifd_num: In) -> Option<&'a Field>; } impl<'a> ProvideUnit<'a> for () { - fn get_field(self, _tag: Tag, _ifd_num: In) -> Option<&'a Field<'a>> { + fn get_field(self, _tag: Tag, _ifd_num: In) -> Option<&'a Field> { None } } -impl<'a> ProvideUnit<'a> for &'a Field<'a> { - fn get_field(self, tag: Tag, ifd_num: In) -> Option<&'a Field<'a>> { +impl<'a> ProvideUnit<'a> for &'a Field { + fn get_field(self, tag: Tag, ifd_num: In) -> Option<&'a Field> { Some(self).filter(|x| x.tag == tag && x.ifd_num == ifd_num) } } @@ -487,7 +537,7 @@ mod tests { fn unknown_field() { let data = b"MM\0\x2a\0\0\0\x08\ \0\x01\x01\0\xff\xff\0\0\0\x01\0\x14\0\0\0\0\0\0"; - let (v, _) = parse_exif(data).unwrap(); + let (v, _) = parse_exif_compat03(data).unwrap(); assert_eq!(v.len(), 1); assert_pat!(v[0].value, Value::Unknown(0xffff, 1, 0x12)); } @@ -545,7 +595,7 @@ mod tests { let exifver = Field { tag: Tag::ExifVersion, ifd_num: In::PRIMARY, - value: Value::Undefined(b"0231", 0), + value: Value::Undefined(b"0231".to_vec(), 0), }; assert_eq!(exifver.display_value().to_string(), "2.31"); diff --git a/src/value.rs b/src/value.rs index b1baf3e..1f47629 100644 --- a/src/value.rs +++ b/src/value.rs @@ -30,13 +30,13 @@ use crate::endian::Endian; /// Types and values of TIFF fields (for Exif attributes). #[derive(Debug)] -pub enum Value<'a> { +pub enum Value { /// Vector of 8-bit unsigned integers. Byte(Vec), /// Vector of slices of 8-bit bytes containing 7-bit ASCII characters. /// The trailing null characters are not included. Note that /// the 8th bits may present if a non-conforming data is given. - Ascii(Vec<&'a [u8]>), + Ascii(Vec>), /// Vector of 16-bit unsigned integers. Short(Vec), /// Vector of 32-bit unsigned integers. @@ -52,7 +52,7 @@ pub enum Value<'a> { /// The interpretation of the value does not generally depend on /// the location, but if it does, the offset information helps. /// When encoding Exif, it is ignored. - Undefined(&'a [u8], u32), + Undefined(Vec, u32), /// Vector of 16-bit signed integers. Unused in the Exif specification. SShort(Vec), /// Vector of 32-bit signed integers. @@ -72,7 +72,7 @@ pub enum Value<'a> { Unknown(u16, u32, u32), } -impl<'a> Value<'a> { +impl Value { /// Returns an object that implements `std::fmt::Display` for /// printing a value in a tag-specific format. /// The tag of the value is specified as the argument. @@ -83,7 +83,7 @@ impl<'a> Value<'a> { /// /// ``` /// use exif::{Value, Tag}; - /// let val = Value::Undefined(b"0231", 0); + /// let val = Value::Undefined(b"0231".to_vec(), 0); /// assert_eq!(val.display_as(Tag::ExifVersion).to_string(), "2.31"); /// let val = Value::Short(vec![2]); /// assert_eq!(val.display_as(Tag::ResolutionUnit).to_string(), "inch"); @@ -149,7 +149,7 @@ impl<'a> ExactSizeIterator for UIntIter<'a> {} #[derive(Copy, Clone)] pub struct Display<'a> { pub fmt: fn(&mut dyn fmt::Write, &Value) -> fmt::Result, - pub value: &'a Value<'a>, + pub value: &'a Value, } impl<'a> fmt::Display for Display<'a> { @@ -173,16 +173,18 @@ pub enum DefaultValue { Unspecified, } -impl<'a> From<&'a DefaultValue> for Option> { +impl From<&DefaultValue> for Option { fn from(defval: &DefaultValue) -> Option { match *defval { DefaultValue::None => None, DefaultValue::Byte(s) => Some(Value::Byte(s.to_vec())), - DefaultValue::Ascii(s) => Some(Value::Ascii(s.to_vec())), + DefaultValue::Ascii(s) => Some(Value::Ascii( + s.iter().map(|&x| x.to_vec()).collect())), DefaultValue::Short(s) => Some(Value::Short(s.to_vec())), DefaultValue::Rational(s) => Some(Value::Rational( s.iter().map(|&x| x.into()).collect())), - DefaultValue::Undefined(s) => Some(Value::Undefined(s, 0)), + DefaultValue::Undefined(s) => Some(Value::Undefined( + s.to_vec(), 0)), DefaultValue::ContextDependent => None, DefaultValue::Unspecified => None, } @@ -295,11 +297,10 @@ fn fmt_rational_sub(f: &mut fmt::Formatter, num: u32, denom: T) } } -type Parser<'a> = fn(&'a [u8], usize, usize) -> Value<'a>; +type Parser = fn(&[u8], usize, usize) -> Value; // Return the length of a single value and the parser of the type. -pub fn get_type_info<'a, E>(typecode: u16) - -> (usize, Parser<'a>) where E: Endian { +pub fn get_type_info(typecode: u16) -> (usize, Parser) where E: Endian { match typecode { 1 => (1, parse_byte), 2 => (1, parse_ascii), @@ -317,25 +318,23 @@ pub fn get_type_info<'a, E>(typecode: u16) } } -fn parse_byte<'a>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> { +fn parse_byte(data: &[u8], offset: usize, count: usize) -> Value { Value::Byte(data[offset .. offset + count].to_vec()) } -fn parse_ascii<'a>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> { +fn parse_ascii(data: &[u8], offset: usize, count: usize) -> Value { // Any ASCII field can contain multiple strings [TIFF6 Image File // Directory]. let iter = (&data[offset .. offset + count]).split(|&b| b == b'\0'); - let mut v: Vec<&[u8]> = iter.collect(); - if v.last().map_or(false, |&s| s.len() == 0) { + let mut v: Vec> = iter.map(|x| x.to_vec()).collect(); + if v.last().map_or(false, |x| x.len() == 0) { v.pop(); } Value::Ascii(v) } -fn parse_short<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_short(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(E::loadu16(data, offset + i * 2)); @@ -343,8 +342,8 @@ fn parse_short<'a, E>(data: &'a [u8], offset: usize, count: usize) Value::Short(val) } -fn parse_long<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_long(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(E::loadu32(data, offset + i * 4)); @@ -352,8 +351,8 @@ fn parse_long<'a, E>(data: &'a [u8], offset: usize, count: usize) Value::Long(val) } -fn parse_rational<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_rational(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(Rational { @@ -364,21 +363,19 @@ fn parse_rational<'a, E>(data: &'a [u8], offset: usize, count: usize) Value::Rational(val) } -fn parse_sbyte<'a>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> { +fn parse_sbyte(data: &[u8], offset: usize, count: usize) -> Value { let bytes = data[offset .. offset + count].into_iter() .map(|x| *x as i8) .collect(); Value::SByte(bytes) } -fn parse_undefined<'a>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> { - Value::Undefined(&data[offset .. offset + count], offset as u32) +fn parse_undefined(data: &[u8], offset: usize, count: usize) -> Value { + Value::Undefined(data[offset .. offset + count].to_vec(), offset as u32) } -fn parse_sshort<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_sshort(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(E::loadu16(data, offset + i * 2) as i16); @@ -386,8 +383,8 @@ fn parse_sshort<'a, E>(data: &'a [u8], offset: usize, count: usize) Value::SShort(val) } -fn parse_slong<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_slong(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(E::loadu32(data, offset + i * 4) as i32); @@ -395,8 +392,8 @@ fn parse_slong<'a, E>(data: &'a [u8], offset: usize, count: usize) Value::SLong(val) } -fn parse_srational<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_srational(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(SRational { @@ -408,8 +405,8 @@ fn parse_srational<'a, E>(data: &'a [u8], offset: usize, count: usize) } // TIFF and Rust use IEEE 754 format, so no conversion is required. -fn parse_float<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_float(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(f32::from_bits(E::loadu32(data, offset + i * 4))); @@ -418,8 +415,8 @@ fn parse_float<'a, E>(data: &'a [u8], offset: usize, count: usize) } // TIFF and Rust use IEEE 754 format, so no conversion is required. -fn parse_double<'a, E>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> where E: Endian { +fn parse_double(data: &[u8], offset: usize, count: usize) + -> Value where E: Endian { let mut val = Vec::with_capacity(count); for i in 0..count { val.push(f64::from_bits(E::loadu64(data, offset + i * 8))); @@ -429,8 +426,7 @@ fn parse_double<'a, E>(data: &'a [u8], offset: usize, count: usize) // This is a dummy function and will never be called. #[allow(unused_variables)] -fn parse_unknown<'a>(data: &'a [u8], offset: usize, count: usize) - -> Value<'a> { +fn parse_unknown(data: &[u8], offset: usize, count: usize) -> Value { unreachable!() } diff --git a/src/writer.rs b/src/writer.rs index 4f87b0c..8f22f5e 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -43,7 +43,7 @@ use crate::value::Value; /// let image_desc = Field { /// tag: Tag::ImageDescription, /// ifd_num: In::PRIMARY, -/// value: Value::Ascii(vec![b"Sample"]), +/// value: Value::Ascii(vec![b"Sample".to_vec()]), /// }; /// let mut writer = Writer::new(); /// let mut buf = std::io::Cursor::new(Vec::new()); @@ -63,10 +63,10 @@ pub struct Writer<'a> { #[derive(Debug, Default)] struct Ifd<'a> { - tiff_fields: Vec<&'a Field<'a>>, - exif_fields: Vec<&'a Field<'a>>, - gps_fields: Vec<&'a Field<'a>>, - interop_fields: Vec<&'a Field<'a>>, + tiff_fields: Vec<&'a Field>, + exif_fields: Vec<&'a Field>, + gps_fields: Vec<&'a Field>, + interop_fields: Vec<&'a Field>, strips: Option<&'a [&'a [u8]]>, tiles: Option<&'a [&'a [u8]]>, jpeg: Option<&'a [u8]>, @@ -85,10 +85,10 @@ impl<'a> Ifd<'a> { } struct WriterState<'a> { - tiff_fields: Vec<&'a Field<'a>>, - exif_fields: Vec<&'a Field<'a>>, - gps_fields: Vec<&'a Field<'a>>, - interop_fields: Vec<&'a Field<'a>>, + tiff_fields: Vec<&'a Field>, + exif_fields: Vec<&'a Field>, + gps_fields: Vec<&'a Field>, + interop_fields: Vec<&'a Field>, tiff_ifd_offset: u32, exif_ifd_offset: u32, gps_ifd_offset: u32, @@ -474,8 +474,8 @@ fn compose_value(value: &Value) Ok((1, vec.len(), vec.clone())), Value::Ascii(ref vec) => { let mut buf = Vec::new(); - for &s in vec { - buf.extend_from_slice(s); + for x in vec { + buf.extend_from_slice(x); buf.push(0); } Ok((2, buf.len(), buf)) @@ -593,7 +593,7 @@ mod tests { let image_desc = Field { tag: Tag::ImageDescription, ifd_num: In::PRIMARY, - value: Value::Ascii(vec![b"Sample"]), + value: Value::Ascii(vec![b"Sample".to_vec()]), }; let mut writer = Writer::new(); let mut buf = Cursor::new(Vec::new()); @@ -612,7 +612,7 @@ mod tests { let exif_ver = Field { tag: Tag::ExifVersion, ifd_num: In::PRIMARY, - value: Value::Undefined(b"0231", 0), + value: Value::Undefined(b"0231".to_vec(), 0), }; let mut writer = Writer::new(); let mut buf = Cursor::new(Vec::new()); @@ -651,7 +651,7 @@ mod tests { let desc = Field { tag: Tag::ImageDescription, ifd_num: In::PRIMARY, - value: Value::Ascii(vec![b"jpg"]), + value: Value::Ascii(vec![b"jpg".to_vec()]), }; let mut writer = Writer::new(); let mut buf = Cursor::new(Vec::new()); @@ -675,7 +675,7 @@ mod tests { let desc = Field { tag: Tag::ImageDescription, ifd_num: In::PRIMARY, - value: Value::Ascii(vec![b"tif"]), + value: Value::Ascii(vec![b"tif".to_vec()]), }; let strips: &[&[u8]] = &[b"STRIP"]; let mut writer = Writer::new(); @@ -699,12 +699,12 @@ mod tests { let image_desc = Field { tag: Tag::ImageDescription, ifd_num: In::PRIMARY, - value: Value::Ascii(vec![b"Sample"]), + value: Value::Ascii(vec![b"Sample".to_vec()]), }; let exif_ver = Field { tag: Tag::ExifVersion, ifd_num: In::PRIMARY, - value: Value::Undefined(b"0231", 0), + value: Value::Undefined(b"0231".to_vec(), 0), }; let gps_ver = Field { tag: Tag::GPSVersionID, @@ -714,7 +714,7 @@ mod tests { let interop_index = Field { tag: Tag::InteroperabilityIndex, ifd_num: In::PRIMARY, - value: Value::Ascii(vec![b"ABC"]), + value: Value::Ascii(vec![b"ABC".to_vec()]), }; let jpeg = b"JPEG"; let mut writer = Writer::new(); @@ -751,17 +751,17 @@ mod tests { let desc0 = Field { tag: Tag::ImageDescription, ifd_num: In::PRIMARY, - value: Value::Ascii(vec![b"p"]), + value: Value::Ascii(vec![b"p".to_vec()]), }; let desc1 = Field { tag: Tag::ImageDescription, ifd_num: In::THUMBNAIL, - value: Value::Ascii(vec![b"t"]), + value: Value::Ascii(vec![b"t".to_vec()]), }; let desc2 = Field { tag: Tag::ImageDescription, ifd_num: In(2), - value: Value::Ascii(vec![b"2"]), + value: Value::Ascii(vec![b"2".to_vec()]), }; let mut writer = Writer::new(); let mut buf = Cursor::new(Vec::new()); @@ -803,7 +803,7 @@ mod tests { let image_desc = Field { tag: Tag::ImageDescription, ifd_num: In::PRIMARY, - value: Value::Ascii(vec![b"Sample"]), + value: Value::Ascii(vec![b"Sample".to_vec()]), }; let mut writer = Writer::new(); writer.push_field(&image_desc); @@ -820,7 +820,7 @@ mod tests { (Value::Byte(vec![1, 2]), (1, 2, vec![1, 2]), (1, 2, vec![1, 2])), - (Value::Ascii(vec![b"a", b"b"]), + (Value::Ascii(vec![b"a".to_vec(), b"b".to_vec()]), (2, 4, b"a\0b\0".to_vec()), (2, 4, b"a\0b\0".to_vec())), (Value::Short(vec![0x0102, 0x0304]), @@ -835,7 +835,7 @@ mod tests { (Value::SByte(vec![-2, -128]), (6, 2, b"\xfe\x80".to_vec()), (6, 2, b"\xfe\x80".to_vec())), - (Value::Undefined(b"abc", 0), + (Value::Undefined(b"abc".to_vec(), 0), (7, 3, b"abc".to_vec()), (7, 3, b"abc".to_vec())), (Value::SShort(vec![-2, -0x8000]),