|
| 1 | +use crate::decoder::ifd; |
| 2 | + |
1 | 3 | macro_rules! tags { |
2 | 4 | { |
3 | 5 | // Permit arbitrary meta items, which include documentation. |
@@ -392,6 +394,111 @@ impl ValueBuffer { |
392 | 394 | } |
393 | 395 | } |
394 | 396 |
|
| 397 | +/// Create a value with native endian byte order. |
| 398 | +impl TryFrom<ifd::Value> for ValueBuffer { |
| 399 | + type Error = crate::TiffError; |
| 400 | + |
| 401 | + fn try_from(value: ifd::Value) -> Result<Self, Self::Error> { |
| 402 | + Self::try_from(&value) |
| 403 | + } |
| 404 | +} |
| 405 | + |
| 406 | +/// Create a value with native endian byte order. |
| 407 | +impl TryFrom<&'_ ifd::Value> for ValueBuffer { |
| 408 | + type Error = crate::TiffError; |
| 409 | + |
| 410 | + fn try_from(value: &'_ ifd::Value) -> Result<Self, Self::Error> { |
| 411 | + use std::borrow::Cow::{self, Borrowed, Owned}; |
| 412 | + |
| 413 | + fn bytes_of_value( |
| 414 | + value: &'_ ifd::Value, |
| 415 | + ) -> Result<(Cow<'_, [u8]>, Type), crate::TiffError> { |
| 416 | + Ok(match value { |
| 417 | + ifd::Value::List(values) => { |
| 418 | + let mut type_ = None; |
| 419 | + let mut bytes = vec![]; |
| 420 | + |
| 421 | + // This is treated separately, also we rely on the caller being faithful in their |
| 422 | + // use of the ifd::Value enum. |
| 423 | + for item in values { |
| 424 | + let (value, newty) = bytes_of_value(item)?; |
| 425 | + |
| 426 | + if type_.map_or(false, |ty| ty != newty) { |
| 427 | + return Err(crate::TiffError::UnsupportedError( |
| 428 | + crate::error::TiffUnsupportedError::UnsupportedDataType, |
| 429 | + )); |
| 430 | + } |
| 431 | + |
| 432 | + type_ = Some(newty); |
| 433 | + bytes.extend_from_slice(&value); |
| 434 | + } |
| 435 | + |
| 436 | + let Some(ty) = type_ else { |
| 437 | + return Err(crate::TiffError::UnsupportedError( |
| 438 | + crate::error::TiffUnsupportedError::UnsupportedDataType, |
| 439 | + )); |
| 440 | + }; |
| 441 | + |
| 442 | + (Owned(bytes), ty) |
| 443 | + } |
| 444 | + ifd::Value::Byte(val) => (Borrowed(bytemuck::bytes_of(val)), Type::BYTE), |
| 445 | + ifd::Value::Short(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SHORT), |
| 446 | + ifd::Value::SignedByte(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SBYTE), |
| 447 | + ifd::Value::SignedShort(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SSHORT), |
| 448 | + ifd::Value::Signed(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SLONG), |
| 449 | + ifd::Value::SignedBig(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SLONG8), |
| 450 | + ifd::Value::Unsigned(val) => (Borrowed(bytemuck::bytes_of(val)), Type::LONG), |
| 451 | + ifd::Value::UnsignedBig(val) => (Borrowed(bytemuck::bytes_of(val)), Type::LONG8), |
| 452 | + ifd::Value::Float(val) => (Borrowed(bytemuck::bytes_of(val)), Type::FLOAT), |
| 453 | + ifd::Value::Double(val) => (Borrowed(bytemuck::bytes_of(val)), Type::DOUBLE), |
| 454 | + ifd::Value::Rational(num, denom) => ( |
| 455 | + Owned([bytemuck::bytes_of(num), bytemuck::bytes_of(denom)].concat()), |
| 456 | + Type::RATIONAL, |
| 457 | + ), |
| 458 | + #[expect(deprecated)] |
| 459 | + ifd::Value::RationalBig(..) | ifd::Value::SRationalBig(..) => { |
| 460 | + return Err(crate::TiffError::UnsupportedError( |
| 461 | + crate::error::TiffUnsupportedError::UnsupportedDataType, |
| 462 | + )); |
| 463 | + } |
| 464 | + ifd::Value::SRational(num, denom) => ( |
| 465 | + Owned([bytemuck::bytes_of(num), bytemuck::bytes_of(denom)].concat()), |
| 466 | + Type::SRATIONAL, |
| 467 | + ), |
| 468 | + ifd::Value::Ascii(st) => (Borrowed(st.as_bytes()), Type::ASCII), |
| 469 | + ifd::Value::Ifd(val) => (Borrowed(bytemuck::bytes_of(val)), Type::IFD), |
| 470 | + ifd::Value::IfdBig(val) => (Borrowed(bytemuck::bytes_of(val)), Type::IFD8), |
| 471 | + }) |
| 472 | + } |
| 473 | + |
| 474 | + let byte_order = ByteOrder::native(); |
| 475 | + |
| 476 | + let (bytes, ty) = bytes_of_value(value)?; |
| 477 | + let bytes = bytes.into_owned(); |
| 478 | + |
| 479 | + // Check the count can be represented. |
| 480 | + if let ifd::Value::List(values) = value { |
| 481 | + let count = |
| 482 | + u64::try_from(values.len()).map_err(|_| crate::TiffError::LimitsExceeded)?; |
| 483 | + let expected = ty.value_bytes(count)?; |
| 484 | + |
| 485 | + if bytes.len() != expected as usize { |
| 486 | + return Err(crate::TiffError::UnsupportedError( |
| 487 | + crate::TiffUnsupportedError::UnsupportedDataType, |
| 488 | + )); |
| 489 | + } |
| 490 | + } else { |
| 491 | + debug_assert_eq!(bytes.len(), ty.byte_len().into()); |
| 492 | + } |
| 493 | + |
| 494 | + Ok(ValueBuffer { |
| 495 | + bytes, |
| 496 | + byte_order, |
| 497 | + ty, |
| 498 | + }) |
| 499 | + } |
| 500 | +} |
| 501 | + |
395 | 502 | /// Byte order of the TIFF file. |
396 | 503 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
397 | 504 | pub enum ByteOrder { |
|
0 commit comments