Try a new API set internally for Value access.

This commit is contained in:
KAMADA Ken'ichi 2020-02-15 19:07:58 +09:00
parent 22395fca25
commit 663a24de79
2 changed files with 108 additions and 105 deletions

View File

@ -780,11 +780,9 @@ fn d_resunit(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// DateTime (TIFF 0x132), DateTimeOriginal (Exif 0x9003), and // DateTime (TIFF 0x132), DateTimeOriginal (Exif 0x9003), and
// DateTimeDigitized (Exif 0x9004) // DateTimeDigitized (Exif 0x9004)
fn d_datetime(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_datetime(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
if let Value::Ascii(ref v) = *value { if let Some(dt) = value.ascii().and_then(|x| x.first()) {
if let Some(dt) = v.first() { if let Ok(dt) = crate::tiff::DateTime::from_ascii(dt) {
if let Ok(dt) = crate::tiff::DateTime::from_ascii(dt) { return write!(w, "{}", dt)
return write!(w, "{}", dt)
}
} }
} }
d_default(w, value) d_default(w, value)
@ -821,13 +819,11 @@ fn d_ycbcrpos(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// ExposureTime (Exif 0x829a) // ExposureTime (Exif 0x829a)
fn d_exptime(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_exptime(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
if let Value::Rational(ref v) = *value { if let Some(et) = value.rational().and_then(|x| x.first()) {
if let Some(et) = v.first() { if et.num >= et.denom {
if et.num >= et.denom { return write!(w, "{}", et.to_f64());
return write!(w, "{}", et.to_f64()); } else if et.num != 0 {
} else if et.num != 0 { return write!(w, "1/{}", et.denom as f64 / et.num as f64);
return write!(w, "1/{}", et.denom as f64 / et.num as f64);
}
} }
} }
d_default(w, value) d_default(w, value)
@ -866,15 +862,13 @@ fn d_sensitivitytype(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// ExifVersion (Exif 0x9000), FlashpixVersion (Exif 0xa000) // ExifVersion (Exif 0x9000), FlashpixVersion (Exif 0xa000)
fn d_exifver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_exifver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
if let Value::Undefined(ref v, _) = *value { if let Some(s) = value.undefined().filter(|s| s.len() == 4) {
if v.len() == 4 { if let Ok(major) = atou16(&s[0..2]) {
if let Ok(major) = atou16(&v[0..2]) { if let Ok(minor) = atou16(&s[2..4]) {
if let Ok(minor) = atou16(&v[2..4]) { if minor % 10 == 0 {
if minor % 10 == 0 { return write!(w, "{}.{}", major, minor / 10);
return write!(w, "{}.{}", major, minor / 10); } else {
} else { return write!(w, "{}.{:02}", major, minor);
return write!(w, "{}.{:02}", major, minor);
}
} }
} }
} }
@ -884,33 +878,28 @@ fn d_exifver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// ComponentsConfiguration (Exif 0x9101) // ComponentsConfiguration (Exif 0x9101)
fn d_cpntcfg(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_cpntcfg(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
if let Value::Undefined(ref v, _) = *value { match value.undefined() {
for x in v { Some(s) => s.iter().try_for_each(|x| match x {
match x { 0 => w.write_char('_'),
0 => w.write_char('_'), 1 => w.write_char('Y'),
1 => w.write_char('Y'), 2 => w.write_str("Cb"),
2 => w.write_str("Cb"), 3 => w.write_str("Cr"),
3 => w.write_str("Cr"), 4 => w.write_char('R'),
4 => w.write_char('R'), 5 => w.write_char('G'),
5 => w.write_char('G'), 6 => w.write_char('B'),
6 => w.write_char('B'), _ => w.write_char('?'),
_ => w.write_char('?'), }),
}?; None => d_default(w, value),
}
return Ok(());
} }
d_default(w, value)
} }
// SubjectDistance (Exif 0x9206) // SubjectDistance (Exif 0x9206)
fn d_subjdist(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_subjdist(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
if let Value::Rational(ref v) = *value { if let Some(dist) = value.rational().and_then(|x| x.first()) {
if let Some(dist) = v.first() { if dist.num == 0 {
if dist.num == 0 { return w.write_str("unknown");
return w.write_str("unknown"); } else if dist.num == 0xffffffff {
} else if dist.num == 0xffffffff { return w.write_str("infinity");
return w.write_str("infinity");
}
} }
} }
d_decimal(w, value) d_decimal(w, value)
@ -1055,10 +1044,7 @@ fn d_sensingmethod(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// FileSource (Exif 0xa300) // FileSource (Exif 0xa300)
fn d_filesrc(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_filesrc(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
let s = match match *value { let s = match value.undefined().and_then(|x| x.first().copied()) {
Value::Undefined(ref v, _) => v.first().map(|&x| x),
_ => None,
} {
Some(0) => "others", Some(0) => "others",
Some(1) => "transparency scanner", Some(1) => "transparency scanner",
Some(2) => "reflective scanner", Some(2) => "reflective scanner",
@ -1070,10 +1056,7 @@ fn d_filesrc(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// SceneType (Exif 0xa301) // SceneType (Exif 0xa301)
fn d_scenetype(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_scenetype(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
let s = match match *value { let s = match value.undefined().and_then(|x| x.first().copied()) {
Value::Undefined(ref v, _) => v.first().map(|&x| x),
_ => None,
} {
Some(1) => "directly photographed image", Some(1) => "directly photographed image",
_ => return d_unknown(w, value, "unknown scene type "), _ => return d_unknown(w, value, "unknown scene type "),
}; };
@ -1113,10 +1096,8 @@ fn d_whitebalance(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// DigitalZoomRatio (Exif 0xa404) // DigitalZoomRatio (Exif 0xa404)
fn d_dzoomratio(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_dzoomratio(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
if let Value::Rational(ref v) = *value { if value.rational().and_then(|x| x.first()).map(|x| x.num) == Some(0) {
if v.len() > 0 && v[0].num == 0 { return w.write_str("unused");
return w.write_str("unused");
}
} }
d_decimal(w, value) d_decimal(w, value)
} }
@ -1200,13 +1181,12 @@ fn d_subjdistrange(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// LensSpecification (Exif 0xa432) // LensSpecification (Exif 0xa432)
fn d_lensspec(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_lensspec(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
match *value { match value.rational().and_then(|x| x.get(..4)) {
Value::Rational(ref v) if v.len() >= 4 => // There are several notations: "F1.4" in Japan, "f/1.4"
// There are several notations: "F1.4" in Japan, "f/1.4" // in the U.S., and so on.
// in the U.S., and so on. Some(s) => write!(w, "{}-{} mm, f/{}-{}",
write!(w, "{}-{} mm, f/{}-{}", s[0].to_f64(), s[1].to_f64(),
v[0].to_f64(), v[1].to_f64(), s[2].to_f64(), s[3].to_f64()),
v[2].to_f64(), v[3].to_f64()),
_ => d_default(w, value), _ => d_default(w, value),
} }
} }
@ -1232,9 +1212,8 @@ fn d_numcpstimg(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSVersionID (Exif/GPS 0x0) // GPSVersionID (Exif/GPS 0x0)
fn d_gpsver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
match *value { match value.byte().and_then(|x| x.get(..4)) {
Value::Byte(ref v) if v.len() >= 4 => Some(s) => write!(w, "{}.{}.{}.{}", s[0], s[1], s[2], s[3]),
write!(w, "{}.{}.{}.{}", v[0], v[1], v[2], v[3]),
_ => d_default(w, value), _ => d_default(w, value),
} }
} }
@ -1242,10 +1221,8 @@ fn d_gpsver(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSLatitudeRef (Exif/GPS 0x1), GPSLongitudeRef (Exif/GPS 0x3) // GPSLatitudeRef (Exif/GPS 0x1), GPSLongitudeRef (Exif/GPS 0x3)
// GPSDestLatitudeRef (Exif/GPS 0x13), GPSDestLongitudeRef (Exif/GPS 0x15) // GPSDestLatitudeRef (Exif/GPS 0x13), GPSDestLongitudeRef (Exif/GPS 0x15)
fn d_gpslatlongref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpslatlongref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
match *value { match value.ascii().and_then(|x| x.first()) {
Value::Ascii(ref v) if (v.len() == 1 && v[0].len() == 1 && Some([c]) if c.is_ascii_uppercase() => w.write_char(*c as char),
v[0][0].is_ascii_uppercase()) =>
w.write_char(v[0][0] as char),
_ => d_default(w, value), _ => d_default(w, value),
} }
} }
@ -1253,10 +1230,9 @@ fn d_gpslatlongref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSLatitude (Exif/GPS 0x2), GPSLongitude (Exif/GPS 0x4), // GPSLatitude (Exif/GPS 0x2), GPSLongitude (Exif/GPS 0x4),
// GPSDestLatitude (Exif/GPS 0x14), GPSDestLongitude (Exif/GPS 0x16) // GPSDestLatitude (Exif/GPS 0x14), GPSDestLongitude (Exif/GPS 0x16)
fn d_gpsdms(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsdms(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
match *value { match value.rational().and_then(|x| x.get(..3)) {
Value::Rational(ref v) if v.len() >= 3 => Some(s) => write!(w, "{} deg {} min {} sec",
write!(w, "{} deg {} min {} sec", s[0].to_f64(), s[1].to_f64(), s[2].to_f64()),
v[0].to_f64(), v[1].to_f64(), v[2].to_f64()),
_ => d_default(w, value), _ => d_default(w, value),
} }
} }
@ -1273,9 +1249,9 @@ fn d_gpsaltref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSTimeStamp (Exif/GPS 0x7) // GPSTimeStamp (Exif/GPS 0x7)
fn d_gpstimestamp(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpstimestamp(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
match *value { match value.rational().and_then(|x| x.get(..3)) {
Value::Rational(ref v) if v.len() >= 3 => { Some(s) => {
let (h, m, s) = (v[0].to_f64(), v[1].to_f64(), v[2].to_f64()); let (h, m, s) = (s[0].to_f64(), s[1].to_f64(), s[2].to_f64());
write!(w, "{}{}:{}{}:{}{}", write!(w, "{}{}:{}{}:{}{}",
if h < 10.0 { "0" } else { "" }, h, if h < 10.0 { "0" } else { "" }, h,
if m < 10.0 { "0" } else { "" }, m, if m < 10.0 { "0" } else { "" }, m,
@ -1287,10 +1263,7 @@ fn d_gpstimestamp(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSStatus (Exif/GPS 0x9) // GPSStatus (Exif/GPS 0x9)
fn d_gpsstatus(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsstatus(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
let s = match match *value { let s = match value.ascii().and_then(|x| x.first()) {
Value::Ascii(ref v) => v.first().map(|x| &x[..]),
_ => None,
} {
Some(b"A") => "measurement in progress", Some(b"A") => "measurement in progress",
Some(b"V") => "measurement interrupted", Some(b"V") => "measurement interrupted",
_ => return d_unknown(w, value, "unknown GPS status "), _ => return d_unknown(w, value, "unknown GPS status "),
@ -1300,10 +1273,7 @@ fn d_gpsstatus(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSMeasure (Exif/GPS 0xa) // GPSMeasure (Exif/GPS 0xa)
fn d_gpsmeasuremode(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsmeasuremode(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
let s = match match *value { let s = match value.ascii().and_then(|x| x.first()) {
Value::Ascii(ref v) => v.first().map(|x| &x[..]),
_ => None,
} {
Some(b"2") => "2-dimensional measurement", Some(b"2") => "2-dimensional measurement",
Some(b"3") => "3-dimensional measurement", Some(b"3") => "3-dimensional measurement",
_ => return d_unknown(w, value, "unknown GPS measurement mode "), _ => return d_unknown(w, value, "unknown GPS measurement mode "),
@ -1313,10 +1283,7 @@ fn d_gpsmeasuremode(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSSpeedRef (Exif/GPS 0xc) // GPSSpeedRef (Exif/GPS 0xc)
fn d_gpsspeedref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsspeedref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
let s = match match *value { let s = match value.ascii().and_then(|x| x.first()) {
Value::Ascii(ref v) => v.first().map(|x| &x[..]),
_ => None,
} {
Some(b"K") => "km/h", Some(b"K") => "km/h",
Some(b"M") => "mph", Some(b"M") => "mph",
Some(b"N") => "knots", Some(b"N") => "knots",
@ -1328,10 +1295,7 @@ fn d_gpsspeedref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSTrackRef (Exif/GPS 0xe), GPSImgDirectionRef (Exif/GPS 0x10), // GPSTrackRef (Exif/GPS 0xe), GPSImgDirectionRef (Exif/GPS 0x10),
// GPSDestBearingRef (Exif/GPS 0x17) // GPSDestBearingRef (Exif/GPS 0x17)
fn d_gpsdirref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsdirref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
let s = match match *value { let s = match value.ascii().and_then(|x| x.first()) {
Value::Ascii(ref v) => v.first().map(|x| &x[..]),
_ => None,
} {
Some(b"T") => "true direction", Some(b"T") => "true direction",
Some(b"M") => "magnetic direction", Some(b"M") => "magnetic direction",
_ => return d_unknown(w, value, "unknown GPS direction ref "), _ => return d_unknown(w, value, "unknown GPS direction ref "),
@ -1341,10 +1305,7 @@ fn d_gpsdirref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSDestDistanceRef (Exif/GPS 0x19) // GPSDestDistanceRef (Exif/GPS 0x19)
fn d_gpsdistref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsdistref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
let s = match match *value { let s = match value.ascii().and_then(|x| x.first()) {
Value::Ascii(ref v) => v.first().map(|x| &x[..]),
_ => None,
} {
Some(b"K") => "km", Some(b"K") => "km",
Some(b"M") => "miles", Some(b"M") => "miles",
Some(b"N") => "nautical miles", Some(b"N") => "nautical miles",
@ -1355,15 +1316,13 @@ fn d_gpsdistref(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
// GPSDateStamp (Exif/GPS 0x1d) // GPSDateStamp (Exif/GPS 0x1d)
fn d_gpsdatestamp(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result { fn d_gpsdatestamp(w: &mut dyn fmt::Write, value: &Value) -> fmt::Result {
if let Value::Ascii(ref v) = *value { if let Some(data) = value.ascii().and_then(|x| x.first()) {
if let Some(data) = v.first() { if data.len() >= 10 && data[4] == b':' && data[7] == b':' {
if data.len() >= 10 && data[4] == b':' && data[7] == b':' { if let Ok(year) = atou16(&data[0..4]) {
if let Ok(year) = atou16(&data[0..4]) { if let Ok(month) = atou16(&data[5..7]) {
if let Ok(month) = atou16(&data[5..7]) { if let Ok(day) = atou16(&data[8..10]) {
if let Ok(day) = atou16(&data[8..10]) { return write!(w, "{:04}-{:02}-{:02}",
return write!(w, "{:04}-{:02}-{:02}", year, month, day);
year, month, day)
}
} }
} }
} }

View File

@ -94,6 +94,42 @@ impl Value {
crate::tag::display_value_as(self, tag) crate::tag::display_value_as(self, tag)
} }
/// Returns the value as a slice if the type is BYTE.
#[inline]
pub(crate) fn byte(&self) -> Option<&[u8]> {
match *self {
Value::Byte(ref v) => Some(v),
_ => None,
}
}
/// Returns the value as `AsciiValues` if the type is ASCII.
#[inline]
pub(crate) fn ascii(&self) -> Option<AsciiValues> {
match *self {
Value::Ascii(ref v) => Some(AsciiValues(v)),
_ => None,
}
}
/// Returns the value as a slice if the type is RATIONAL.
#[inline]
pub(crate) fn rational(&self) -> Option<&[Rational]> {
match *self {
Value::Rational(ref v) => Some(v),
_ => None,
}
}
/// Returns the value as a slice if the type is UNDEFINED.
#[inline]
pub(crate) fn undefined(&self) -> Option<&[u8]> {
match *self {
Value::Undefined(ref v, _) => Some(v),
_ => None,
}
}
/// Returns the unsigned integer at the given position. /// Returns the unsigned integer at the given position.
/// None is returned if the value type is not unsigned integer /// None is returned if the value type is not unsigned integer
/// (BYTE, SHORT, or LONG) or the position is out of bounds. /// (BYTE, SHORT, or LONG) or the position is out of bounds.
@ -125,6 +161,14 @@ impl Value {
} }
} }
pub struct AsciiValues<'a>(&'a [Vec<u8>]);
impl<'a> AsciiValues<'a> {
pub fn first(&self) -> Option<&'a [u8]> {
self.0.first().map(|x| &x[..])
}
}
// A struct that wraps std::slice::Iter<'a, u8/u16/u32>. // A struct that wraps std::slice::Iter<'a, u8/u16/u32>.
pub struct UIntIter<'a> { pub struct UIntIter<'a> {
iter: Box<dyn ExactSizeIterator<Item=u32> + 'a> iter: Box<dyn ExactSizeIterator<Item=u32> + 'a>