Skip to content

Commit 612eed0

Browse files
committed
se bulk byte order conversion for tag reads
1 parent 97fe0e9 commit 612eed0

File tree

3 files changed

+266
-97
lines changed

3 files changed

+266
-97
lines changed

src/decoder/ifd.rs

Lines changed: 193 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -565,74 +565,157 @@ impl Entry {
565565
}
566566

567567
// Case 4: there is more than one value, and it doesn't fit in the offset field.
568+
let mut v;
569+
self.set_reader_offset(bo, bigtiff, reader)?;
570+
568571
match self.type_ {
569572
// TODO check if this could give wrong results
570573
// at a different endianess of file/computer.
571-
Type::BYTE => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
572-
let mut buf = [0; 1];
573-
reader.inner().read_exact(&mut buf)?;
574-
Ok(Byte(buf[0]))
575-
}),
576-
Type::SBYTE => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
577-
Ok(SignedByte(reader.read_i8()?))
578-
}),
579-
Type::SHORT => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
580-
Ok(Short(reader.read_u16()?))
581-
}),
582-
Type::SSHORT => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
583-
Ok(SignedShort(reader.read_i16()?))
584-
}),
585-
Type::LONG => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
586-
Ok(Unsigned(reader.read_u32()?))
587-
}),
588-
Type::SLONG => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
589-
Ok(Signed(reader.read_i32()?))
590-
}),
591-
Type::FLOAT => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
592-
Ok(Float(reader.read_f32()?))
593-
}),
594-
Type::DOUBLE => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
595-
Ok(Double(reader.read_f64()?))
596-
}),
574+
Type::UNDEFINED => {
575+
v = Self::vec_with_capacity(self.count, limits)?;
576+
self.decode_values(self.count, self.type_, reader, |bytes| {
577+
v.extend(bytes.iter().copied().map(|v| Byte(v)))
578+
})
579+
}
580+
Type::BYTE => {
581+
v = Self::vec_with_capacity(self.count, limits)?;
582+
self.decode_values(self.count, self.type_, reader, |bytes| {
583+
v.extend(bytes.iter().copied().map(|v| Byte(v)))
584+
})
585+
}
586+
Type::SBYTE => {
587+
v = Self::vec_with_capacity(self.count, limits)?;
588+
self.decode_values(self.count, self.type_, reader, |bytes| {
589+
v.extend(bytes.iter().copied().map(|v| SignedByte(v as i8)))
590+
})
591+
}
592+
Type::SHORT => {
593+
v = Self::vec_with_capacity(self.count, limits)?;
594+
self.decode_values(self.count, self.type_, reader, |bytes| {
595+
v.extend(
596+
bytes
597+
.chunks_exact(2)
598+
.map(|ch| Short(u16::from_ne_bytes(ch.try_into().unwrap()))),
599+
)
600+
})
601+
}
602+
Type::SSHORT => {
603+
v = Self::vec_with_capacity(self.count, limits)?;
604+
self.decode_values(self.count, self.type_, reader, |bytes| {
605+
v.extend(
606+
bytes
607+
.chunks_exact(2)
608+
.map(|ch| SignedShort(i16::from_ne_bytes(ch.try_into().unwrap()))),
609+
)
610+
})
611+
}
612+
Type::LONG => {
613+
v = Self::vec_with_capacity(self.count, limits)?;
614+
self.decode_values(self.count, self.type_, reader, |bytes| {
615+
v.extend(
616+
bytes
617+
.chunks_exact(4)
618+
.map(|ch| Unsigned(u32::from_ne_bytes(ch.try_into().unwrap()))),
619+
)
620+
})
621+
}
622+
Type::SLONG => {
623+
v = Self::vec_with_capacity(self.count, limits)?;
624+
self.decode_values(self.count, self.type_, reader, |bytes| {
625+
v.extend(
626+
bytes
627+
.chunks_exact(4)
628+
.map(|ch| Signed(i32::from_ne_bytes(ch.try_into().unwrap()))),
629+
)
630+
})
631+
}
632+
Type::FLOAT => {
633+
v = Self::vec_with_capacity(self.count, limits)?;
634+
self.decode_values(self.count, self.type_, reader, |bytes| {
635+
v.extend(
636+
bytes
637+
.chunks_exact(4)
638+
.map(|ch| Float(f32::from_ne_bytes(ch.try_into().unwrap()))),
639+
)
640+
})
641+
}
642+
Type::DOUBLE => {
643+
v = Self::vec_with_capacity(self.count, limits)?;
644+
self.decode_values(self.count, self.type_, reader, |bytes| {
645+
v.extend(
646+
bytes
647+
.chunks_exact(8)
648+
.map(|ch| Double(f64::from_ne_bytes(ch.try_into().unwrap()))),
649+
)
650+
})
651+
}
597652
Type::RATIONAL => {
598-
self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
599-
Ok(Rational(reader.read_u32()?, reader.read_u32()?))
653+
v = Self::vec_with_capacity(self.count, limits)?;
654+
self.decode_values(self.count, self.type_, reader, |bytes| {
655+
v.extend(bytes.chunks_exact(8).map(|ch| {
656+
Rational(
657+
u32::from_ne_bytes(ch[..4].try_into().unwrap()),
658+
u32::from_ne_bytes(ch[4..].try_into().unwrap()),
659+
)
660+
}))
600661
})
601662
}
602663
Type::SRATIONAL => {
603-
self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
604-
Ok(SRational(reader.read_i32()?, reader.read_i32()?))
664+
v = Self::vec_with_capacity(self.count, limits)?;
665+
self.decode_values(self.count, self.type_, reader, |bytes| {
666+
v.extend(bytes.chunks_exact(8).map(|ch| {
667+
SRational(
668+
i32::from_ne_bytes(ch[..4].try_into().unwrap()),
669+
i32::from_ne_bytes(ch[4..].try_into().unwrap()),
670+
)
671+
}))
605672
})
606673
}
607-
Type::LONG8 => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
608-
Ok(UnsignedBig(reader.read_u64()?))
609-
}),
610-
Type::SLONG8 => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
611-
Ok(SignedBig(reader.read_i64()?))
612-
}),
613-
Type::IFD => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
614-
Ok(Ifd(reader.read_u32()?))
615-
}),
616-
Type::IFD8 => self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
617-
Ok(IfdBig(reader.read_u64()?))
618-
}),
619-
Type::UNDEFINED => {
620-
self.decode_offset(self.count, bo, bigtiff, limits, reader, |reader| {
621-
let mut buf = [0; 1];
622-
reader.inner().read_exact(&mut buf)?;
623-
Ok(Byte(buf[0]))
674+
Type::LONG8 => {
675+
v = Self::vec_with_capacity(self.count, limits)?;
676+
self.decode_values(self.count, self.type_, reader, |bytes| {
677+
v.extend(
678+
bytes
679+
.chunks_exact(8)
680+
.map(|ch| UnsignedBig(u64::from_ne_bytes(ch.try_into().unwrap()))),
681+
)
682+
})
683+
}
684+
Type::SLONG8 => {
685+
v = Self::vec_with_capacity(self.count, limits)?;
686+
self.decode_values(self.count, self.type_, reader, |bytes| {
687+
v.extend(
688+
bytes
689+
.chunks_exact(8)
690+
.map(|ch| SignedBig(i64::from_ne_bytes(ch.try_into().unwrap()))),
691+
)
692+
})
693+
}
694+
Type::IFD => {
695+
v = Self::vec_with_capacity(self.count, limits)?;
696+
self.decode_values(self.count, self.type_, reader, |bytes| {
697+
v.extend(
698+
bytes
699+
.chunks_exact(4)
700+
.map(|ch| Ifd(u32::from_ne_bytes(ch.try_into().unwrap()))),
701+
)
702+
})
703+
}
704+
Type::IFD8 => {
705+
v = Self::vec_with_capacity(self.count, limits)?;
706+
self.decode_values(self.count, self.type_, reader, |bytes| {
707+
v.extend(
708+
bytes
709+
.chunks_exact(8)
710+
.map(|ch| IfdBig(u64::from_ne_bytes(ch.try_into().unwrap()))),
711+
)
624712
})
625713
}
626714
Type::ASCII => {
627715
let n = usize::try_from(self.count)?;
628-
if n > limits.decoding_buffer_size {
629-
return Err(TiffError::LimitsExceeded);
630-
}
631716

632-
if bigtiff {
633-
reader.goto_offset(self.offset_field_reader(bo).read_u64()?)?
634-
} else {
635-
reader.goto_offset(self.offset_field_reader(bo).read_u32()?.into())?
717+
if n > limits.decoding_buffer_size {
718+
return Err(dbg!(TiffError::LimitsExceeded));
636719
}
637720

638721
let mut out = vec![0; n];
@@ -641,43 +724,81 @@ impl Entry {
641724
if let Some(first) = out.iter().position(|&b| b == 0) {
642725
out.truncate(first);
643726
}
644-
Ok(Ascii(String::from_utf8(out)?))
727+
728+
return Ok(Ascii(String::from_utf8(out)?));
645729
}
646-
}
730+
}?;
731+
732+
Ok(List(v))
647733
}
648734

649-
#[inline]
650-
fn decode_offset<R, F>(
651-
&self,
735+
fn vec_with_capacity(
652736
value_count: u64,
653-
bo: ByteOrder,
654-
bigtiff: bool,
655737
limits: &super::Limits,
656-
reader: &mut EndianReader<R>,
657-
decode_fn: F,
658-
) -> TiffResult<Value>
659-
where
660-
R: Read + Seek,
661-
F: Fn(&mut EndianReader<R>) -> TiffResult<Value>,
662-
{
738+
) -> Result<Vec<Value>, TiffError> {
663739
let value_count = usize::try_from(value_count)?;
740+
664741
if value_count > limits.decoding_buffer_size / mem::size_of::<Value>() {
665742
return Err(TiffError::LimitsExceeded);
666743
}
667744

668-
let mut v = Vec::with_capacity(value_count);
745+
Ok(Vec::with_capacity(value_count))
746+
}
669747

748+
fn set_reader_offset<R>(
749+
&self,
750+
bo: ByteOrder,
751+
bigtiff: bool,
752+
reader: &mut EndianReader<R>,
753+
) -> TiffResult<()>
754+
where
755+
R: Read + Seek,
756+
{
670757
let offset = if bigtiff {
671758
self.offset_field_reader(bo).read_u64()?
672759
} else {
673760
self.offset_field_reader(bo).read_u32()?.into()
674761
};
762+
675763
reader.goto_offset(offset)?;
676764

677-
for _ in 0..value_count {
678-
v.push(decode_fn(reader)?)
765+
Ok(())
766+
}
767+
768+
#[inline]
769+
fn decode_values<R, F>(
770+
&self,
771+
value_count: u64,
772+
type_: Type,
773+
reader: &mut EndianReader<R>,
774+
mut collect: F,
775+
) -> TiffResult<()>
776+
where
777+
R: Read + Seek,
778+
F: FnMut(&[u8]),
779+
{
780+
let mut total_bytes = type_.value_bytes(value_count)?;
781+
let mut buffer = [0u8; 512];
782+
783+
let buf_unit = usize::from(type_.byte_len());
784+
let mul_of_ty = buffer.len() / buf_unit * buf_unit;
785+
786+
let cls = type_.byte_order_class();
787+
let native = ByteOrder::native();
788+
789+
while total_bytes > 0 {
790+
// `now <= mul_of_ty < 512` so casting is mathematical
791+
let now = total_bytes.min(mul_of_ty as u64);
792+
total_bytes -= now;
793+
794+
let buffer = &mut buffer[..now as usize];
795+
reader.inner().read_exact(buffer)?;
796+
797+
reader.byte_order.convert_class(cls, buffer, native);
798+
collect(buffer);
679799
}
680-
Ok(List(v))
800+
801+
Ok(())
681802
}
682803
}
683804

src/decoder/mod.rs

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -535,32 +535,16 @@ fn invert_colors(
535535

536536
/// Fix endianness. If `byte_order` matches the host, then conversion is a no-op.
537537
fn fix_endianness(buf: &mut [u8], byte_order: ByteOrder, bit_depth: u8) {
538-
match byte_order {
539-
ByteOrder::LittleEndian => match bit_depth {
540-
0..=8 => {}
541-
9..=16 => buf.chunks_exact_mut(2).for_each(|v| {
542-
v.copy_from_slice(&u16::from_le_bytes((*v).try_into().unwrap()).to_ne_bytes())
543-
}),
544-
17..=32 => buf.chunks_exact_mut(4).for_each(|v| {
545-
v.copy_from_slice(&u32::from_le_bytes((*v).try_into().unwrap()).to_ne_bytes())
546-
}),
547-
_ => buf.chunks_exact_mut(8).for_each(|v| {
548-
v.copy_from_slice(&u64::from_le_bytes((*v).try_into().unwrap()).to_ne_bytes())
549-
}),
550-
},
551-
ByteOrder::BigEndian => match bit_depth {
552-
0..=8 => {}
553-
9..=16 => buf.chunks_exact_mut(2).for_each(|v| {
554-
v.copy_from_slice(&u16::from_be_bytes((*v).try_into().unwrap()).to_ne_bytes())
555-
}),
556-
17..=32 => buf.chunks_exact_mut(4).for_each(|v| {
557-
v.copy_from_slice(&u32::from_be_bytes((*v).try_into().unwrap()).to_ne_bytes())
558-
}),
559-
_ => buf.chunks_exact_mut(8).for_each(|v| {
560-
v.copy_from_slice(&u64::from_be_bytes((*v).try_into().unwrap()).to_ne_bytes())
561-
}),
562-
},
538+
let host = ByteOrder::native();
539+
540+
let class = match bit_depth {
541+
0..=8 => crate::tags::ByteOrderClass::OneByte,
542+
9..=16 => crate::tags::ByteOrderClass::TwoByte,
543+
17..=32 => crate::tags::ByteOrderClass::FourByte,
544+
_ => crate::tags::ByteOrderClass::EightByte,
563545
};
546+
547+
host.convert_class(class, buf, byte_order);
564548
}
565549

566550
impl<R: Read + Seek> Decoder<R> {
@@ -747,6 +731,11 @@ impl<R: Read + Seek> Decoder<R> {
747731
}
748732

749733
/// Returns the byte_order of the file.
734+
///
735+
/// # Usage
736+
///
737+
/// This is only relevant to interpreting raw bytes read from tags. The image decoding methods
738+
/// will correct to the host byte order automatically.
750739
pub fn byte_order(&self) -> ByteOrder {
751740
self.value_reader.reader.byte_order
752741
}

0 commit comments

Comments
 (0)