Do not reference the raw buffer from Value and Field.

Previously, they borrowed the buffer, so users had some difficulty to
manage the lifetime of the buffer and Value/Field.  For example,
a user structure was unable to contain both the buffer and a Field.
This commit is contained in:
KAMADA Ken'ichi 2019-12-14 21:57:35 +09:00
parent 1533be5a2a
commit 1bd083cbae
9 changed files with 178 additions and 131 deletions

View File

@ -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"

View File

@ -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::<Vec<_>>());
v.iter().map(|x| escape(x)).collect::<Vec<_>>());
} 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(),

View File

@ -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);
}
},

View File

@ -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<u8> 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};

View File

@ -64,11 +64,11 @@ pub struct Reader {
// TIFF data.
buf: Vec<u8>,
// Exif fields.
fields: Vec<Field<'static>>,
fields: Vec<Field>,
// 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<Field>, Vec<Field>>(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)
}
}

View File

@ -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),

View File

@ -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<Field>,
}
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::<LittleEndian>(&mut field.value, data);
} else {
Self::parse_value::<BigEndian>(&mut field.value, data);
}
}
}
// Converts a partially parsed value into a real one.
fn parse_value<E>(value: &mut Value, data: &[u8]) where E: Endian {
match *value {
Value::Unknown(typ, cnt, ofs) => {
let (unitlen, parser) = get_type_info::<E>(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<Field>, bool), Error> {
pub fn parse_exif_compat03(data: &[u8]) -> Result<(Vec<Field>, 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<IfdEntry>, 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<Field>, bool), Error> {
}
fn parse_exif_sub<E>(data: &[u8])
-> Result<Vec<Field>, Error> where E: Endian {
-> Result<Vec<IfdEntry>, 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<E>(data: &[u8])
return Err(Error::InvalidFormat("Limit the IFD count to 8"));
}
ifd_offset = parse_ifd::<E>(
&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<Field<'a>>, data: &'a [u8],
offset: usize, ctx: Context, ifd_num: u16)
-> Result<usize, Error> where E: Endian {
fn parse_ifd<E>(entries: &mut Vec<IfdEntry>, data: &[u8],
offset: usize, ctx: Context, ifd_num: u16)
-> Result<usize, Error> 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<Field<'a>>, 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::<E>(typ);
let vallen = unitlen.checked_mul(cnt).ok_or(
let (unitlen, _parser) = get_type_info::<E>(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::<E>(
fields, data, &val, Context::EXIF, ifd_num)?,
entries, data, &mut val, Context::EXIF, ifd_num)?,
Tag::GPSInfoIFDPointer => parse_child_ifd::<E>(
fields, data, &val, Context::GPS, ifd_num)?,
entries, data, &mut val, Context::GPS, ifd_num)?,
Tag::InteropIFDPointer => parse_child_ifd::<E>(
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<Field<'a>>, data: &'a [u8],
Ok(next_ifd_offset)
}
fn parse_child_ifd<'a, E>(fields: &mut Vec<Field<'a>>, data: &'a [u8],
pointer: &Value, ctx: Context, ifd_num: u16)
-> Result<(), Error> where E: Endian {
fn parse_child_ifd<E>(entries: &mut Vec<IfdEntry>, 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::<E>(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::<E>(fields, data, ofs, ctx, ifd_num)? {
match parse_ifd::<E>(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");

View File

@ -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<u8>),
/// 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<Vec<u8>>),
/// Vector of 16-bit unsigned integers.
Short(Vec<u16>),
/// 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<u8>, u32),
/// Vector of 16-bit signed integers. Unused in the Exif specification.
SShort(Vec<i16>),
/// 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<Value<'a>> {
impl From<&DefaultValue> for Option<Value> {
fn from(defval: &DefaultValue) -> Option<Value> {
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<T>(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<E>(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<Vec<u8>> = 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<E>(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<E>(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<E>(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<E>(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<E>(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<E>(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<E>(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<E>(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!()
}

View File

@ -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<E>(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]),